brentyi / tyro

CLI interfaces & config objects, from types
https://brentyi.github.io/tyro
MIT License
467 stars 23 forks source link

Support `typing.Self` #119

Closed apoorvkh closed 7 months ago

apoorvkh commented 7 months ago

Hey Brent -- thanks once again for this great library! I am using it in several projects.

I was wondering if you can add support for the typing.Self (or typing_extensions.Self) type.

As a minimal example, I think the following script should have a CLI prompt for --a [int] --b [int].

from dataclasses import dataclass

import tyro
from typing_extensions import Self

@dataclass
class Experiment:
    a: int
    b: int

    @classmethod
    def run(cls, experiment: Self) -> None:
        print(experiment.a + experiment.b)

if __name__ == "__main__":
    tyro.cli(Experiment.run)

But it results in the following error:

Traceback (most recent call last):
  File "test.py", line 18, in <module>
    tyro.cli(Experiment.run)
  File ".venv/lib/python3.9/site-packages/tyro/_cli.py", line 187, in cli
    output = _cli_impl(
  File ".venv/lib/python3.9/site-packages/tyro/_cli.py", line 378, in _cli_impl
    parser_spec = _parsers.ParserSpecification.from_callable_or_type(
  File ".venv/lib/python3.9/site-packages/tyro/_parsers.py", line 123, in from_callable_or_type
    if field_out.lowered.required:
  File ".venv/lib/python3.9/functools.py", line 993, in __get__
    val = self.func(instance)
  File ".venv/lib/python3.9/site-packages/tyro/_arguments.py", line 200, in lowered
    return functools.reduce(
  File ".venv/lib/python3.9/site-packages/tyro/_arguments.py", line 201, in <lambda>
    lambda lowered, rule: rule(self, lowered),
  File ".venv/lib/python3.9/site-packages/tyro/_arguments.py", line 313, in _rule_recursive_instantiator_from_type
    instantiator, metadata = _instantiators.instantiator_from_type(
  File ".venv/lib/python3.9/site-packages/tyro/_instantiators.py", line 214, in instantiator_from_type
    elif not is_type_string_converter(typ):
  File ".venv/lib/python3.9/site-packages/tyro/_instantiators.py", line 124, in is_type_string_converter
    type_annotations = _resolver.get_type_hints_with_nicer_errors(typ)
  File ".venv/lib/python3.9/site-packages/tyro/_resolver.py", line 369, in get_type_hints_with_nicer_errors
    raise e
  File ".venv/lib/python3.9/site-packages/tyro/_resolver.py", line 345, in get_type_hints_with_nicer_errors
    return get_type_hints(obj, include_extras=include_extras)
  File ".venv/lib/python3.9/site-packages/typing_extensions.py", line 1104, in get_type_hints
    hint = typing.get_type_hints(
  File ".venv/lib/python3.9/typing.py", line 1482, in get_type_hints
    raise TypeError('{!r} is not a module, class, method, '

I know that I could create a separate function (i.e. not a @classmethod) to do this, but I would prefer to do it this way, because I would like to subclass my Experiment class and this way would be more convenient.

Thanks for your consideration!

apoorvkh commented 7 months ago

That's awesome, thanks so much for the quick addition @brentyi!

I tried it and it works on my end 👍