Comments (8)
I think I found the error source, but I don't know how to fix.
The custom formatter is called by NewFormatter
, a class declared in the wrapper itself. This class has the format_unit
method which prepares the unit with pint.delegates.formatter._compound_unit_helpers.prepare_compount_unit
. In the case of a dimensionless quantity, that last function has a conditional I don't understand:
pint/pint/delegates/formatter/_compound_unit_helpers.py
Lines 268 to 271 in ad02b87
So with a spec without a "~", the first output of prepare_compount_unit
is [("dimensionless", 1)]
. NewFormatter
goes on and wraps this into a UnitsContainer
:
pint/pint/delegates/formatter/_to_register.py
Line 102 in ad02b87
The resulting container prints (repr) as <UnitsContainer({'dimensionless': 1})>
. However, if we go back to the initial unit, its container rather prints as repr(u._units)
<UnitsContainer({})>
. I thus assume the first UnitsContainer, the one sent by NewFormatter
to the custom function, is wrong.
from pint.
Adding return ([("dimensionless", 1)], [])
was the most obvious way I saw to get the formatters to return "dimensionless" as the longform. I'm not sure what the previous behaviour was.
Why do you need to create a unit inside your custom formatter?
from pint.
Because the custom formatter builds on the default formatter. For calling the default one it needs a Unit object.
But I guess one solution would be to copy the formatter
call from the default formatter instead of actually calling it. Hopefully, that solution would work with previous pint versions as well.
from pint.
@aulemahal Can you provide a little bit more in detail you use case? I do not understand it too well.
from pint.
My usecase is this : https://github.com/xarray-contrib/cf-xarray/blob/c511cc5624ef0a217e83cb0f820a7acd16b877ae/cf_xarray/units.py#L19 I myself didn't write this function, but I think the code comes from a time where this was done outside of pint, not as a custom formatter, which might explain why it looks weird.
To make things simple we begin by format the units using the short default format ("~D"). Then, using regex we split the result into its components to remove the division and exponentiation signs. Then remove the multiplication signs, replace "Δ" with "delta" and "percent" with "%".
I had not re-read the exact way this was written and I now realize this is much more complex than re-writing the units directly from the container. The only issue I foresee is that we would want the "cf" formatter to always act as a short one, as if "~cf" was written.
from pint.
If you are sure that the input is unit, then recreating is not necessary.
You can also subclass the existing formatter, this would be a direct replacement to your (I haven't tried yet)
class MyFormatter(DefaultFormatter):
def format_unit(
self,
unit: PlainUnit | Iterable[tuple[str, Any]],
uspec: str = "",
sort_func: SortFunc | None = None,
**babel_kwds: Unpack[BabelKwds],
) -> str:
"""Format a unit (can be compound) into string
given a string formatting specification and locale related arguments.
"""
if "~" not in uspec:
uspec = "~" + uspec
s = super().format_unit(unit, uspec, sort_func, **babal_kwds)
# Search and replace patterns
pat = r"(?P<inverse>(?:1 )?/ )?(?P<unit>\w+)(?: \*\* (?P<pow>\d))?"
def repl(m):
i, u, p = m.groups()
p = p or (1 if i else "")
neg = "-" if i else ""
return f"{u}{neg}{p}"
out, n = re.subn(pat, repl, s)
# Remove multiplications
out = out.replace(" * ", " ")
# Delta degrees:
out = out.replace("Δ°", "delta_deg")
return out.replace("percent", "%")
# we need a better way here
ureg.formatter._formatters["cf"] = MyFormatter
and then if you look into the DefaultFormatter you can actually directly copy the parse_unit and avoid calling the super function.
from pint.
By the way, I want to change the prepare_compount_unit
function to stop accepting spec
. The only spec that is used now is ~
. So I would rather have a boolean flag about using the short version.
from pint.
Closing this as it makes more sense to fix the issue in cf-xarray
.
from pint.
Related Issues (20)
- KeyError when using Quantity.check("dimensionless")
- Temperature conversion issue HOT 1
- Get the dimensionality of quantities whose units are ratios of the same unit
- parse_pattern doesn´t parse compound units HOT 4
- degree_Celsius to_compact raises DimensionalityError (Pint 0.23) HOT 1
- 0.24: pytest fails in 4 units HOT 12
- Default format of dimensionless Unit: undocumented change in 0.24 HOT 2
- Another package for ecosystem.rst HOT 4
- What does `registry=None` mean in custom formatter ? HOT 5
- Issue using currency symbols ($, €) HOT 4
- pint-convert fails with uncertainties related error if numpy is not installed as well - document numpy dependence or give a better error message HOT 13
- Custom formatters not working with modifiers (Undocumented breaking change in 0.24) HOT 4
- Euro symbol cannot be parsed by the UnitRegistry HOT 1
- regression on python 3.12 UndefinedUnitError for string `−66.11*10**-62` HOT 3
- TypeError: unsupported operand type(s) for -: 'ParserHelper' and 'ParserHelper'
- strange behavior when using @ureg.wraps HOT 1
- Operations with pandas 3
- Verification on unit conversion: `1 * ureg.electron_volt / ureg.angstrom**3 == 1 / (1e3 * ureg.joule) * 1.0e24 * 1e9 * ureg.pascal`. HOT 1
- Default Unit registry initialization is not thread safe
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pint.