-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CF unit formatter incompatible with latest pint #522
Comments
I realized our method was a bit complicated and could be made simpler using pint formatting tools instead of regex. However, I haven't found a solution that was backwards-compatible. Here are 3 solutions I found: Custom formatter classIdea suggested by @hgrecco from pint.delegates.formatter.plain import DefaultFormatter
from pint.delegates.formatter._compound_unit_helpers import prepare_compount_unit
from pint import formatter
class CFUnitFormatter(DefaultFormatter):
def format_unit(self, unit, uspec, sort_func, **babel_kwds):
numerator, denominator = prepare_compount_unit(
unit,
"~D",
sort_func=sort_func,
**babel_kwds,
registry=self._registry,
)
out = formatter(
numerator,
denominator,
as_ratio=False,
product_fmt=" ",
power_fmt="{}{}",
parentheses_fmt=r"{}",
)
out = out.replace("Δ°", "delta_deg")
return out.replace("percent", "%")`
# Add to the registry
units.formatter._formatters['cf'] = CFUnitFormatter
Simpler custom function@pint.register_unit_format("cf")
def short_formatter(unit, registry, **options):
num = [(u, e) for u, e in unit.items() if e >= 0]
den = [(u, e) for u, e in unit.items() if e < 0]
# in pint < 0.24, the first argument of `formatter` is num + den
# a test with packaging.version could make this work for all pint versions
out = formatter(
num,
den,
as_ratio=False,
product_fmt="{} {}",
power_fmt="{}{}"
)
out = out.replace("Δ°", "delta_deg")
return out.replace("percent", "%") The trouble here is that we don't have control on the "shortening" of the units. What was previously
Hack and forgetSimply fix the dimensionless issue and don't think about it anymore. @pint.register_unit_format("cf")
def short_formatter(unit, registry, **options):
import re
# avoid issue in pint >= 0.24.1
unit = unit._units.__class__({k.replace('dimensionless', ''): v for k, v in unit._units.items()})
# convert UnitContainer back to Unit
unit = registry.Unit(unit)
# Print units using abbreviations (millimeter -> mm)
s = f"{unit:~D}"
# 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", "%")
|
I found something that works in all cases! @pint.register_unit_format("cf")
def short_formatter(unit, registry, **options):
# pint 0.24.1 gives this for dimensionless units
if unit == {'dimensionless': 1}:
return ""
# Shorten the names
unit = pint.util.UnitsContainer({
registry._get_symbol(u): exp
for u, exp in unit.items()
})
if Version(pint.__version__) < Version('0.24'):
args = (unit.items(),)
else:
args = (
((u, e) for u, e in unit.items() if e >= 0),
((u, e) for u, e in unit.items() if e < 0),
)
out = pint.formatter(
*args,
as_ratio=False,
product_fmt=" ",
power_fmt="{}{}"
)
out = out.replace("Δ°", "delta_deg")
return out.replace("percent", "%") Should gives the same result as before for all versions of pint (except 0.24.0, of course). In pint < 0.24, a dimensionless unit will yield I am using |
Nice work! Happy to merge this change. Let's also add a Just curious, why |
The Both "Δ°C" and "delta_degC" are not recognized by udunits, so my guess is that this is to avoid unicode problems down the line in a netCDF ? I recently stumbled upon these delta in xclim and I added an automatic translation into the related absolute unit in the specific function. ( |
Let's add that as a comment in the code when you send in your PR. |
With pint 0.24, the formatting machinery changed a lot. In 0.24.0 our formatter broke because we couldn't re-create Unit object, the registry was None (see hgrecco/pint#2009), this was fixed, but another bugfix broke the specific case of a dimensionless variable, see hgrecco/pint#2024.
MWE with cf-xarray
raises the error shown in the pint issue.
The text was updated successfully, but these errors were encountered: