python-corekit 0.1.0__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.
- {python_corekit-0.1.0/python_corekit.egg-info → python_corekit-0.2.0}/PKG-INFO +105 -100
- {python_corekit-0.1.0 → python_corekit-0.2.0}/README.md +102 -97
- python_corekit-0.2.0/corekit/api/__init__.py +24 -0
- python_corekit-0.2.0/corekit/api/application.py +237 -0
- python_corekit-0.2.0/corekit/api/lifespan.py +210 -0
- python_corekit-0.2.0/corekit/api/middleware.py +93 -0
- python_corekit-0.2.0/corekit/api/routers.py +223 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/concurrency/worker.py +65 -65
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/config/settings.py +3 -3
- python_corekit-0.2.0/corekit/connections/sql/__init__.py +38 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/connection.py +19 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/migration/__init__.py +5 -5
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/migration/base.py +3 -3
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/migration/operations.py +66 -42
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/migration/registry.py +2 -2
- python_corekit-0.2.0/corekit/connections/sql/operations/__init__.py +24 -0
- python_corekit-0.2.0/corekit/connections/sql/operations/base.py +102 -0
- python_corekit-0.2.0/corekit/connections/sql/operations/statements.py +150 -0
- python_corekit-0.2.0/corekit/connections/sql/query.py +10 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/table.py +30 -4
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/constants.py +45 -45
- python_corekit-0.2.0/corekit/crypto/constants.py +7 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/data/__init__.py +8 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/data/expressions/__init__.py +10 -2
- python_corekit-0.2.0/corekit/data/expressions/comparison.py +332 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/data/expressions/expression.py +103 -98
- python_corekit-0.2.0/corekit/data/expressions/operator.py +54 -0
- python_corekit-0.2.0/corekit/data/expressions/target.py +21 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/data/record.py +147 -147
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/data/stats.py +159 -157
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/decorators/__init__.py +2 -2
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/decorators/exception_handling.py +2 -1
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/connection.py +44 -44
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/websocket.py +3 -2
- python_corekit-0.2.0/corekit/exceptions/__init__.py +18 -0
- python_corekit-0.2.0/corekit/http/__init__.py +13 -0
- python_corekit-0.2.0/corekit/jobs/__init__.py +26 -0
- python_corekit-0.2.0/corekit/jobs/registry.py +87 -0
- python_corekit-0.2.0/corekit/jobs/runner.py +69 -0
- python_corekit-0.2.0/corekit/jobs/task.py +152 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/observability/__init__.py +5 -3
- python_corekit-0.2.0/corekit/observability/request_context.py +135 -0
- python_corekit-0.2.0/corekit/registry/__init__.py +17 -0
- python_corekit-0.2.0/corekit/registry/ordered.py +86 -0
- python_corekit-0.2.0/corekit/schemas/__init__.py +10 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/schemas/enum.py +49 -49
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/schemas/models/arbitrary.py +11 -11
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/schemas/pydantic/fields.py +35 -35
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/schemas/types.py +40 -40
- python_corekit-0.2.0/corekit/serialization/__init__.py +22 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/serialization/serializer.py +1 -1
- python_corekit-0.2.0/corekit/utils/__init__.py +59 -0
- python_corekit-0.2.0/corekit/utils/coercion.py +118 -0
- python_corekit-0.2.0/corekit/utils/collections.py +115 -0
- python_corekit-0.2.0/corekit/utils/ids.py +61 -0
- python_corekit-0.2.0/corekit/utils/payload.py +100 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/utils/raise_exc.py +8 -8
- python_corekit-0.2.0/corekit/utils/text.py +56 -0
- python_corekit-0.2.0/corekit/utils/time.py +74 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/utils/validators.py +15 -15
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/utils/void.py +8 -8
- {python_corekit-0.1.0 → python_corekit-0.2.0}/pyproject.toml +3 -3
- {python_corekit-0.1.0 → python_corekit-0.2.0/python_corekit.egg-info}/PKG-INFO +105 -100
- {python_corekit-0.1.0 → python_corekit-0.2.0}/python_corekit.egg-info/SOURCES.txt +34 -1
- python_corekit-0.2.0/tests/test_application.py +315 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_architecture.py +1 -0
- python_corekit-0.2.0/tests/test_expressions.py +255 -0
- python_corekit-0.2.0/tests/test_expressions_sqlalchemy.py +198 -0
- python_corekit-0.2.0/tests/test_jobs.py +167 -0
- python_corekit-0.2.0/tests/test_lifespan.py +225 -0
- python_corekit-0.2.0/tests/test_middleware_stack.py +134 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_migration.py +59 -10
- python_corekit-0.2.0/tests/test_operations.py +159 -0
- python_corekit-0.2.0/tests/test_ordered_registry.py +78 -0
- python_corekit-0.2.0/tests/test_request_context.py +131 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_sql.py +58 -0
- python_corekit-0.2.0/tests/test_utils_coercion.py +94 -0
- python_corekit-0.2.0/tests/test_utils_collections.py +84 -0
- python_corekit-0.2.0/tests/test_utils_ids.py +51 -0
- python_corekit-0.2.0/tests/test_utils_payload.py +65 -0
- python_corekit-0.2.0/tests/test_utils_text.py +56 -0
- python_corekit-0.2.0/tests/test_utils_time.py +62 -0
- python_corekit-0.1.0/corekit/api/__init__.py +0 -9
- python_corekit-0.1.0/corekit/api/routers.py +0 -115
- python_corekit-0.1.0/corekit/connections/sql/__init__.py +0 -10
- python_corekit-0.1.0/corekit/connections/sql/query.py +0 -68
- python_corekit-0.1.0/corekit/crypto/constants.py +0 -7
- python_corekit-0.1.0/corekit/data/expressions/comparison.py +0 -252
- python_corekit-0.1.0/corekit/registry/__init__.py +0 -12
- python_corekit-0.1.0/corekit/schemas/dataclasses/__init__.py +0 -0
- python_corekit-0.1.0/corekit/schemas/models/__init__.py +0 -0
- python_corekit-0.1.0/corekit/schemas/pydantic/__init__.py +0 -0
- python_corekit-0.1.0/corekit/serialization/__init__.py +0 -0
- python_corekit-0.1.0/corekit/utils/__init__.py +0 -5
- python_corekit-0.1.0/corekit/utils/ids.py +0 -5
- python_corekit-0.1.0/corekit/utils/time.py +0 -21
- {python_corekit-0.1.0 → python_corekit-0.2.0}/LICENSE +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/api/handler.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/api/responses.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/concurrency/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/concurrency/decorators.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/concurrency/thread_local.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/config/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/config/loader.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/config/sources.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/connectable.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/decorators.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/redis/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/redis/connection.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/registry.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/fields/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/fields/jsonb.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/connections/sql/migration/table.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/crypto/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/crypto/enum.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/crypto/hasher.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/data/dataset.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/decorators/warnings.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/docker/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/docker/watchdog.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/extract/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/extract/extractor.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/extract/schemas.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/load/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/load/loader.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/load/schemas.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/orchestrator.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/schemas.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/transform/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/transform/schemas.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/etl/transform/transformer.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/enum.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/frames.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/models.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/publisher.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/reader.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/events/sse.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/exceptions/base.py +0 -0
- {python_corekit-0.1.0/corekit/exceptions → python_corekit-0.2.0/corekit/exceptions/custom}/__init__.py +0 -0
- {python_corekit-0.1.0/corekit/exceptions/custom → python_corekit-0.2.0/corekit/exceptions/http}/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/exceptions/http/exceptions.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/exceptions/types.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/files/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/files/base.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/files/enum.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/files/json.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/files/pickle.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/files/toml.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/http/client.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/http/exponential_backoff.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/http/response.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/log_monitor/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/log_monitor/constants.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/log_monitor/models.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/log_monitor/service.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/notifications/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/notifications/base.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/notifications/models.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/observability/benchmarkable.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/observability/loggable.py +0 -0
- {python_corekit-0.1.0/corekit/exceptions/http → python_corekit-0.2.0/corekit/observability/timing}/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/observability/timing/constants.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/observability/timing/split.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/observability/timing/timer.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/py.typed +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/registry/registry.py +0 -0
- {python_corekit-0.1.0/corekit/http → python_corekit-0.2.0/corekit/schemas/dataclasses}/__init__.py +0 -0
- {python_corekit-0.1.0/corekit/observability/timing → python_corekit-0.2.0/corekit/schemas/models}/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/schemas/models/date_models.py +0 -0
- {python_corekit-0.1.0/corekit/schemas → python_corekit-0.2.0/corekit/schemas/pydantic}/__init__.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/serialization/enum.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/corekit/serialization/serializable.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/python_corekit.egg-info/dependency_links.txt +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/python_corekit.egg-info/requires.txt +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/python_corekit.egg-info/top_level.txt +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/setup.cfg +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/setup.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_api.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_concurrency.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_config.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_connections.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_data.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_docker.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_etl.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_events.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_files.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_imports.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_imports_are_top_level.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_log_monitor.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_redis.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_registry.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_requests.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_serialization.py +0 -0
- {python_corekit-0.1.0 → python_corekit-0.2.0}/tests/test_utils.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.2.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
|
|
|
@@ -47,17 +47,15 @@ Requires Python 3.11+.
|
|
|
47
47
|
pip install python-corekit
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
corekit can be cloned and built by anyone, including inside a Docker build.
|
|
50
|
+
The distribution is `python-corekit`; the import is `corekit`.
|
|
52
51
|
|
|
53
52
|
Every dependency corekit needs is installed with it. There are no optional
|
|
54
53
|
extras to remember, and no import that fails because something was left out.
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
release rather than tracking whatever is newest:
|
|
55
|
+
Pin a compatible release rather than tracking whatever is newest:
|
|
58
56
|
|
|
59
57
|
```
|
|
60
|
-
python-corekit~=0.
|
|
58
|
+
python-corekit~=0.2.0
|
|
61
59
|
```
|
|
62
60
|
|
|
63
61
|
Before 1.0, the minor version carries breaking changes.
|
|
@@ -90,6 +88,57 @@ class Report(Benchmarkable):
|
|
|
90
88
|
self.timing("queried") # logs the time since the previous split
|
|
91
89
|
```
|
|
92
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
|
+
|
|
93
142
|
## Routers and handlers
|
|
94
143
|
|
|
95
144
|
A router and the handler holding its business logic travel together. Declare the
|
|
@@ -149,113 +198,67 @@ people.get_record("Ada").age # O(1) lookup by id
|
|
|
149
198
|
|
|
150
199
|
Stores pickle cleanly, including their dynamically generated record class.
|
|
151
200
|
|
|
152
|
-
##
|
|
201
|
+
## SQL statements
|
|
153
202
|
|
|
154
|
-
|
|
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.
|
|
155
205
|
|
|
156
206
|
```python
|
|
157
|
-
from corekit.
|
|
207
|
+
from corekit.connections.sql import SQLConnection, Select, Insert, Update, Delete
|
|
208
|
+
from corekit.data import Field
|
|
158
209
|
|
|
159
|
-
|
|
160
|
-
watchdog.restart_container_by_name("minecraft")
|
|
161
|
-
watchdog.find_and_stop(label="app", value="staging")
|
|
162
|
-
```
|
|
210
|
+
conn = SQLConnection("sqlite:///app.db")
|
|
163
211
|
|
|
164
|
-
|
|
165
|
-
the `watchdog=true` label can be started, stopped or paused, so a mistyped name
|
|
166
|
-
cannot take down something unrelated. Leave it on unless the watchdog is meant
|
|
167
|
-
to control everything on the host.
|
|
168
|
-
|
|
169
|
-
### Reacting to logs
|
|
170
|
-
|
|
171
|
-
Describe what to watch for and what to do about it:
|
|
172
|
-
|
|
173
|
-
```yaml
|
|
174
|
-
# config.yaml
|
|
175
|
-
containers:
|
|
176
|
-
- name: "minecraft-.*"
|
|
177
|
-
rules:
|
|
178
|
-
- name: "out of memory"
|
|
179
|
-
pattern: "java.lang.OutOfMemoryError"
|
|
180
|
-
severity: critical
|
|
181
|
-
send_notification: true
|
|
182
|
-
actions:
|
|
183
|
-
- type: restart_container
|
|
184
|
-
max_restarts: 3
|
|
185
|
-
restart_window: 3600
|
|
186
|
-
advanced:
|
|
187
|
-
ignore_patterns:
|
|
188
|
-
- "healthcheck"
|
|
189
|
-
rate_limits:
|
|
190
|
-
restart_container:
|
|
191
|
-
count: 5
|
|
192
|
-
period: hour
|
|
193
|
-
```
|
|
212
|
+
conn.execute(Insert(table=User, rows=[{"name": "Ada", "age": 36}]).add(name="Bob", age=17))
|
|
194
213
|
|
|
195
|
-
|
|
196
|
-
from corekit.log_monitor import LogMonitor
|
|
214
|
+
adults = conn.fetch(Select(table=User).where(User.age >= 18).order_by(User.name).limit(10))
|
|
197
215
|
|
|
198
|
-
|
|
216
|
+
conn.execute(Update(table=User).where(User.name == "Bob").set(age=18))
|
|
217
|
+
conn.execute(Delete(table=User).where(User.age < 13))
|
|
199
218
|
```
|
|
200
219
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
### 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:
|
|
204
222
|
|
|
205
223
|
```python
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
class DiscordNotifier(BaseNotificationService):
|
|
209
|
-
"""
|
|
210
|
-
Sends notifications to a Discord channel.
|
|
211
|
-
"""
|
|
212
|
-
|
|
213
|
-
def _send(self, message: str) -> None:
|
|
214
|
-
discord.post(message)
|
|
215
|
-
|
|
216
|
-
notifier.notify(Notification(message="disk full", type=NotificationType.ERROR))
|
|
224
|
+
Select(table=User).where(Field("age") >= 18)
|
|
217
225
|
```
|
|
218
226
|
|
|
219
|
-
|
|
220
|
-
|
|
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.
|
|
221
230
|
|
|
222
|
-
|
|
231
|
+
A `Delete` or `Update` with no condition raises rather than running:
|
|
223
232
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
```python
|
|
227
|
-
from corekit.events import EventPublisher
|
|
228
|
-
|
|
229
|
-
publisher = EventPublisher.for_resource("minecraft", "server", "survival")
|
|
230
|
-
publisher.publish("backup_finished", {"size": "4.2GB"})
|
|
233
|
+
```
|
|
234
|
+
Delete on User needs a condition; use truncate to empty a table
|
|
231
235
|
```
|
|
232
236
|
|
|
233
|
-
|
|
237
|
+
## Background tasks
|
|
234
238
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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.
|
|
238
242
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
```
|
|
243
|
+
```python
|
|
244
|
+
from corekit.jobs import Task, run_task
|
|
245
|
+
from corekit.utils import encode_payload
|
|
243
246
|
|
|
244
|
-
|
|
247
|
+
class SendDigest(Task):
|
|
248
|
+
def task_function(self, user: str) -> None:
|
|
249
|
+
...
|
|
245
250
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
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"]))
|
|
249
253
|
```
|
|
250
254
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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.
|
|
256
260
|
|
|
257
|
-
|
|
258
|
-
the operation that produced it. `publish` returns whether it worked.
|
|
261
|
+
`ScheduledTask` adds an `interval` for tasks a scheduler should repeat.
|
|
259
262
|
|
|
260
263
|
## Parallel work
|
|
261
264
|
|
|
@@ -371,23 +374,25 @@ Imports go downward only.
|
|
|
371
374
|
|
|
372
375
|
```
|
|
373
376
|
corekit/
|
|
374
|
-
config
|
|
377
|
+
config/ settings, sources, loader
|
|
378
|
+
constants.py
|
|
375
379
|
|
|
376
380
|
exceptions/ error types
|
|
377
381
|
|
|
378
382
|
observability/ Loggable, Benchmarkable, Timer
|
|
379
|
-
registry/ schemas/ utils/
|
|
383
|
+
registry/ schemas/ utils/ registries, enums and fields, helpers
|
|
380
384
|
data/ Dataset and its filter expressions
|
|
385
|
+
jobs/ queue-independent background tasks
|
|
381
386
|
crypto/ files/ serialization/
|
|
382
387
|
concurrency/ ThreadLocalRegistry, ThreadWorker
|
|
383
388
|
decorators/
|
|
384
389
|
|
|
385
390
|
connections/ the Connectable lifecycle and @connect
|
|
386
|
-
sql/ SQLConnection,
|
|
391
|
+
sql/ SQLConnection, statements, migrations
|
|
387
392
|
redis/ RedisConnection
|
|
388
393
|
http/ BaseApiClient, retries, responses
|
|
389
394
|
|
|
390
|
-
api/
|
|
395
|
+
api/ Application, lifespan, middleware, routers
|
|
391
396
|
docker/ notifications/ etl/
|
|
392
397
|
|
|
393
398
|
events/ log_monitor/ built on the capabilities above
|
|
@@ -404,13 +409,13 @@ layering deliberately.
|
|
|
404
409
|
## Development
|
|
405
410
|
|
|
406
411
|
```bash
|
|
407
|
-
pip install -e ".[dev
|
|
412
|
+
pip install -e ".[dev]"
|
|
408
413
|
pytest
|
|
409
414
|
ruff format . && ruff check --fix .
|
|
410
415
|
```
|
|
411
416
|
|
|
412
|
-
`tests/test_imports.py` imports every module in the package
|
|
413
|
-
|
|
417
|
+
`tests/test_imports.py` imports every module in the package, so a module that
|
|
418
|
+
nothing else happens to import still has to be importable.
|
|
414
419
|
|
|
415
420
|
## Licence
|
|
416
421
|
|
|
@@ -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
|
|
|
@@ -12,17 +12,15 @@ Requires Python 3.11+.
|
|
|
12
12
|
pip install python-corekit
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
corekit can be cloned and built by anyone, including inside a Docker build.
|
|
15
|
+
The distribution is `python-corekit`; the import is `corekit`.
|
|
17
16
|
|
|
18
17
|
Every dependency corekit needs is installed with it. There are no optional
|
|
19
18
|
extras to remember, and no import that fails because something was left out.
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
release rather than tracking whatever is newest:
|
|
20
|
+
Pin a compatible release rather than tracking whatever is newest:
|
|
23
21
|
|
|
24
22
|
```
|
|
25
|
-
python-corekit~=0.
|
|
23
|
+
python-corekit~=0.2.0
|
|
26
24
|
```
|
|
27
25
|
|
|
28
26
|
Before 1.0, the minor version carries breaking changes.
|
|
@@ -55,6 +53,57 @@ class Report(Benchmarkable):
|
|
|
55
53
|
self.timing("queried") # logs the time since the previous split
|
|
56
54
|
```
|
|
57
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
|
+
|
|
58
107
|
## Routers and handlers
|
|
59
108
|
|
|
60
109
|
A router and the handler holding its business logic travel together. Declare the
|
|
@@ -114,113 +163,67 @@ people.get_record("Ada").age # O(1) lookup by id
|
|
|
114
163
|
|
|
115
164
|
Stores pickle cleanly, including their dynamically generated record class.
|
|
116
165
|
|
|
117
|
-
##
|
|
166
|
+
## SQL statements
|
|
118
167
|
|
|
119
|
-
|
|
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.
|
|
120
170
|
|
|
121
171
|
```python
|
|
122
|
-
from corekit.
|
|
172
|
+
from corekit.connections.sql import SQLConnection, Select, Insert, Update, Delete
|
|
173
|
+
from corekit.data import Field
|
|
123
174
|
|
|
124
|
-
|
|
125
|
-
watchdog.restart_container_by_name("minecraft")
|
|
126
|
-
watchdog.find_and_stop(label="app", value="staging")
|
|
127
|
-
```
|
|
175
|
+
conn = SQLConnection("sqlite:///app.db")
|
|
128
176
|
|
|
129
|
-
|
|
130
|
-
the `watchdog=true` label can be started, stopped or paused, so a mistyped name
|
|
131
|
-
cannot take down something unrelated. Leave it on unless the watchdog is meant
|
|
132
|
-
to control everything on the host.
|
|
133
|
-
|
|
134
|
-
### Reacting to logs
|
|
135
|
-
|
|
136
|
-
Describe what to watch for and what to do about it:
|
|
137
|
-
|
|
138
|
-
```yaml
|
|
139
|
-
# config.yaml
|
|
140
|
-
containers:
|
|
141
|
-
- name: "minecraft-.*"
|
|
142
|
-
rules:
|
|
143
|
-
- name: "out of memory"
|
|
144
|
-
pattern: "java.lang.OutOfMemoryError"
|
|
145
|
-
severity: critical
|
|
146
|
-
send_notification: true
|
|
147
|
-
actions:
|
|
148
|
-
- type: restart_container
|
|
149
|
-
max_restarts: 3
|
|
150
|
-
restart_window: 3600
|
|
151
|
-
advanced:
|
|
152
|
-
ignore_patterns:
|
|
153
|
-
- "healthcheck"
|
|
154
|
-
rate_limits:
|
|
155
|
-
restart_container:
|
|
156
|
-
count: 5
|
|
157
|
-
period: hour
|
|
158
|
-
```
|
|
177
|
+
conn.execute(Insert(table=User, rows=[{"name": "Ada", "age": 36}]).add(name="Bob", age=17))
|
|
159
178
|
|
|
160
|
-
|
|
161
|
-
from corekit.log_monitor import LogMonitor
|
|
179
|
+
adults = conn.fetch(Select(table=User).where(User.age >= 18).order_by(User.name).limit(10))
|
|
162
180
|
|
|
163
|
-
|
|
181
|
+
conn.execute(Update(table=User).where(User.name == "Bob").set(age=18))
|
|
182
|
+
conn.execute(Delete(table=User).where(User.age < 13))
|
|
164
183
|
```
|
|
165
184
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
### 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:
|
|
169
187
|
|
|
170
188
|
```python
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
class DiscordNotifier(BaseNotificationService):
|
|
174
|
-
"""
|
|
175
|
-
Sends notifications to a Discord channel.
|
|
176
|
-
"""
|
|
177
|
-
|
|
178
|
-
def _send(self, message: str) -> None:
|
|
179
|
-
discord.post(message)
|
|
180
|
-
|
|
181
|
-
notifier.notify(Notification(message="disk full", type=NotificationType.ERROR))
|
|
189
|
+
Select(table=User).where(Field("age") >= 18)
|
|
182
190
|
```
|
|
183
191
|
|
|
184
|
-
|
|
185
|
-
|
|
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.
|
|
186
195
|
|
|
187
|
-
|
|
196
|
+
A `Delete` or `Update` with no condition raises rather than running:
|
|
188
197
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
```python
|
|
192
|
-
from corekit.events import EventPublisher
|
|
193
|
-
|
|
194
|
-
publisher = EventPublisher.for_resource("minecraft", "server", "survival")
|
|
195
|
-
publisher.publish("backup_finished", {"size": "4.2GB"})
|
|
198
|
+
```
|
|
199
|
+
Delete on User needs a condition; use truncate to empty a table
|
|
196
200
|
```
|
|
197
201
|
|
|
198
|
-
|
|
202
|
+
## Background tasks
|
|
199
203
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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.
|
|
203
207
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
```
|
|
208
|
+
```python
|
|
209
|
+
from corekit.jobs import Task, run_task
|
|
210
|
+
from corekit.utils import encode_payload
|
|
208
211
|
|
|
209
|
-
|
|
212
|
+
class SendDigest(Task):
|
|
213
|
+
def task_function(self, user: str) -> None:
|
|
214
|
+
...
|
|
210
215
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
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"]))
|
|
214
218
|
```
|
|
215
219
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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.
|
|
221
225
|
|
|
222
|
-
|
|
223
|
-
the operation that produced it. `publish` returns whether it worked.
|
|
226
|
+
`ScheduledTask` adds an `interval` for tasks a scheduler should repeat.
|
|
224
227
|
|
|
225
228
|
## Parallel work
|
|
226
229
|
|
|
@@ -336,23 +339,25 @@ Imports go downward only.
|
|
|
336
339
|
|
|
337
340
|
```
|
|
338
341
|
corekit/
|
|
339
|
-
config
|
|
342
|
+
config/ settings, sources, loader
|
|
343
|
+
constants.py
|
|
340
344
|
|
|
341
345
|
exceptions/ error types
|
|
342
346
|
|
|
343
347
|
observability/ Loggable, Benchmarkable, Timer
|
|
344
|
-
registry/ schemas/ utils/
|
|
348
|
+
registry/ schemas/ utils/ registries, enums and fields, helpers
|
|
345
349
|
data/ Dataset and its filter expressions
|
|
350
|
+
jobs/ queue-independent background tasks
|
|
346
351
|
crypto/ files/ serialization/
|
|
347
352
|
concurrency/ ThreadLocalRegistry, ThreadWorker
|
|
348
353
|
decorators/
|
|
349
354
|
|
|
350
355
|
connections/ the Connectable lifecycle and @connect
|
|
351
|
-
sql/ SQLConnection,
|
|
356
|
+
sql/ SQLConnection, statements, migrations
|
|
352
357
|
redis/ RedisConnection
|
|
353
358
|
http/ BaseApiClient, retries, responses
|
|
354
359
|
|
|
355
|
-
api/
|
|
360
|
+
api/ Application, lifespan, middleware, routers
|
|
356
361
|
docker/ notifications/ etl/
|
|
357
362
|
|
|
358
363
|
events/ log_monitor/ built on the capabilities above
|
|
@@ -369,13 +374,13 @@ layering deliberately.
|
|
|
369
374
|
## Development
|
|
370
375
|
|
|
371
376
|
```bash
|
|
372
|
-
pip install -e ".[dev
|
|
377
|
+
pip install -e ".[dev]"
|
|
373
378
|
pytest
|
|
374
379
|
ruff format . && ruff check --fix .
|
|
375
380
|
```
|
|
376
381
|
|
|
377
|
-
`tests/test_imports.py` imports every module in the package
|
|
378
|
-
|
|
382
|
+
`tests/test_imports.py` imports every module in the package, so a module that
|
|
383
|
+
nothing else happens to import still has to be importable.
|
|
379
384
|
|
|
380
385
|
## Licence
|
|
381
386
|
|
|
@@ -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
|
+
]
|