microbootstrap 0.0.4__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/PKG-INFO +84 -22
  2. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/README.md +79 -21
  3. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/__init__.py +4 -0
  4. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/bootstrappers/litestar.py +52 -1
  5. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/instruments/base.py +13 -10
  6. microbootstrap-0.2.0/microbootstrap/instruments/cors_instrument.py +29 -0
  7. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/instruments/logging_instrument.py +6 -15
  8. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/instruments/opentelemetry_instrument.py +4 -15
  9. microbootstrap-0.2.0/microbootstrap/instruments/prometheus_instrument.py +28 -0
  10. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/instruments/sentry_instrument.py +2 -16
  11. microbootstrap-0.2.0/microbootstrap/instruments/swagger_instrument.py +30 -0
  12. microbootstrap-0.2.0/microbootstrap/py.typed +0 -0
  13. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/settings.py +7 -5
  14. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/pyproject.toml +14 -7
  15. microbootstrap-0.0.4/microbootstrap/instruments/__init__.py +0 -7
  16. microbootstrap-0.0.4/microbootstrap/instruments/prometheus_instrument.py +0 -45
  17. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/bootstrappers/__init__.py +0 -0
  18. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/bootstrappers/base.py +0 -0
  19. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/console_writer.py +0 -0
  20. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/exceptions.py +0 -0
  21. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/granian_server.py +0 -0
  22. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/helpers.py +0 -0
  23. {microbootstrap-0.0.4/microbootstrap/middlewares → microbootstrap-0.2.0/microbootstrap/instruments}/__init__.py +0 -0
  24. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/instruments/instrument_box.py +0 -0
  25. /microbootstrap-0.0.4/microbootstrap/py.typed → /microbootstrap-0.2.0/microbootstrap/middlewares/__init__.py +0 -0
  26. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/middlewares/fastapi.py +0 -0
  27. {microbootstrap-0.0.4 → microbootstrap-0.2.0}/microbootstrap/middlewares/litestar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: microbootstrap
3
- Version: 0.0.4
3
+ Version: 0.2.0
4
4
  Summary: Package for bootstrapping new micro-services
5
5
  Keywords: python,microservice,bootstrap,opentelemetry,logging,error-tracing,litestar,fastapi
6
6
  Author: community-of-python
@@ -24,6 +24,7 @@ Requires-Dist: eval-type-backport (>=0.2.0,<0.3.0)
24
24
  Requires-Dist: fastapi (>=0.111.0,<0.112.0) ; extra == "fastapi"
25
25
  Requires-Dist: granian[reload] (>=1.4.4,<2.0.0)
26
26
  Requires-Dist: litestar (>=2.9.1,<3.0.0) ; extra == "litestar"
27
+ Requires-Dist: litestar-offline-docs (>=1.0.1,<2.0.0) ; extra == "litestar"
27
28
  Requires-Dist: opentelemetry-api (>=1.25.0,<2.0.0)
28
29
  Requires-Dist: opentelemetry-exporter-otlp (>=1.25.0,<2.0.0)
29
30
  Requires-Dist: opentelemetry-exporter-prometheus-remote-write (>=0.46b0,<0.47)
@@ -39,6 +40,9 @@ Requires-Dist: rich (>=13.7.1,<14.0.0)
39
40
  Requires-Dist: sentry-sdk (>=2.7.1,<3.0.0)
40
41
  Requires-Dist: structlog (>=24.2.0,<25.0.0)
41
42
  Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
43
+ Project-URL: documentation, https://pypi.org/project/microbootstrap/
44
+ Project-URL: homepage, https://github.com/community-of-python/microbootstrap
45
+ Project-URL: repository, https://github.com/community-of-python/microbootstrap
42
46
  Description-Content-Type: text/markdown
43
47
 
44
48
  <p align="center">
@@ -46,15 +50,9 @@ Description-Content-Type: text/markdown
46
50
  </p>
47
51
  <br>
48
52
  <p align="center">
49
- <a href="https://codecov.io/gh/community-of-python/microbootstrap" target="_blank">
50
- <img src="https://codecov.io/gh/community-of-python/microbootstrap/branch/main/graph/badge.svg">
51
- </a>
52
- <a href="https://pypi.org/project/microbootstrap/" target="_blank">
53
- <img src="https://img.shields.io/pypi/pyversions/microbootstrap">
54
- </a>
55
- <a href="https://pypi.org/project/microbootstrap/" target="_blank">
56
- <img src="https://img.shields.io/pypi/v/microbootstrap">
57
- </a>
53
+ <a href="https://codecov.io/gh/community-of-python/microbootstrap" target="_blank"><img src="https://codecov.io/gh/community-of-python/microbootstrap/branch/main/graph/badge.svg"></a>
54
+ <a href="https://pypi.org/project/microbootstrap/" target="_blank"><img src="https://img.shields.io/pypi/pyversions/microbootstrap"></a>
55
+ <a href="https://pypi.org/project/microbootstrap/" target="_blank"><img src="https://img.shields.io/pypi/v/microbootstrap"></a>
58
56
  </p>
59
57
 
60
58
  # microbootstrap
@@ -83,14 +81,15 @@ from your_application.settings import settings
83
81
  application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
84
82
  ```
85
83
 
86
- With <b>microbootstrap</b>, you get an application with built-in support for:
84
+ Only `litestar` is supported yet.
85
+ With <b>microbootstrap</b>, you get an application with lightweight built-in support for:
87
86
 
88
87
  - `sentry`
89
88
  - `prometheus`
90
89
  - `opentelemetry`
91
90
  - `logging`
92
-
93
- <b>microbootstrap</b> supports only `litestar` framework for now.
91
+ - `cors`
92
+ - `swagger` - additional offline version support
94
93
 
95
94
  Interested? Let's jump right into it ⚡
96
95
 
@@ -107,7 +106,7 @@ $ poetry add microbootstrap -E litestar
107
106
  pip:
108
107
 
109
108
  ```bash
110
- $ poetry add microbootstrap[litestar]
109
+ $ pip install microbootstrap[litestar]
111
110
  ```
112
111
 
113
112
  ## Quickstart
@@ -212,6 +211,8 @@ Currently, these instruments are already supported for bootstrapping:
212
211
  - `prometheus`
213
212
  - `opentelemetry`
214
213
  - `logging`
214
+ - `cors`
215
+ - `swagger`
215
216
 
216
217
  Let's make it clear, what it takes to bootstrap them.
217
218
 
@@ -296,7 +297,7 @@ class YourSettings(BaseBootstrapSettings):
296
297
 
297
298
  All these settings are then passed to [opentelemetry](https://opentelemetry.io/), completing your Opentelemetry integration.
298
299
 
299
- ## Logging
300
+ ### Logging
300
301
 
301
302
  <b>microbootstrap</b> provides in-memory json logging using [structlog](https://pypi.org/project/structlog/).
302
303
  To learn more about in-memory logging, check out [MemoryHandler](https://docs.python.org/3/library/logging.handlers.html#memoryhandler)
@@ -329,6 +330,59 @@ Parameters description:
329
330
  - `logging_extra_processors` - set additional structlog processors if you have some.
330
331
  - `logging_exclude_endpoints` - remove logging on certain endpoints.
331
332
 
333
+ ### Swagger
334
+
335
+ ```python
336
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
337
+
338
+
339
+ class YourSettings(BaseBootstrapSettings):
340
+ service_name: str = "micro-service"
341
+ service_description: str = "Micro service description"
342
+ service_version: str = "1.0.0"
343
+ service_static_path: str = "/static"
344
+
345
+ swagger_path: str = "/docs"
346
+ swagger_offline_docs: bool = False
347
+ swagger_extra_params: dict[str, Any] = {}
348
+ ```
349
+
350
+ Parameters description:
351
+
352
+ - `service_environment` - will be displayed in docs.
353
+ - `service_name` - will be displayed in docs.
354
+ - `service_description` - will be displayed in docs.
355
+ - `service_static_path` - set additional structlog processors if you have some.
356
+ - `swagger_path` - path of the docs.
357
+ - `swagger_offline_docs` - makes swagger js bundles access offline, because service starts to host via static.
358
+ - `swagger_extra_params` - additional params to pass into openapi config.
359
+
360
+ ### Cors
361
+
362
+ ```python
363
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
364
+
365
+
366
+ class YourSettings(BaseBootstrapSettings):
367
+ cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)
368
+ cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)
369
+ cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)
370
+ cors_exposed_headers: list[str] = pydantic.Field(default_factory=list)
371
+ cors_allowed_credentials: bool = False
372
+ cors_allowed_origin_regex: str | None = None
373
+ cors_max_age: int = 600
374
+ ```
375
+
376
+ Parameters description:
377
+
378
+ - `cors_allowed_origins` - list of origins that are allowed.
379
+ - `cors_allowed_methods` - list of allowed HTTP methods.
380
+ - `cors_allowed_headers` - list of allowed headers.
381
+ - `cors_exposed_headers` - list of headers that are exposed via the 'Access-Control-Expose-Headers' header.
382
+ - `cors_allowed_credentials` - boolean dictating whether or not to set the 'Access-Control-Allow-Credentials' header.
383
+ - `cors_allowed_origin_regex` - regex to match origins against.
384
+ - `cors_max_age` - response caching TTL in seconds, defaults to 600.
385
+
332
386
  ## Configuration
333
387
 
334
388
  Despite settings being pretty convenient mechanism, it's not always possible to store everything in settings.
@@ -343,6 +397,8 @@ To configure instruemt manually, you have to import one of available configs fro
343
397
  - `OpentelemetryConfig`
344
398
  - `PrometheusConfig`
345
399
  - `LoggingConfig`
400
+ - `SwaggerConfig`
401
+ - `CorsConfig`
346
402
 
347
403
  And pass them into `.configure_instrument` or `.configure_instruments` bootstrapper method.
348
404
 
@@ -453,7 +509,7 @@ application: litestar.Litestar = (
453
509
  > ```
454
510
  >
455
511
  > In this case prometheus will receive `{"first_value: 1", "second_value": 2}` inside `prometheus_additional_params`
456
- > This is also true for `list`, `tuple` and `set`s
512
+ > This is also true for `list`, `tuple` and `set`
457
513
 
458
514
  ## Advanced
459
515
 
@@ -477,8 +533,8 @@ from microbootstrap.instruments.base import Instrument
477
533
 
478
534
 
479
535
  class MyInstrument(Instrument[MyInstrumentConfig]):
480
- def write_status(self, console_writer: ConsoleWriter) -> None:
481
- pass
536
+ instrument_name: str
537
+ ready_condition: str
482
538
 
483
539
  def is_ready(self) -> bool:
484
540
  pass
@@ -496,10 +552,16 @@ class MyInstrument(Instrument[MyInstrumentConfig]):
496
552
 
497
553
  And now you can define behaviour of your instrument
498
554
 
499
- - `write_status` - writes status to console, indicating, is instrument bootstrapped.
500
- - `is_ready` - defines ready for bootstrapping state of instrument, based on it's config values.
501
- - `teardown` - graceful shutdown for instrument during application shutdown.
502
- - `bootstrap` - main instrument's logic.
555
+ Attributes:
556
+
557
+ - `instrument_name` - Will be displayed in your console during bootstrap.
558
+ - `ready_condition` - Will be displayed in your console during bootstrap if instument is not ready.
559
+
560
+ Methods:
561
+
562
+ - `is_ready` - defines ready for bootstrapping state of instrument, based on it's config values. Required.
563
+ - `teardown` - graceful shutdown for instrument during application shutdown. Not required.
564
+ - `bootstrap` - main instrument's logic. Not required.
503
565
 
504
566
  When you have a carcass of instrument, you can adapt it for every framework existing.
505
567
  Let's adapt it for litestar for example
@@ -3,15 +3,9 @@
3
3
  </p>
4
4
  <br>
5
5
  <p align="center">
6
- <a href="https://codecov.io/gh/community-of-python/microbootstrap" target="_blank">
7
- <img src="https://codecov.io/gh/community-of-python/microbootstrap/branch/main/graph/badge.svg">
8
- </a>
9
- <a href="https://pypi.org/project/microbootstrap/" target="_blank">
10
- <img src="https://img.shields.io/pypi/pyversions/microbootstrap">
11
- </a>
12
- <a href="https://pypi.org/project/microbootstrap/" target="_blank">
13
- <img src="https://img.shields.io/pypi/v/microbootstrap">
14
- </a>
6
+ <a href="https://codecov.io/gh/community-of-python/microbootstrap" target="_blank"><img src="https://codecov.io/gh/community-of-python/microbootstrap/branch/main/graph/badge.svg"></a>
7
+ <a href="https://pypi.org/project/microbootstrap/" target="_blank"><img src="https://img.shields.io/pypi/pyversions/microbootstrap"></a>
8
+ <a href="https://pypi.org/project/microbootstrap/" target="_blank"><img src="https://img.shields.io/pypi/v/microbootstrap"></a>
15
9
  </p>
16
10
 
17
11
  # microbootstrap
@@ -40,14 +34,15 @@ from your_application.settings import settings
40
34
  application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
41
35
  ```
42
36
 
43
- With <b>microbootstrap</b>, you get an application with built-in support for:
37
+ Only `litestar` is supported yet.
38
+ With <b>microbootstrap</b>, you get an application with lightweight built-in support for:
44
39
 
45
40
  - `sentry`
46
41
  - `prometheus`
47
42
  - `opentelemetry`
48
43
  - `logging`
49
-
50
- <b>microbootstrap</b> supports only `litestar` framework for now.
44
+ - `cors`
45
+ - `swagger` - additional offline version support
51
46
 
52
47
  Interested? Let's jump right into it ⚡
53
48
 
@@ -64,7 +59,7 @@ $ poetry add microbootstrap -E litestar
64
59
  pip:
65
60
 
66
61
  ```bash
67
- $ poetry add microbootstrap[litestar]
62
+ $ pip install microbootstrap[litestar]
68
63
  ```
69
64
 
70
65
  ## Quickstart
@@ -169,6 +164,8 @@ Currently, these instruments are already supported for bootstrapping:
169
164
  - `prometheus`
170
165
  - `opentelemetry`
171
166
  - `logging`
167
+ - `cors`
168
+ - `swagger`
172
169
 
173
170
  Let's make it clear, what it takes to bootstrap them.
174
171
 
@@ -253,7 +250,7 @@ class YourSettings(BaseBootstrapSettings):
253
250
 
254
251
  All these settings are then passed to [opentelemetry](https://opentelemetry.io/), completing your Opentelemetry integration.
255
252
 
256
- ## Logging
253
+ ### Logging
257
254
 
258
255
  <b>microbootstrap</b> provides in-memory json logging using [structlog](https://pypi.org/project/structlog/).
259
256
  To learn more about in-memory logging, check out [MemoryHandler](https://docs.python.org/3/library/logging.handlers.html#memoryhandler)
@@ -286,6 +283,59 @@ Parameters description:
286
283
  - `logging_extra_processors` - set additional structlog processors if you have some.
287
284
  - `logging_exclude_endpoints` - remove logging on certain endpoints.
288
285
 
286
+ ### Swagger
287
+
288
+ ```python
289
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
290
+
291
+
292
+ class YourSettings(BaseBootstrapSettings):
293
+ service_name: str = "micro-service"
294
+ service_description: str = "Micro service description"
295
+ service_version: str = "1.0.0"
296
+ service_static_path: str = "/static"
297
+
298
+ swagger_path: str = "/docs"
299
+ swagger_offline_docs: bool = False
300
+ swagger_extra_params: dict[str, Any] = {}
301
+ ```
302
+
303
+ Parameters description:
304
+
305
+ - `service_environment` - will be displayed in docs.
306
+ - `service_name` - will be displayed in docs.
307
+ - `service_description` - will be displayed in docs.
308
+ - `service_static_path` - set additional structlog processors if you have some.
309
+ - `swagger_path` - path of the docs.
310
+ - `swagger_offline_docs` - makes swagger js bundles access offline, because service starts to host via static.
311
+ - `swagger_extra_params` - additional params to pass into openapi config.
312
+
313
+ ### Cors
314
+
315
+ ```python
316
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
317
+
318
+
319
+ class YourSettings(BaseBootstrapSettings):
320
+ cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)
321
+ cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)
322
+ cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)
323
+ cors_exposed_headers: list[str] = pydantic.Field(default_factory=list)
324
+ cors_allowed_credentials: bool = False
325
+ cors_allowed_origin_regex: str | None = None
326
+ cors_max_age: int = 600
327
+ ```
328
+
329
+ Parameters description:
330
+
331
+ - `cors_allowed_origins` - list of origins that are allowed.
332
+ - `cors_allowed_methods` - list of allowed HTTP methods.
333
+ - `cors_allowed_headers` - list of allowed headers.
334
+ - `cors_exposed_headers` - list of headers that are exposed via the 'Access-Control-Expose-Headers' header.
335
+ - `cors_allowed_credentials` - boolean dictating whether or not to set the 'Access-Control-Allow-Credentials' header.
336
+ - `cors_allowed_origin_regex` - regex to match origins against.
337
+ - `cors_max_age` - response caching TTL in seconds, defaults to 600.
338
+
289
339
  ## Configuration
290
340
 
291
341
  Despite settings being pretty convenient mechanism, it's not always possible to store everything in settings.
@@ -300,6 +350,8 @@ To configure instruemt manually, you have to import one of available configs fro
300
350
  - `OpentelemetryConfig`
301
351
  - `PrometheusConfig`
302
352
  - `LoggingConfig`
353
+ - `SwaggerConfig`
354
+ - `CorsConfig`
303
355
 
304
356
  And pass them into `.configure_instrument` or `.configure_instruments` bootstrapper method.
305
357
 
@@ -410,7 +462,7 @@ application: litestar.Litestar = (
410
462
  > ```
411
463
  >
412
464
  > In this case prometheus will receive `{"first_value: 1", "second_value": 2}` inside `prometheus_additional_params`
413
- > This is also true for `list`, `tuple` and `set`s
465
+ > This is also true for `list`, `tuple` and `set`
414
466
 
415
467
  ## Advanced
416
468
 
@@ -434,8 +486,8 @@ from microbootstrap.instruments.base import Instrument
434
486
 
435
487
 
436
488
  class MyInstrument(Instrument[MyInstrumentConfig]):
437
- def write_status(self, console_writer: ConsoleWriter) -> None:
438
- pass
489
+ instrument_name: str
490
+ ready_condition: str
439
491
 
440
492
  def is_ready(self) -> bool:
441
493
  pass
@@ -453,10 +505,16 @@ class MyInstrument(Instrument[MyInstrumentConfig]):
453
505
 
454
506
  And now you can define behaviour of your instrument
455
507
 
456
- - `write_status` - writes status to console, indicating, is instrument bootstrapped.
457
- - `is_ready` - defines ready for bootstrapping state of instrument, based on it's config values.
458
- - `teardown` - graceful shutdown for instrument during application shutdown.
459
- - `bootstrap` - main instrument's logic.
508
+ Attributes:
509
+
510
+ - `instrument_name` - Will be displayed in your console during bootstrap.
511
+ - `ready_condition` - Will be displayed in your console during bootstrap if instument is not ready.
512
+
513
+ Methods:
514
+
515
+ - `is_ready` - defines ready for bootstrapping state of instrument, based on it's config values. Required.
516
+ - `teardown` - graceful shutdown for instrument during application shutdown. Not required.
517
+ - `bootstrap` - main instrument's logic. Not required.
460
518
 
461
519
  When you have a carcass of instrument, you can adapt it for every framework existing.
462
520
  Let's adapt it for litestar for example
@@ -1,7 +1,9 @@
1
+ from microbootstrap.instruments.cors_instrument import CorsConfig
1
2
  from microbootstrap.instruments.logging_instrument import LoggingConfig
2
3
  from microbootstrap.instruments.opentelemetry_instrument import OpentelemetryConfig
3
4
  from microbootstrap.instruments.prometheus_instrument import PrometheusConfig
4
5
  from microbootstrap.instruments.sentry_instrument import SentryConfig
6
+ from microbootstrap.instruments.swagger_instrument import SwaggerConfig
5
7
  from microbootstrap.settings import LitestarSettings
6
8
 
7
9
 
@@ -12,4 +14,6 @@ __all__ = (
12
14
  "LoggingConfig",
13
15
  "LitestarBootstrapper",
14
16
  "LitestarSettings",
17
+ "CorsConfig",
18
+ "SwaggerConfig",
15
19
  )
@@ -5,18 +5,22 @@ import litestar
5
5
  import litestar.types
6
6
  import sentry_sdk
7
7
  import typing_extensions
8
- from litestar import status_codes
8
+ from litestar import openapi, status_codes
9
9
  from litestar.config.app import AppConfig as LitestarConfig
10
+ from litestar.config.cors import CORSConfig as LitestarCorsConfig
10
11
  from litestar.contrib.opentelemetry.config import OpenTelemetryConfig as LitestarOpentelemetryConfig
11
12
  from litestar.contrib.prometheus import PrometheusConfig as LitestarPrometheusConfig
12
13
  from litestar.contrib.prometheus import PrometheusController
13
14
  from litestar.exceptions.http_exceptions import HTTPException
15
+ from litestar_offline_docs import generate_static_files_config
14
16
 
15
17
  from microbootstrap.bootstrappers.base import ApplicationBootstrapper
18
+ from microbootstrap.instruments.cors_instrument import CorsInstrument
16
19
  from microbootstrap.instruments.logging_instrument import LoggingInstrument
17
20
  from microbootstrap.instruments.opentelemetry_instrument import OpentelemetryInstrument
18
21
  from microbootstrap.instruments.prometheus_instrument import PrometheusInstrument
19
22
  from microbootstrap.instruments.sentry_instrument import SentryInstrument
23
+ from microbootstrap.instruments.swagger_instrument import SwaggerInstrument
20
24
  from microbootstrap.middlewares.litestar import build_litestar_logging_middleware
21
25
  from microbootstrap.settings import LitestarSettings
22
26
 
@@ -52,6 +56,53 @@ class LitestarSentryInstrument(SentryInstrument):
52
56
  return {"after_exception": [self.sentry_exception_catcher_hook]}
53
57
 
54
58
 
59
+ @LitestarBootstrapper.use_instrument()
60
+ class LitestarSwaggerInstrument(SwaggerInstrument):
61
+ def bootstrap_before(self) -> dict[str, typing.Any]:
62
+ class LitestarOpenAPIController(openapi.OpenAPIController):
63
+ path = self.instrument_config.swagger_path
64
+ if self.instrument_config.swagger_offline_docs:
65
+ swagger_ui_standalone_preset_js_url = (
66
+ f"{self.instrument_config.service_static_path}/swagger-ui-standalone-preset.js"
67
+ )
68
+ swagger_bundle_path: str = f"{self.instrument_config.service_static_path}/swagger-ui-bundle.js"
69
+ swagger_css_url: str = f"{self.instrument_config.service_static_path}/swagger-ui.css"
70
+
71
+ openapi_config: typing.Final = openapi.OpenAPIConfig(
72
+ title=self.instrument_config.service_name,
73
+ version=self.instrument_config.service_version,
74
+ description=self.instrument_config.service_description,
75
+ openapi_controller=LitestarOpenAPIController,
76
+ **self.instrument_config.swagger_extra_params,
77
+ )
78
+
79
+ bootstrap_result = {}
80
+ if self.instrument_config.swagger_offline_docs:
81
+ bootstrap_result["static_files_config"] = [
82
+ generate_static_files_config(static_files_handler_path=self.instrument_config.service_static_path),
83
+ ]
84
+ return {
85
+ **bootstrap_result,
86
+ "openapi_config": openapi_config,
87
+ }
88
+
89
+
90
+ @LitestarBootstrapper.use_instrument()
91
+ class LitestarCorsInstrument(CorsInstrument):
92
+ def bootstrap_before(self) -> dict[str, typing.Any]:
93
+ return {
94
+ "cors_config": LitestarCorsConfig(
95
+ allow_origins=self.instrument_config.cors_allowed_origins,
96
+ allow_methods=self.instrument_config.cors_allowed_methods,
97
+ allow_headers=self.instrument_config.cors_allowed_headers,
98
+ allow_credentials=self.instrument_config.cors_allowed_credentials,
99
+ allow_origin_regex=self.instrument_config.cors_allowed_origin_regex,
100
+ expose_headers=self.instrument_config.cors_exposed_headers,
101
+ max_age=self.instrument_config.cors_max_age,
102
+ ),
103
+ }
104
+
105
+
55
106
  @LitestarBootstrapper.use_instrument()
56
107
  class LitetstarOpentelemetryInstrument(OpentelemetryInstrument):
57
108
  def bootstrap_before(self) -> dict[str, typing.Any]:
@@ -23,6 +23,8 @@ class BaseInstrumentConfig(pydantic.BaseModel):
23
23
  @dataclasses.dataclass
24
24
  class Instrument(abc.ABC, typing.Generic[InstrumentConfigT]):
25
25
  instrument_config: InstrumentConfigT
26
+ instrument_name: typing.ClassVar[str]
27
+ ready_condition: typing.ClassVar[str]
26
28
 
27
29
  def configure_instrument(
28
30
  self,
@@ -30,27 +32,28 @@ class Instrument(abc.ABC, typing.Generic[InstrumentConfigT]):
30
32
  ) -> None:
31
33
  self.instrument_config = merge_pydantic_configs(self.instrument_config, incoming_config)
32
34
 
33
- @abc.abstractmethod
34
35
  def write_status(self, console_writer: ConsoleWriter) -> None:
35
- raise NotImplementedError
36
+ console_writer.write_instrument_status(
37
+ self.instrument_name,
38
+ is_enabled=self.is_ready(),
39
+ disable_reason=None if self.is_ready() else self.ready_condition,
40
+ )
36
41
 
37
42
  @abc.abstractmethod
38
43
  def is_ready(self) -> bool:
39
44
  raise NotImplementedError
40
45
 
41
- @abc.abstractmethod
42
- def bootstrap(self) -> None:
43
- raise NotImplementedError
44
-
45
- @abc.abstractmethod
46
- def teardown(self) -> None:
47
- raise NotImplementedError
48
-
49
46
  @classmethod
50
47
  @abc.abstractmethod
51
48
  def get_config_type(cls) -> type[InstrumentConfigT]:
52
49
  raise NotImplementedError
53
50
 
51
+ def bootstrap(self) -> None:
52
+ return None
53
+
54
+ def teardown(self) -> None:
55
+ return None
56
+
54
57
  def bootstrap_before(self) -> dict[str, typing.Any]:
55
58
  """Add some framework-related parameters to final bootstrap result before application creation."""
56
59
  return {}
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ import pydantic
4
+
5
+ from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
6
+
7
+
8
+ class CorsConfig(BaseInstrumentConfig):
9
+ cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)
10
+ cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)
11
+ cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)
12
+ cors_exposed_headers: list[str] = pydantic.Field(default_factory=list)
13
+ cors_allowed_credentials: bool = False
14
+ cors_allowed_origin_regex: str | None = None
15
+ cors_max_age: int = 600
16
+
17
+
18
+ class CorsInstrument(Instrument[CorsConfig]):
19
+ instrument_name = "Cors"
20
+ ready_condition = "Provide allowed origins or regex"
21
+
22
+ def is_ready(self) -> bool:
23
+ return bool(self.instrument_config.cors_allowed_origins) or bool(
24
+ self.instrument_config.cors_allowed_origin_regex,
25
+ )
26
+
27
+ @classmethod
28
+ def get_config_type(cls) -> type[CorsConfig]:
29
+ return CorsConfig
@@ -17,8 +17,6 @@ if typing.TYPE_CHECKING:
17
17
  import litestar
18
18
  from structlog.typing import EventDict, WrappedLogger
19
19
 
20
- from microbootstrap.console_writer import ConsoleWriter
21
-
22
20
 
23
21
  ScopeType = typing.MutableMapping[str, typing.Any]
24
22
 
@@ -120,26 +118,19 @@ class MemoryLoggerFactory(structlog.stdlib.LoggerFactory):
120
118
  class LoggingConfig(BaseInstrumentConfig):
121
119
  service_debug: bool = True
122
120
 
123
- logging_log_level: int = pydantic.Field(default=logging.INFO)
124
- logging_flush_level: int = pydantic.Field(default=logging.ERROR)
125
- logging_buffer_capacity: int = pydantic.Field(default=10)
121
+ logging_log_level: int = logging.INFO
122
+ logging_flush_level: int = logging.ERROR
123
+ logging_buffer_capacity: int = 10
126
124
  logging_extra_processors: list[typing.Any] = pydantic.Field(default_factory=list)
127
125
  logging_unset_handlers: list[str] = pydantic.Field(
128
126
  default_factory=lambda: ["uvicorn", "uvicorn.access"],
129
127
  )
130
- logging_exclude_endpoints: list[str] = pydantic.Field(default_factory=lambda: ["/health"])
128
+ logging_exclude_endpoints: list[str] = pydantic.Field(default_factory=list)
131
129
 
132
130
 
133
131
  class LoggingInstrument(Instrument[LoggingConfig]):
134
- def write_status(self, console_writer: ConsoleWriter) -> None:
135
- if self.is_ready():
136
- console_writer.write_instrument_status("Logging", is_enabled=True)
137
- else:
138
- console_writer.write_instrument_status(
139
- "Logging",
140
- is_enabled=False,
141
- disable_reason="Works only in non-debug mode",
142
- )
132
+ instrument_name = "Logging"
133
+ ready_condition = "Works only in non-debug mode"
143
134
 
144
135
  def is_ready(self) -> bool:
145
136
  return not self.instrument_config.service_debug
@@ -12,10 +12,6 @@ from opentelemetry.sdk.trace.export import BatchSpanProcessor
12
12
  from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
13
13
 
14
14
 
15
- if typing.TYPE_CHECKING:
16
- from microbootstrap.console_writer import ConsoleWriter
17
-
18
-
19
15
  @dataclasses.dataclass()
20
16
  class OpenTelemetryInstrumentor:
21
17
  instrumentor: BaseInstrumentor
@@ -23,8 +19,8 @@ class OpenTelemetryInstrumentor:
23
19
 
24
20
 
25
21
  class OpentelemetryConfig(BaseInstrumentConfig):
26
- service_name: str = pydantic.Field(default="micro-service")
27
- service_version: str = pydantic.Field(default="1.0.0")
22
+ service_name: str = "micro-service"
23
+ service_version: str = "1.0.0"
28
24
 
29
25
  opentelemetry_container_name: str | None = None
30
26
  opentelemetry_endpoint: str | None = None
@@ -35,15 +31,8 @@ class OpentelemetryConfig(BaseInstrumentConfig):
35
31
 
36
32
 
37
33
  class OpentelemetryInstrument(Instrument[OpentelemetryConfig]):
38
- def write_status(self, console_writer: ConsoleWriter) -> None:
39
- if self.is_ready():
40
- console_writer.write_instrument_status("Opentelemetry", is_enabled=True)
41
- else:
42
- console_writer.write_instrument_status(
43
- "Opentelemetry",
44
- is_enabled=False,
45
- disable_reason="Provide all necessary config parameters",
46
- )
34
+ instrument_name = "Opentelemetry"
35
+ ready_condition = "Provide all necessary config parameters"
47
36
 
48
37
  def is_ready(self) -> bool:
49
38
  return all(
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+ import typing
3
+
4
+ import pydantic
5
+
6
+ from microbootstrap.helpers import is_valid_path
7
+ from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
8
+
9
+
10
+ class PrometheusConfig(BaseInstrumentConfig):
11
+ service_name: str = "micro-service"
12
+
13
+ prometheus_metrics_path: str = "/metrics"
14
+ prometheus_additional_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
15
+
16
+
17
+ class PrometheusInstrument(Instrument[PrometheusConfig]):
18
+ instrument_name = "Prometheus"
19
+ ready_condition = "Provide metrics_path for metrics exposure"
20
+
21
+ def is_ready(self) -> bool:
22
+ return bool(self.instrument_config.prometheus_metrics_path) and is_valid_path(
23
+ self.instrument_config.prometheus_metrics_path,
24
+ )
25
+
26
+ @classmethod
27
+ def get_config_type(cls) -> type[PrometheusConfig]:
28
+ return PrometheusConfig
@@ -8,10 +8,6 @@ from sentry_sdk.integrations import Integration # noqa: TCH002
8
8
  from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
9
9
 
10
10
 
11
- if typing.TYPE_CHECKING:
12
- from microbootstrap.console_writer import ConsoleWriter
13
-
14
-
15
11
  class SentryConfig(BaseInstrumentConfig):
16
12
  service_environment: str | None = None
17
13
 
@@ -25,22 +21,12 @@ class SentryConfig(BaseInstrumentConfig):
25
21
 
26
22
 
27
23
  class SentryInstrument(Instrument[SentryConfig]):
28
- def write_status(self, console_writer: ConsoleWriter) -> None:
29
- if self.is_ready():
30
- console_writer.write_instrument_status("Sentry", is_enabled=True)
31
- else:
32
- console_writer.write_instrument_status(
33
- "Sentry",
34
- is_enabled=False,
35
- disable_reason="Provide sentry_dsn",
36
- )
24
+ instrument_name = "Sentry"
25
+ ready_condition = "Provide sentry_dsn"
37
26
 
38
27
  def is_ready(self) -> bool:
39
28
  return bool(self.instrument_config.sentry_dsn)
40
29
 
41
- def teardown(self) -> None:
42
- return
43
-
44
30
  def bootstrap(self) -> None:
45
31
  sentry_sdk.init(
46
32
  dsn=self.instrument_config.sentry_dsn,
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+ import typing
3
+
4
+ import pydantic
5
+
6
+ from microbootstrap.helpers import is_valid_path
7
+ from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
8
+
9
+
10
+ class SwaggerConfig(BaseInstrumentConfig):
11
+ service_name: str = "micro-service"
12
+ service_description: str = "Micro service description"
13
+ service_version: str = "1.0.0"
14
+ service_static_path: str = "/static"
15
+
16
+ swagger_path: str = "/docs"
17
+ swagger_offline_docs: bool = False
18
+ swagger_extra_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
19
+
20
+
21
+ class SwaggerInstrument(Instrument[SwaggerConfig]):
22
+ instrument_name = "Swagger"
23
+ ready_condition = "Provide valid swagger_path"
24
+
25
+ def is_ready(self) -> bool:
26
+ return bool(self.instrument_config.swagger_path) and is_valid_path(self.instrument_config.swagger_path)
27
+
28
+ @classmethod
29
+ def get_config_type(cls) -> type[SwaggerConfig]:
30
+ return SwaggerConfig
File without changes
@@ -2,10 +2,9 @@ from __future__ import annotations
2
2
  import os
3
3
  import typing
4
4
 
5
- import pydantic
6
5
  import pydantic_settings
7
6
 
8
- from microbootstrap.instruments import LoggingConfig, OpentelemetryConfig, PrometheusConfig, SentryConfig
7
+ from microbootstrap import CorsConfig, LoggingConfig, OpentelemetryConfig, PrometheusConfig, SentryConfig, SwaggerConfig
9
8
 
10
9
 
11
10
  SettingsT = typing.TypeVar("SettingsT", bound="BaseBootstrapSettings")
@@ -19,12 +18,15 @@ class BaseBootstrapSettings(
19
18
  OpentelemetryConfig,
20
19
  SentryConfig,
21
20
  PrometheusConfig,
21
+ SwaggerConfig,
22
+ CorsConfig,
22
23
  ):
23
24
  service_debug: bool = True
24
25
  service_environment: str | None = None
25
- service_name: str = pydantic.Field(default="micro-service")
26
- service_description: str = pydantic.Field(default="Micro service description")
27
- service_version: str = pydantic.Field(default="1.0.0")
26
+ service_name: str = "micro-service"
27
+ service_description: str = "Micro service description"
28
+ service_version: str = "1.0.0"
29
+ service_static_path: str = "/static"
28
30
 
29
31
  server_host: str = "0.0.0.0" # noqa: S104
30
32
  server_port: int = 8000
@@ -26,16 +26,25 @@ classifiers = [
26
26
  "Programming Language :: Python :: 3.11",
27
27
  "Programming Language :: Python :: 3.12",
28
28
  ]
29
- version = "0.0.4"
29
+ version = "0.2.0"
30
30
  description = "Package for bootstrapping new micro-services"
31
31
  authors = ["community-of-python"]
32
32
  readme = "README.md"
33
33
  packages = [{ include = "microbootstrap" }]
34
34
 
35
+ [tool.poetry.urls]
36
+ homepage = "https://github.com/community-of-python/microbootstrap"
37
+ repository = "https://github.com/community-of-python/microbootstrap"
38
+ documentation = "https://pypi.org/project/microbootstrap/"
39
+
40
+
35
41
  [tool.poetry.dependencies]
36
42
  python = "^3.9"
37
43
  pydantic-settings = "^2.3.4"
38
44
  granian = { version = "^1.4.4", extras = ["reload"] }
45
+ typing-extensions = "^4.12.2"
46
+ rich = "^13.7.1"
47
+ eval-type-backport = "^0.2.0"
39
48
  # for logging boostrap
40
49
  structlog = "^24.2.0"
41
50
  # for sentry bootstrap
@@ -49,15 +58,13 @@ opentelemetry-instrumentation = "^0.46b0"
49
58
  opentelemetry-instrumentation-asgi = "^0.46b0"
50
59
  opentelemetry-instrumentation-system-metrics = "^0.46b0"
51
60
  # optional extras for Litestar
52
- litestar = "^2.9.1"
61
+ litestar = { version = "^2.9.1", optional = true }
53
62
  prometheus-client = { version = "^0.20.0", optional = true }
63
+ litestar-offline-docs = { version = "^1.0.1", optional = true }
54
64
  # optional extras for FastAPI
55
- fastapi = "^0.111.0"
65
+ fastapi = { version = "^0.111.0", optional = true }
56
66
  prometheus-fastapi-instrumentator = { version = "^6.1.0", optional = true }
57
67
  opentelemetry-instrumentation-fastapi = { version = "^0.46b0", optional = true }
58
- typing-extensions = "^4.12.2"
59
- rich = "^13.7.1"
60
- eval-type-backport = "^0.2.0"
61
68
 
62
69
 
63
70
  [tool.poetry.group.dev.dependencies]
@@ -78,7 +85,7 @@ fastapi = [
78
85
  "opentelemetry-instrumentation-fastapi",
79
86
  "prometheus-fastapi-instrumentator",
80
87
  ]
81
- litestar = ["litestar", "prometheus-client"]
88
+ litestar = ["litestar", "prometheus-client", "litestar-offline-docs"]
82
89
 
83
90
  [build-system]
84
91
  requires = ["poetry-core"]
@@ -1,7 +0,0 @@
1
- from microbootstrap.instruments.logging_instrument import LoggingConfig
2
- from microbootstrap.instruments.opentelemetry_instrument import OpentelemetryConfig
3
- from microbootstrap.instruments.prometheus_instrument import PrometheusConfig
4
- from microbootstrap.instruments.sentry_instrument import SentryConfig
5
-
6
-
7
- __all__ = ("SentryConfig", "OpentelemetryConfig", "PrometheusConfig", "LoggingConfig")
@@ -1,45 +0,0 @@
1
- from __future__ import annotations
2
- import typing
3
-
4
- import pydantic
5
-
6
- from microbootstrap.helpers import is_valid_path
7
- from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
8
-
9
-
10
- if typing.TYPE_CHECKING:
11
- from microbootstrap.console_writer import ConsoleWriter
12
-
13
-
14
- class PrometheusConfig(BaseInstrumentConfig):
15
- service_name: str = pydantic.Field(default="micro-service")
16
-
17
- prometheus_metrics_path: str = pydantic.Field(default="/metrics")
18
- prometheus_additional_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
19
-
20
-
21
- class PrometheusInstrument(Instrument[PrometheusConfig]):
22
- def write_status(self, console_writer: ConsoleWriter) -> None:
23
- if self.is_ready():
24
- console_writer.write_instrument_status("Prometheus", is_enabled=True)
25
- else:
26
- console_writer.write_instrument_status(
27
- "Prometheus",
28
- is_enabled=False,
29
- disable_reason="Provide metrics_path for metrics exposure",
30
- )
31
-
32
- def is_ready(self) -> bool:
33
- return bool(self.instrument_config.prometheus_metrics_path) and is_valid_path(
34
- self.instrument_config.prometheus_metrics_path,
35
- )
36
-
37
- def teardown(self) -> None:
38
- return
39
-
40
- def bootstrap(self) -> None:
41
- pass
42
-
43
- @classmethod
44
- def get_config_type(cls) -> type[PrometheusConfig]:
45
- return PrometheusConfig