
Add Or Fix Type Checking
- 18 installs
- 163k repo stars
- Updated August 5, 2026
- huggingface/transformers
add-or-fix-type-checking resolves ty typing errors in Transformers modules.
About
The add-or-fix-type-checking skill fixes broken typing checks detected by ty, make typing, or make check-repo in the Hugging Face Transformers repository. Workflow runs make typing or uses CI output to identify failing modules, then ty check with respect-ignore-files and protobuf excludes on the narrowest target covering failures. Triage categories include missing annotations, union attribute access, broad return unions, mixin self-types, dynamic module attributes, and third-party stub gaps. Fix priority favors isinstance and None checks over cast, local variables for closure narrowing, TypeGuard for structural checks, and TypedDict or Protocol for dynamic shapes. Guardrails forbid cast for module attribute narrowing and require if-raise over assert for None narrowing. Validates with ty check and make typing until clean. 1. **Identify scope from the failing run**: Choose the narrowest target that covers the failures.
- Fixes ty and make typing failures in Transformers code.
- Triages errors by annotation, union, and stub categories.
- Prefers isinstance narrowing over cast shortcuts.
- Uses narrowest ty check target from CI failures.
- Validates with make typing until checks pass.
Add Or Fix Type Checking by the numbers
- 18 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #189 of 290 Python skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
add-or-fix-type-checking capabilities & compatibility
- Capabilities
- workflow and triage categories · fix priority order with isinstance patterns
- Works with
- github
- Use cases
- testing · refactoring
What add-or-fix-type-checking says it does
Fixes broken typing checks detected by ty, make typing, or make check-repo
npx skills add https://github.com/huggingface/transformers --skill add-or-fix-type-checkingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 18 |
|---|---|
| repo stars | ★ 163k |
| Last updated | August 5, 2026 |
| Repository | huggingface/transformers ↗ |
How do I fix ty union narrowing errors in Transformers?
Fix typing errors detected by ty, make typing, or make check-repo in Transformers.
Who is it for?
Transformers contributors fixing CI typing failures.
Skip if: Skip for runtime bugs without typing checker failures.
When should I use this skill?
Typing errors appear in ty, make typing, or check-repo CI logs.
What you get
Clean ty check and make typing for the target module.
Files
Add Or Fix Type Checking
Input
<target>: module or directory to type-check (if known).- Optional
make typingor CI output showing typing failures.
Workflow
1. Identify scope from the failing run:
- If you already have
make typingor CI output, extract the failing file/module paths. - If not, run:
make typing- Choose the narrowest target that covers the failures.
2. Run `ty check` for the target to get a focused baseline:
ty check --respect-ignore-files --exclude '**/*_pb*' <target>3. Triage errors by category before fixing anything:
- Wrong/missing type annotations on signatures
- Attribute access on union types (for example
X | None) - Functions returning broad unions (for example
str | list | BatchEncoding) - Mixin/protocol self-type issues
- Dynamic attributes on objects or modules
- Third-party stub gaps (missing kwargs, missing
__version__, etc.)
4. Apply fixes using this priority order (simplest first):
a. Narrow unions with `isinstance()` / `if x is None` / `hasattr()`. This is the primary tool for resolving union-type errors. ty narrows through all of these patterns, including the negative forms:
# Narrow X | None — use `if ...: raise`, never `assert`
if x is None:
raise ValueError("x must not be None")
x.method() # ty knows x is X here
# Narrow str | UploadFile
if isinstance(field, str):
raise TypeError("Expected file upload, got string")
await field.read() # ty knows field is UploadFile here
# Narrow broad union parameters early in a function body
# (common for methods accepting e.g. list | dict | BatchEncoding)
if isinstance(encoded_inputs, (list, tuple)):
raise TypeError("Expected a mapping, got sequence")
encoded_inputs.keys() # ty sees only the dict/mapping types nowb. Use local variables to help ty track narrowing across closures. When self.x is X | None and you need to pass it to nested functions or closures, ty cannot track that self.x stays non-None. Copy to a local variable and narrow the local:
manager = self.batching_manager
if manager is None:
raise RuntimeError("Manager not initialized")
# Use `manager` (not `self.batching_manager`) in nested functionsc. Split chained calls when the intermediate type is a broad union. If func().method() fails because func() returns a union, split it:
# BAD: ty can't narrow through chained calls
result = func(return_dict=True).to(device)["input_ids"]
# GOOD: split, narrow, then chain
result = func(return_dict=True)
if not hasattr(result, "to"):
raise TypeError("Expected dict-like result")
inputs = result.to(device)["input_ids"]d. Fix incorrect type hints at the source. If a parameter is typed X | None but can never be None when actually called, remove None from the hint.
e. Annotate untyped attributes. Add type annotations to instance variables set in __init__ or elsewhere (for example self.foo: list[int] = []). Declare class-level attributes that are set dynamically later (for example _cache: Cache, _token_tensor: torch.Tensor | None).
f. Use `@overload` for methods with input-dependent return types. When a method returns different types based on the input type (e.g. __getitem__ with str vs int keys), use @overload to declare each signature separately:
from typing import overload
@overload
def __getitem__(self, item: str) -> ValueType: ...
@overload
def __getitem__(self, item: int) -> EncodingType: ...
@overload
def __getitem__(self, item: slice) -> dict[str, ValueType]: ...
def __getitem__(self, item: int | str | slice) -> ValueType | EncodingType | dict[str, ValueType]:
... # actual implementationThis eliminates cast() calls at usage sites by giving the checker precise return types for each call pattern.
g. Make container classes generic to propagate value types. When a class like UserDict holds values whose type changes after transformation (e.g. lists → tensors after .to()), make the class generic so methods can return narrowed types:
from typing import Generic, overload
from typing_extensions import TypeVar
_V = TypeVar("_V", default=Any) # default=Any keeps existing code working
class MyDict(UserDict, Generic[_V]):
@overload
def __getitem__(self, item: str) -> _V: ...
# ...
def to(self, device) -> MyDict[torch.Tensor]:
# after .to(), values are tensors
...
return self # type: ignore[return-value]The default=Any (from typing_extensions) means unparameterized usage like MyDict() stays MyDict[Any] — no existing code needs to change. Only methods that narrow the value type (like .to()) declare a specific return type. This eliminates cast() at all call sites.
h. Use `self: "ProtocolType"` for mixins. When a mixin accesses attributes from its host class, define a Protocol in src/transformers/_typing.py and annotate self on methods that need it. Apply this consistently to all methods in the mixin. Import under TYPE_CHECKING to avoid circular imports.
i. Use `TypeGuard` functions for dynamic module attributes (for example torch.npu, torch.xpu, torch.compiler). Instead of getattr(torch, "npu") or hasattr(torch, "npu") and torch.npu.is_available(), define a type guard function in src/transformers/_typing.py:
def has_torch_npu(mod: ModuleType) -> TypeGuard[Any]:
return hasattr(mod, "npu") and mod.npu.is_available()Then use it as a narrowing check: if has_torch_npu(torch): torch.npu.device_count(). After the guard, ty treats the module as Any, allowing attribute access without getattr() or cast(). See existing guards in _typing.py for all device backends.
Key rules for type guards:
- Use
TypeGuard[Any](not a Protocol) — this is the simplest form that works
with ty and avoids losing the original module's known attributes.
- The guard function must be called directly in an
ifcondition for narrowing
to work. ty does NOT narrow through and conditions or if not guard: return.
- Import guards with
from .._typing import has_torch_xxx(not via module
attribute _typing.has_torch_xxx) — ty only resolves TypeGuard from direct imports.
j. Use `getattr()` / `setattr()` for dynamic model/config attributes. For runtime-injected fields (for example config/model flags), use getattr(obj, "field", default) for reads and setattr(obj, "field", value) for writes. Also use getattr() for third-party packages missing type stubs (for example getattr(safetensors, "__version__", "unknown")). Avoid getattr(torch, "npu") style — use type guards instead (see above).
k. Use `cast()` as a last resort before `# type: ignore`. Use when you've structurally validated the type but the checker can't see it: pattern-matched AST nodes, known-typed dict values, or validated API responses.
# After structural validation confirms the type:
stmt = cast(cst.Assign, node.body[0])
annotations = cast(list[Annotation], [])Do not use cast() for module attribute narrowing — use type guards. Do not use cast() when @overload or generics can solve it at the source.
l. Use `# type: ignore` only for third-party stub defects. This means cases where the third-party package's type stubs are wrong or incomplete and there is no way to narrow or cast around it. Examples:
- A kwarg that exists at runtime but is missing from the stubs
- A method that exists but isn't declared in the stubs
Always add the specific error code: # type: ignore[call-arg], not bare # type: ignore.
5. Things to never do:
- Never use `assert` for type narrowing. Asserts are stripped by
python -O
and must not be relied on for correctness. Use if ...: raise instead.
- Never use `# type: ignore` as a first resort. Exhaust all approaches above first.
- Do not use
getattr(torch, "backend")to access dynamic device backends
(npu, xpu, hpu, musa, mlu, neuron, compiler) — use type guards
- Do not use
cast()for module attribute narrowing — use type guards - Do not use
cast()when@overloador generics can eliminate it at the source - Do not add helper methods or abstractions just to satisfy the type checker
(especially for only 1-2 occurrences)
- Do not pollute base classes with domain-specific fields; use Protocols
- Do not add
if x is not Noneguards for values guaranteed non-None
by the call chain; fix the annotation instead
- Do not use conditional inheritance patterns; annotate
selfinstead
6. Organization:
- Keep shared Protocols and type aliases in
src/transformers/_typing.py - Import type-only symbols under
if TYPE_CHECKING:to avoid circular deps - Use
from __future__ import annotationsfor PEP 604 syntax (X | Y)
7. Verify and close the PR loop:
- Re-run
ty checkon the same<target> - Re-run
make typingto confirm the type/model-rules step passes - If working toward merge readiness, run
make check-repo - Ensure runtime behavior did not change and run relevant tests
8. Update CI coverage when adding new typed areas:
- Update
ty_check_dirsinMakefileto include newly type-checked directories.
Related skills
FAQ
What does add-or-fix-type-checking do?
add-or-fix-type-checking resolves ty typing errors in Transformers modules.
When should I use add-or-fix-type-checking?
Typing errors appear in ty, make typing, or check-repo CI logs.
Is this skill safe to install?
Review the Security Audits panel on this page before installing in production.