Skip to content

Typing & Type Hints

BetterPy enhances PyCharm's type system support with smart wrapping/unwrapping intentions, completions driven by expected types, and convenient annotation editing tools.


Completions

NewType/TypeVar/ParamSpec reference & rename

Since 2026.04.05 · Maturity Stable · Issues PY-82966PY-53658

Python typing helpers often repeat a symbol name inside a string literal. BetterPy connects those string literals to the Python symbol so navigation and rename stay consistent.

How to invoke

  • Use ⌘+Click / Ctrl+Click on the name string in NewType, TypeVar, or ParamSpec calls to jump to the matching assigned symbol, for example from "UserId" to UserId.
  • Use ⇧F6 / Shift+F6 on the Python symbol to rename it. BetterPy keeps the matching string literal in sync.
  • For NewType, if the string was edited manually and no longer matches the assigned symbol, use the quick-fix on the highlighted string to update it.

Examples

from typing import NewType

UserId = NewType("UserId", int)
from typing import TypeVar

ItemT = TypeVar("ItemT")
from typing import ParamSpec

P = ParamSpec("P")

Renaming UserId to AccountId updates both the target name and the string literal:

AccountId = NewType("AccountId", int)

If a NewType literal drifted manually, BetterPy highlights the mismatch and offers to update the string:

AccountId = NewType("UserId", int)

The quick-fix rewrites it to:

AccountId = NewType("AccountId", int)

What it supports

  • typing.NewType, typing.TypeVar, and typing.ParamSpec style declarations.
  • String-literal references from the helper call back to the assigned Python symbol.
  • Rename synchronization for the declaration and the literal.
  • A quick-fix for manual NewType string drift when the literal no longer matches the assigned symbol. PyCharm's built-in quick-fix handles the same drift for TypeVar and ParamSpec.
  • Navigation and reference search in regular project files.

What it deliberately avoids

  • Calls where the string literal intentionally does not match the assigned symbol.
  • Dynamic names or computed string arguments.
  • Unrelated string literals that happen to contain the same text.
  • Library and stub files outside your project.

Notes

  • This feature reduces rename drift in typing-heavy modules without changing runtime behavior.
  • The feature is gated by the NewType/TypeVar/ParamSpec reference & rename setting under Settings | BetterPy | Typing & Type Hints | Completions.

Type Editing

Strip signature type annotations

Since 2026.04.05 · Maturity Stable

Remove all type annotations from a function signature in one action. The function body stays unchanged, making this a focused cleanup tool for examples, dynamic APIs, or code that should not expose annotations.

How to invoke

Place the caret inside a typed function signature and use ⌥⏎ / Alt+Enter -> "Strip type annotations from signature".

Example

def create_user(name: str, email: str, age: int) -> User:
    ...

becomes:

def create_user(name, email, age):
    ...

What it supports

  • Parameter annotations.
  • Return annotations.
  • Regular functions and methods.
  • Preserving default values, decorators, parameter order, and the function body.

What it deliberately avoids

  • Removing annotations outside the current function signature.
  • Rewriting variable annotations in the body.
  • Changing call sites.
  • Files outside your own project sources.

Notes

  • This action is intentionally narrow: it removes signature annotations only.
  • The feature is gated by the Strip signature type annotations setting under Settings | BetterPy | Typing & Type Hints | Type Editing.

Copy method annotations from parent

Since 2026.04.05 · Maturity Incubating

Copy missing type annotations from a parent method into an overriding method. This is useful when subclass methods intentionally keep the same signature but were written without annotations.

How to invoke

Place the caret on an overriding method and use ⌥⏎ / Alt+Enter -> "Copy type annotations from parent".

Example

class Handler:
    def handle(self, event: Event) -> Result:
        ...


class AuditHandler(Handler):
    def handle(self, event):
        ...

becomes:

class AuditHandler(Handler):
    def handle(self, event: Event) -> Result:
        ...

What it supports

  • Copying missing parameter annotations.
  • Copying missing return annotations.
  • Keeping existing child annotations when they are already present.
  • Adding imports required by copied annotation names.
  • Rewriting common alias imports so the resulting annotation resolves in the child file.

What it deliberately avoids

  • Methods with no typed parent method.
  • Signature shapes that do not line up with the parent method.
  • Blindly overwriting annotations already present on the child.
  • Applying a fix when import or name conflicts need explicit review.

Notes

  • The intention can be used directly, and the overridden-method inspection can offer it as a quick-fix.
  • The feature is gated by the Copy method annotations from parent setting under Settings | BetterPy | Typing & Type Hints | Type Editing.

Inspections & Quick Fixes

Missing |None annotation inspection

Since 2026.04.05 · Maturity Incubating · Issues PY-88504

PyCharm 2026.1 and newer also reports parameters whose default value is None but whose type annotation does not admit None. BetterPy keeps its own inspection for the same code shape so the "BetterPy: Add | None to annotation" quick-fix is available as an inspection quick-fix in the highlighted-code actions.

How to invoke

Place the caret on the highlighted None default or initializer, then use ⌥⏎ / Alt+Enter -> "BetterPy: Add | None to annotation".

Example

def fetch_user(user_id: str, timeout: int = None):
    ...

becomes:

def fetch_user(user_id: str, timeout: int | None = None):
    ...

It also handles annotated assignments with None initializers:

current_user: User = None

becomes:

current_user: User | None = None

What it supports

  • Parameters with None defaults.
  • Annotated assignments initialized with None.
  • Existing union syntax such as Union[T, None] and T | None.
  • Quick-fixing only the annotation while preserving the default expression.

What it deliberately avoids

  • Values that are not actually initialized with None.
  • Unannotated parameters or assignments.
  • Annotations that already allow None.
  • Library and stub files outside your project.

Notes

  • PyCharm 2026.1 and newer has its own diagnostic for this pattern. BetterPy's inspection intentionally overlaps with it so the BetterPy quick-fix appears with the highlighted inspection actions.
  • The quick-fix is gated by the Missing |None annotation inspection setting under Settings | BetterPy | Typing & Type Hints | Code Inspections.

Overridden method missing type annotations inspection

Since 2026.04.05 · Maturity Incubating

Report overriding methods that dropped type annotations from the parent method. The quick-fix copies the missing annotations from the parent so subclass signatures stay readable and type-checker friendly.

How to invoke

Enable the inspection, place the caret on a highlighted override, then use ⌥⏎ / Alt+Enter -> "Copy type annotations from parent".

Example

class Repository:
    def save(self, item: Order) -> None:
        ...


class SqlRepository(Repository):
    def save(self, item):
        ...

becomes:

class SqlRepository(Repository):
    def save(self, item: Order) -> None:
        ...

What it supports

  • Overrides that inherit parameter and return annotations from a parent method.
  • Partial fixes when only some annotations are missing.
  • Import insertion when copied annotations need names from another module.
  • Alias-aware imports in common cases.

What it deliberately avoids

  • Methods that do not override a typed parent method.
  • Overrides where the parent and child signatures are incompatible.
  • Applying a fix when copied names would introduce unresolved or conflicting references without user confirmation.
  • Library and stub files outside your project.

Notes

  • This inspection is the diagnostic companion to the Copy method annotations from parent intention.
  • The feature is gated by the Overridden method missing type annotations inspection setting under Settings | BetterPy | Typing & Type Hints | Code Inspections.