Skip to content

Commit 67632fd

Browse files
authored
Merge pull request #48 from community-of-python/feature/refactor
unlock packages versions, use mypy strict
2 parents 16c3b72 + fce0e67 commit 67632fd

27 files changed

+203
-3297
lines changed

.github/workflows/workflow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ on:
1414

1515
jobs:
1616
ci:
17-
uses: community-of-python/community-workflow/.github/workflows/preset.yml@main
17+
uses: community-of-python/community-workflow/.github/workflows/preset_with_just.yml@main
1818
secrets: inherit

.gitignore

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,21 @@
1-
.idea/
2-
.vscode/
3-
# Byte-compiled / optimized / DLL files
4-
pycache/
5-
__pycache__
6-
*.py[cod]
7-
*$py.class
8-
__test*
9-
10-
# C extensions
11-
*.so
12-
13-
# Distribution / packaging
14-
.Python
15-
build/
16-
develop-eggs/
17-
dist/
18-
downloads/
19-
eggs/
20-
.eggs/
21-
lib/
22-
lib64/
23-
parts/
24-
sdist/
25-
var/
26-
wheels/
27-
share/python-wheels/
28-
*.egg-info/
29-
.installed.cfg
30-
*.egg
31-
MANIFEST
32-
33-
# Unit test / coverage reports
34-
htmlcov/
35-
.tox/
36-
.nox/
1+
*.pyc
2+
*~
3+
__pycache__/*
4+
*.swp
5+
*.sqlite3
6+
*.map
7+
.vscode
8+
.idea
9+
.DS_Store
10+
.env
11+
.mypy_cache
12+
.pytest_cache
13+
.ruff_cache
3714
.coverage
38-
.coverage.*
39-
.cache
40-
nosetests.xml
15+
htmlcov/
4116
coverage.xml
42-
*.cover
43-
*.py,cover
44-
.hypothesis/
45-
.pytest_cache/
46-
cover/
47-
48-
# Environments
49-
.env
50-
.gen.env
17+
pytest.xml
18+
dist/
19+
.python-version
5120
.venv
52-
env/
53-
venv/
54-
ENV/
55-
env.bak/
56-
venv.bak/
57-
58-
# mypy
59-
.mypy_cache/
60-
.dmypy.json
61-
dmypy.json
62-
63-
# Cython debug symbols
64-
cython_debug/
65-
node_modules
66-
.temp
21+
poetry.lock

.pre-commit-config.yaml

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
repos:
2-
- repo: https://github.com/pre-commit/mirrors-mypy
3-
rev: v1.11.2
2+
- repo: local
43
hooks:
5-
- id: mypy
6-
name: mypy
7-
always_run: true
8-
additional_dependencies: [pydantic>=2.3.4]
9-
- repo: https://github.com/astral-sh/ruff-pre-commit
10-
rev: v0.6.9
11-
hooks:
12-
- id: ruff
13-
name: ruff-check
14-
always_run: true
15-
args: [--fix]
16-
- id: ruff-format
17-
name: ruff-format
18-
always_run: true
4+
- id: lint
5+
name: lint
6+
entry: just
7+
args: [lint]
8+
language: system
9+
types: [python]
10+
pass_filenames: false

Justfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
default: install lint test
2+
3+
test *args:
4+
poetry run pytest {{ args }}
5+
6+
install:
7+
poetry install --sync --no-root --all-extras
8+
9+
lint:
10+
poetry run ruff format
11+
poetry run ruff check --fix
12+
poetry run mypy .
13+
14+
lint-ci:
15+
poetry run ruff format --check
16+
poetry run ruff check --no-fix
17+
poetry run mypy .

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class YourFastApiSettings(FastApiSettings):
248248

249249
Parameters description:
250250

251-
- `service_name` - will be attached to metric's names, but has to be named in [snake_case](https://en.wikipedia.org/wiki/Snake_case).
251+
- `service_name` - will be attached to metrics's names, but has to be named in [snake_case](https://en.wikipedia.org/wiki/Snake_case).
252252
- `prometheus_metrics_path` - path to metrics handler.
253253
- `prometheus_metrics_include_in_schema` - whether to include metrics route in OpenAPI schema.
254254
- `prometheus_instrumentator_params` - will be passed to `Instrumentor` during initialization.

microbootstrap/bootstrappers/base.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@
22
import abc
33
import typing
44

5-
import typing_extensions
6-
75
from microbootstrap.console_writer import ConsoleWriter
86
from microbootstrap.helpers import dataclass_to_dict_no_defaults, merge_dataclasses_configs, merge_dict_configs
97
from microbootstrap.instruments.instrument_box import InstrumentBox
108
from microbootstrap.settings import SettingsT
119

1210

1311
if typing.TYPE_CHECKING:
14-
from _typeshed import DataclassInstance
12+
import typing_extensions
1513

1614
from microbootstrap.instruments.base import Instrument, InstrumentConfigT
1715

1816

19-
ApplicationT = typing.TypeVar("ApplicationT")
20-
DataclassT = typing.TypeVar("DataclassT", bound="DataclassInstance")
17+
class DataclassInstance(typing.Protocol):
18+
__dataclass_fields__: typing.ClassVar[dict[str, typing.Any]]
19+
20+
21+
ApplicationT = typing.TypeVar("ApplicationT", bound=typing.Any)
22+
DataclassT = typing.TypeVar("DataclassT", bound=DataclassInstance)
2123

2224

2325
class ApplicationBootstrapper(abc.ABC, typing.Generic[SettingsT, ApplicationT, DataclassT]):
@@ -35,21 +37,21 @@ def __init__(self, settings: SettingsT) -> None:
3537
self.instrument_box.initialize(self.settings)
3638

3739
def configure_application(
38-
self: typing_extensions.Self,
40+
self,
3941
application_config: DataclassT,
4042
) -> typing_extensions.Self:
4143
self.application_config = merge_dataclasses_configs(self.application_config, application_config)
4244
return self
4345

4446
def configure_instrument(
45-
self: typing_extensions.Self,
47+
self,
4648
instrument_config: InstrumentConfigT,
4749
) -> typing_extensions.Self:
4850
self.instrument_box.configure_instrument(instrument_config)
4951
return self
5052

5153
def configure_instruments(
52-
self: typing_extensions.Self,
54+
self,
5355
*instrument_configs: InstrumentConfigT,
5456
) -> typing_extensions.Self:
5557
for instrument_config in instrument_configs:
@@ -67,7 +69,7 @@ def use_instrument(
6769
cls.instrument_box = InstrumentBox()
6870
return cls.instrument_box.extend_instruments
6971

70-
def bootstrap(self: typing_extensions.Self) -> ApplicationT:
72+
def bootstrap(self) -> ApplicationT:
7173
resulting_application_config: dict[str, typing.Any] = {}
7274
for instrument in self.instrument_box.instruments:
7375
if instrument.is_ready():
@@ -92,14 +94,14 @@ def bootstrap(self: typing_extensions.Self) -> ApplicationT:
9294

9395
return self.bootstrap_after(application)
9496

95-
def bootstrap_before(self: typing_extensions.Self) -> dict[str, typing.Any]:
97+
def bootstrap_before(self) -> dict[str, typing.Any]:
9698
"""Add some framework-related parameters to final bootstrap result before application creation."""
9799
return {}
98100

99-
def bootstrap_after(self: typing_extensions.Self, application: ApplicationT) -> ApplicationT:
101+
def bootstrap_after(self, application: ApplicationT) -> ApplicationT:
100102
"""Add some framework-related parameters to final bootstrap result after application creation."""
101103
return application
102104

103-
def teardown(self: typing_extensions.Self) -> None:
105+
def teardown(self) -> None:
104106
for instrument in self.instrument_box.instruments:
105107
instrument.teardown()

microbootstrap/bootstrappers/fastapi.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import typing
22

33
import fastapi
4-
import typing_extensions
54
from fastapi.middleware.cors import CORSMiddleware
65
from fastapi_offline_docs import enable_offline_docs
76
from health_checks.fastapi_healthcheck import build_fastapi_health_check_router
@@ -22,13 +21,16 @@
2221
from microbootstrap.settings import FastApiSettings
2322

2423

24+
ApplicationT = typing.TypeVar("ApplicationT", bound=fastapi.FastAPI)
25+
26+
2527
class FastApiBootstrapper(
2628
ApplicationBootstrapper[FastApiSettings, fastapi.FastAPI, FastApiConfig],
2729
):
2830
application_config = FastApiConfig()
2931
application_type = fastapi.FastAPI
3032

31-
def bootstrap_before(self: typing_extensions.Self) -> dict[str, typing.Any]:
33+
def bootstrap_before(self) -> dict[str, typing.Any]:
3234
return {
3335
"debug": self.settings.service_debug,
3436
"on_shutdown": [self.teardown],
@@ -57,15 +59,15 @@ def bootstrap_before(self) -> dict[str, typing.Any]:
5759
"version": self.instrument_config.service_version,
5860
}
5961

60-
def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
62+
def bootstrap_after(self, application: ApplicationT) -> ApplicationT:
6163
if self.instrument_config.swagger_offline_docs:
6264
enable_offline_docs(application, static_files_handler=self.instrument_config.service_static_path)
6365
return application
6466

6567

6668
@FastApiBootstrapper.use_instrument()
6769
class FastApiCorsInstrument(CorsInstrument):
68-
def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
70+
def bootstrap_after(self, application: ApplicationT) -> ApplicationT:
6971
application.add_middleware(
7072
CORSMiddleware,
7173
allow_origins=self.instrument_config.cors_allowed_origins,
@@ -81,7 +83,7 @@ def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
8183

8284
@FastApiBootstrapper.use_instrument()
8385
class FastApiOpentelemetryInstrument(OpentelemetryInstrument):
84-
def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
86+
def bootstrap_after(self, application: ApplicationT) -> ApplicationT:
8587
FastAPIInstrumentor.instrument_app(
8688
application,
8789
tracer_provider=self.tracer_provider,
@@ -92,16 +94,16 @@ def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
9294

9395
@FastApiBootstrapper.use_instrument()
9496
class FastApiLoggingInstrument(LoggingInstrument):
95-
def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
96-
application.add_middleware(
97-
build_fastapi_logging_middleware(self.instrument_config.logging_exclude_endpoints),
97+
def bootstrap_after(self, application: ApplicationT) -> ApplicationT:
98+
application.add_middleware( # type: ignore[call-arg]
99+
build_fastapi_logging_middleware(self.instrument_config.logging_exclude_endpoints), # type: ignore[arg-type]
98100
)
99101
return application
100102

101103

102104
@FastApiBootstrapper.use_instrument()
103105
class FastApiPrometheusInstrument(PrometheusInstrument[FastApiPrometheusConfig]):
104-
def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
106+
def bootstrap_after(self, application: ApplicationT) -> ApplicationT:
105107
Instrumentator(**self.instrument_config.prometheus_instrumentator_params).instrument(
106108
application,
107109
**self.instrument_config.prometheus_instrument_params,
@@ -120,7 +122,7 @@ def get_config_type(cls) -> type[FastApiPrometheusConfig]:
120122

121123
@FastApiBootstrapper.use_instrument()
122124
class FastApiHealthChecksInstrument(HealthChecksInstrument):
123-
def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
125+
def bootstrap_after(self, application: ApplicationT) -> ApplicationT:
124126
application.include_router(
125127
build_fastapi_health_check_router(
126128
health_check=self.health_check,

microbootstrap/config/fastapi.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@
88

99

1010
if typing.TYPE_CHECKING:
11-
from fastapi import FastAPI, Request, routing
11+
from fastapi import Request, routing
12+
from fastapi.applications import AppType
1213
from fastapi.middleware import Middleware
1314
from fastapi.params import Depends
1415
from starlette.responses import Response
1516
from starlette.routing import BaseRoute
1617
from starlette.types import Lifespan
1718

1819

19-
AppType = typing.TypeVar("AppType", bound="FastAPI")
20-
21-
2220
@dataclasses.dataclass
2321
class FastApiConfig:
2422
debug: bool = False
@@ -47,7 +45,7 @@ class FastApiConfig:
4745
) = None
4846
on_startup: typing.Sequence[typing.Callable[[], typing.Any]] | None = None
4947
on_shutdown: typing.Sequence[typing.Callable[[], typing.Any]] | None = None
50-
lifespan: Lifespan[AppType] | None = None
48+
lifespan: Lifespan[AppType] | None = None # type: ignore[valid-type]
5149
terms_of_service: str | None = None
5250
contact: dict[str, str | typing.Any] | None = None
5351
license_info: dict[str, str | typing.Any] | None = None

microbootstrap/instruments/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414

1515
InstrumentConfigT = typing.TypeVar("InstrumentConfigT", bound="BaseInstrumentConfig")
16-
ApplicationT = typing.TypeVar("ApplicationT")
16+
ApplicationT = typing.TypeVar("ApplicationT", bound=typing.Any)
1717

1818

1919
class BaseInstrumentConfig(pydantic.BaseModel):

microbootstrap/instruments/cors_instrument.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
from __future__ import annotations
2+
import typing
23

34
import pydantic
5+
from litestar.types import Method # noqa: TC002
46

57
from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
68

79

810
class CorsConfig(BaseInstrumentConfig):
911
cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)
10-
cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)
12+
cors_allowed_methods: list[typing.Literal["*"] | Method] = pydantic.Field(default_factory=list)
1113
cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)
1214
cors_exposed_headers: list[str] = pydantic.Field(default_factory=list)
1315
cors_allowed_credentials: bool = False

0 commit comments

Comments
 (0)