1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
from __future__ import annotations
from dataclasses import dataclass
from typing import Annotated, NamedTuple, TypedDict
import attrs
from pydantic import BaseModel
from cyclopts import Parameter
def test_future_annotations_basic(app, assert_parse_args):
@app.default
def default(value: str):
pass
assert_parse_args(default, "foo", "foo")
# TODO: Resolving stringified type-hinted class with closure/local scope
# is really hard.
@dataclass
class DataclassMovie:
title: str
year: int
def test_future_annotations_dataclass(app, assert_parse_args):
"""
https://github.com/BrianPugh/cyclopts/issues/352
"""
@app.command
def add(movie: DataclassMovie):
print(f"Adding movie: {movie}")
assert_parse_args(add, "add BladeRunner 1982", DataclassMovie("BladeRunner", 1982))
# This is unrelated to "from __future__ import annotations", but it's a very similar problem
class GenericMovie:
def __init__(self, title: str, year: int):
self.title = title
self.year = year
def __eq__(self, other):
if not isinstance(other, type(self)):
return False
return self.title == other.title and self.year == other.year
def test_future_annotations_generic_class(app, assert_parse_args):
@app.command
def add(movie: Annotated[GenericMovie, Parameter(accepts_keys=True)]):
print(f"Adding movie: {movie}")
assert_parse_args(add, "add BladeRunner 1982", GenericMovie("BladeRunner", 1982))
@attrs.define
class AttrsMovie:
title: str
year: int
def test_future_annotations_attrs_movie(app, assert_parse_args):
@app.command
def add(movie: Annotated[AttrsMovie, Parameter(accepts_keys=True)]):
print(f"Adding movie: {movie}")
assert_parse_args(add, "add BladeRunner 1982", AttrsMovie("BladeRunner", 1982))
class TypedDictMovie(TypedDict):
title: str
year: int
def test_future_annotations_typed_dict_movie(app, assert_parse_args):
@app.command
def add(movie: Annotated[TypedDictMovie, Parameter(accepts_keys=True)]):
print(f"Adding movie: {movie}")
assert_parse_args(
add, "add --movie.title=BladeRunner --movie.year=1982", TypedDictMovie(title="BladeRunner", year=1982)
)
class NamedTupleMovie(NamedTuple):
title: str
year: int
def test_future_annotations_named_tuple_movie(app, assert_parse_args):
@app.command
def add(movie: Annotated[NamedTupleMovie, Parameter(accepts_keys=True)]):
print(f"Adding movie: {movie}")
assert_parse_args(add, "add BladeRunner 1982", NamedTupleMovie(title="BladeRunner", year=1982))
class PydanticMovie(BaseModel):
title: str
year: int
def test_future_annotations_pydantic_movie(app, assert_parse_args):
@app.command
def add(movie: Annotated[PydanticMovie, Parameter(accepts_keys=True)]):
print(f"Adding movie: {movie}")
assert_parse_args(add, "add BladeRunner 1982", PydanticMovie(title="BladeRunner", year=1982))
|