How to Use pyrefly infer to Generate Python Type Annotations

pyrefly infer is the built-in command that automatically adds type annotations to existing Python code by running the type checker, collecting inferred types, and inserting them directly into source files.

The pyrefly infer command in the facebook/pyrefly repository provides an automated way to add static type hints to unannotated Python codebases. This tool analyzes function bodies, determines precise types for parameters and return values, and modifies source files in-place to include the annotations.

Command-Line Interface and Flags

The pyrefly infer command accepts several flags that control which elements receive type annotations. These options are defined in the InferFlags struct located in [pyrefly/lib/commands/infer.rs](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/commands/infer.rs) (lines 52-87).

Available flags include:

  • --containers – Annotate empty containers such as list and dict with their inferred element types.
  • --return-types – Add return-type hints to function definitions (enabled by default).
  • --parameter-types – Add parameter type hints to function signatures.
  • --imports – Automatically insert required import statements for types defined in other modules.

You can negate boolean flags using the --no- prefix. For example, --no-return-types disables return-type inference while keeping parameter annotations enabled.

The Inference Pipeline

The pyrefly infer command follows a seven-stage pipeline to transform untyped Python code into fully annotated code. The core logic resides in the InferArgs::run method in [pyrefly/lib/commands/infer.rs](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/commands/infer.rs).

Configuration Enforcement

Before type checking begins, the command ensures the type checker runs with inference-specific settings. In lines 82-89 of infer.rs, the code forces two configuration options unless explicitly overridden by the user:

  • check_unannotated_defs – Ensures the analyzer processes function bodies without existing annotations.
  • infer_return_types – Enables return-type inference from return statements.

This guarantees that the checker produces the type information necessary for annotation generation.

Type Checking and Data Collection

The command creates a State object and runs a Forgetter transaction across all selected files (lines 99-124). The call to transaction.run(&handles, Require::Everything, None) executes the full type-checking pipeline in parallel.

After analysis completes, the system extracts inferred types through two primary methods:

  • transaction.inferred_types – Returns tuples of (position, Type, AnnotationKind) for return values and variables (line 126).
  • transaction.infer_parameter_annotations – Provides inferred parameter hints when the --parameter-types flag is enabled (lines 128-131).

Formatting and Import Resolution

The format_hints function (lines 74-126) processes the raw type data by:

  1. Filtering out undesirable types such as Any, Unknown, and Overload.
  2. Converting each Type into a printable string using hint_to_string.
  3. Recording which modules require imports to support the generated annotations.

This step ensures that generated annotations use valid Python syntax and that all referenced types are importable.

File Modification

The command writes annotations back to disk using two specialized functions:

  • add_annotations_to_file (lines 88-103) – Inserts formatted type strings (: type for parameters, -> type for returns) at the exact byte offsets recorded during analysis.
  • add_imports_to_file (lines 104-117) – Adds necessary from <module> import <name> statements immediately after any __future__ imports or module docstrings.

After processing all files, the command exits with CommandExitStatus::Success (line 85), leaving the modified Python files with inline type hints and required imports.

Practical Usage Examples

Basic inference on a single file:

pyrefly infer path/to/file.py

Include container type annotations:

pyrefly infer --containers path/to/file.py

Disable return-type inference (parameters only):

pyrefly infer --no-return-types path/to/file.py

Process an entire directory recursively:

pyrefly infer path/to/project/

Combine multiple flags:

pyrefly infer --containers --no-imports path/to/project/

Using a configuration file:

Create a pyrefly.toml file:

project_includes = ["src/**/*.py"]
project_excludes = ["src/tests/**/*.py"]
infer-return-types = "checked"

Then run:

pyrefly infer --config pyrefly.toml

Before and After Examples

Input (example.py):

def add(a, b):
    return a + b

Output after pyrefly infer:

def add(a: int, b: int) -> int:
    return a + b

Handling external imports:


# Before

def make():
    return Example()

# After (assuming Example is defined in models.py)

from models import Example

def make() -> Example:
    return Example()

Key Implementation Files

The pyrefly infer functionality is centralized in [pyrefly/lib/commands/infer.rs](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/commands/infer.rs). Critical sections include:

  • Lines 52-87 – Definition of InferFlags controlling CLI behavior.
  • Lines 82-89 – Configuration enforcement for unannotated definition checking.
  • Lines 74-126 – The format_hints function for type string conversion.
  • Lines 88-103add_annotations_to_file for source code modification.
  • Lines 104-117add_imports_to_file for import statement injection.
  • Lines 495-530 – Test suite demonstrating end-to-end inference scenarios.

Additional user-facing documentation is available in website/docs/autotype.mdx.

Summary

  • pyrefly infer automatically adds type annotations by analyzing code with the Pyrefly type checker and inserting hints at the correct source positions.
  • The command supports granular control via flags like --containers, --return-types, --parameter-types, and --imports.
  • Configuration options check_unannotated_defs and infer_return_types are automatically enabled to ensure comprehensive type discovery.
  • The tool modifies files in-place, adding both annotations and necessary import statements while preserving existing code structure.
  • Implementation resides primarily in pyrefly/lib/commands/infer.rs, with distinct functions handling formatting, annotation insertion, and import management.

Frequently Asked Questions

What is the difference between pyrefly infer and pyrefly check?

pyrefly check analyzes code for type errors and reports diagnostics without modifying files. pyrefly infer runs the same type analysis but uses the results to generate and insert type annotations directly into the source code, effectively automating the migration to typed Python.

Does pyrefly infer modify files in-place?

Yes, pyrefly infer modifies Python files in-place by inserting type annotations at the byte positions determined during analysis. The command uses add_annotations_to_file to write type hints and add_imports_to_file to insert necessary import statements, preserving the original formatting and structure of the code.

How does pyrefly infer handle imports for custom types?

When the --imports flag is enabled, the inference pipeline tracks which modules define the types used in annotations. The format_hints function records these dependencies, and add_imports_to_file inserts appropriate from <module> import <name> statements after any __future__ imports or module docstrings, ensuring the annotated code remains valid and executable.

Can I use pyrefly infer with a pyrefly.toml configuration file?

Yes, pyrefly infer respects configuration files. You can define project includes, excludes, and default inference settings in pyrefly.toml, then invoke the command with pyrefly infer --config pyrefly.toml. Configuration options like infer-return-types can be set to "checked" to match the command's default behavior.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →