Replies: 2 comments
|
The assertion is a Typer limitation for a complex list element type; moving the metadata to the outer from typing import Annotated
import typer
from astropy import units as u
app = typer.Typer()
@app.command()
def main(x: Annotated[list[str] | None, typer.Option()] = None):
times = [u.Quantity(raw).to(u.s) for raw in (x or [])]
print(times)
if __name__ == '__main__':
app()
# e.g. --x '5 s' --x '2 min'
|
|
Typer only unwraps the outer In the meantime I'd drop the metadata from the type and pass a from typing import Annotated
import typer
from astropy import units as u
def time_quantity(value: str) -> u.Quantity:
q = u.Quantity(value)
if q.unit.physical_type != u.physical.time:
raise typer.BadParameter(f"{value!r} is not a time")
return q
app = typer.Typer()
@app.command()
def main(x: Annotated[list[u.Quantity], typer.Option(parser=time_quantity)] = []):
print([q.to(u.s) for q in x])
app()Tried it on typer 0.27.2 / Python 3.12. Note you can't keep |
Uh oh!
There was an error while loading. Please reload this page.
First Check
Example Code
Description
The code results in:
AssertionError: List types with complex sub-types are not currently supported
Typer honours Annotated metadata on a scalar parameter's type, but asserts when the same type appears as a list element.
We use Astropy quantities, where the way to pin a unit or a physical type to a type is Annotated metadata:
u.Quantity[u.s] == Annotated[Quantity, Unit("s")]. So the natural spelling of "a repeatable option that takes times" is
Annotated[list[u.Quantity[u.physical.time]], typer.Option()]
which is rejected, while the scalar equivalent is fine.
We currently work around it by putting the metadata on the outer Annotated instead, which parses but reads oddly:
Annotated[list[u.Quantity], u.physical.time, typer.Option()]
Operating System
macOS
Operating System Details
No response
Project Version
Typer 0.27.2
Python Version
3.12
Additional Context
No response
All reactions