Use `Annotated` to add aliases to options
The documentation gives an example of how to create aliases:
def echo(*text:Parameter.REQUIRED,
prefix:'p'='', suffix:'s'='', reverse:'r'=False, repeat:'n'=1):
...
This, however, causes most linters to warn:
Unresolved reference 'p'
for all the aliases thus defined.
Since Python 3.9, typing.Annotated is available to add metadata to annotations, so this could be defined as
def echo(*text:Parameter.REQUIRED,
prefix: Annotated[str, 'p'] ='',
suffix: Annotated[str, 's'] = '',
reverse: Annotated[str, 'r'] = False,
repeat: Annotated[int, 'n'] = 1,
):
...
and linters wouldn't complain.
Hello!
Currently there is rudimentary support for using typing.Annotated in 5.0.0. It is not in the documentation, but there is an example that uses it: https://github.com/epsy/clize/blob/v5.0.0/examples/typed_cli.py
You have to wrap parts of the annotation meant for Clize with Clize[], for example your example would read:
def echo(*text:Parameter.REQUIRED,
prefix: Annotated[str, Clize['p']] ='',
suffix: Annotated[str, Clize['s']] = '',
reverse: Annotated[bool, Clize['r']] = False,
repeat: Annotated[int, Clize['n']] = 1,
):
...
There's room to make this better, but this is a start. Let me know if you have feedback or ideas.
Is Clize needed? Can't just be a Literal?
It is kind of needed for me to require it, yes.
See PEP 593 which introduces typings.Annotated, which says:
Ultimately, the responsibility of how to interpret the annotations (if at all) is the responsibility of the tool or library encountering the Annotated type. A tool or library encountering an Annotated type can scan through the annotations to determine if they are of interest (e.g., using isinstance()).
and then later:
Namespaces are not needed for annotations since the class used by the annotations acts as a namespace.
So it seems like the PEP expects library authors to distinguish different annotations by their type, so unfortunately str would be too ambiguous.
I hear you on this being very verbose. The PEP has a suggestion on the subject:
T = TypeVar('T')
Const = Annotated[T, my_annotations.CONST]
class C:
def const_method(self: Const[List[int]]) -> int:
Perhaps in the future it could be applied like:
ValueType = TypeVar("ValueType")
ClizeAnnotationsT = TypeVar("ClizeAnnotationsT")
TypeAndClize = typings.Annotated[T, ClizeAnnotationsT]
def main(prefix: TypeAndClize[str, "p"]):
...
Though I think Clize may have to be updated to understand TypeVar/ClizeAnnotationsT
Though I think Clize may have to be updated to understand TypeVar/ClizeAnnotationsT
Agreed. And we may need to say something like
def main(a: str, b: Annotated[int, Parameter.REQUIRED]):
...
I don't know how to handle this case without Annotated...