Skip to content

units.quantity_input with annotated Quantity type hint in a Union causes error #17017

@vandalt

Description

@vandalt

Description

Hi!

I'm not sure if this is a bug report or feature request for unsupported use case.

I have a case where an argument could be either a Quantity or a string that will later be converted to quantity. I tried type hinting with Union[Quantity["angle"], str], but this causes the error shown below when using a string as the argument. See the minimal example below for the error when using the units.quantity_input decorator.

My understanding of the issue is it comes from the QuantityInput decorator: non-quantity parts of the Union are set to False and then dropped from valid_targets before the decorator performs a check on the quantity. Then if the argument is not a quantity the check will fail because the string has no units.

Thank you!

Expected behavior

The behavior I would have expected is that non-quantity types are considered as part of the Union when validating the input. I could see two ways to fix/support this:

  1. Recognize other types parts of Union and check if the argument isinstance of one of them when it's not a Quantity
  2. When the type is a union, just drop validation, as would be the case with a non-annotated quantity. I think this is less desirable as it could let pass wrong units unexpectedly for users.

I could try implementing one of these if you think it is a good way forward.

How to Reproduce

  1. Install latest main branch from github
  2. Run the snippet below
  3. Get the error below the snippet

The code:

from typing import Union

import astropy.units as u
from astropy.units import Quantity


@u.quantity_input
def afun(length_or_str: Union[Quantity["length"], str]):
    print(f"Worked with {length_or_str}")

afun(1 * u.m)  # Works
afun("1m")  # Fails

The error:

Worked with 1.0 m
Traceback (most recent call last):
  File "/home/vandal/repos/astro/astropy/astropy/units/decorators.py", line 69, in _validate_arg_value
    if arg.unit.is_equivalent(allowed_unit, equivalencies=equivalencies):
       ^^^^^^^^
AttributeError: 'str' object has no attribute 'unit'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/vandal/repos/astro/astropy/quantity_input_minimal.py", line 12, in <module>
    afun("1m")  # Fails
    ^^^^^^^^^^
  File "/home/vandal/repos/astro/astropy/astropy/units/decorators.py", line 298, in wrapper
    _validate_arg_value(
  File "/home/vandal/repos/astro/astropy/astropy/units/decorators.py", line 78, in _validate_arg_value
    raise TypeError(
TypeError: Argument 'length_or_str' to function 'afun' has no 'unit' attribute. You should pass in an astropy Quantity instead.

Versions

import astropy
try:
    astropy.system_info()
except AttributeError:
    import platform; print(platform.platform())
    import sys; print("Python", sys.version)
    import astropy; print("astropy", astropy.__version__)
    import numpy; print("Numpy", numpy.__version__)
    import erfa; print("pyerfa", erfa.__version__)
    try:
        import scipy
        print("Scipy", scipy.__version__)
    except ImportError:
        print("Scipy not installed")
    try:
        import matplotlib
        print("Matplotlib", matplotlib.__version__)
    except ImportError:
        print("Matplotlib not installed")
# Paste the result here
platform
--------
platform.platform() = 'Linux-6.10.9-arch1-2-x86_64-with-glibc2.40'
platform.version() = '#1 SMP PREEMPT_DYNAMIC Tue, 10 Sep 2024 14:37:32 +0000'
platform.python_version() = '3.12.5'

packages
--------
astropy              7.0.0.dev436+g3b88b55dfc
numpy                2.0.0
scipy                1.14.0
matplotlib           3.9.1
pandas               2.2.2
pyerfa               2.0.1.4

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions