Skip to content
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

Custom formatters not working with modifiers (Undocumented breaking change in 0.24) #2017

Closed
ManuelHu opened this issue Jun 20, 2024 · 4 comments · Fixed by #2021
Closed

Comments

@ManuelHu
Copy link

Combining a custom format registered with @pint.register_unit_format and a modifier does not work on 0.24 any more. Apparently the formatter is silently not even called.

import pint

ureg = pint.get_application_registry().get()

@pint.register_unit_format("test")
def _test_format(unit, registry, **options):
    print("format called")
    proc = {u.replace("µ", "u"): e for u, e in unit.items()}
    fmt = pint.formatting if hasattr(pint, "formatting") else pint
    return fmt.formatter(
        proc.items(),
        as_ratio=True,
        single_denominator=False,
        product_fmt="*",
        division_fmt="/",
        power_fmt="{}{}",
        parentheses_fmt="({})",
        **options,
    )

base_unit = ureg.microsecond
print(f"with modifier - {base_unit:~test}")
print(f"without modifier - {base_unit:test}")

Output on pint 0.23

format called
with modifier - us
format called
without modifier - microsecond

Output on pint 0.24

with modifier - µs
format called
without modifier - microsecond

unfortunately we currently have to still support python 3.9, so only supporting pint 0.24+ is not an option for us, our code has to work on both versions... :-(

@hgrecco
Copy link
Owner

hgrecco commented Jun 20, 2024

I think this is the same problem that is fixed in #2011

@ManuelHu
Copy link
Author

ManuelHu commented Jun 20, 2024

I tried to apply that patch locally, and it does not work.

For more debuggin I added a print statement like this https://github.com/hgrecco/pint/pull/2011/files#diff-78134f4ee1d9944843acb020969e96a7d9541da73502c992a4fa1a1567251154L105:

     def get_formatter(self, spec: str):
         if spec == "":
             return self._formatters["D"]
         for k, v in self._formatters.items():
             if k in spec:
                 return v
+        print(spec)
         try:
             orphan_fmt = REGISTERED_FORMATTERS[spec]
         except KeyError:
             return self._formatters["D"]

which gives a spec of ~test in my testcase above. And that format spec is certainly not defined, as it still contains the ~ modifier - so the default Dformat spec is used.

@hgrecco
Copy link
Owner

hgrecco commented Jun 21, 2024

The problem is that is returning an orphan formatter (i.e. one not attached to the registry)

Try replacing:

        try:
            orphan_fmt = REGISTERED_FORMATTERS[spec]
        except KeyError:
            return self._formatters["D"]

by

        for k, v in REGISTERED_FORMATTERS.items():
            if k in spec:
                orphan_fmt = REGISTERED_FORMATTERS[spec]
                break
        else:
            return self._formatters["D"]

Please notice that the check is: if k in spec:. That means that if k == test and spec == ~test this should return the right formatter.

If it works, please submit a PR linking to @2011 ping: @andrewgsavage

@andrewgsavage
Copy link
Collaborator

should be working now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants