Skip to content

Commit

Permalink
Use FieldInfo repr. This non-trivially changes how the output is form…
Browse files Browse the repository at this point in the history
…atted
  • Loading branch information
mpkocher committed Sep 18, 2024
1 parent 5df8a90 commit 20217fe
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 58 deletions.
58 changes: 1 addition & 57 deletions pydantic_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import pydantic
from pydantic import BaseModel
from pydantic.fields import FieldInfo
from pydantic_core import PydanticUndefined

from ._version import __version__

Expand Down Expand Up @@ -61,7 +60,6 @@ def run(self) -> None: ...
SubCmdKlassT = Mapping[str, CmdKlassT]
CmdOrSubCmdKlassT = CmdKlassT | SubCmdKlassT
NOT_PROVIDED = ...
NONE_TYPE = type(None)


def _is_sequence(annotation: Any) -> bool:
Expand All @@ -76,54 +74,6 @@ def _is_sequence(annotation: Any) -> bool:
return getattr(annotation, "__origin__", "NOTFOUND") in ALL_SEQ


def __try_to_pretty_type(field_type: Any) -> str:
"""
This is a marginal improvement to get the types to be
displayed in slightly better format.
FIXME. This needs to be display Union types better.
"""

args = typing.get_args(field_type)
if args:
if len(args) == 1:
name = field_type.__name__
else:
name = "|".join(map(lambda x: x.__name__, args))
else:
try:
name = field_type.__name__
except AttributeError:
name = repr(field_type)

return f"type:{name}"


def __to_type_description(
default_value: Any = NOT_PROVIDED,
field_type: Any = NOT_PROVIDED,
allow_none: bool = False,
is_required: bool = False,
) -> str:
t = "" if field_type is NOT_PROVIDED else __try_to_pretty_type(field_type)

# avoid using in with a Set to avoid assumptions that default_value is hashable
allowed_defaults: list[Any] = (
[NOT_PROVIDED, PydanticUndefined]
if allow_none
else [NOT_PROVIDED, PydanticUndefined, None, type(None)]
)
v = (
""
if any((default_value is x) for x in allowed_defaults)
else f"default:{default_value}"
)
required = " *required*" if is_required else ""
sep = " " if v else ""
xs = sep.join([t, v]) + required
return xs


@pydantic.validate_call
def __process_tuple(tuple_one_or_two: Tuple1or2Type, long_arg: str) -> Tuple1or2Type:
"""
Expand Down Expand Up @@ -190,7 +140,6 @@ def _add_pydantic_field_to_parser(
cli_short_long: Tuple1or2Type = __process_tuple(cli_custom_, default_long_arg)

is_required = field_info.is_required()
is_nullable = type(None) in typing.get_args(field_info.annotation)
default_value = field_info.default
is_sequence = _is_sequence(field_info.annotation)

Expand All @@ -200,19 +149,14 @@ def _add_pydantic_field_to_parser(
default_value = override_value
is_required = False

type_desc = __to_type_description(
default_value, field_info.annotation, is_nullable, is_required
)

# 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}")

# MK. I don't think there's any point trying to fight with argparse to get
# the types correct here. It's just a mess from a type standpoint.
shape_kw = {"nargs": "+"} if is_sequence else {}
desc = description or ""
parser.add_argument(
*cli_short_long,
help=f"{desc} ({type_desc})",
help=repr(field_info),
default=default_value,
dest=field_id,
required=is_required,
Expand Down
2 changes: 1 addition & 1 deletion pydantic_cli/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "9.0.0"
__version__ = "9.1.0"

0 comments on commit 20217fe

Please sign in to comment.