From ee6acc67912f952160655f7511cb1b7b86e23540 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Wed, 17 Sep 2025 11:44:47 +0200 Subject: [PATCH 1/4] moved import of optional packages into classes --- python_repositories/adapters/minio_adapter.py | 8 +++++--- python_repositories/adapters/redis_adapter.py | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/python_repositories/adapters/minio_adapter.py b/python_repositories/adapters/minio_adapter.py index 560ca2c..ada3196 100644 --- a/python_repositories/adapters/minio_adapter.py +++ b/python_repositories/adapters/minio_adapter.py @@ -3,10 +3,7 @@ from __future__ import annotations import os from io import BytesIO - import structlog -from minio import Minio, S3Error - from python_utils import check_env from python_repositories.interfaces import ( @@ -28,6 +25,11 @@ class MinioAdapter( chunk_size: int = 5 * 2**20 # 5 MiB def __init__(self) -> None: + # Import here to avoid hard dependency if MinioAdapter is not used + try: + from minio import Minio, S3Error # type: ignore[import] + except ImportError as e: + raise RuntimeError("MinioAdapter dependencies missing") from e # Setup logger self.logger = structlog.get_logger( self.__class__.__name__, diff --git a/python_repositories/adapters/redis_adapter.py b/python_repositories/adapters/redis_adapter.py index 660939d..1ed86d4 100644 --- a/python_repositories/adapters/redis_adapter.py +++ b/python_repositories/adapters/redis_adapter.py @@ -2,13 +2,9 @@ from __future__ import annotations from typing import cast - import os import structlog -import redis -from redis.commands.json.path import Path as RedisPath - from python_utils import check_env from python_repositories.interfaces import ( @@ -28,6 +24,12 @@ class RedisAdapter( encoding: str = "UTF-8" def __init__(self) -> None: + # Import here to avoid hard dependency to optional package + try: + import redis # type: ignore[import] + from redis.commands.json.path import Path as RedisPath # type: ignore[import] + except ImportError as e: + raise RuntimeError("RedisAdapter dependencies missing") from e # Setup logger self.logger = structlog.get_logger( self.__class__.__name__, From 538b26b62fddd9837a0274f038352051539a8905 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Wed, 17 Sep 2025 12:04:45 +0200 Subject: [PATCH 2/4] mypy fixed --- python_repositories/adapters/minio_adapter.py | 7 ++++++- python_repositories/adapters/redis_adapter.py | 11 ++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/python_repositories/adapters/minio_adapter.py b/python_repositories/adapters/minio_adapter.py index ada3196..241cfeb 100644 --- a/python_repositories/adapters/minio_adapter.py +++ b/python_repositories/adapters/minio_adapter.py @@ -3,6 +3,7 @@ from __future__ import annotations import os from io import BytesIO +from typing import TYPE_CHECKING import structlog from python_utils import check_env @@ -11,6 +12,10 @@ from python_repositories.interfaces import ( ConnectionAwareInterface, ) +# Import for mypy type checking only +if TYPE_CHECKING: + from minio import Minio, S3Error + class MinioAdapter( ContextAwareInterface, @@ -27,7 +32,7 @@ class MinioAdapter( def __init__(self) -> None: # Import here to avoid hard dependency if MinioAdapter is not used try: - from minio import Minio, S3Error # type: ignore[import] + from minio import Minio, S3Error except ImportError as e: raise RuntimeError("MinioAdapter dependencies missing") from e # Setup logger diff --git a/python_repositories/adapters/redis_adapter.py b/python_repositories/adapters/redis_adapter.py index 1ed86d4..9f40db9 100644 --- a/python_repositories/adapters/redis_adapter.py +++ b/python_repositories/adapters/redis_adapter.py @@ -1,7 +1,7 @@ """Definition of RedisAdapter class.""" from __future__ import annotations -from typing import cast +from typing import cast, TYPE_CHECKING import os import structlog @@ -12,6 +12,11 @@ from python_repositories.interfaces import ( ConnectionAwareInterface, ) +# Import for mypy type checking only +if TYPE_CHECKING: + import redis + from redis.commands.json.path import Path as RedisPath + class RedisAdapter( ContextAwareInterface, @@ -26,8 +31,8 @@ class RedisAdapter( def __init__(self) -> None: # Import here to avoid hard dependency to optional package try: - import redis # type: ignore[import] - from redis.commands.json.path import Path as RedisPath # type: ignore[import] + import redis + from redis.commands.json.path import Path as RedisPath except ImportError as e: raise RuntimeError("RedisAdapter dependencies missing") from e # Setup logger From 396cf83a0599f001b8e72ec7583d8a5bf47f2551 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Wed, 17 Sep 2025 12:14:37 +0200 Subject: [PATCH 3/4] code quality fixes --- python_repositories/adapters/minio_adapter.py | 23 ++++++++----------- python_repositories/adapters/redis_adapter.py | 19 ++++++++------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/python_repositories/adapters/minio_adapter.py b/python_repositories/adapters/minio_adapter.py index 241cfeb..965ec4f 100644 --- a/python_repositories/adapters/minio_adapter.py +++ b/python_repositories/adapters/minio_adapter.py @@ -3,7 +3,7 @@ from __future__ import annotations import os from io import BytesIO -from typing import TYPE_CHECKING +from importlib.util import find_spec import structlog from python_utils import check_env @@ -12,9 +12,11 @@ from python_repositories.interfaces import ( ConnectionAwareInterface, ) -# Import for mypy type checking only -if TYPE_CHECKING: - from minio import Minio, S3Error +# Handle optional dependencies +if find_spec("minio") is not None: + import minio +else: + minio = None class MinioAdapter( @@ -30,11 +32,6 @@ class MinioAdapter( chunk_size: int = 5 * 2**20 # 5 MiB def __init__(self) -> None: - # Import here to avoid hard dependency if MinioAdapter is not used - try: - from minio import Minio, S3Error - except ImportError as e: - raise RuntimeError("MinioAdapter dependencies missing") from e # Setup logger self.logger = structlog.get_logger( self.__class__.__name__, @@ -49,7 +46,7 @@ class MinioAdapter( }, ) # Prepare internal variables - self._client: Minio | None = None + self._client: minio.Minio | None = None self._bucket_name: str | None = None def __enter__(self) -> MinioAdapter: @@ -84,7 +81,7 @@ class MinioAdapter( secret_key = str(os.getenv(self.secret_key_env_var_name)) bucket = str(os.getenv(self.bucket_env_var_name)) # Connect client - client = Minio( + client = minio.Minio( endpoint=endpoint, access_key=access_key, secret_key=secret_key, @@ -114,7 +111,7 @@ class MinioAdapter( @property def is_connected(self) -> bool: """Check if connected to Minio server.""" - res = bool(isinstance(self._client, Minio)) + res = bool(isinstance(self._client, minio.Minio)) self.logger.debug(res) return res @@ -168,7 +165,7 @@ class MinioAdapter( f"Got object '{object_name}' from bucket '{self._bucket_name}'" ) return buffer - except S3Error as exc: + except minio.S3Error as exc: if exc.code == "NoSuchKey": self.logger.warning( f"Object '{object_name}' not found in bucket '{self._bucket_name}'" diff --git a/python_repositories/adapters/redis_adapter.py b/python_repositories/adapters/redis_adapter.py index 9f40db9..e8d845b 100644 --- a/python_repositories/adapters/redis_adapter.py +++ b/python_repositories/adapters/redis_adapter.py @@ -1,7 +1,8 @@ """Definition of RedisAdapter class.""" from __future__ import annotations -from typing import cast, TYPE_CHECKING +from typing import cast +from importlib.util import find_spec import os import structlog @@ -12,10 +13,13 @@ from python_repositories.interfaces import ( ConnectionAwareInterface, ) -# Import for mypy type checking only -if TYPE_CHECKING: +# Handle optional dependencies +if find_spec("redis") is not None: import redis from redis.commands.json.path import Path as RedisPath +else: + redis = None # type: ignore + RedisPath = None # type: ignore class RedisAdapter( @@ -25,16 +29,10 @@ class RedisAdapter( """Redis adapter exposing basic CRUD functionality.""" uri_env_var_name: str = "REDIS_URI" - path: str = RedisPath.root_path() + path: str = "." # JSON root path, updated in __init__ encoding: str = "UTF-8" def __init__(self) -> None: - # Import here to avoid hard dependency to optional package - try: - import redis - from redis.commands.json.path import Path as RedisPath - except ImportError as e: - raise RuntimeError("RedisAdapter dependencies missing") from e # Setup logger self.logger = structlog.get_logger( self.__class__.__name__, @@ -43,6 +41,7 @@ class RedisAdapter( check_env(self.uri_env_var_name) # Prepare internal variables self._client: redis.Redis | None = None + self.path: str = RedisPath.root_path() def __enter__(self) -> RedisAdapter: """Enter the context.""" From e5c4025aeb53cf09c30869546671e4abcdcf6ae3 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Wed, 17 Sep 2025 12:36:22 +0200 Subject: [PATCH 4/4] added graceful handling of missing optional packages --- python_repositories/adapters/minio_adapter.py | 2 -- python_repositories/adapters/redis_adapter.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/python_repositories/adapters/minio_adapter.py b/python_repositories/adapters/minio_adapter.py index 965ec4f..0c67290 100644 --- a/python_repositories/adapters/minio_adapter.py +++ b/python_repositories/adapters/minio_adapter.py @@ -15,8 +15,6 @@ from python_repositories.interfaces import ( # Handle optional dependencies if find_spec("minio") is not None: import minio -else: - minio = None class MinioAdapter( diff --git a/python_repositories/adapters/redis_adapter.py b/python_repositories/adapters/redis_adapter.py index e8d845b..8b3ed8b 100644 --- a/python_repositories/adapters/redis_adapter.py +++ b/python_repositories/adapters/redis_adapter.py @@ -17,9 +17,6 @@ from python_repositories.interfaces import ( if find_spec("redis") is not None: import redis from redis.commands.json.path import Path as RedisPath -else: - redis = None # type: ignore - RedisPath = None # type: ignore class RedisAdapter(