python-corekit 0.1.1__tar.gz → 0.3.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.
- {python_corekit-0.1.1/python_corekit.egg-info → python_corekit-0.3.0}/PKG-INFO +103 -97
- {python_corekit-0.1.1 → python_corekit-0.3.0}/README.md +100 -94
- python_corekit-0.3.0/corekit/api/__init__.py +24 -0
- python_corekit-0.3.0/corekit/api/application.py +275 -0
- python_corekit-0.3.0/corekit/api/lifespan.py +233 -0
- python_corekit-0.3.0/corekit/api/middleware.py +93 -0
- python_corekit-0.3.0/corekit/api/routers.py +223 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/concurrency/__init__.py +2 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/concurrency/decorators.py +32 -5
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/concurrency/thread_local.py +2 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/concurrency/worker.py +74 -65
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/config/loader.py +42 -5
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/config/settings.py +11 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/__init__.py +7 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/connectable.py +45 -4
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/redis/connection.py +53 -10
- python_corekit-0.3.0/corekit/connections/sql/__init__.py +39 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/connection.py +56 -3
- python_corekit-0.3.0/corekit/connections/sql/fields/__init__.py +7 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/fields/jsonb.py +13 -6
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/migration/__init__.py +9 -5
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/migration/base.py +3 -3
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/migration/operations.py +135 -44
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/migration/registry.py +2 -2
- python_corekit-0.3.0/corekit/connections/sql/operations/__init__.py +24 -0
- python_corekit-0.3.0/corekit/connections/sql/operations/base.py +111 -0
- python_corekit-0.3.0/corekit/connections/sql/operations/statements.py +170 -0
- python_corekit-0.3.0/corekit/connections/sql/query.py +10 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/table.py +33 -29
- python_corekit-0.3.0/corekit/crypto/__init__.py +3 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/crypto/constants.py +2 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/crypto/hasher.py +9 -4
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/data/__init__.py +8 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/data/dataset.py +8 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/data/expressions/__init__.py +10 -2
- python_corekit-0.3.0/corekit/data/expressions/comparison.py +271 -0
- python_corekit-0.3.0/corekit/data/expressions/expression.py +71 -0
- python_corekit-0.3.0/corekit/data/expressions/operator.py +39 -0
- python_corekit-0.3.0/corekit/data/expressions/target.py +21 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/data/record.py +147 -147
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/data/stats.py +162 -157
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/decorators/__init__.py +2 -2
- python_corekit-0.3.0/corekit/decorators/exception_handling.py +72 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/docker/watchdog.py +50 -31
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/__init__.py +2 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/connection.py +46 -44
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/extract/extractor.py +6 -13
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/orchestrator.py +19 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/schemas.py +2 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/transform/transformer.py +4 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/publisher.py +1 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/reader.py +26 -21
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/sse.py +4 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/websocket.py +27 -13
- python_corekit-0.3.0/corekit/exceptions/__init__.py +33 -0
- python_corekit-0.3.0/corekit/exceptions/base.py +174 -0
- python_corekit-0.3.0/corekit/exceptions/enum.py +17 -0
- python_corekit-0.3.0/corekit/exceptions/types.py +17 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/files/__init__.py +2 -4
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/files/base.py +15 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/files/enum.py +0 -5
- python_corekit-0.3.0/corekit/files/json.py +26 -0
- python_corekit-0.3.0/corekit/http/__init__.py +51 -0
- python_corekit-0.3.0/corekit/http/api.py +24 -0
- python_corekit-0.3.0/corekit/http/client.py +203 -0
- python_corekit-0.3.0/corekit/http/exceptions.py +140 -0
- python_corekit-0.3.0/corekit/http/response.py +61 -0
- python_corekit-0.3.0/corekit/http/status.py +89 -0
- python_corekit-0.3.0/corekit/jobs/__init__.py +26 -0
- python_corekit-0.3.0/corekit/jobs/registry.py +87 -0
- python_corekit-0.3.0/corekit/jobs/runner.py +80 -0
- python_corekit-0.3.0/corekit/jobs/task.py +173 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/log_monitor/models.py +8 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/log_monitor/service.py +77 -38
- python_corekit-0.3.0/corekit/notifications/base.py +59 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/observability/__init__.py +12 -3
- python_corekit-0.3.0/corekit/observability/benchmarkable.py +30 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/observability/loggable.py +21 -0
- python_corekit-0.3.0/corekit/observability/request_context.py +188 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/observability/timing/timer.py +4 -2
- python_corekit-0.3.0/corekit/registry/__init__.py +17 -0
- python_corekit-0.3.0/corekit/registry/ordered.py +86 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/registry/registry.py +55 -14
- python_corekit-0.3.0/corekit/schemas/__init__.py +10 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/schemas/enum.py +70 -49
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/schemas/models/arbitrary.py +11 -11
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/schemas/pydantic/fields.py +35 -35
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/schemas/types.py +45 -40
- python_corekit-0.3.0/corekit/serialization/__init__.py +24 -0
- python_corekit-0.3.0/corekit/serialization/pickle_file.py +61 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/serialization/serializable.py +22 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/serialization/serializer.py +10 -3
- python_corekit-0.3.0/corekit/utils/__init__.py +59 -0
- python_corekit-0.3.0/corekit/utils/coercion.py +118 -0
- python_corekit-0.3.0/corekit/utils/collections.py +124 -0
- python_corekit-0.3.0/corekit/utils/ids.py +61 -0
- python_corekit-0.3.0/corekit/utils/payload.py +112 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/utils/raise_exc.py +8 -8
- python_corekit-0.3.0/corekit/utils/text.py +56 -0
- python_corekit-0.3.0/corekit/utils/time.py +74 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/utils/validators.py +15 -15
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/utils/void.py +8 -8
- {python_corekit-0.1.1 → python_corekit-0.3.0}/pyproject.toml +4 -4
- {python_corekit-0.1.1 → python_corekit-0.3.0/python_corekit.egg-info}/PKG-INFO +103 -97
- {python_corekit-0.1.1 → python_corekit-0.3.0}/python_corekit.egg-info/SOURCES.txt +43 -4
- python_corekit-0.3.0/tests/test_application.py +361 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_architecture.py +6 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_config.py +6 -5
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_connections.py +26 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_data.py +10 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_docker.py +13 -2
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_etl.py +24 -1
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_events.py +67 -6
- python_corekit-0.3.0/tests/test_exceptions.py +90 -0
- python_corekit-0.3.0/tests/test_expressions.py +177 -0
- python_corekit-0.3.0/tests/test_expressions_sqlalchemy.py +221 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_files.py +23 -3
- python_corekit-0.3.0/tests/test_jobs.py +199 -0
- python_corekit-0.3.0/tests/test_lifespan.py +239 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_log_monitor.py +115 -0
- python_corekit-0.3.0/tests/test_middleware_stack.py +134 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_migration.py +101 -10
- python_corekit-0.3.0/tests/test_notifications.py +40 -0
- python_corekit-0.3.0/tests/test_observability.py +51 -0
- python_corekit-0.3.0/tests/test_operations.py +195 -0
- python_corekit-0.3.0/tests/test_ordered_registry.py +78 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_redis.py +47 -4
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_registry.py +34 -1
- python_corekit-0.3.0/tests/test_request_context.py +163 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_requests.py +58 -5
- python_corekit-0.3.0/tests/test_schemas_enum.py +36 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_serialization.py +25 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_sql.py +102 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_utils.py +24 -1
- python_corekit-0.3.0/tests/test_utils_coercion.py +94 -0
- python_corekit-0.3.0/tests/test_utils_collections.py +128 -0
- python_corekit-0.3.0/tests/test_utils_ids.py +51 -0
- python_corekit-0.3.0/tests/test_utils_payload.py +81 -0
- python_corekit-0.3.0/tests/test_utils_text.py +56 -0
- python_corekit-0.3.0/tests/test_utils_time.py +62 -0
- python_corekit-0.1.1/corekit/api/__init__.py +0 -9
- python_corekit-0.1.1/corekit/api/routers.py +0 -115
- python_corekit-0.1.1/corekit/connections/sql/__init__.py +0 -10
- python_corekit-0.1.1/corekit/connections/sql/fields/__init__.py +0 -7
- python_corekit-0.1.1/corekit/connections/sql/query.py +0 -68
- python_corekit-0.1.1/corekit/constants.py +0 -45
- python_corekit-0.1.1/corekit/crypto/__init__.py +0 -1
- python_corekit-0.1.1/corekit/data/expressions/comparison.py +0 -252
- python_corekit-0.1.1/corekit/data/expressions/expression.py +0 -98
- python_corekit-0.1.1/corekit/decorators/exception_handling.py +0 -43
- python_corekit-0.1.1/corekit/exceptions/base.py +0 -45
- python_corekit-0.1.1/corekit/exceptions/http/exceptions.py +0 -37
- python_corekit-0.1.1/corekit/exceptions/types.py +0 -17
- python_corekit-0.1.1/corekit/files/json.py +0 -12
- python_corekit-0.1.1/corekit/files/pickle.py +0 -12
- python_corekit-0.1.1/corekit/http/client.py +0 -176
- python_corekit-0.1.1/corekit/http/response.py +0 -12
- python_corekit-0.1.1/corekit/notifications/base.py +0 -51
- python_corekit-0.1.1/corekit/observability/benchmarkable.py +0 -12
- python_corekit-0.1.1/corekit/registry/__init__.py +0 -12
- python_corekit-0.1.1/corekit/schemas/dataclasses/__init__.py +0 -0
- python_corekit-0.1.1/corekit/schemas/models/__init__.py +0 -0
- python_corekit-0.1.1/corekit/schemas/pydantic/__init__.py +0 -0
- python_corekit-0.1.1/corekit/serialization/__init__.py +0 -0
- python_corekit-0.1.1/corekit/utils/__init__.py +0 -5
- python_corekit-0.1.1/corekit/utils/ids.py +0 -5
- python_corekit-0.1.1/corekit/utils/time.py +0 -21
- {python_corekit-0.1.1 → python_corekit-0.3.0}/LICENSE +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/api/handler.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/api/responses.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/config/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/config/sources.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/decorators.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/redis/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/registry.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/connections/sql/migration/table.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/crypto/enum.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/decorators/warnings.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/docker/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/extract/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/extract/schemas.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/load/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/load/loader.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/load/schemas.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/transform/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/etl/transform/schemas.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/enum.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/frames.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/events/models.py +0 -0
- {python_corekit-0.1.1/corekit/exceptions → python_corekit-0.3.0/corekit/exceptions/custom}/__init__.py +0 -0
- {python_corekit-0.1.1/corekit/exceptions/custom → python_corekit-0.3.0/corekit/exceptions/http}/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/files/toml.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/http/exponential_backoff.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/log_monitor/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/log_monitor/constants.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/notifications/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/notifications/models.py +0 -0
- {python_corekit-0.1.1/corekit/exceptions/http → python_corekit-0.3.0/corekit/observability/timing}/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/observability/timing/constants.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/observability/timing/split.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/py.typed +0 -0
- {python_corekit-0.1.1/corekit/http → python_corekit-0.3.0/corekit/schemas/dataclasses}/__init__.py +0 -0
- {python_corekit-0.1.1/corekit/observability/timing → python_corekit-0.3.0/corekit/schemas/models}/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/schemas/models/date_models.py +0 -0
- {python_corekit-0.1.1/corekit/schemas → python_corekit-0.3.0/corekit/schemas/pydantic}/__init__.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/corekit/serialization/enum.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/python_corekit.egg-info/dependency_links.txt +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/python_corekit.egg-info/requires.txt +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/python_corekit.egg-info/top_level.txt +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/setup.cfg +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/setup.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_api.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_concurrency.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_imports.py +0 -0
- {python_corekit-0.1.1 → python_corekit-0.3.0}/tests/test_imports_are_top_level.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-corekit
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Shared foundations for Python projects: logging, benchmarking, registries, FastAPI routers
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Shared foundations for Python projects: logging, benchmarking, registries, FastAPI application and routers, SQL statements and migrations, background tasks, and ETL
|
|
5
5
|
Author: Steven Jacobsen
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/stevejaker/corekit
|
|
8
8
|
Project-URL: Issues, https://github.com/stevejaker/corekit/issues
|
|
9
|
-
Keywords: fastapi,etl,
|
|
9
|
+
Keywords: fastapi,etl,logging,benchmarking,sqlmodel,migrations
|
|
10
10
|
Classifier: Development Status :: 3 - Alpha
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -36,8 +36,8 @@ Dynamic: license-file
|
|
|
36
36
|
# corekit
|
|
37
37
|
|
|
38
38
|
Shared foundations for Python projects: structured logging, benchmarking,
|
|
39
|
-
registries, FastAPI
|
|
40
|
-
and ETL scaffolding.
|
|
39
|
+
registries, a FastAPI application with routers and handlers, SQL statements and
|
|
40
|
+
migrations, background tasks, an in-memory record store, and ETL scaffolding.
|
|
41
41
|
|
|
42
42
|
Requires Python 3.11+.
|
|
43
43
|
|
|
@@ -55,7 +55,7 @@ extras to remember, and no import that fails because something was left out.
|
|
|
55
55
|
Pin a compatible release rather than tracking whatever is newest:
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
python-corekit~=0.
|
|
58
|
+
python-corekit~=0.3.0
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
Before 1.0, the minor version carries breaking changes.
|
|
@@ -88,6 +88,57 @@ class Report(Benchmarkable):
|
|
|
88
88
|
self.timing("queried") # logs the time since the previous split
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
## Assembling an application
|
|
92
|
+
|
|
93
|
+
`Application` is a plain `FastAPI` subclass — every constructor argument,
|
|
94
|
+
including `lifespan`, passes straight through. What it adds is a short set of
|
|
95
|
+
assembly steps, each of which logs what it did.
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from corekit.api import Application, Lifespan
|
|
99
|
+
from app.backend import routers
|
|
100
|
+
|
|
101
|
+
lifespan = Lifespan()
|
|
102
|
+
lifespan.add("cache", startup=cache.connect, shutdown=cache.disconnect)
|
|
103
|
+
|
|
104
|
+
app = Application(lifespan=lifespan)
|
|
105
|
+
app.discover_routers(routers)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`discover_routers` imports every module under the package so each router can
|
|
109
|
+
register itself. It raises if it finds none: passing a package is a statement
|
|
110
|
+
that routers live there, and an app that silently serves nothing is worse than
|
|
111
|
+
one that refuses to start.
|
|
112
|
+
|
|
113
|
+
Lifespan steps start in the order added and shut down in reverse, the way
|
|
114
|
+
nested `with` blocks unwind. If a step fails on the way up, the steps that
|
|
115
|
+
already started are still torn down. A shutdown hook runs only if its own
|
|
116
|
+
startup completed, so it may assume the state that startup builds — and a hook
|
|
117
|
+
that raises cannot stop the unwind.
|
|
118
|
+
|
|
119
|
+
### Middleware
|
|
120
|
+
|
|
121
|
+
Middleware order is a security property: a host check that reads a client
|
|
122
|
+
address before the proxy-header layer has rewritten it is checking the proxy,
|
|
123
|
+
not the client. So middleware is never auto-discovered, and corekit installs
|
|
124
|
+
none by default. A stack is declared in one place, outermost first — the order
|
|
125
|
+
a request actually meets the layers.
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from corekit.api import MiddlewareStack
|
|
129
|
+
|
|
130
|
+
stack = (
|
|
131
|
+
MiddlewareStack()
|
|
132
|
+
.add(ProxyHeadersMiddleware, trusted_hosts="*")
|
|
133
|
+
.add(TrustedHostMiddleware, allowed_hosts=HOSTS)
|
|
134
|
+
.add(CORSMiddleware, allow_origins=ORIGINS, allow_credentials=True)
|
|
135
|
+
)
|
|
136
|
+
app.add_middleware_stack(stack)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Reading top to bottom gives the order a request travels, which is the property
|
|
140
|
+
you need when reviewing it.
|
|
141
|
+
|
|
91
142
|
## Routers and handlers
|
|
92
143
|
|
|
93
144
|
A router and the handler holding its business logic travel together. Declare the
|
|
@@ -147,113 +198,67 @@ people.get_record("Ada").age # O(1) lookup by id
|
|
|
147
198
|
|
|
148
199
|
Stores pickle cleanly, including their dynamically generated record class.
|
|
149
200
|
|
|
150
|
-
##
|
|
201
|
+
## SQL statements
|
|
151
202
|
|
|
152
|
-
|
|
203
|
+
Select, insert, update and delete are objects you build and then execute, so a
|
|
204
|
+
statement can be assembled in pieces and passed around before it runs.
|
|
153
205
|
|
|
154
206
|
```python
|
|
155
|
-
from corekit.
|
|
207
|
+
from corekit.connections.sql import SQLConnection, Select, Insert, Update, Delete
|
|
208
|
+
from corekit.data import Field
|
|
156
209
|
|
|
157
|
-
|
|
158
|
-
watchdog.restart_container_by_name("minecraft")
|
|
159
|
-
watchdog.find_and_stop(label="app", value="staging")
|
|
160
|
-
```
|
|
210
|
+
conn = SQLConnection("sqlite:///app.db")
|
|
161
211
|
|
|
162
|
-
|
|
163
|
-
the `watchdog=true` label can be started, stopped or paused, so a mistyped name
|
|
164
|
-
cannot take down something unrelated. Leave it on unless the watchdog is meant
|
|
165
|
-
to control everything on the host.
|
|
166
|
-
|
|
167
|
-
### Reacting to logs
|
|
168
|
-
|
|
169
|
-
Describe what to watch for and what to do about it:
|
|
170
|
-
|
|
171
|
-
```yaml
|
|
172
|
-
# config.yaml
|
|
173
|
-
containers:
|
|
174
|
-
- name: "minecraft-.*"
|
|
175
|
-
rules:
|
|
176
|
-
- name: "out of memory"
|
|
177
|
-
pattern: "java.lang.OutOfMemoryError"
|
|
178
|
-
severity: critical
|
|
179
|
-
send_notification: true
|
|
180
|
-
actions:
|
|
181
|
-
- type: restart_container
|
|
182
|
-
max_restarts: 3
|
|
183
|
-
restart_window: 3600
|
|
184
|
-
advanced:
|
|
185
|
-
ignore_patterns:
|
|
186
|
-
- "healthcheck"
|
|
187
|
-
rate_limits:
|
|
188
|
-
restart_container:
|
|
189
|
-
count: 5
|
|
190
|
-
period: hour
|
|
191
|
-
```
|
|
212
|
+
conn.execute(Insert(table=User, rows=[{"name": "Ada", "age": 36}]).add(name="Bob", age=17))
|
|
192
213
|
|
|
193
|
-
|
|
194
|
-
from corekit.log_monitor import LogMonitor
|
|
214
|
+
adults = conn.fetch(Select(table=User).where(User.age >= 18).order_by(User.name).limit(10))
|
|
195
215
|
|
|
196
|
-
|
|
216
|
+
conn.execute(Update(table=User).where(User.name == "Bob").set(age=18))
|
|
217
|
+
conn.execute(Delete(table=User).where(User.age < 13))
|
|
197
218
|
```
|
|
198
219
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
### Notifications
|
|
220
|
+
`where` accepts a SQLAlchemy expression or a `corekit.data` one, so the same
|
|
221
|
+
predicate language that filters a `Dataset` also filters a table:
|
|
202
222
|
|
|
203
223
|
```python
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
class DiscordNotifier(BaseNotificationService):
|
|
207
|
-
"""
|
|
208
|
-
Sends notifications to a Discord channel.
|
|
209
|
-
"""
|
|
210
|
-
|
|
211
|
-
def _send(self, message: str) -> None:
|
|
212
|
-
discord.post(message)
|
|
213
|
-
|
|
214
|
-
notifier.notify(Notification(message="disk full", type=NotificationType.ERROR))
|
|
224
|
+
Select(table=User).where(Field("age") >= 18)
|
|
215
225
|
```
|
|
216
226
|
|
|
217
|
-
|
|
218
|
-
|
|
227
|
+
Update and delete compile to a single statement rather than fetching rows and
|
|
228
|
+
looping, which matters most over a network, where fetch-and-loop pays a round
|
|
229
|
+
trip per row.
|
|
219
230
|
|
|
220
|
-
|
|
231
|
+
A `Delete` or `Update` with no condition raises rather than running:
|
|
221
232
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
```python
|
|
225
|
-
from corekit.events import EventPublisher
|
|
226
|
-
|
|
227
|
-
publisher = EventPublisher.for_resource("minecraft", "server", "survival")
|
|
228
|
-
publisher.publish("backup_finished", {"size": "4.2GB"})
|
|
233
|
+
```
|
|
234
|
+
Delete on User needs a condition; use truncate to empty a table
|
|
229
235
|
```
|
|
230
236
|
|
|
231
|
-
|
|
237
|
+
## Background tasks
|
|
232
238
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
239
|
+
Tasks describe work and register themselves by name. Nothing here imports a
|
|
240
|
+
queue library, so the same task runs under RQ, Celery, a cron entry, or a test
|
|
241
|
+
with no queue at all.
|
|
236
242
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
```
|
|
243
|
+
```python
|
|
244
|
+
from corekit.jobs import Task, run_task
|
|
245
|
+
from corekit.utils import encode_payload
|
|
241
246
|
|
|
242
|
-
|
|
247
|
+
class SendDigest(Task):
|
|
248
|
+
def task_function(self, user: str) -> None:
|
|
249
|
+
...
|
|
243
250
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
source.addEventListener("backup_finished", e => console.log(JSON.parse(e.data)));
|
|
251
|
+
# a worker, holding only a name and a JSON string
|
|
252
|
+
run_task("SendDigest", encode_payload(["ada"]))
|
|
247
253
|
```
|
|
248
254
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
255
|
+
Arguments cross the queue as JSON, never as a serialized object. `pickle` and
|
|
256
|
+
`dill` execute code while loading, so a queue holding objects turns write
|
|
257
|
+
access to the queue into code execution in a worker. `encode_payload` and
|
|
258
|
+
`decode_payload` live in `corekit.utils`, since crossing a process boundary as
|
|
259
|
+
data is not specific to queues.
|
|
254
260
|
|
|
255
|
-
|
|
256
|
-
the operation that produced it. `publish` returns whether it worked.
|
|
261
|
+
`ScheduledTask` adds an `interval` for tasks a scheduler should repeat.
|
|
257
262
|
|
|
258
263
|
## Parallel work
|
|
259
264
|
|
|
@@ -279,7 +284,7 @@ instead, which loses results silently and so is opt-in.
|
|
|
279
284
|
## HTTP clients
|
|
280
285
|
|
|
281
286
|
```python
|
|
282
|
-
from corekit.http
|
|
287
|
+
from corekit.http import BaseApiClient
|
|
283
288
|
|
|
284
289
|
class GithubClient(BaseApiClient):
|
|
285
290
|
"""
|
|
@@ -296,7 +301,8 @@ response.data["login"]
|
|
|
296
301
|
|
|
297
302
|
Retries 429 and 5xx with exponential backoff. Every response is a
|
|
298
303
|
`BaseApiResponse`, so a non-JSON error page leaves `data` empty rather than
|
|
299
|
-
raising.
|
|
304
|
+
raising. The same methods are awaitable inside a running event loop:
|
|
305
|
+
`await client.get(...)`.
|
|
300
306
|
|
|
301
307
|
## Serialization
|
|
302
308
|
|
|
@@ -346,7 +352,7 @@ Settings are grouped by concern, so `get_settings().concurrency.max_threads`
|
|
|
346
352
|
says where a value belongs. Environment variables use a double underscore for
|
|
347
353
|
the section: `COREKIT_CONCURRENCY__MAX_THREADS=16`.
|
|
348
354
|
|
|
349
|
-
Environment variables use a `COREKIT_` prefix (`
|
|
355
|
+
Environment variables use a `COREKIT_` prefix (`COREKIT_CRYPTO__SALT`). Empty
|
|
350
356
|
values are treated as unset, because container runtimes routinely pass `FOO=`
|
|
351
357
|
for a variable that was never set.
|
|
352
358
|
|
|
@@ -370,23 +376,23 @@ Imports go downward only.
|
|
|
370
376
|
```
|
|
371
377
|
corekit/
|
|
372
378
|
config/ settings, sources, loader
|
|
373
|
-
constants.py
|
|
374
379
|
|
|
375
380
|
exceptions/ error types
|
|
376
381
|
|
|
377
382
|
observability/ Loggable, Benchmarkable, Timer
|
|
378
|
-
registry/ schemas/ utils/
|
|
383
|
+
registry/ schemas/ utils/ registries, enums and fields, helpers
|
|
379
384
|
data/ Dataset and its filter expressions
|
|
385
|
+
jobs/ queue-independent background tasks
|
|
380
386
|
crypto/ files/ serialization/
|
|
381
387
|
concurrency/ ThreadLocalRegistry, ThreadWorker
|
|
382
388
|
decorators/
|
|
383
389
|
|
|
384
390
|
connections/ the Connectable lifecycle and @connect
|
|
385
|
-
sql/ SQLConnection,
|
|
391
|
+
sql/ SQLConnection, statements, migrations
|
|
386
392
|
redis/ RedisConnection
|
|
387
|
-
http/ BaseApiClient, retries, responses
|
|
393
|
+
http/ BaseHttpClient, BaseApiClient, retries, responses
|
|
388
394
|
|
|
389
|
-
api/
|
|
395
|
+
api/ Application, lifespan, middleware, routers
|
|
390
396
|
docker/ notifications/ etl/
|
|
391
397
|
|
|
392
398
|
events/ log_monitor/ built on the capabilities above
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# corekit
|
|
2
2
|
|
|
3
3
|
Shared foundations for Python projects: structured logging, benchmarking,
|
|
4
|
-
registries, FastAPI
|
|
5
|
-
and ETL scaffolding.
|
|
4
|
+
registries, a FastAPI application with routers and handlers, SQL statements and
|
|
5
|
+
migrations, background tasks, an in-memory record store, and ETL scaffolding.
|
|
6
6
|
|
|
7
7
|
Requires Python 3.11+.
|
|
8
8
|
|
|
@@ -20,7 +20,7 @@ extras to remember, and no import that fails because something was left out.
|
|
|
20
20
|
Pin a compatible release rather than tracking whatever is newest:
|
|
21
21
|
|
|
22
22
|
```
|
|
23
|
-
python-corekit~=0.
|
|
23
|
+
python-corekit~=0.3.0
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Before 1.0, the minor version carries breaking changes.
|
|
@@ -53,6 +53,57 @@ class Report(Benchmarkable):
|
|
|
53
53
|
self.timing("queried") # logs the time since the previous split
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
## Assembling an application
|
|
57
|
+
|
|
58
|
+
`Application` is a plain `FastAPI` subclass — every constructor argument,
|
|
59
|
+
including `lifespan`, passes straight through. What it adds is a short set of
|
|
60
|
+
assembly steps, each of which logs what it did.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from corekit.api import Application, Lifespan
|
|
64
|
+
from app.backend import routers
|
|
65
|
+
|
|
66
|
+
lifespan = Lifespan()
|
|
67
|
+
lifespan.add("cache", startup=cache.connect, shutdown=cache.disconnect)
|
|
68
|
+
|
|
69
|
+
app = Application(lifespan=lifespan)
|
|
70
|
+
app.discover_routers(routers)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`discover_routers` imports every module under the package so each router can
|
|
74
|
+
register itself. It raises if it finds none: passing a package is a statement
|
|
75
|
+
that routers live there, and an app that silently serves nothing is worse than
|
|
76
|
+
one that refuses to start.
|
|
77
|
+
|
|
78
|
+
Lifespan steps start in the order added and shut down in reverse, the way
|
|
79
|
+
nested `with` blocks unwind. If a step fails on the way up, the steps that
|
|
80
|
+
already started are still torn down. A shutdown hook runs only if its own
|
|
81
|
+
startup completed, so it may assume the state that startup builds — and a hook
|
|
82
|
+
that raises cannot stop the unwind.
|
|
83
|
+
|
|
84
|
+
### Middleware
|
|
85
|
+
|
|
86
|
+
Middleware order is a security property: a host check that reads a client
|
|
87
|
+
address before the proxy-header layer has rewritten it is checking the proxy,
|
|
88
|
+
not the client. So middleware is never auto-discovered, and corekit installs
|
|
89
|
+
none by default. A stack is declared in one place, outermost first — the order
|
|
90
|
+
a request actually meets the layers.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from corekit.api import MiddlewareStack
|
|
94
|
+
|
|
95
|
+
stack = (
|
|
96
|
+
MiddlewareStack()
|
|
97
|
+
.add(ProxyHeadersMiddleware, trusted_hosts="*")
|
|
98
|
+
.add(TrustedHostMiddleware, allowed_hosts=HOSTS)
|
|
99
|
+
.add(CORSMiddleware, allow_origins=ORIGINS, allow_credentials=True)
|
|
100
|
+
)
|
|
101
|
+
app.add_middleware_stack(stack)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Reading top to bottom gives the order a request travels, which is the property
|
|
105
|
+
you need when reviewing it.
|
|
106
|
+
|
|
56
107
|
## Routers and handlers
|
|
57
108
|
|
|
58
109
|
A router and the handler holding its business logic travel together. Declare the
|
|
@@ -112,113 +163,67 @@ people.get_record("Ada").age # O(1) lookup by id
|
|
|
112
163
|
|
|
113
164
|
Stores pickle cleanly, including their dynamically generated record class.
|
|
114
165
|
|
|
115
|
-
##
|
|
166
|
+
## SQL statements
|
|
116
167
|
|
|
117
|
-
|
|
168
|
+
Select, insert, update and delete are objects you build and then execute, so a
|
|
169
|
+
statement can be assembled in pieces and passed around before it runs.
|
|
118
170
|
|
|
119
171
|
```python
|
|
120
|
-
from corekit.
|
|
172
|
+
from corekit.connections.sql import SQLConnection, Select, Insert, Update, Delete
|
|
173
|
+
from corekit.data import Field
|
|
121
174
|
|
|
122
|
-
|
|
123
|
-
watchdog.restart_container_by_name("minecraft")
|
|
124
|
-
watchdog.find_and_stop(label="app", value="staging")
|
|
125
|
-
```
|
|
175
|
+
conn = SQLConnection("sqlite:///app.db")
|
|
126
176
|
|
|
127
|
-
|
|
128
|
-
the `watchdog=true` label can be started, stopped or paused, so a mistyped name
|
|
129
|
-
cannot take down something unrelated. Leave it on unless the watchdog is meant
|
|
130
|
-
to control everything on the host.
|
|
131
|
-
|
|
132
|
-
### Reacting to logs
|
|
133
|
-
|
|
134
|
-
Describe what to watch for and what to do about it:
|
|
135
|
-
|
|
136
|
-
```yaml
|
|
137
|
-
# config.yaml
|
|
138
|
-
containers:
|
|
139
|
-
- name: "minecraft-.*"
|
|
140
|
-
rules:
|
|
141
|
-
- name: "out of memory"
|
|
142
|
-
pattern: "java.lang.OutOfMemoryError"
|
|
143
|
-
severity: critical
|
|
144
|
-
send_notification: true
|
|
145
|
-
actions:
|
|
146
|
-
- type: restart_container
|
|
147
|
-
max_restarts: 3
|
|
148
|
-
restart_window: 3600
|
|
149
|
-
advanced:
|
|
150
|
-
ignore_patterns:
|
|
151
|
-
- "healthcheck"
|
|
152
|
-
rate_limits:
|
|
153
|
-
restart_container:
|
|
154
|
-
count: 5
|
|
155
|
-
period: hour
|
|
156
|
-
```
|
|
177
|
+
conn.execute(Insert(table=User, rows=[{"name": "Ada", "age": 36}]).add(name="Bob", age=17))
|
|
157
178
|
|
|
158
|
-
|
|
159
|
-
from corekit.log_monitor import LogMonitor
|
|
179
|
+
adults = conn.fetch(Select(table=User).where(User.age >= 18).order_by(User.name).limit(10))
|
|
160
180
|
|
|
161
|
-
|
|
181
|
+
conn.execute(Update(table=User).where(User.name == "Bob").set(age=18))
|
|
182
|
+
conn.execute(Delete(table=User).where(User.age < 13))
|
|
162
183
|
```
|
|
163
184
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
### Notifications
|
|
185
|
+
`where` accepts a SQLAlchemy expression or a `corekit.data` one, so the same
|
|
186
|
+
predicate language that filters a `Dataset` also filters a table:
|
|
167
187
|
|
|
168
188
|
```python
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
class DiscordNotifier(BaseNotificationService):
|
|
172
|
-
"""
|
|
173
|
-
Sends notifications to a Discord channel.
|
|
174
|
-
"""
|
|
175
|
-
|
|
176
|
-
def _send(self, message: str) -> None:
|
|
177
|
-
discord.post(message)
|
|
178
|
-
|
|
179
|
-
notifier.notify(Notification(message="disk full", type=NotificationType.ERROR))
|
|
189
|
+
Select(table=User).where(Field("age") >= 18)
|
|
180
190
|
```
|
|
181
191
|
|
|
182
|
-
|
|
183
|
-
|
|
192
|
+
Update and delete compile to a single statement rather than fetching rows and
|
|
193
|
+
looping, which matters most over a network, where fetch-and-loop pays a round
|
|
194
|
+
trip per row.
|
|
184
195
|
|
|
185
|
-
|
|
196
|
+
A `Delete` or `Update` with no condition raises rather than running:
|
|
186
197
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
```python
|
|
190
|
-
from corekit.events import EventPublisher
|
|
191
|
-
|
|
192
|
-
publisher = EventPublisher.for_resource("minecraft", "server", "survival")
|
|
193
|
-
publisher.publish("backup_finished", {"size": "4.2GB"})
|
|
198
|
+
```
|
|
199
|
+
Delete on User needs a condition; use truncate to empty a table
|
|
194
200
|
```
|
|
195
201
|
|
|
196
|
-
|
|
202
|
+
## Background tasks
|
|
197
203
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
Tasks describe work and register themselves by name. Nothing here imports a
|
|
205
|
+
queue library, so the same task runs under RQ, Celery, a cron entry, or a test
|
|
206
|
+
with no queue at all.
|
|
201
207
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
```
|
|
208
|
+
```python
|
|
209
|
+
from corekit.jobs import Task, run_task
|
|
210
|
+
from corekit.utils import encode_payload
|
|
206
211
|
|
|
207
|
-
|
|
212
|
+
class SendDigest(Task):
|
|
213
|
+
def task_function(self, user: str) -> None:
|
|
214
|
+
...
|
|
208
215
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
source.addEventListener("backup_finished", e => console.log(JSON.parse(e.data)));
|
|
216
|
+
# a worker, holding only a name and a JSON string
|
|
217
|
+
run_task("SendDigest", encode_payload(["ada"]))
|
|
212
218
|
```
|
|
213
219
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
Arguments cross the queue as JSON, never as a serialized object. `pickle` and
|
|
221
|
+
`dill` execute code while loading, so a queue holding objects turns write
|
|
222
|
+
access to the queue into code execution in a worker. `encode_payload` and
|
|
223
|
+
`decode_payload` live in `corekit.utils`, since crossing a process boundary as
|
|
224
|
+
data is not specific to queues.
|
|
219
225
|
|
|
220
|
-
|
|
221
|
-
the operation that produced it. `publish` returns whether it worked.
|
|
226
|
+
`ScheduledTask` adds an `interval` for tasks a scheduler should repeat.
|
|
222
227
|
|
|
223
228
|
## Parallel work
|
|
224
229
|
|
|
@@ -244,7 +249,7 @@ instead, which loses results silently and so is opt-in.
|
|
|
244
249
|
## HTTP clients
|
|
245
250
|
|
|
246
251
|
```python
|
|
247
|
-
from corekit.http
|
|
252
|
+
from corekit.http import BaseApiClient
|
|
248
253
|
|
|
249
254
|
class GithubClient(BaseApiClient):
|
|
250
255
|
"""
|
|
@@ -261,7 +266,8 @@ response.data["login"]
|
|
|
261
266
|
|
|
262
267
|
Retries 429 and 5xx with exponential backoff. Every response is a
|
|
263
268
|
`BaseApiResponse`, so a non-JSON error page leaves `data` empty rather than
|
|
264
|
-
raising.
|
|
269
|
+
raising. The same methods are awaitable inside a running event loop:
|
|
270
|
+
`await client.get(...)`.
|
|
265
271
|
|
|
266
272
|
## Serialization
|
|
267
273
|
|
|
@@ -311,7 +317,7 @@ Settings are grouped by concern, so `get_settings().concurrency.max_threads`
|
|
|
311
317
|
says where a value belongs. Environment variables use a double underscore for
|
|
312
318
|
the section: `COREKIT_CONCURRENCY__MAX_THREADS=16`.
|
|
313
319
|
|
|
314
|
-
Environment variables use a `COREKIT_` prefix (`
|
|
320
|
+
Environment variables use a `COREKIT_` prefix (`COREKIT_CRYPTO__SALT`). Empty
|
|
315
321
|
values are treated as unset, because container runtimes routinely pass `FOO=`
|
|
316
322
|
for a variable that was never set.
|
|
317
323
|
|
|
@@ -335,23 +341,23 @@ Imports go downward only.
|
|
|
335
341
|
```
|
|
336
342
|
corekit/
|
|
337
343
|
config/ settings, sources, loader
|
|
338
|
-
constants.py
|
|
339
344
|
|
|
340
345
|
exceptions/ error types
|
|
341
346
|
|
|
342
347
|
observability/ Loggable, Benchmarkable, Timer
|
|
343
|
-
registry/ schemas/ utils/
|
|
348
|
+
registry/ schemas/ utils/ registries, enums and fields, helpers
|
|
344
349
|
data/ Dataset and its filter expressions
|
|
350
|
+
jobs/ queue-independent background tasks
|
|
345
351
|
crypto/ files/ serialization/
|
|
346
352
|
concurrency/ ThreadLocalRegistry, ThreadWorker
|
|
347
353
|
decorators/
|
|
348
354
|
|
|
349
355
|
connections/ the Connectable lifecycle and @connect
|
|
350
|
-
sql/ SQLConnection,
|
|
356
|
+
sql/ SQLConnection, statements, migrations
|
|
351
357
|
redis/ RedisConnection
|
|
352
|
-
http/ BaseApiClient, retries, responses
|
|
358
|
+
http/ BaseHttpClient, BaseApiClient, retries, responses
|
|
353
359
|
|
|
354
|
-
api/
|
|
360
|
+
api/ Application, lifespan, middleware, routers
|
|
355
361
|
docker/ notifications/ etl/
|
|
356
362
|
|
|
357
363
|
events/ log_monitor/ built on the capabilities above
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FastAPI building blocks: an application, its lifespan, handlers, routers and responses.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from corekit.api.application import Application
|
|
6
|
+
from corekit.api.handler import BaseHandler
|
|
7
|
+
from corekit.api.lifespan import Lifespan, LifespanStep
|
|
8
|
+
from corekit.api.middleware import MiddlewareLayer, MiddlewareStack
|
|
9
|
+
from corekit.api.responses import SSEResponse
|
|
10
|
+
from corekit.api.routers import CatchAllRouter, SimpleRouter, SmartRouter, router_registry
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"Application",
|
|
14
|
+
"BaseHandler",
|
|
15
|
+
"CatchAllRouter",
|
|
16
|
+
"Lifespan",
|
|
17
|
+
"LifespanStep",
|
|
18
|
+
"MiddlewareLayer",
|
|
19
|
+
"MiddlewareStack",
|
|
20
|
+
"SSEResponse",
|
|
21
|
+
"SimpleRouter",
|
|
22
|
+
"SmartRouter",
|
|
23
|
+
"router_registry",
|
|
24
|
+
]
|