Skip to content

refactor: replace wildcard imports with explicit imports in model __init__.py files#45452

Open
DavidSolanas wants to merge 2 commits intohuggingface:mainfrom
DavidSolanas:fix/import_star_usage
Open

refactor: replace wildcard imports with explicit imports in model __init__.py files#45452
DavidSolanas wants to merge 2 commits intohuggingface:mainfrom
DavidSolanas:fix/import_star_usage

Conversation

@DavidSolanas
Copy link
Copy Markdown

Fixes #45306

What and why

All models/X/__init__.py files used from .module import * inside the
TYPE_CHECKING block. This makes it impossible for static analysis tools
(pyright, mypy, IDEs) to know which symbols are actually exported, and
creates silent namespace pollution risks.

This PR replaces every wildcard import with an explicit one derived from
the submodule's __all__.

Before (models/bert/__init__.py):

if TYPE_CHECKING:
    from .configuration_bert import *
    from .modeling_bert import *
    from .tokenization_bert import *

After:

if TYPE_CHECKING:
    from .configuration_bert import BertConfig
    from .modeling_bert import (
        BertForMaskedLM,
        BertForMultipleChoice,
        ...
    )
    from .tokenization_bert import BertTokenizer

How

The fix was generated mechanically: for each models/X/__init__.py,
parse the TYPE_CHECKING block, read __all__ from the referenced
submodule, and emit an explicit import. Runtime behavior is completely
unchanged — only the TYPE_CHECKING branch (used by type checkers, not
at runtime) is affected.

Scope

  • 446 model __init__.py files updated
  • src/transformers/models/__init__.py and src/transformers/__init__.py
    (top-level aggregators) are out of scope — those require a separate
    discussion about how the public namespace is defined
  • tests/utils/test_file_utils.py:23 (from transformers import *) is
    intentional and left untouched

Known gaps (follow-up candidates)

A small number of wildcard imports could not be resolved automatically and
were left as-is:

  • Submodule file does not exist in the repo (deprecated aliases, e.g.
    tokenization_bloom.py, feature_extraction_detr.py)
  • Submodule exists but does not define __all__ (e.g.
    generation_dia.py, conversion scripts like
    convert_funnel_original_tf_checkpoint_to_pytorch.py)

These can be addressed in follow-up PRs once the owning teams decide how
to handle them.

Testing

python utils/checkers.py imports   # ✓ All 1 checks passed
python utils/checkers.py inits     # ✓ All 1 checks passed
python -m pytest tests/utils/test_file_utils.py -x -q  # 5 passed

@github-actions
Copy link
Copy Markdown
Contributor

[For maintainers] Suggested jobs to run (before merge)

run-slow: afmoe, aimv2, albert, align, altclip, apertus, arcee, aria, audio_spectrogram_transformer, audioflamingo3, auto, autoformer, aya_vision, bamba, bark, bart

@LysandreJik
Copy link
Copy Markdown
Member

I'm not very knowledgeable about mypy, but this seems redundant to me: we're already defining in each module's __all__ attribute which objects we want to export. If we want to add a new object to export, we now need to add it to the module's __all__ as well as every downstream __init__.py file which would import it, instead of the current wildcard approach.

For models specifically this was always a feature more than a bug: any object in the model module's __all__ should be propagated up to the main transformers init.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove import * usage

2 participants