File: test_future_annotations.py

package info (click to toggle)
python-cyclopts 3.12.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,288 kB
  • sloc: python: 11,445; makefile: 24
file content (112 lines) | stat: -rw-r--r-- 3,005 bytes parent folder | download | duplicates (2)
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))