Skip to content

Commit b343dc3

Browse files
authored
Merge pull request #70 from mpkocher/use-pydantic-repr
Use FieldInfo repr. This non-trivially changes how the output is displayed.
2 parents 5df8a90 + 13b3a4b commit b343dc3

File tree

3 files changed

+11
-58
lines changed

3 files changed

+11
-58
lines changed

.github/workflows/pre-commit.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ jobs:
1111
steps:
1212
- uses: actions/checkout@v4
1313
- uses: actions/setup-python@v5
14+
with:
15+
python-version: '3.12'
1416
- uses: pre-commit/action@v3.0.1

pydantic_cli/__init__.py

Lines changed: 8 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
import traceback
66
import logging
77
import typing
8+
from copy import deepcopy
89
from typing import overload
910
from typing import Any, Mapping, Callable
1011

1112

1213
import pydantic
1314
from pydantic import BaseModel
1415
from pydantic.fields import FieldInfo
15-
from pydantic_core import PydanticUndefined
1616

1717
from ._version import __version__
1818

@@ -61,7 +61,6 @@ def run(self) -> None: ...
6161
SubCmdKlassT = Mapping[str, CmdKlassT]
6262
CmdOrSubCmdKlassT = CmdKlassT | SubCmdKlassT
6363
NOT_PROVIDED = ...
64-
NONE_TYPE = type(None)
6564

6665

6766
def _is_sequence(annotation: Any) -> bool:
@@ -76,54 +75,6 @@ def _is_sequence(annotation: Any) -> bool:
7675
return getattr(annotation, "__origin__", "NOTFOUND") in ALL_SEQ
7776

7877

79-
def __try_to_pretty_type(field_type: Any) -> str:
80-
"""
81-
This is a marginal improvement to get the types to be
82-
displayed in slightly better format.
83-
84-
FIXME. This needs to be display Union types better.
85-
"""
86-
87-
args = typing.get_args(field_type)
88-
if args:
89-
if len(args) == 1:
90-
name = field_type.__name__
91-
else:
92-
name = "|".join(map(lambda x: x.__name__, args))
93-
else:
94-
try:
95-
name = field_type.__name__
96-
except AttributeError:
97-
name = repr(field_type)
98-
99-
return f"type:{name}"
100-
101-
102-
def __to_type_description(
103-
default_value: Any = NOT_PROVIDED,
104-
field_type: Any = NOT_PROVIDED,
105-
allow_none: bool = False,
106-
is_required: bool = False,
107-
) -> str:
108-
t = "" if field_type is NOT_PROVIDED else __try_to_pretty_type(field_type)
109-
110-
# avoid using in with a Set to avoid assumptions that default_value is hashable
111-
allowed_defaults: list[Any] = (
112-
[NOT_PROVIDED, PydanticUndefined]
113-
if allow_none
114-
else [NOT_PROVIDED, PydanticUndefined, None, type(None)]
115-
)
116-
v = (
117-
""
118-
if any((default_value is x) for x in allowed_defaults)
119-
else f"default:{default_value}"
120-
)
121-
required = " *required*" if is_required else ""
122-
sep = " " if v else ""
123-
xs = sep.join([t, v]) + required
124-
return xs
125-
126-
12778
@pydantic.validate_call
12879
def __process_tuple(tuple_one_or_two: Tuple1or2Type, long_arg: str) -> Tuple1or2Type:
12980
"""
@@ -180,7 +131,6 @@ def _add_pydantic_field_to_parser(
180131
"""
181132

182133
default_long_arg = "".join([long_prefix, field_id])
183-
description = field_info.description
184134
# there's mypy type issues here
185135
cli_custom_: Tuple1or2Type = (
186136
(default_long_arg,)
@@ -190,7 +140,6 @@ def _add_pydantic_field_to_parser(
190140
cli_short_long: Tuple1or2Type = __process_tuple(cli_custom_, default_long_arg)
191141

192142
is_required = field_info.is_required()
193-
is_nullable = type(None) in typing.get_args(field_info.annotation)
194143
default_value = field_info.default
195144
is_sequence = _is_sequence(field_info.annotation)
196145

@@ -200,19 +149,21 @@ def _add_pydantic_field_to_parser(
200149
default_value = override_value
201150
is_required = False
202151

203-
type_desc = __to_type_description(
204-
default_value, field_info.annotation, is_nullable, is_required
205-
)
152+
# Delete cli and json_schema_extras metadata isn't in FieldInfo and won't be displayed
153+
# Not sure if this is the correct, or expected behavior.
154+
cfield_info = deepcopy(field_info)
155+
cfield_info.json_schema_extra = None
156+
# write this to keep backward compat with 3.10
157+
help_ = "".join(["Field(", field_info.__repr_str__(", "), ")"])
206158

207159
# log.debug(f"Creating Argument Field={field_id} opts:{cli_short_long}, allow_none={field.allow_none} default={default_value} type={field.type_} required={is_required} dest={field_id} desc={description}")
208160

209161
# MK. I don't think there's any point trying to fight with argparse to get
210162
# the types correct here. It's just a mess from a type standpoint.
211163
shape_kw = {"nargs": "+"} if is_sequence else {}
212-
desc = description or ""
213164
parser.add_argument(
214165
*cli_short_long,
215-
help=f"{desc} ({type_desc})",
166+
help=help_,
216167
default=default_value,
217168
dest=field_id,
218169
required=is_required,

pydantic_cli/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "9.0.0"
1+
__version__ = "9.1.0"

0 commit comments

Comments
 (0)