Skip to content

Commit

Permalink
CLI: Fix deduced option type for DynamicEntryPointCommandGroup
Browse files Browse the repository at this point in the history
The `type` for the click command options were based of the `annotation`
property of the model fields. These annotations can sometimes be
compound, however, e.g, `Union[int, float]` and `Optional[str]` but
these are not supported by `click.option`. It would more or less work
for Python 3.10 and up, but it would except for Python 3.9 because the
type would be wrapped in the `click.FuncParamType` which would call
`__name__` on the type, but this was only added in Python 3.10.

The solution is to extract the arguments in case of a compound type. The
`typing.get_args()` method does just this. If the annotation is a plain
type, it simply returns an empty tuple.
  • Loading branch information
sphuber committed Dec 12, 2023
1 parent 0a2dd6d commit f17fea2
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 1 deletion.
8 changes: 7 additions & 1 deletion aiida/cmdline/groups/dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,15 @@ def list_options(self, entry_point: str) -> list:

for key, field_info in cls.Configuration.model_fields.items():
default = field_info.default_factory if field_info.default is PydanticUndefined else field_info.default

# The ``field_info.annotation`` property returns the annotation of the field. This can be a plain type
# or a type from ``typing``, e.g., ``Union[int, float]`` or ``Optional[str]``. In these cases, the type
# that needs to be passed to ``click`` is the arguments of the type, which can be obtained using the
# ``typing.get_args()`` method. If it is not a compound type, this returns an empty tuplem so in that
# case, the type is simply the ``field_info.annotation``.
options_spec[key] = {
'required': field_info.is_required(),
'type': field_info.annotation,
'type': t.get_args(field_info.annotation) or field_info.annotation,
'prompt': field_info.title,
'default': default,
'help': field_info.description,
Expand Down
1 change: 1 addition & 0 deletions tests/cmdline/groups/test_dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ def test_list_options(entry_points):
option = option_decorators(lambda x: True).__click_params__[0]
field = CustomClass.Configuration.model_fields[option.name]
assert option.default == field.default_factory if field.default is PydanticUndefined else field.default
assert option.type == t.get_args(field.annotation) or field.annotation

0 comments on commit f17fea2

Please sign in to comment.