Skip to content

Refactor Nexity authentication to use inline lazy imports#1972

Draft
iMicknl wants to merge 2 commits intov2/mainfrom
v2/lazy_load_auth_strategies
Draft

Refactor Nexity authentication to use inline lazy imports#1972
iMicknl wants to merge 2 commits intov2/mainfrom
v2/lazy_load_auth_strategies

Conversation

@iMicknl
Copy link
Copy Markdown
Owner

@iMicknl iMicknl commented Apr 5, 2026

Refactors the Nexity authentication strategy to load optional dependencies lazily at runtime using standard inline import statements inside the login() method, rather than importing them at the module level. This keeps the code readable while avoiding unnecessary imports unless Nexity authentication is actually used.

Dependency loading improvements:

  • Moved imports of boto3, botocore.config, botocore.exceptions, and warrant_lite from the module level into the body of NexityAuthStrategy.login(), using a try/except ImportError block to raise a clear NexityServiceException if the optional dependencies are missing.
  • Removed the intermediate _load_nexity_auth_dependencies helper function and the import importlib module-level import, restoring full type information (no Any or cast workarounds).

Testing updates:

  • Updated tests to patch boto3.client and warrant_lite.WarrantLite directly, which is the correct approach when the imports live inside the method body rather than at module level.

@iMicknl
Copy link
Copy Markdown
Owner Author

iMicknl commented Apr 6, 2026

@copilot is this the best way to lazy load these packages, that are only used for authentication of Nexity (which isn't used a lot).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors Nexity authentication so its third-party dependencies (boto3 / botocore / warrant_lite) are imported dynamically at runtime rather than at module import time, and updates tests to patch the new loader.

Changes:

  • Added _load_nexity_auth_dependencies() to import Nexity-specific libraries on demand and raise a Nexity-specific exception on missing deps.
  • Updated NexityAuthStrategy.login() to use the dynamically loaded modules/classes.
  • Updated Nexity auth tests to patch _load_nexity_auth_dependencies() instead of patching module-level imports.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
pyoverkiz/auth/strategies.py Introduces a dynamic dependency loader and rewires Nexity login to use it.
tests/test_auth.py Adjusts Nexity auth error-mapping tests to patch the new loader return values.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +448 to +452
except ImportError as error:
raise NexityServiceException(
"Nexity authentication requires optional dependencies. Install with the "
"Nexity auth extras."
) from error
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message here references installing "Nexity auth extras", but the project currently lists boto3 and warrant-lite as required dependencies in pyproject.toml (not optional), and there is no [project.optional-dependencies] entry for Nexity. Either define a real extras group and move these deps out of the base dependencies, or update the message to instruct installing the specific packages (or the correct extras name).

Copilot uses AI. Check for mistakes.
Comment on lines +441 to +459
def _load_nexity_auth_dependencies() -> tuple[Any, Any, type[Exception], Any]:
"""Load Nexity optional dependencies only when Nexity auth is used."""
try:
boto3_module = importlib.import_module("boto3")
botocore_config_module = importlib.import_module("botocore.config")
botocore_exceptions_module = importlib.import_module("botocore.exceptions")
warrant_lite_module = importlib.import_module("warrant_lite")
except ImportError as error:
raise NexityServiceException(
"Nexity authentication requires optional dependencies. Install with the "
"Nexity auth extras."
) from error

return (
boto3_module,
botocore_config_module.Config,
cast(type[Exception], botocore_exceptions_module.ClientError),
warrant_lite_module.WarrantLite,
)
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_load_nexity_auth_dependencies() returns an unstructured 4-tuple of Any, which makes call sites easy to mis-order and obscures what each value represents. Consider returning a NamedTuple/dataclass (or a small object) with named fields and tighter types (e.g., types.ModuleType for boto3_module, the specific Config/ClientError/WarrantLite types) to keep the refactor readable and type-checker friendly.

Copilot uses AI. Check for mistakes.
Comment on lines +256 to +263
loop = asyncio.get_running_loop()
boto3_module, config_class, client_error_class, warrant_lite_class = (
_load_nexity_auth_dependencies()
)

def _client() -> BaseClient:
return boto3.client(
"cognito-idp", config=Config(region_name=NEXITY_COGNITO_REGION)
def _client() -> Any:
return boto3_module.client(
"cognito-idp", config=config_class(region_name=NEXITY_COGNITO_REGION)
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

importlib.import_module(...) runs synchronously on the event loop the first time Nexity login is used, which can briefly block the loop due to filesystem I/O during imports. Consider caching the loaded dependencies (module-level cache) and/or running the dependency loading in the executor along with the boto3 client creation to avoid blocking async workloads.

Copilot uses AI. Check for mistakes.
Comment on lines +443 to +452
try:
boto3_module = importlib.import_module("boto3")
botocore_config_module = importlib.import_module("botocore.config")
botocore_exceptions_module = importlib.import_module("botocore.exceptions")
warrant_lite_module = importlib.import_module("warrant_lite")
except ImportError as error:
raise NexityServiceException(
"Nexity authentication requires optional dependencies. Install with the "
"Nexity auth extras."
) from error
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new ImportError-to-NexityServiceException mapping in _load_nexity_auth_dependencies() is new behavior and currently has no test coverage. Adding a test that forces _load_nexity_auth_dependencies() to raise ImportError (and asserts NexityServiceException with a helpful message) would prevent regressions and validate the intended UX.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 6, 2026

@copilot is this the best way to lazy load these packages, that are only used for authentication of Nexity (which isn't used a lot).

The importlib approach wasn't the best choice here. The simpler, more idiomatic Python pattern is to put import statements directly inside the method — Python caches modules in sys.modules, so there's no re-import overhead on subsequent calls.

The inline import approach has several advantages over the importlib version:

  • Full type information is preserved (no Any, no cast workarounds)
  • More readable — reads like normal Python
  • Easier to test — patch boto3.client and warrant_lite.WarrantLite directly rather than mocking a helper function

Refactored in commit 158f38c.

Copilot AI changed the title Refactor Nexity authentication to load optional dependencies dynamically Refactor Nexity authentication to use inline lazy imports Apr 6, 2026
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.

3 participants