pycharter 0.0.24__py3-none-any.whl → 0.0.26__py3-none-any.whl
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.
- pycharter/__init__.py +6 -0
- pycharter/api/README.md +340 -0
- {api → pycharter/api}/__init__.py +1 -1
- {api → pycharter/api}/dependencies/__init__.py +2 -2
- pycharter/api/dependencies/auth.py +158 -0
- {api → pycharter/api}/main.py +32 -4
- {api → pycharter/api}/models/__init__.py +4 -4
- pycharter/api/models/etl.py +66 -0
- {api → pycharter/api}/routes/v1/__init__.py +5 -1
- pycharter/api/routes/v1/auth.py +97 -0
- {api → pycharter/api}/routes/v1/contracts.py +14 -12
- {api → pycharter/api}/routes/v1/docs.py +2 -2
- pycharter/api/routes/v1/etl.py +131 -0
- {api → pycharter/api}/routes/v1/evolution.py +2 -2
- {api → pycharter/api}/routes/v1/metadata.py +5 -5
- {api → pycharter/api}/routes/v1/quality.py +3 -3
- {api → pycharter/api}/routes/v1/schemas.py +1 -1
- {api → pycharter/api}/routes/v1/settings.py +1 -1
- {api → pycharter/api}/routes/v1/tracking.py +1 -1
- {api → pycharter/api}/routes/v1/validation.py +2 -2
- {api → pycharter/api}/routes/v1/validation_jobs.py +3 -3
- pycharter/cli.py +9 -11
- pycharter/config.py +69 -0
- pycharter/contract_builder/builder.py +32 -37
- pycharter/data/seed/compliance_frameworks.yaml +22 -0
- pycharter/data/seed/contracts.yaml +130 -0
- pycharter/data/seed/data_feeds.yaml +22 -0
- pycharter/data/seed/domains.yaml +13 -0
- pycharter/data/seed/environments.yaml +19 -0
- pycharter/data/seed/owners.yaml +21 -0
- pycharter/data/seed/systems.yaml +13 -0
- pycharter/data/seed/tags.yaml +25 -0
- pycharter/data/templates/contract/README.md +161 -0
- pycharter/data/templates/contract/template_contract.yaml +37 -0
- pycharter/data/templates/etl/README.md +1 -1
- pycharter/data/templates/etl/extract_with_validation.yaml +86 -0
- pycharter/data/templates/etl/load_with_validation.yaml +111 -0
- pycharter/data/templates/etl/settings.yaml +55 -0
- pycharter/db/README.md +179 -0
- pycharter/db/cli.py +126 -4
- pycharter/db/migrations/versions/20260122000000_change_artifact_unique_constraints_to_title_version.py +2 -2
- pycharter/db/schemas/README.md +96 -0
- pycharter/etl_generator/ASYNC_AND_EXECUTION.md +91 -0
- pycharter/etl_generator/INTERFACES.md +142 -0
- pycharter/etl_generator/README.md +271 -0
- pycharter/etl_generator/TRANSFORMATION_GUIDE.md +452 -0
- pycharter/etl_generator/__init__.py +47 -11
- pycharter/etl_generator/config_models.py +673 -0
- pycharter/etl_generator/config_validator.py +133 -157
- pycharter/etl_generator/context.py +3 -0
- pycharter/etl_generator/database.py +5 -1
- pycharter/etl_generator/extractors/__init__.py +4 -2
- pycharter/etl_generator/extractors/cloud_storage.py +9 -9
- pycharter/etl_generator/extractors/database.py +2 -2
- pycharter/etl_generator/extractors/factory.py +15 -33
- pycharter/etl_generator/extractors/file.py +2 -2
- pycharter/etl_generator/extractors/http.py +2 -2
- pycharter/etl_generator/extractors/mongodb.py +393 -0
- pycharter/etl_generator/extractors/streaming.py +2 -2
- pycharter/etl_generator/loaders/__init__.py +15 -9
- pycharter/etl_generator/loaders/{cloud_storage_loader.py → cloud_storage.py} +95 -2
- pycharter/etl_generator/loaders/factory.py +16 -29
- pycharter/etl_generator/loaders/file.py +135 -1
- pycharter/etl_generator/loaders/mongodb.py +416 -0
- pycharter/etl_generator/pipeline.py +283 -164
- pycharter/etl_generator/result.py +16 -0
- pycharter/etl_generator/schemas/__init__.py +71 -42
- pycharter/etl_generator/transformers/config.py +3 -2
- pycharter/etl_generator/transformers/simple_operations.py +57 -4
- pycharter/etl_generator/validation.py +551 -0
- pycharter/metadata_store/README.md +229 -0
- pycharter/quality/README.md +235 -0
- pycharter/runtime_validator/__init__.py +7 -0
- pycharter/runtime_validator/utils.py +33 -0
- pycharter/runtime_validator/validator.py +13 -10
- pycharter/ui/.eslintrc.json +4 -0
- pycharter/ui/README.md +186 -0
- {ui → pycharter/ui}/__init__.py +3 -3
- pycharter/ui/components.json +17 -0
- pycharter/ui/package-lock.json +6617 -0
- pycharter/ui/package.json +37 -0
- {ui → pycharter/ui}/server.py +7 -8
- pycharter/ui/static/404/index.html +1 -0
- pycharter/ui/static/404.html +1 -0
- pycharter/ui/static/__next.__PAGE__.txt +10 -0
- pycharter/ui/static/__next._full.txt +30 -0
- pycharter/ui/static/__next._head.txt +7 -0
- pycharter/ui/static/__next._index.txt +9 -0
- pycharter/ui/static/__next._tree.txt +2 -0
- pycharter/ui/static/_next/static/YCnlK66gA7FV5vvcixspB/_clientMiddlewareManifest.json +1 -0
- pycharter/ui/static/_next/static/chunks/0fc1f70b787b8845.js +1 -0
- pycharter/ui/static/_next/static/chunks/17bb8075d7b75663.css +1 -0
- pycharter/ui/static/_next/static/chunks/381932864dcbfdb8.js +1 -0
- pycharter/ui/static/_next/static/chunks/4c951b8e4507e2b3.js +1 -0
- pycharter/ui/static/_next/static/chunks/68b87a6f65abd3ed.js +1 -0
- pycharter/ui/static/_next/static/chunks/78572617b8fae189.js +1 -0
- pycharter/ui/static/_next/static/chunks/8b7be2803e3fe184.js +1 -0
- pycharter/ui/static/_next/static/chunks/a8e529fd1e67f121.js +1 -0
- pycharter/ui/static/_next/static/chunks/c35d998f80be3ff5.js +1 -0
- pycharter/ui/static/_next/static/chunks/e453aa5d01c32c17.js +1 -0
- pycharter/ui/static/_next/static/chunks/f2d240eb057f898a.js +970 -0
- pycharter/ui/static/_next/static/chunks/f7722448f6040846.js +1 -0
- pycharter/ui/static/_not-found/__next._full.txt +17 -0
- pycharter/ui/static/_not-found/__next._head.txt +7 -0
- pycharter/ui/static/_not-found/__next._index.txt +9 -0
- pycharter/ui/static/_not-found/__next._not-found.__PAGE__.txt +5 -0
- pycharter/ui/static/_not-found/__next._not-found.txt +4 -0
- pycharter/ui/static/_not-found/__next._tree.txt +2 -0
- pycharter/ui/static/_not-found/index.html +1 -0
- pycharter/ui/static/_not-found/index.txt +17 -0
- pycharter/ui/static/contracts/__next._full.txt +21 -0
- pycharter/ui/static/contracts/__next._head.txt +7 -0
- pycharter/ui/static/contracts/__next._index.txt +9 -0
- pycharter/ui/static/contracts/__next._tree.txt +2 -0
- pycharter/ui/static/contracts/__next.contracts.__PAGE__.txt +9 -0
- pycharter/ui/static/contracts/__next.contracts.txt +4 -0
- pycharter/ui/static/contracts/index.html +1 -0
- pycharter/ui/static/contracts/index.txt +21 -0
- pycharter/ui/static/documentation/__next._full.txt +21 -0
- pycharter/ui/static/documentation/__next._head.txt +7 -0
- pycharter/ui/static/documentation/__next._index.txt +9 -0
- pycharter/ui/static/documentation/__next._tree.txt +2 -0
- pycharter/ui/static/documentation/__next.documentation.__PAGE__.txt +9 -0
- pycharter/ui/static/documentation/__next.documentation.txt +4 -0
- pycharter/ui/static/documentation/index.html +93 -0
- pycharter/ui/static/documentation/index.txt +21 -0
- pycharter/ui/static/etl/__next._full.txt +21 -0
- pycharter/ui/static/etl/__next._head.txt +7 -0
- pycharter/ui/static/etl/__next._index.txt +9 -0
- pycharter/ui/static/etl/__next._tree.txt +2 -0
- pycharter/ui/static/etl/__next.etl.__PAGE__.txt +9 -0
- pycharter/ui/static/etl/__next.etl.txt +4 -0
- pycharter/ui/static/etl/index.html +2 -0
- pycharter/ui/static/etl/index.txt +21 -0
- pycharter/ui/static/index.html +1 -0
- pycharter/ui/static/index.txt +30 -0
- pycharter/ui/static/metadata/__next._full.txt +21 -0
- pycharter/ui/static/metadata/__next._head.txt +7 -0
- pycharter/ui/static/metadata/__next._index.txt +9 -0
- pycharter/ui/static/metadata/__next._tree.txt +2 -0
- pycharter/ui/static/metadata/__next.metadata.__PAGE__.txt +9 -0
- pycharter/ui/static/metadata/__next.metadata.txt +4 -0
- pycharter/ui/static/metadata/index.html +1 -0
- pycharter/ui/static/metadata/index.txt +21 -0
- pycharter/ui/static/quality/__next._full.txt +21 -0
- pycharter/ui/static/quality/__next._head.txt +7 -0
- pycharter/ui/static/quality/__next._index.txt +9 -0
- pycharter/ui/static/quality/__next._tree.txt +2 -0
- pycharter/ui/static/quality/__next.quality.__PAGE__.txt +9 -0
- pycharter/ui/static/quality/__next.quality.txt +4 -0
- pycharter/ui/static/quality/index.html +2 -0
- pycharter/ui/static/quality/index.txt +21 -0
- pycharter/ui/static/rules/__next._full.txt +21 -0
- pycharter/ui/static/rules/__next._head.txt +7 -0
- pycharter/ui/static/rules/__next._index.txt +9 -0
- pycharter/ui/static/rules/__next._tree.txt +2 -0
- pycharter/ui/static/rules/__next.rules.__PAGE__.txt +9 -0
- pycharter/ui/static/rules/__next.rules.txt +4 -0
- pycharter/ui/static/rules/index.html +1 -0
- pycharter/ui/static/rules/index.txt +21 -0
- pycharter/ui/static/schemas/__next._full.txt +21 -0
- pycharter/ui/static/schemas/__next._head.txt +7 -0
- pycharter/ui/static/schemas/__next._index.txt +9 -0
- pycharter/ui/static/schemas/__next._tree.txt +2 -0
- pycharter/ui/static/schemas/__next.schemas.__PAGE__.txt +9 -0
- pycharter/ui/static/schemas/__next.schemas.txt +4 -0
- pycharter/ui/static/schemas/index.html +1 -0
- pycharter/ui/static/schemas/index.txt +21 -0
- pycharter/ui/static/settings/__next._full.txt +21 -0
- pycharter/ui/static/settings/__next._head.txt +7 -0
- pycharter/ui/static/settings/__next._index.txt +9 -0
- pycharter/ui/static/settings/__next._tree.txt +2 -0
- pycharter/ui/static/settings/__next.settings.__PAGE__.txt +9 -0
- pycharter/ui/static/settings/__next.settings.txt +4 -0
- pycharter/ui/static/settings/index.html +1 -0
- pycharter/ui/static/settings/index.txt +21 -0
- pycharter/ui/static/static/_next/static/2gKjNv6YvE6BcIdFthBLs/_clientMiddlewareManifest.json +1 -0
- pycharter/ui/static/static/static/_next/static/0rYA78L88aUyD2Uh38hhX/_clientMiddlewareManifest.json +1 -0
- pycharter/ui/static/static/static/_next/static/chunks/f7d1a90dd75d2572.js +1 -0
- pycharter/ui/static/static/static/static/.gitkeep +0 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/222442f6da32302a.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/247eb132b7f7b574.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/297d55555b71baba.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/414e77373f8ff61c.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/652ad0aa26265c47.js +2 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/9c23f44fff36548a.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/a6dad97d9634a72d.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/b32a0963684b9933.js +4 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/db913959c675cea6.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/f2e7afeab1178138.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/ff1a16fafef87110.js +1 -0
- pycharter/ui/static/static/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +3 -0
- pycharter/ui/static/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_buildManifest.js +11 -0
- pycharter/ui/static/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_clientMiddlewareManifest.json +1 -0
- pycharter/ui/static/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_ssgManifest.js +1 -0
- pycharter/ui/static/validation/__next._full.txt +21 -0
- pycharter/ui/static/validation/__next._head.txt +7 -0
- pycharter/ui/static/validation/__next._index.txt +9 -0
- pycharter/ui/static/validation/__next._tree.txt +2 -0
- pycharter/ui/static/validation/__next.validation.__PAGE__.txt +9 -0
- pycharter/ui/static/validation/__next.validation.txt +4 -0
- pycharter/ui/static/validation/index.html +1 -0
- pycharter/ui/static/validation/index.txt +21 -0
- pycharter/ui/tsconfig.json +42 -0
- pycharter/worker/README.md +187 -0
- pycharter/worker/backends/__init__.py +8 -0
- pycharter/worker/backends/base.py +46 -0
- pycharter/worker/backends/spark.py +233 -0
- {worker → pycharter/worker}/cli.py +1 -1
- {worker → pycharter/worker}/processor.py +2 -2
- pycharter/worker/queue/__init__.py +8 -0
- pycharter/worker/queue/redis_queue.py +147 -0
- {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/METADATA +57 -26
- pycharter-0.0.26.dist-info/RECORD +702 -0
- pycharter-0.0.26.dist-info/top_level.txt +1 -0
- pycharter/etl_generator/config_loader.py +0 -394
- pycharter/etl_generator/loaders/cloud.py +0 -87
- pycharter/etl_generator/loaders/file_loader.py +0 -130
- pycharter-0.0.24.dist-info/RECORD +0 -543
- pycharter-0.0.24.dist-info/top_level.txt +0 -4
- {api → pycharter/api}/dependencies/database.py +0 -0
- {api → pycharter/api}/dependencies/store.py +0 -0
- {api → pycharter/api}/models/contracts.py +0 -0
- {api → pycharter/api}/models/docs.py +0 -0
- {api → pycharter/api}/models/evolution.py +0 -0
- {api → pycharter/api}/models/metadata.py +0 -0
- {api → pycharter/api}/models/metadata_entities.py +0 -0
- {api → pycharter/api}/models/quality.py +0 -0
- {api → pycharter/api}/models/schemas.py +0 -0
- {api → pycharter/api}/models/tracking.py +0 -0
- {api → pycharter/api}/models/validation.py +0 -0
- {api → pycharter/api}/routes/__init__.py +0 -0
- {api → pycharter/api}/routes/v1/templates.py +0 -0
- {api → pycharter/api}/utils.py +0 -0
- {ui → pycharter/ui}/build.py +0 -0
- {ui → pycharter/ui}/dev.py +0 -0
- {ui → pycharter/ui}/static/.gitkeep +0 -0
- {ui/static/_next/static/2gKjNv6YvE6BcIdFthBLs → pycharter/ui/static/_next/static/YCnlK66gA7FV5vvcixspB}/_buildManifest.js +0 -0
- {ui/static/_next/static/2gKjNv6YvE6BcIdFthBLs → pycharter/ui/static/_next/static/YCnlK66gA7FV5vvcixspB}/_ssgManifest.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/222442f6da32302a.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/247eb132b7f7b574.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/297d55555b71baba.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/414e77373f8ff61c.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/652ad0aa26265c47.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/9c23f44fff36548a.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/a6dad97d9634a72d.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/b32a0963684b9933.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/db913959c675cea6.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/f2e7afeab1178138.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/f7d1a90dd75d2572.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/ff1a16fafef87110.js +0 -0
- {ui → pycharter/ui}/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +0 -0
- {ui → pycharter/ui}/static/static/.gitkeep +0 -0
- {ui → pycharter/ui/static}/static/404/index.html +0 -0
- {ui → pycharter/ui/static}/static/404.html +0 -0
- {ui → pycharter/ui/static}/static/__next.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/__next._tree.txt +0 -0
- {ui/static/static/_next/static/0rYA78L88aUyD2Uh38hhX → pycharter/ui/static/static/_next/static/2gKjNv6YvE6BcIdFthBLs}/_buildManifest.js +0 -0
- {ui/static/static/_next/static/0rYA78L88aUyD2Uh38hhX → pycharter/ui/static/static/_next/static/2gKjNv6YvE6BcIdFthBLs}/_ssgManifest.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/13d4a0fbd74c1ee4.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/222442f6da32302a.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/247eb132b7f7b574.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/26dfc590f7714c03.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/297d55555b71baba.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/2ab439ce003cd691.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/2edb43b48432ac04.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/34d289e6db2ef551.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/414e77373f8ff61c.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/49ca65abd26ae49e.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/652ad0aa26265c47.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/9667e7a3d359eb39.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/99508d9d5869cc27.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/9c23f44fff36548a.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/a6dad97d9634a72d.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/b313c35a6ba76574.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/b32a0963684b9933.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/c69f6cba366bd988.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/d2363397e1b2bcab.css +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/db913959c675cea6.js +0 -0
- {ui → pycharter/ui/static}/static/_next/static/chunks/f061a4be97bfc3b3.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/f2e7afeab1178138.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/f7d1a90dd75d2572.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/ff1a16fafef87110.js +0 -0
- {ui → pycharter/ui}/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +0 -0
- {ui → pycharter/ui/static}/static/_not-found/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/_not-found/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/_not-found/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/_not-found/__next._not-found.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/_not-found/__next._not-found.txt +0 -0
- {ui → pycharter/ui/static}/static/_not-found/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/_not-found/index.html +0 -0
- {ui → pycharter/ui/static}/static/_not-found/index.txt +0 -0
- {ui → pycharter/ui/static}/static/contracts/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/contracts/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/contracts/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/contracts/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/contracts/__next.contracts.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/contracts/__next.contracts.txt +0 -0
- {ui → pycharter/ui/static}/static/contracts/index.html +0 -0
- {ui → pycharter/ui/static}/static/contracts/index.txt +0 -0
- {ui → pycharter/ui/static}/static/documentation/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/documentation/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/documentation/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/documentation/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/documentation/__next.documentation.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/documentation/__next.documentation.txt +0 -0
- {ui → pycharter/ui/static}/static/documentation/index.html +0 -0
- {ui → pycharter/ui/static}/static/documentation/index.txt +0 -0
- {ui → pycharter/ui/static}/static/index.html +0 -0
- {ui → pycharter/ui/static}/static/index.txt +0 -0
- {ui → pycharter/ui/static}/static/metadata/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/metadata/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/metadata/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/metadata/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/metadata/__next.metadata.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/metadata/__next.metadata.txt +0 -0
- {ui → pycharter/ui/static}/static/metadata/index.html +0 -0
- {ui → pycharter/ui/static}/static/metadata/index.txt +0 -0
- {ui → pycharter/ui/static}/static/quality/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/quality/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/quality/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/quality/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/quality/__next.quality.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/quality/__next.quality.txt +0 -0
- {ui → pycharter/ui/static}/static/quality/index.html +0 -0
- {ui → pycharter/ui/static}/static/quality/index.txt +0 -0
- {ui → pycharter/ui/static}/static/rules/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/rules/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/rules/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/rules/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/rules/__next.rules.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/rules/__next.rules.txt +0 -0
- {ui → pycharter/ui/static}/static/rules/index.html +0 -0
- {ui → pycharter/ui/static}/static/rules/index.txt +0 -0
- {ui → pycharter/ui/static}/static/schemas/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/schemas/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/schemas/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/schemas/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/schemas/__next.schemas.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/schemas/__next.schemas.txt +0 -0
- {ui → pycharter/ui/static}/static/schemas/index.html +0 -0
- {ui → pycharter/ui/static}/static/schemas/index.txt +0 -0
- {ui → pycharter/ui/static}/static/settings/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/settings/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/settings/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/settings/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/settings/__next.settings.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/settings/__next.settings.txt +0 -0
- {ui → pycharter/ui/static}/static/settings/index.html +0 -0
- {ui → pycharter/ui/static}/static/settings/index.txt +0 -0
- {ui → pycharter/ui}/static/static/static/.gitkeep +0 -0
- {ui → pycharter/ui/static}/static/static/404/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/404.html +0 -0
- {ui → pycharter/ui/static}/static/static/__next.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/__next._tree.txt +0 -0
- {ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl → pycharter/ui/static/static/static/_next/static/0rYA78L88aUyD2Uh38hhX}/_buildManifest.js +0 -0
- {ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl → pycharter/ui/static/static/static/_next/static/0rYA78L88aUyD2Uh38hhX}/_ssgManifest.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/13d4a0fbd74c1ee4.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/222442f6da32302a.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/247eb132b7f7b574.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/297d55555b71baba.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/2ab439ce003cd691.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/2edb43b48432ac04.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/414e77373f8ff61c.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/49ca65abd26ae49e.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/5e04d10c4a7b58a3.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/652ad0aa26265c47.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/75d88a058d8ffaa6.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/8c89634cf6bad76f.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/9667e7a3d359eb39.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/9c23f44fff36548a.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/a6dad97d9634a72d.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/b32a0963684b9933.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/c4fa4f4114b7c352.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/c69f6cba366bd988.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/d2363397e1b2bcab.css +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/db913959c675cea6.js +0 -0
- {ui → pycharter/ui/static}/static/static/_next/static/chunks/f061a4be97bfc3b3.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/f2e7afeab1178138.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/ff1a16fafef87110.js +0 -0
- {ui → pycharter/ui}/static/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/__next._not-found.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/__next._not-found.txt +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/_not-found/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/__next.contracts.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/__next.contracts.txt +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/contracts/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/__next.documentation.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/__next.documentation.txt +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/documentation/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/__next.metadata.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/__next.metadata.txt +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/metadata/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/quality/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/quality/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/quality/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/quality/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/quality/__next.quality.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/quality/__next.quality.txt +0 -0
- {ui → pycharter/ui/static}/static/static/quality/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/quality/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/rules/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/rules/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/rules/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/rules/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/rules/__next.rules.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/rules/__next.rules.txt +0 -0
- {ui → pycharter/ui/static}/static/static/rules/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/rules/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/__next.schemas.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/__next.schemas.txt +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/schemas/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/settings/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/settings/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/settings/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/settings/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/settings/__next.settings.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/settings/__next.settings.txt +0 -0
- {ui → pycharter/ui/static}/static/static/settings/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/settings/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/404/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/404.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/__next.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/2ab439ce003cd691.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/49ca65abd26ae49e.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/4e310fe5005770a3.css +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/5e04d10c4a7b58a3.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/5fc14c00a2779dc5.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/75d88a058d8ffaa6.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/8c89634cf6bad76f.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/9667e7a3d359eb39.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/b584574fdc8ab13e.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/c69f6cba366bd988.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/d5989c94d3614b3a.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/f061a4be97bfc3b3.js +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/__next._not-found.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/__next._not-found.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/_not-found/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/__next.contracts.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/__next.contracts.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/contracts/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/__next.documentation.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/__next.documentation.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/documentation/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/__next.metadata.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/__next.metadata.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/metadata/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/__next.quality.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/__next.quality.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/quality/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/__next.rules.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/__next.rules.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/rules/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/__next.schemas.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/__next.schemas.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/schemas/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/__next.settings.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/__next.settings.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/settings/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/__next.validation.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/__next.validation.txt +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/static/validation/index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/validation/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/static/validation/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/static/validation/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/static/validation/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/static/validation/__next.validation.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/static/validation/__next.validation.txt +0 -0
- {ui → pycharter/ui/static}/static/static/validation/index.html +0 -0
- {ui → pycharter/ui/static}/static/static/validation/index.txt +0 -0
- {ui → pycharter/ui/static}/static/validation/__next._full.txt +0 -0
- {ui → pycharter/ui/static}/static/validation/__next._head.txt +0 -0
- {ui → pycharter/ui/static}/static/validation/__next._index.txt +0 -0
- {ui → pycharter/ui/static}/static/validation/__next._tree.txt +0 -0
- {ui → pycharter/ui/static}/static/validation/__next.validation.__PAGE__.txt +0 -0
- {ui → pycharter/ui/static}/static/validation/__next.validation.txt +0 -0
- {ui → pycharter/ui/static}/static/validation/index.html +0 -0
- {ui → pycharter/ui/static}/static/validation/index.txt +0 -0
- {worker → pycharter/worker}/__init__.py +0 -0
- {worker → pycharter/worker}/models.py +0 -0
- {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/WHEEL +0 -0
- {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/entry_points.txt +0 -0
- {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,7 +3,15 @@ Contract Builder - Constructs consolidated data contracts from separate artifact
|
|
|
3
3
|
|
|
4
4
|
This module provides functionality to combine separate artifacts (schema, coercion rules,
|
|
5
5
|
validation rules, metadata) into a single consolidated data contract that tracks all
|
|
6
|
-
component versions
|
|
6
|
+
component versions.
|
|
7
|
+
|
|
8
|
+
Note: The contract dict contains RAW schema + separate rules. The Validator class
|
|
9
|
+
handles merging rules into the schema internally during validation. This separation
|
|
10
|
+
ensures clarity:
|
|
11
|
+
- contract["schema"] = raw schema (editable, source of truth)
|
|
12
|
+
- contract["coercion_rules"] = separate coercion rules
|
|
13
|
+
- contract["validation_rules"] = separate validation rules
|
|
14
|
+
- For merged schema, use Validator or merge_rules_into_schema() utility
|
|
7
15
|
"""
|
|
8
16
|
|
|
9
17
|
import copy
|
|
@@ -11,10 +19,6 @@ from dataclasses import dataclass
|
|
|
11
19
|
from typing import Any, Dict, Optional
|
|
12
20
|
|
|
13
21
|
from pycharter.metadata_store import MetadataStoreClient
|
|
14
|
-
from pycharter.metadata_store.client import (
|
|
15
|
-
_merge_coercion_rules,
|
|
16
|
-
_merge_validation_rules,
|
|
17
|
-
)
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
@dataclass
|
|
@@ -82,8 +86,12 @@ def build_contract(
|
|
|
82
86
|
Build a consolidated data contract from separate artifacts.
|
|
83
87
|
|
|
84
88
|
This function combines schema, coercion rules, validation rules, and metadata
|
|
85
|
-
into a single consolidated contract. It tracks versions of all components
|
|
86
|
-
|
|
89
|
+
into a single consolidated contract. It tracks versions of all components.
|
|
90
|
+
|
|
91
|
+
IMPORTANT: The schema in the returned contract is RAW (not merged with rules).
|
|
92
|
+
The Validator class handles merging rules into the schema internally during
|
|
93
|
+
validation. To get a merged schema explicitly, use merge_rules_into_schema()
|
|
94
|
+
from pycharter.runtime_validator.utils.
|
|
87
95
|
|
|
88
96
|
Args:
|
|
89
97
|
artifacts: ContractArtifacts object containing all separate artifacts
|
|
@@ -93,9 +101,9 @@ def build_contract(
|
|
|
93
101
|
|
|
94
102
|
Returns:
|
|
95
103
|
Consolidated contract dictionary with:
|
|
96
|
-
- schema:
|
|
97
|
-
- coercion_rules: Coercion rules (
|
|
98
|
-
- validation_rules: Validation rules (
|
|
104
|
+
- schema: RAW schema (no coercion/validation merged; must have version)
|
|
105
|
+
- coercion_rules: Coercion rules dictionary (always present, may be empty)
|
|
106
|
+
- validation_rules: Validation rules dictionary (always present, may be empty)
|
|
99
107
|
- metadata: Metadata containing ownership and governance_rules (if include_metadata=True)
|
|
100
108
|
- versions: Dictionary tracking versions of all components
|
|
101
109
|
|
|
@@ -116,10 +124,10 @@ def build_contract(
|
|
|
116
124
|
>>> contract = build_contract(artifacts)
|
|
117
125
|
>>> contract["versions"]
|
|
118
126
|
{'schema': '1.0.0', 'coercion_rules': '1.0.0', 'validation_rules': '1.0.0', 'metadata': '1.0.0'}
|
|
119
|
-
>>> contract["
|
|
120
|
-
{'
|
|
121
|
-
>>> contract["
|
|
122
|
-
|
|
127
|
+
>>> contract["coercion_rules"] # Separate from schema
|
|
128
|
+
{'age': 'coerce_to_integer'}
|
|
129
|
+
>>> contract["schema"]["properties"]["age"].get("coercion") # Not in schema
|
|
130
|
+
None
|
|
123
131
|
"""
|
|
124
132
|
if not artifacts.schema:
|
|
125
133
|
raise ValueError("Schema is required to build a contract")
|
|
@@ -131,34 +139,21 @@ def build_contract(
|
|
|
131
139
|
"Please ensure the schema dictionary contains 'version': '<version_string>'."
|
|
132
140
|
)
|
|
133
141
|
|
|
134
|
-
# Deep copy schema to avoid modifying original
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
# Extract and merge coercion rules
|
|
138
|
-
coercion_rules = _extract_rules(artifacts.coercion_rules)
|
|
139
|
-
if coercion_rules:
|
|
140
|
-
_merge_coercion_rules(complete_schema, coercion_rules)
|
|
142
|
+
# Deep copy schema to avoid modifying original - NO MERGING
|
|
143
|
+
# The Validator class handles merging internally during validation
|
|
144
|
+
raw_schema = copy.deepcopy(artifacts.schema)
|
|
141
145
|
|
|
142
|
-
# Extract
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
_merge_validation_rules(complete_schema, validation_rules)
|
|
146
|
+
# Extract rules (but do NOT merge into schema)
|
|
147
|
+
coercion_rules = _extract_rules(artifacts.coercion_rules) or {}
|
|
148
|
+
validation_rules = _extract_rules(artifacts.validation_rules) or {}
|
|
146
149
|
|
|
147
|
-
# Build contract
|
|
150
|
+
# Build contract with raw schema and separate rules
|
|
148
151
|
contract: Dict[str, Any] = {
|
|
149
|
-
"schema":
|
|
152
|
+
"schema": raw_schema,
|
|
153
|
+
"coercion_rules": copy.deepcopy(coercion_rules) if coercion_rules else {},
|
|
154
|
+
"validation_rules": copy.deepcopy(validation_rules) if validation_rules else {},
|
|
150
155
|
}
|
|
151
156
|
|
|
152
|
-
# Add coercion rules as top-level field (for UI display)
|
|
153
|
-
# Note: coercion_rules is already extracted above
|
|
154
|
-
if coercion_rules:
|
|
155
|
-
contract["coercion_rules"] = copy.deepcopy(coercion_rules)
|
|
156
|
-
|
|
157
|
-
# Add validation rules as top-level field (for UI display)
|
|
158
|
-
# Note: validation_rules is already extracted above
|
|
159
|
-
if validation_rules:
|
|
160
|
-
contract["validation_rules"] = copy.deepcopy(validation_rules)
|
|
161
|
-
|
|
162
157
|
# Track versions
|
|
163
158
|
versions: Dict[str, str] = {}
|
|
164
159
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generic seed: compliance_frameworks (name required; code, description, framework_type, is_active, additional_metadata optional)
|
|
2
|
+
|
|
3
|
+
- name: "internal-policy"
|
|
4
|
+
code: "INTERNAL"
|
|
5
|
+
description: "Internal data policy"
|
|
6
|
+
framework_type: "policy"
|
|
7
|
+
is_active: true
|
|
8
|
+
additional_metadata: {}
|
|
9
|
+
|
|
10
|
+
- name: "soc2"
|
|
11
|
+
code: "SOC2"
|
|
12
|
+
description: "System and Organization Controls 2"
|
|
13
|
+
framework_type: "certification"
|
|
14
|
+
is_active: true
|
|
15
|
+
additional_metadata: {}
|
|
16
|
+
|
|
17
|
+
- name: "gdpr"
|
|
18
|
+
code: "GDPR"
|
|
19
|
+
description: "General Data Protection Regulation"
|
|
20
|
+
framework_type: "regulation"
|
|
21
|
+
is_active: true
|
|
22
|
+
additional_metadata: {}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Example contract artifacts for pycharter db seed
|
|
2
|
+
# Each entry creates a data contract with schema, coercion rules, validation rules, and metadata.
|
|
3
|
+
# Skipped if a contract with the same name and version already exists.
|
|
4
|
+
|
|
5
|
+
- name: example_user_contract
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
status: active
|
|
8
|
+
description: Example user data contract with schema, coercion, validation, and metadata
|
|
9
|
+
|
|
10
|
+
schema:
|
|
11
|
+
type: object
|
|
12
|
+
title: example_user
|
|
13
|
+
version: "1.0.0"
|
|
14
|
+
properties:
|
|
15
|
+
user_id:
|
|
16
|
+
type: string
|
|
17
|
+
description: Unique user identifier
|
|
18
|
+
minLength: 1
|
|
19
|
+
name:
|
|
20
|
+
type: string
|
|
21
|
+
description: Full name
|
|
22
|
+
minLength: 1
|
|
23
|
+
maxLength: 100
|
|
24
|
+
email:
|
|
25
|
+
type: string
|
|
26
|
+
format: email
|
|
27
|
+
description: Email address
|
|
28
|
+
status:
|
|
29
|
+
type: string
|
|
30
|
+
enum: [active, inactive, pending]
|
|
31
|
+
description: Account status
|
|
32
|
+
created_at:
|
|
33
|
+
type: string
|
|
34
|
+
format: date-time
|
|
35
|
+
description: Creation timestamp
|
|
36
|
+
required:
|
|
37
|
+
- user_id
|
|
38
|
+
- name
|
|
39
|
+
- email
|
|
40
|
+
- status
|
|
41
|
+
- created_at
|
|
42
|
+
|
|
43
|
+
coercion_rules:
|
|
44
|
+
title: example_user_coercion
|
|
45
|
+
version: "1.0.0"
|
|
46
|
+
rules:
|
|
47
|
+
user_id: coerce_to_string
|
|
48
|
+
name: coerce_to_stripped_string
|
|
49
|
+
email: coerce_to_lowercase
|
|
50
|
+
status: coerce_to_lowercase
|
|
51
|
+
created_at: coerce_to_datetime
|
|
52
|
+
|
|
53
|
+
validation_rules:
|
|
54
|
+
title: example_user_validation
|
|
55
|
+
version: "1.0.0"
|
|
56
|
+
rules:
|
|
57
|
+
user_id:
|
|
58
|
+
non_empty_string: null
|
|
59
|
+
name:
|
|
60
|
+
non_empty_string: null
|
|
61
|
+
max_length:
|
|
62
|
+
threshold: 100
|
|
63
|
+
email:
|
|
64
|
+
is_email: null
|
|
65
|
+
status:
|
|
66
|
+
only_allow:
|
|
67
|
+
allowed_values: [active, inactive, pending]
|
|
68
|
+
|
|
69
|
+
metadata:
|
|
70
|
+
title: example_user_metadata
|
|
71
|
+
version: "1.0.0"
|
|
72
|
+
status: active
|
|
73
|
+
description: Example user contract metadata
|
|
74
|
+
governance_rules:
|
|
75
|
+
data_retention:
|
|
76
|
+
days: 365
|
|
77
|
+
reason: Standard retention
|
|
78
|
+
sensitivity: internal
|
|
79
|
+
access_control:
|
|
80
|
+
read: [data-team]
|
|
81
|
+
write: [data-team]
|
|
82
|
+
|
|
83
|
+
# Second example: minimal event contract
|
|
84
|
+
- name: example_event_contract
|
|
85
|
+
version: "1.0.0"
|
|
86
|
+
status: active
|
|
87
|
+
description: Minimal event contract for demos
|
|
88
|
+
|
|
89
|
+
schema:
|
|
90
|
+
type: object
|
|
91
|
+
title: example_event
|
|
92
|
+
version: "1.0.0"
|
|
93
|
+
properties:
|
|
94
|
+
event_id:
|
|
95
|
+
type: string
|
|
96
|
+
description: Event identifier
|
|
97
|
+
event_type:
|
|
98
|
+
type: string
|
|
99
|
+
description: Type of event
|
|
100
|
+
occurred_at:
|
|
101
|
+
type: string
|
|
102
|
+
format: date-time
|
|
103
|
+
required:
|
|
104
|
+
- event_id
|
|
105
|
+
- event_type
|
|
106
|
+
- occurred_at
|
|
107
|
+
|
|
108
|
+
coercion_rules:
|
|
109
|
+
title: example_event_coercion
|
|
110
|
+
version: "1.0.0"
|
|
111
|
+
rules:
|
|
112
|
+
event_id: coerce_to_string
|
|
113
|
+
event_type: coerce_to_lowercase
|
|
114
|
+
occurred_at: coerce_to_datetime
|
|
115
|
+
|
|
116
|
+
validation_rules:
|
|
117
|
+
title: example_event_validation
|
|
118
|
+
version: "1.0.0"
|
|
119
|
+
rules:
|
|
120
|
+
event_id:
|
|
121
|
+
non_empty_string: null
|
|
122
|
+
event_type:
|
|
123
|
+
non_empty_string: null
|
|
124
|
+
|
|
125
|
+
metadata:
|
|
126
|
+
title: example_event_metadata
|
|
127
|
+
version: "1.0.0"
|
|
128
|
+
status: active
|
|
129
|
+
description: Example event contract metadata
|
|
130
|
+
governance_rules: {}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generic seed: data_feeds (name required; title, feed_type, description, is_active, additional_metadata optional)
|
|
2
|
+
|
|
3
|
+
- name: "default_feed"
|
|
4
|
+
title: "Default Feed"
|
|
5
|
+
feed_type: "batch"
|
|
6
|
+
description: "Default data feed"
|
|
7
|
+
is_active: true
|
|
8
|
+
additional_metadata: {}
|
|
9
|
+
|
|
10
|
+
- name: "streaming_feed"
|
|
11
|
+
title: "Streaming Feed"
|
|
12
|
+
feed_type: "streaming"
|
|
13
|
+
description: "Streaming data feed"
|
|
14
|
+
is_active: true
|
|
15
|
+
additional_metadata: {}
|
|
16
|
+
|
|
17
|
+
- name: "operational_feed"
|
|
18
|
+
title: "Operational Feed"
|
|
19
|
+
feed_type: "operational"
|
|
20
|
+
description: "Operational data feed"
|
|
21
|
+
is_active: true
|
|
22
|
+
additional_metadata: {}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Generic seed: domains (name required; description optional)
|
|
2
|
+
|
|
3
|
+
- name: "default"
|
|
4
|
+
description: "Default domain"
|
|
5
|
+
|
|
6
|
+
- name: "operations"
|
|
7
|
+
description: "Operations and runbooks"
|
|
8
|
+
|
|
9
|
+
- name: "analytics"
|
|
10
|
+
description: "Analytics and reporting"
|
|
11
|
+
|
|
12
|
+
- name: "platform"
|
|
13
|
+
description: "Platform and infrastructure"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Generic seed: environments (name required; description, environment_type, is_production, additional_metadata optional)
|
|
2
|
+
|
|
3
|
+
- name: "development"
|
|
4
|
+
description: "Development environment"
|
|
5
|
+
environment_type: "non_production"
|
|
6
|
+
is_production: false
|
|
7
|
+
additional_metadata: {}
|
|
8
|
+
|
|
9
|
+
- name: "staging"
|
|
10
|
+
description: "Staging environment"
|
|
11
|
+
environment_type: "non_production"
|
|
12
|
+
is_production: false
|
|
13
|
+
additional_metadata: {}
|
|
14
|
+
|
|
15
|
+
- name: "production"
|
|
16
|
+
description: "Production environment"
|
|
17
|
+
environment_type: "production"
|
|
18
|
+
is_production: true
|
|
19
|
+
additional_metadata: {}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Generic seed: owners (id is required; name, email, team, additional_info optional)
|
|
2
|
+
|
|
3
|
+
- id: "default-owner"
|
|
4
|
+
name: "Default Owner"
|
|
5
|
+
email: "owner@example.com"
|
|
6
|
+
team: "data-engineering"
|
|
7
|
+
additional_info: {}
|
|
8
|
+
|
|
9
|
+
- id: "platform-team"
|
|
10
|
+
name: "Platform Team"
|
|
11
|
+
email: "platform@example.com"
|
|
12
|
+
team: "platform-engineering"
|
|
13
|
+
additional_info:
|
|
14
|
+
description: "Platform and infrastructure"
|
|
15
|
+
|
|
16
|
+
- id: "product-team"
|
|
17
|
+
name: "Product Team"
|
|
18
|
+
email: "product@example.com"
|
|
19
|
+
team: "product"
|
|
20
|
+
additional_info:
|
|
21
|
+
description: "Product and analytics"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Generic seed: systems (name required; app_id, description optional)
|
|
2
|
+
|
|
3
|
+
- name: "core-api"
|
|
4
|
+
app_id: "APP-CORE"
|
|
5
|
+
description: "Core API service"
|
|
6
|
+
|
|
7
|
+
- name: "pipeline-engine"
|
|
8
|
+
app_id: "APP-PIPELINE"
|
|
9
|
+
description: "Data pipeline engine"
|
|
10
|
+
|
|
11
|
+
- name: "catalog"
|
|
12
|
+
app_id: "APP-CATALOG"
|
|
13
|
+
description: "Data catalog and metadata"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generic seed: tags (name required; description, category, color, additional_metadata optional)
|
|
2
|
+
|
|
3
|
+
- name: "default"
|
|
4
|
+
description: "Default tag"
|
|
5
|
+
category: "general"
|
|
6
|
+
color: "#808080"
|
|
7
|
+
additional_metadata: {}
|
|
8
|
+
|
|
9
|
+
- name: "critical"
|
|
10
|
+
description: "Critical data"
|
|
11
|
+
category: "classification"
|
|
12
|
+
color: "#FF0000"
|
|
13
|
+
additional_metadata: {}
|
|
14
|
+
|
|
15
|
+
- name: "internal"
|
|
16
|
+
description: "Internal use only"
|
|
17
|
+
category: "classification"
|
|
18
|
+
color: "#FFA500"
|
|
19
|
+
additional_metadata: {}
|
|
20
|
+
|
|
21
|
+
- name: "pii"
|
|
22
|
+
description: "Personally identifiable information"
|
|
23
|
+
category: "classification"
|
|
24
|
+
color: "#9933CC"
|
|
25
|
+
additional_metadata: {}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Data Contract Templates
|
|
2
|
+
|
|
3
|
+
Templates for creating data contracts with schema, coercion rules, validation rules, and metadata.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from pycharter import parse_contract, validate_with_contract
|
|
9
|
+
|
|
10
|
+
# Option 1: Complete contract in one file
|
|
11
|
+
contract = {
|
|
12
|
+
"schema": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"id": {"type": "string"},
|
|
16
|
+
"name": {"type": "string", "minLength": 1},
|
|
17
|
+
},
|
|
18
|
+
"required": ["id", "name"]
|
|
19
|
+
},
|
|
20
|
+
"metadata": {"version": "1.0.0"},
|
|
21
|
+
"ownership": {"owner": "data-team"}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Validate data
|
|
25
|
+
result = validate_with_contract(contract, {"id": "123", "name": "Alice"})
|
|
26
|
+
print(f"Valid: {result.is_valid}")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Template Files
|
|
30
|
+
|
|
31
|
+
| Template | Description |
|
|
32
|
+
|----------|-------------|
|
|
33
|
+
| `template_contract.yaml` | Complete contract (schema + rules + metadata) |
|
|
34
|
+
| `template_schema.yaml` | JSON Schema with PyCharter extensions |
|
|
35
|
+
| `template_coercion_rules.yaml` | Data type transformation rules |
|
|
36
|
+
| `template_validation_rules.yaml` | Business validation rules |
|
|
37
|
+
| `template_metadata.yaml` | Ownership and governance metadata |
|
|
38
|
+
|
|
39
|
+
## Contract Structure
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
# Complete contract structure (parse_contract / create-mixed compatible)
|
|
43
|
+
schema: # JSON Schema (required). May include inline coercion/validations
|
|
44
|
+
type: object
|
|
45
|
+
title: my_entity
|
|
46
|
+
version: "1.0.0"
|
|
47
|
+
properties:
|
|
48
|
+
field_name:
|
|
49
|
+
type: string
|
|
50
|
+
coercion: coerce_to_string # Optional: inline coercion
|
|
51
|
+
validations: # Optional: inline validation rules
|
|
52
|
+
max_length: {threshold: 100}
|
|
53
|
+
|
|
54
|
+
# Optional: top-level rules (same format as template_coercion_rules / template_validation_rules)
|
|
55
|
+
coercion_rules:
|
|
56
|
+
version: "1.0.0"
|
|
57
|
+
rules:
|
|
58
|
+
field_name: coerce_to_string
|
|
59
|
+
validation_rules:
|
|
60
|
+
version: "1.0.0"
|
|
61
|
+
rules:
|
|
62
|
+
field_name: { max_length: { threshold: 100 } }
|
|
63
|
+
|
|
64
|
+
# Metadata: version, description; ownership and governance_rules must be nested here
|
|
65
|
+
metadata:
|
|
66
|
+
version: "1.0.0"
|
|
67
|
+
description: "Contract description"
|
|
68
|
+
ownership: # Nested in metadata (not top-level)
|
|
69
|
+
owner: team-name
|
|
70
|
+
team: department
|
|
71
|
+
governance_rules: # Nested in metadata
|
|
72
|
+
data_retention: {days: 365}
|
|
73
|
+
pii_fields: {fields: [email]}
|
|
74
|
+
|
|
75
|
+
versions: # Optional: explicit version tracking
|
|
76
|
+
schema: "1.0.0"
|
|
77
|
+
coercion_rules: "1.0.0"
|
|
78
|
+
validation_rules: "1.0.0"
|
|
79
|
+
metadata: "1.0.0"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Coercion Rules
|
|
83
|
+
|
|
84
|
+
Applied BEFORE Pydantic validation to transform input data:
|
|
85
|
+
|
|
86
|
+
| Rule | Description |
|
|
87
|
+
|------|-------------|
|
|
88
|
+
| `coerce_to_string` | Convert to string |
|
|
89
|
+
| `coerce_to_integer` | Convert to int |
|
|
90
|
+
| `coerce_to_float` | Convert to float |
|
|
91
|
+
| `coerce_to_boolean` | Convert to bool |
|
|
92
|
+
| `coerce_to_datetime` | Parse datetime |
|
|
93
|
+
| `coerce_to_date` | Parse date |
|
|
94
|
+
| `coerce_to_uuid` | Parse UUID |
|
|
95
|
+
| `coerce_to_lowercase` | Lowercase string |
|
|
96
|
+
| `coerce_to_uppercase` | Uppercase string |
|
|
97
|
+
| `coerce_to_stripped_string` | Trim whitespace |
|
|
98
|
+
| `coerce_to_nullable_*` | Handle null values |
|
|
99
|
+
|
|
100
|
+
## Validation Rules
|
|
101
|
+
|
|
102
|
+
Applied AFTER Pydantic validation for business rules:
|
|
103
|
+
|
|
104
|
+
| Rule | Parameters | Description |
|
|
105
|
+
|------|------------|-------------|
|
|
106
|
+
| `min_length` | `{threshold: N}` | Minimum string length |
|
|
107
|
+
| `max_length` | `{threshold: N}` | Maximum string length |
|
|
108
|
+
| `greater_than_or_equal_to` | `{threshold: N}` | Minimum value |
|
|
109
|
+
| `less_than_or_equal_to` | `{threshold: N}` | Maximum value |
|
|
110
|
+
| `only_allow` | `{allowed_values: [...]}` | Enum validation |
|
|
111
|
+
| `non_empty_string` | `null` | Non-empty string |
|
|
112
|
+
| `is_email` | `null` | Email format |
|
|
113
|
+
| `is_url` | `null` | URL format |
|
|
114
|
+
| `matches_regex` | `{pattern: "..."}` | Regex match |
|
|
115
|
+
|
|
116
|
+
## Usage Patterns
|
|
117
|
+
|
|
118
|
+
### 1. Validate with Contract
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from pycharter import validate_with_contract
|
|
122
|
+
|
|
123
|
+
result = validate_with_contract(
|
|
124
|
+
"path/to/contract.yaml", # or dict
|
|
125
|
+
{"id": "123", "name": "Alice"}
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if result.is_valid:
|
|
129
|
+
print(f"Data: {result.data}")
|
|
130
|
+
else:
|
|
131
|
+
print(f"Errors: {result.errors}")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 2. Build Contract from Artifacts
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from pycharter import build_contract
|
|
138
|
+
|
|
139
|
+
contract = build_contract(
|
|
140
|
+
schema=schema_dict,
|
|
141
|
+
metadata=metadata_dict,
|
|
142
|
+
coercion_rules=coercion_dict,
|
|
143
|
+
validation_rules=validation_dict,
|
|
144
|
+
)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 3. Quality Check
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from pycharter import QualityCheck
|
|
151
|
+
|
|
152
|
+
report = QualityCheck().run(
|
|
153
|
+
contract=contract,
|
|
154
|
+
data=records
|
|
155
|
+
)
|
|
156
|
+
print(f"Score: {report.quality_score.overall_score}/100")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Examples
|
|
160
|
+
|
|
161
|
+
See `docs/notebooks/03_contracts.ipynb` and `docs/notebooks/04_validation_quality.ipynb` for working examples.
|
|
@@ -89,6 +89,43 @@ schema:
|
|
|
89
89
|
- status
|
|
90
90
|
- created_at
|
|
91
91
|
|
|
92
|
+
# Optional: top-level coercion rules (same as template_coercion_rules.yaml structure)
|
|
93
|
+
# When present, parse_contract returns them; use with create-mixed or store for separate artifacts.
|
|
94
|
+
coercion_rules:
|
|
95
|
+
version: "1.0.0"
|
|
96
|
+
rules:
|
|
97
|
+
user_id: coerce_to_string
|
|
98
|
+
name: coerce_to_stripped_string
|
|
99
|
+
email: coerce_to_lowercase
|
|
100
|
+
age: coerce_to_integer
|
|
101
|
+
status: coerce_to_lowercase
|
|
102
|
+
created_at: coerce_to_datetime
|
|
103
|
+
notes: coerce_to_nullable_string
|
|
104
|
+
|
|
105
|
+
# Optional: top-level validation rules (same as template_validation_rules.yaml structure)
|
|
106
|
+
validation_rules:
|
|
107
|
+
version: "1.0.0"
|
|
108
|
+
rules:
|
|
109
|
+
user_id:
|
|
110
|
+
non_empty_string: null
|
|
111
|
+
name:
|
|
112
|
+
non_empty_string: null
|
|
113
|
+
max_length:
|
|
114
|
+
threshold: 100
|
|
115
|
+
email:
|
|
116
|
+
is_email: null
|
|
117
|
+
age:
|
|
118
|
+
greater_than_or_equal_to:
|
|
119
|
+
threshold: 0
|
|
120
|
+
less_than_or_equal_to:
|
|
121
|
+
threshold: 150
|
|
122
|
+
status:
|
|
123
|
+
only_allow:
|
|
124
|
+
allowed_values: [active, inactive, pending]
|
|
125
|
+
notes:
|
|
126
|
+
max_length:
|
|
127
|
+
threshold: 500
|
|
128
|
+
|
|
92
129
|
# Contract metadata (ownership and governance nested inside)
|
|
93
130
|
metadata:
|
|
94
131
|
version: "1.0.0"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Template: HTTP Extraction with Source Validation
|
|
2
|
+
# Copy to your pipeline directory as extract.yaml
|
|
3
|
+
#
|
|
4
|
+
# This template demonstrates source schema validation after extraction.
|
|
5
|
+
# Invalid records can be skipped, quarantined (sent to DLQ), or cause failures.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# pipeline = Pipeline.from_config_dir("path/to/pipeline")
|
|
9
|
+
# result = await pipeline.run()
|
|
10
|
+
# print(f"Valid records: {result.rows_transformed}")
|
|
11
|
+
# print(f"Quarantined at extract: {result.rows_quarantined_extract}")
|
|
12
|
+
|
|
13
|
+
title: http_extraction_with_validation
|
|
14
|
+
description: Extract from HTTP API with source schema validation
|
|
15
|
+
version: "1.0.0"
|
|
16
|
+
|
|
17
|
+
# Source type (required)
|
|
18
|
+
type: http
|
|
19
|
+
|
|
20
|
+
# API URL
|
|
21
|
+
url: https://api.example.com/v1/orders
|
|
22
|
+
|
|
23
|
+
# HTTP method
|
|
24
|
+
method: GET
|
|
25
|
+
|
|
26
|
+
# Request headers
|
|
27
|
+
headers:
|
|
28
|
+
Accept: application/json
|
|
29
|
+
Authorization: Bearer ${API_TOKEN}
|
|
30
|
+
|
|
31
|
+
# Response handling
|
|
32
|
+
response_format: json
|
|
33
|
+
response_path: data.orders # Path to data array in response
|
|
34
|
+
|
|
35
|
+
# Batch size
|
|
36
|
+
batch_size: 1000
|
|
37
|
+
|
|
38
|
+
# ============================================================================
|
|
39
|
+
# Source Schema Validation (Optional)
|
|
40
|
+
# ============================================================================
|
|
41
|
+
# Validate extracted data against a JSON/YAML schema before transformation.
|
|
42
|
+
# This catches malformed data early in the pipeline.
|
|
43
|
+
|
|
44
|
+
validation:
|
|
45
|
+
# Path to source schema file (JSON Schema or Pydantic schema YAML)
|
|
46
|
+
# Can be absolute or relative to config directory
|
|
47
|
+
schema: ./source_schema.yaml
|
|
48
|
+
|
|
49
|
+
# Action when validation fails:
|
|
50
|
+
# - fail: Stop pipeline immediately (default)
|
|
51
|
+
# - warn: Log warning but continue with all records
|
|
52
|
+
# - skip: Skip invalid records silently
|
|
53
|
+
# - quarantine: Send invalid records to DLQ
|
|
54
|
+
on_error: quarantine
|
|
55
|
+
|
|
56
|
+
# DLQ configuration (optional, overrides settings.yaml)
|
|
57
|
+
# Can be true (use settings.yaml defaults), false (disable), or object
|
|
58
|
+
dlq: true # Use default DLQ from settings.yaml
|
|
59
|
+
|
|
60
|
+
# Or customize per-stage:
|
|
61
|
+
# dlq:
|
|
62
|
+
# enabled: true
|
|
63
|
+
# backend: file
|
|
64
|
+
# path: ./dlq/extract
|
|
65
|
+
|
|
66
|
+
# ============================================================================
|
|
67
|
+
# Example Source Schema (create as source_schema.yaml)
|
|
68
|
+
# ============================================================================
|
|
69
|
+
# version: "1.0.0"
|
|
70
|
+
# type: object
|
|
71
|
+
# properties:
|
|
72
|
+
# order_id:
|
|
73
|
+
# type: string
|
|
74
|
+
# pattern: "^ORD-[0-9]{6}$"
|
|
75
|
+
# customer_id:
|
|
76
|
+
# type: integer
|
|
77
|
+
# status:
|
|
78
|
+
# type: string
|
|
79
|
+
# enum: ["pending", "processing", "shipped", "delivered"]
|
|
80
|
+
# total_amount:
|
|
81
|
+
# type: number
|
|
82
|
+
# minimum: 0
|
|
83
|
+
# required:
|
|
84
|
+
# - order_id
|
|
85
|
+
# - customer_id
|
|
86
|
+
# - status
|