Skip to content

Commit f2cda36

Browse files
committed
refactor(deps): improve optionnal dependencies check system/tests
1 parent 1750eea commit f2cda36

File tree

8 files changed

+58
-45
lines changed

8 files changed

+58
-45
lines changed

pyproject.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,20 @@ core = [
2424
"argon2-cffi>=25.1.0",
2525
"bcrypt>=5.0.0",
2626
]
27+
28+
typer = [
29+
"typer>=0.12.5",
30+
]
2731
fastapi = [
2832
"fastapi>=0.118.0",
2933
]
3034
all = [
35+
"typer>=0.12.5",
3136
"fastapi>=0.118.0",
3237
"sqlalchemy>=2.0.43",
3338
"argon2-cffi>=25.1.0",
3439
"bcrypt>=5.0.0",
3540
]
36-
cli = [
37-
"typer>=0.12.5",
38-
]
3941

4042
[build-system]
4143
requires = ["hatchling"]

src/fastapi_api_key/api.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1+
try:
2+
import fastapi # noqa: F401
3+
except ModuleNotFoundError as e:
4+
raise ImportError("API support requires 'fastapi'. Install it with: uv add fastapi-api-key[fastapi]") from e
5+
16
import warnings
27

38

49
from fastapi_api_key.services.service import AbstractApiKeyService
510
from fastapi_api_key.types import SecurityHTTPBearer, SecurityAPIKeyHeader
611

7-
try:
8-
import fastapi # noqa: F401
9-
import sqlalchemy # noqa: F401
10-
except ModuleNotFoundError as e:
11-
raise ImportError(
12-
"FastAPI and SQLAlchemy backend requires 'fastapi' and 'sqlalchemy'. "
13-
"Install it with: uv add fastapi_api_key[fastapi]"
14-
) from e
15-
1612
from datetime import datetime
1713
from typing import Annotated, Awaitable, Callable, List, Optional, TypeVar, Literal, Union
1814

src/fastapi_api_key/cli.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
try:
2+
import typer # noqa: F401
3+
except ModuleNotFoundError as e:
4+
raise ImportError("CLI support requires 'typer'. Install it with: uv add fastapi-api-key[typer]") from e
5+
16
import asyncio
27
import json
38
from dataclasses import asdict, is_dataclass
49
from datetime import datetime, timezone
510
from typing import Any, Awaitable, Callable, Optional
611

12+
from typer import Typer
13+
714
from fastapi_api_key.domain.base import ApiKeyEntity
815
from fastapi_api_key.domain.errors import (
916
InvalidKey,
@@ -25,7 +32,7 @@
2532

2633
def create_api_keys_cli(
2734
service_factory: ServiceFactory,
28-
app: Optional[Any] = None,
35+
app: Optional[Typer] = None,
2936
) -> Any:
3037
"""Build a Typer CLI bound to an :class:`AbstractApiKeyService`.
3138
@@ -36,8 +43,6 @@ def create_api_keys_cli(
3643
Returns:
3744
A configured Typer application exposing CRUD helpers for API keys.
3845
"""
39-
40-
typer = _import_typer()
4146
cli = app or typer.Typer(help="Manage API keys using fastapi-api-key services.", no_args_is_help=True)
4247

4348
def run_async(coro: Awaitable[Any]) -> Any:
@@ -275,13 +280,3 @@ def _serialize_entity(entity: ApiKeyEntity) -> dict[str, Any]:
275280
if isinstance(value, datetime):
276281
data[key] = value.isoformat()
277282
return data
278-
279-
280-
def _import_typer() -> Any:
281-
try:
282-
import typer
283-
except ImportError as exc: # pragma: no cover - import guard
284-
raise RuntimeError(
285-
"Typer is required to build the CLI. Install it with 'pip install fastapi-api-key[cli]'"
286-
) from exc
287-
return typer

src/fastapi_api_key/hasher/argon2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
try:
22
import argon2 # noqa: F401
33
except ModuleNotFoundError as e:
4-
raise ImportError("SQLAlchemy backend requires 'argon2'. Install it with: uv add fastapi_api_key[argon2]") from e
4+
raise ImportError("SQLAlchemy backend requires 'argon2'. Install it with: uv add fastapi-api-key[argon2]") from e
55

66
from typing import Optional
77

src/fastapi_api_key/hasher/bcrypt.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
from typing import Optional
2-
31
try:
42
import bcrypt # noqa: F401
53
except ModuleNotFoundError as e:
6-
raise ImportError("SQLAlchemy backend requires 'bcrypt'. Install it with: uv add fastapi_api_key[bcrypt]") from e
4+
raise ImportError("SQLAlchemy backend requires 'bcrypt'. Install it with: uv add fastapi-api-key[bcrypt]") from e
75
import bcrypt
86

7+
from typing import Optional
8+
9+
910
from fastapi_api_key.hasher.base import BaseApiKeyHasher
1011

1112

src/fastapi_api_key/repositories/sql.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
from fastapi_api_key.domain.base import D
2-
31
try:
42
import sqlalchemy # noqa: F401
53
except ModuleNotFoundError as e:
64
raise ImportError(
7-
"SQLAlchemy backend requires 'sqlalchemy'. Install it with: uv add fastapi_api_key[sqlalchemy]"
5+
"SQLAlchemy backend requires 'sqlalchemy'. Install it with: uv add fastapi-api-key[sqlalchemy]"
86
) from e
97

8+
from fastapi_api_key.domain.base import D
9+
1010

1111
from datetime import datetime
1212
from typing import Callable, Generic, Type, TypeVar, List

tests/test_regression.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import importlib
2-
import sys
3-
from typing import Optional, Type
4-
5-
import pytest
6-
from fastapi_api_key.hasher.base import ApiKeyHasher
72
import re
83
import string
4+
import sys
95
from datetime import datetime, timezone
6+
from typing import Optional, Type
107

8+
import pytest
119

10+
from fastapi_api_key.hasher.base import ApiKeyHasher
1211
from fastapi_api_key.utils import (
1312
uuid_factory,
1413
key_id_factory,
@@ -23,8 +22,7 @@ def test_version():
2322

2423
assert hasattr(module, "__version__")
2524
assert isinstance(module.__version__, str)
26-
assert module.__version__ == "0.3.0" # Replace with the expected version
27-
25+
assert module.__version__ == "0.3.0" # Replace with the expected version
2826

2927

3028
@pytest.mark.parametrize(
@@ -103,15 +101,34 @@ def test_warning_default_pepper(hasher_class: Type[ApiKeyHasher]):
103101
["argon2", "fastapi_api_key.hasher.argon2"],
104102
],
105103
)
106-
def test_sqlalchemy_backend_import_error(monkeypatch: pytest.MonkeyPatch, library: str, module_path: str):
104+
def test_import_backend_error(monkeypatch: pytest.MonkeyPatch, library: str, module_path: str):
105+
"""Simulate absence of SQLAlchemy and check for ImportError."""
106+
monkeypatch.setitem(sys.modules, library, None)
107+
108+
with pytest.raises(ImportError) as exc_info:
109+
module = importlib.import_module(module_path)
110+
importlib.reload(module)
111+
112+
expected = f"backend requires '{library}'. Install it with: uv add fastapi-api-key[{library}]"
113+
assert expected in f"{exc_info.value}"
114+
115+
116+
@pytest.mark.parametrize(
117+
["library", "module_path"],
118+
[
119+
["typer", "fastapi_api_key.cli"],
120+
["fastapi", "fastapi_api_key.api"],
121+
],
122+
)
123+
def test_import_support_error(monkeypatch: pytest.MonkeyPatch, library: str, module_path: str):
107124
"""Simulate absence of SQLAlchemy and check for ImportError."""
108125
monkeypatch.setitem(sys.modules, library, None)
109126

110127
with pytest.raises(ImportError) as exc_info:
111128
module = importlib.import_module(module_path)
112129
importlib.reload(module)
113130

114-
expected = f"backend requires '{library}'. Install it with: uv add fastapi_api_key[{library}]"
131+
expected = f"support requires '{library}'. Install it with: uv add fastapi-api-key[{library}]"
115132
assert expected in f"{exc_info.value}"
116133

117134

uv.lock

Lines changed: 6 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)