fix(python): import converters and specs lazily so inference does not load torch - #2080
Open
Anai-Guo wants to merge 1 commit into
Open
fix(python): import converters and specs lazily so inference does not load torch#2080Anai-Guo wants to merge 1 commit into
Anai-Guo wants to merge 1 commit into
Conversation
… load torch `import ctranslate2` eagerly imported the `converters` and `specs` submodules, both of which import torch at module level (`converters` also imports transformers and huggingface_hub). Those dependencies are only needed to convert models, so every inference-only user with torch in the environment paid for the import. Import both submodules on first attribute access via a module-level `__getattr__` (PEP 562). `from ctranslate2 import converters`, `import ctranslate2.converters` and the `ct2-*-converter` entry points are unaffected; `models` stays eager because it only imports from the compiled extension. Measured with torch 2.5.1+cu121 installed: `import ctranslate2` drops from 3.04s to 0.15s (the package's own import subtree, per -X importtime, from 2.73s to 0.11s). Fixes OpenNMT#2078
jordimas
reviewed
Jul 30, 2026
| import sys | ||
|
|
||
| import pytest | ||
|
|
Collaborator
There was a problem hiding this comment.
Thanks for your work
Could we add a small regression test for from ctranslate2 import *?
Before this change, wildcard imports exposed converters and specs. Since wildcard import uses __all__ if defined, otherwise current module globals, it would be good to check that this behavior is still preserved with the lazy imports.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2078 (#2079 is a duplicate of the same report).
Problem
import ctranslate2unconditionally imports torch, transformers and huggingface_hub when they are present in the environment, even for inference-only use (Translator/Generator/Whisper).python/ctranslate2/__init__.pyends with:converters/__init__.pyimportsconverters.transformers, which doestry: import huggingface_hub, torch, transformers.specs/model_spec.pydoestry: import torchto settorch_is_available.Both are only needed for model conversion, never for inference — so every inference-only user with torch installed pays the import cost. As the reporter notes, this also forces users who mix CTranslate2 inference with onnxruntime in one process to shell out to a subprocess just to keep torch out of it.
Change
Import
convertersandspecson first attribute access using a module-level__getattr__(PEP 562), plus a matching__dir__.modelsstays eager — it only imports from the compiled_ext, so it costs nothing.Compatibility
All existing access patterns still work, verified against an installed 4.7.1 with the patch applied:
import ctranslate2; ctranslate2.converters.TransformersConverterimport ctranslate2; ctranslate2.specs.TransformerSpecfrom ctranslate2 import convertersfrom ctranslate2 import specsimport ctranslate2.convertersfrom ctranslate2.converters import TransformersConverterfrom ctranslate2.specs import TransformerSpecfrom ctranslate2.specs import model_spec→torch_is_availableTrue'converters' in dir(ctranslate2)/'specs' in dir(...)Truectranslate2.does_not_existAttributeErrorAll 6
ct2-*-converterconsole_scripts entry points still resolve (ctranslate2.converters.{transformers,opennmt_py,fairseq,marian,opus_mt,openai_gpt2}:main— each imports and exposes a callablemain).Measurements
Windows, Python 3.12.10, torch 2.5.1+cu121, ctranslate2 4.7.1:
import ctranslate2(subprocess, min of 3)-X importtime)Test
Added
test_import_does_not_load_conversion_dependenciestopython/tests/test_misc.py, parametrized overtorchandtransformers. It runsimport ctranslate2in a subprocess (the test session itself imports both, so an in-process check would be meaningless).Against the installed package:
black,isort(profile=black, lines_between_types=1) andflake8(max-line-length=100) are clean on both changed files.AI disclosure, per CONTRIBUTING.md: this change was written with AI assistance (Claude Code). The reported import chain was verified by reading the actual source on
master, and every claim above — the compatibility matrix, entry points, timings, and before/after test results — was produced by running it locally against an installed CTranslate2, not inferred.🤖 Generated with Claude Code