When I refactor code I often find myself tediously adding type annotations that are obvious from context: functions that don't return anything, boolean flags, etcetera. That's where autotyping comes in: it automatically adds those types and inserts the right annotations.
Autotyping can be called directly from the CLI, be used as a pre-commit hook or run via the libcst interface as a codemod.
Here's how to use it from the CLI:
pip install autotypingpython -m autotyping /path/to/my/codeBy default it does nothing; you have to add flags to make it do more transformations. The following are supported:
--none-return: add a -> None return type to functions without any
return, yield, or raise in their body--scalar-return: add a return annotation to functions that only return
literal bool, str, bytes, int, or float objects.--bool-param: add a : bool annotation to any function
parameter with a default of True or False--int-param, --float-param, --str-param, --bytes-param: add
an annotation to any parameter for which the default is a literal int,
float, str, or bytes object--annotate-optional foo:bar.Baz: for any parameter of the form
foo=None, add Baz, imported from bar, as the type. For example,
use --annotate-optional uid:my_types.Uid to annotate any uid in your
codebase with a None default as Optional[my_types.Uid].--annotate-named-param foo:bar.Baz: annotate any parameter with no
default that is named foo with bar.Baz. For example, use
--annotate-named-param uid:my_types.Uid to annotate any uid
parameter in your codebase with no default as my_types.Uid.--guess-common-names: infer certain parameter types from their names
based on common patterns in open-source Python code. For example, infer
that a verbose parameter is of type bool.--annotate-magics: add type annotation to certain magic methods.
Currently this does the following:
__str__ returns str__repr__ returns str__len__ returns int__length_hint__ returns int__init__ returns None__del__ returns None__bool__ returns bool__bytes__ returns bytes__format__ returns str__contains__ returns bool__complex__ returns complex__int__ returns int__float__ returns float__index__ returns int__exit__: the three parameters are Optional[Type[BaseException]],
Optional[BaseException], and Optional[TracebackType]__aexit__: same as __exit__--annotate-imprecise-magics: add imprecise type annotations for
some additional magic methods. Currently this adds typing.Iterator
return annotations to __iter__, __await__, and __reversed__.
These annotations should have a generic parameter to indicate what
you're iterating over, but that's too hard for autotyping to figure
out.--pyanalyze-report: takes types suggested by
pyanalyze's suggested_parameter_type
and suggested_return_type codes and applies them. You can generate these
with a command like:
pyanalyze --json-output failures.json -e suggested_return_type -e suggested_parameter_type -v .--only-without-imports: only apply pyanalyze suggestions that do not require
new imports. This is useful because suggestions that require imports may need
more manual work.There are two shortcut flags to enable multiple transformations at once:
--safe enables changes that should always be safe. This includes
--none-return, --scalar-return, and --annotate-magics.--aggressive enables riskier changes that are more likely to produce
new type checker errors. It includes all of --safe as well as --bool-param,
--int-param, --float-param, --str-param, --bytes-param, and
--annotate-imprecise-magics.Autotyping is built as a LibCST codemod; see the LibCST documentation for more information on how to use codemods.
If you wish to run things through the libcst.tool interface, you can do this like so:
.libcst.codemod.yaml with 'autotyping' in the modules list.
For an example, see the .libcst.codemod.yaml in this repo.python -m libcst.tool codemod autotyping.AutotypeCommand /path/to/my/codePre-commit hooks are scripts that runs automatically before a commit is made, which makes them really handy for checking and enforcing code-formatting (or in this case, typing)
autotyping as a pre-commit hook,
you will first need to install pre-commit if you haven't already:pip install pre-commit
.pre-commit-config.yaml file at the root
of your repository and add in:- repos:
- repo: https://github.com/JelleZijlstra/autotyping
rev: 24.9.0
hooks:
- id: autotyping
stages: [pre-commit]
types: [python]
args: [--safe] # or alternatively, --aggressive, or any of the other flags mentioned above
pre-commit install
Now whenever you commit changes, autotyping will automatically add type annotations to your code!
Autotyping is intended to be a simple tool that uses heuristics to find annotations that would be tedious to add by hand. The heuristics may fail, and after you run autotyping you should run a type checker to verify that the types it added are correct.
Known limitations:
None returnspython3 -m autotyping to invoke the tool. (Thanks to Shantanu Jain.)iterables (contributed by
Marco Gorelli)--guess-common-names (contributed by John Litborn)--safe and --aggressive flags so they don't take
ignored arguments--length-hint should return int (contributed by Nikita Sobolev)--safe and --aggressive--pyanalyze-reportNone return types to methods marked with @abstractmethod and
to methods in stub files"string" % ... is always strb"bytes" % ... is always bytesand or or operator where left and right sides are of the same type
returns that typeis, is not, in, and not in always return boolPython
100.0%
When I refactor code I often find myself tediously adding type annotations that are obvious from context: functions that don't return anything, boolean flags, etcetera. That's where autotyping comes in: it automatically adds those types and inserts the right annotations.
Autotyping can be called directly from the CLI, be used as a pre-commit hook or run via the libcst interface as a codemod.
Here's how to use it from the CLI:
pip install autotypingpython -m autotyping /path/to/my/codeBy default it does nothing; you have to add flags to make it do more transformations. The following are supported:
--none-return: add a -> None return type to functions without any
return, yield, or raise in their body--scalar-return: add a return annotation to functions that only return
literal bool, str, bytes, int, or float objects.--bool-param: add a : bool annotation to any function
parameter with a default of True or False--int-param, --float-param, --str-param, --bytes-param: add
an annotation to any parameter for which the default is a literal int,
float, str, or bytes object--annotate-optional foo:bar.Baz: for any parameter of the form
foo=None, add Baz, imported from bar, as the type. For example,
use --annotate-optional uid:my_types.Uid to annotate any uid in your
codebase with a None default as Optional[my_types.Uid].--annotate-named-param foo:bar.Baz: annotate any parameter with no
default that is named foo with bar.Baz. For example, use
--annotate-named-param uid:my_types.Uid to annotate any uid
parameter in your codebase with no default as my_types.Uid.--guess-common-names: infer certain parameter types from their names
based on common patterns in open-source Python code. For example, infer
that a verbose parameter is of type bool.--annotate-magics: add type annotation to certain magic methods.
Currently this does the following:
__str__ returns str__repr__ returns str__len__ returns int__length_hint__ returns int__init__ returns None__del__ returns None__bool__ returns bool__bytes__ returns bytes__format__ returns str__contains__ returns bool__complex__ returns complex__int__ returns int__float__ returns float__index__ returns int__exit__: the three parameters are Optional[Type[BaseException]],
Optional[BaseException], and Optional[TracebackType]__aexit__: same as __exit__--annotate-imprecise-magics: add imprecise type annotations for
some additional magic methods. Currently this adds typing.Iterator
return annotations to __iter__, __await__, and __reversed__.
These annotations should have a generic parameter to indicate what
you're iterating over, but that's too hard for autotyping to figure
out.--pyanalyze-report: takes types suggested by
pyanalyze's suggested_parameter_type
and suggested_return_type codes and applies them. You can generate these
with a command like:
pyanalyze --json-output failures.json -e suggested_return_type -e suggested_parameter_type -v .--only-without-imports: only apply pyanalyze suggestions that do not require
new imports. This is useful because suggestions that require imports may need
more manual work.There are two shortcut flags to enable multiple transformations at once:
--safe enables changes that should always be safe. This includes
--none-return, --scalar-return, and --annotate-magics.--aggressive enables riskier changes that are more likely to produce
new type checker errors. It includes all of --safe as well as --bool-param,
--int-param, --float-param, --str-param, --bytes-param, and
--annotate-imprecise-magics.Autotyping is built as a LibCST codemod; see the LibCST documentation for more information on how to use codemods.
If you wish to run things through the libcst.tool interface, you can do this like so:
.libcst.codemod.yaml with 'autotyping' in the modules list.
For an example, see the .libcst.codemod.yaml in this repo.python -m libcst.tool codemod autotyping.AutotypeCommand /path/to/my/codePre-commit hooks are scripts that runs automatically before a commit is made, which makes them really handy for checking and enforcing code-formatting (or in this case, typing)
autotyping as a pre-commit hook,
you will first need to install pre-commit if you haven't already:pip install pre-commit
.pre-commit-config.yaml file at the root
of your repository and add in:- repos:
- repo: https://github.com/JelleZijlstra/autotyping
rev: 24.9.0
hooks:
- id: autotyping
stages: [pre-commit]
types: [python]
args: [--safe] # or alternatively, --aggressive, or any of the other flags mentioned above
pre-commit install
Now whenever you commit changes, autotyping will automatically add type annotations to your code!
Autotyping is intended to be a simple tool that uses heuristics to find annotations that would be tedious to add by hand. The heuristics may fail, and after you run autotyping you should run a type checker to verify that the types it added are correct.
Known limitations:
None returnspython3 -m autotyping to invoke the tool. (Thanks to Shantanu Jain.)iterables (contributed by
Marco Gorelli)--guess-common-names (contributed by John Litborn)--safe and --aggressive flags so they don't take
ignored arguments--length-hint should return int (contributed by Nikita Sobolev)--safe and --aggressive--pyanalyze-reportNone return types to methods marked with @abstractmethod and
to methods in stub files"string" % ... is always strb"bytes" % ... is always bytesand or or operator where left and right sides are of the same type
returns that typeis, is not, in, and not in always return boolPython
100.0%