MAINT: Lazy Imports for perf#1668
Merged
rlundeen2 merged 11 commits intomicrosoft:mainfrom Apr 30, 2026
Merged
Conversation
Use PEP 562 __getattr__-based lazy imports in four __init__.py files to defer loading of heavy third-party dependencies until first use: - prompt_target: HuggingFaceChatTarget (defers transformers ~4s) - prompt_converter: 5 audio converters (defers scipy ~1.3s), TextJailbreakConverter (defers datasets/pandas ~0.5s) - score: 19 symbols for audio/video scorers and scorer_evaluation (defers av, pandas, scipy.stats) - common: 5 download_hf_model functions (defers huggingface_hub ~0.3s) Reduces pyrit_scan --list-scenarios wall-clock time from ~12s to ~5.4s (~55% improvement). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Layer 1: Make 4 symbols lazy in pyrit/common/__init__.py: - convert_local_image_to_data_url (defers pyrit.models -> openai, azure.storage.blob) - display_image_response (defers PIL, pyrit.memory -> sqlalchemy) - get_httpx_client, make_request_and_raise_if_error_async (defers httpx) This cuts 'import pyrit' from ~4s to ~0.3s, benefiting all CLI entry points. Layer 2: Defer frontend_core in pyrit_scan.py: - Import from _cli_args directly for arg parsing (already lightweight) - Move frontend_core import inside main() after parse_args() - Move 'Starting PyRIT...' print after arg parsing Result: pyrit_scan --help goes from ~5.4s to ~0.36s. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document two patterns for performance-sensitive imports: - PEP 562 __getattr__ lazy loading in __init__.py files - Deferred imports in CLI entry points for instant --help Also add guidance in Performance Considerations section for when to use lazy imports (modules with heavy third-party deps on the CLI startup path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document two patterns for performance-sensitive imports: - PEP 562 __getattr__ lazy loading in __init__.py files - Deferred imports in CLI entry points for instant --help Also add guidance in Performance Considerations section for when to use lazy imports (modules with heavy third-party deps on the CLI startup path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of PEP 562 lazy loading in pyrit/common/__init__.py, simply don't re-export heavy submodules (data_url_converter, display_response, net_utility, download_hf_model). Consumers now import directly from the specific file, which is more readable and has the same perf benefit. Updated the 5 files that imported convert_local_image_to_data_url via pyrit.common to import from pyrit.common.data_url_converter instead. The other symbols already had direct imports everywhere. Also updated the style guide: 'Keeping __init__.py Startup Fast' now describes both the direct-import pattern (for internal packages) and the __getattr__ pattern (for public API packages). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- storage_io.py: Defer azure.storage.blob, azure.core.exceptions, and pyrit.auth into AzureBlobStorageIO methods (saves ~1.37s for DiskStorageIO users who never need azure) - memory_interface.py: Defer pyrit.memory.migration (alembic ~1.07s) into _run_schema_migration() and reset_database(); defer memory_embedding (openai ~1.16s) into enable_embedding() - score/__init__.py: Move scorer_metrics/scorer_metrics_io (no heavy deps) back to eager imports, keeping only truly heavy symbols lazy - Update test patch paths for relocated imports Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…b.com/rlundeen2/PyRIT into users/rlundeen/2026_04_29_lazy_import
Subprocess-based tests verify that heavy modules (transformers, azure SDK, alembic, openai, pandas, scipy, av) are NOT loaded at key import points: - CLI arg parsing (ensures --help stays ~0.3s) - import pyrit (ensures package stays lightweight) - PromptTarget base class (ensures ML deps stay lazy) Also updates style guide to document deferred imports in internal modules as an allowed pattern for heavy optional dependencies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
romanlutz
approved these changes
Apr 29, 2026
Subprocess-based tests verify that heavy modules (transformers, azure SDK, alembic, openai, pandas, scipy, av) are NOT loaded at key import points: - CLI arg parsing (ensures --help stays ~0.3s) - import pyrit (ensures package stays lightweight) - PromptTarget base class (ensures ML deps stay lazy) Also updates style guide to document deferred imports in internal modules as an allowed pattern for heavy optional dependencies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…b.com/rlundeen2/PyRIT into users/rlundeen/2026_04_29_lazy_import # Conflicts: # .github/instructions/style-guide.instructions.md
…4_29_lazy_import # Conflicts: # pyrit/models/storage_io.py
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.
Uses PEP 562 getattr-based lazy imports in init.py files to defer expensive third-party dependencies (transformers, scipy, openai, PIL, azure.storage.blob, httpx, pandas, huggingface_hub) until first use.
Also defers frontend_core import in pyrit_scan.py to after arg parsing so --help and bad arguments skip the full framework load entirely.
pyrit_scan --helppyrit_scan --list-scenariosAlso added a test to prevent some heavy model import regressions.