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
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,33558,e=>{"use strict";var t=e.i(43476),r=e.i(71645),a=e.i(19455),i=e.i(61246),o=e.i(75254);let n=(0,o.default)("Play",[["polygon",{points:"6 3 20 12 6 21 6 3",key:"1oa8hb"}]]),s=(0,o.default)("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]),c=(0,o.default)("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);var d=e.i(78583),l=e.i(58041);let m=(0,o.default)("Code",[["polyline",{points:"16 18 22 12 16 6",key:"z7tu5w"}],["polyline",{points:"8 6 2 12 8 18",key:"1eg1df"}]]),p=(0,o.default)("ShieldCheck",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);var u=e.i(42009);let _=(0,o.default)("Layers",[["path",{d:"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",key:"zw3jo"}],["path",{d:"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",key:"1wduqc"}],["path",{d:"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",key:"kqbvx6"}]]),h=(0,o.default)("BookOpen",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]),f=(0,o.default)("Activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]),y=(0,o.default)("GitCompare",[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M13 6h3a2 2 0 0 1 2 2v7",key:"1yeb86"}],["path",{d:"M11 18H8a2 2 0 0 1-2-2V9",key:"19pyzm"}]]);e.i(80428);var g=e.i(50398);let v=[{id:"parse_contract",title:"Contract Parser",description:"Read and decompose data contract files",method:"parse_contract(contract_dict, validate=True)",apiEndpoint:"/api/v1/contracts/parse",apiMethod:"POST",exampleRequest:{contract:{schema:{type:"object",properties:{name:{type:"string"},age:{type:"integer"}}},metadata:{title:"User Contract",version:"1.0.0"}}},exampleCode:`from pycharter import parse_contract, parse_contract_file
|
|
2
|
+
|
|
3
|
+
parse_contract(contract_dict)
|
|
4
|
+
parse_contract_file(file_path)`,arguments:[{name:"contract_data",type:"Dict[str, Any]",description:"Contract data as dictionary containing schema, metadata, ownership, governance_rules, coercion_rules, and validation_rules",required:!0},{name:"validate",type:"bool",description:"If True (default), validate contract against schema before parsing",required:!1,default:"True"}],returns:{type:"ContractMetadata",description:"ContractMetadata object with decomposed components (schema, metadata, ownership, governance_rules, coercion_rules, validation_rules) and version tracking"}},{id:"parse_contract_file",title:"Contract Parser - From File",description:"Parse a data contract from an uploaded file (YAML or JSON)",method:"parse_contract_file(file_path, validate=True)",apiEndpoint:"/api/v1/contracts/parse/upload",apiMethod:"POST",exampleRequest:null,exampleCode:`from pycharter import parse_contract_file
|
|
5
|
+
|
|
6
|
+
# Parse contract from file
|
|
7
|
+
contract_metadata = parse_contract_file("contract.yaml")
|
|
8
|
+
# or
|
|
9
|
+
contract_metadata = parse_contract_file("contract.json", validate=True)`,arguments:[{name:"file_path",type:"str",description:"Path to contract file (YAML or JSON)",required:!0},{name:"validate",type:"bool",description:"If True (default), validate contract against schema before parsing",required:!1,default:"True"}],returns:{type:"ContractMetadata",description:"ContractMetadata object with decomposed components (schema, metadata, ownership, governance_rules, coercion_rules, validation_rules)"}},{id:"build_contract",title:"Contract Builder",description:"Construct consolidated contracts from separate artifacts",method:"build_contract(artifacts: ContractArtifacts, include_metadata=True, include_ownership=True, include_governance=True)",apiEndpoint:"/api/v1/contracts/build",apiMethod:"POST",exampleRequest:{artifacts:{schema:{type:"object",version:"1.0.0",properties:{name:{type:"string"},age:{type:"integer"}}},coercion_rules:{version:"1.0.0",age:"coerce_to_integer"},validation_rules:{version:"1.0.0",age:{greater_than_or_equal_to:{threshold:0}}},metadata:{version:"1.0.0",description:"User contract"}},include_metadata:!0,include_ownership:!0,include_governance:!0},exampleCode:`from pycharter import build_contract, ContractArtifacts
|
|
10
|
+
|
|
11
|
+
artifacts = ContractArtifacts(
|
|
12
|
+
schema={"type": "object", "version": "1.0.0", "properties": {...}},
|
|
13
|
+
coercion_rules={"version": "1.0.0", "age": "coerce_to_integer"},
|
|
14
|
+
validation_rules={"version": "1.0.0", "age": {...}},
|
|
15
|
+
metadata={"version": "1.0.0", "description": "User contract"}
|
|
16
|
+
)
|
|
17
|
+
contract = build_contract(artifacts)`,arguments:[{name:"artifacts",type:"ContractArtifacts",description:"ContractArtifacts dataclass containing schema (required), coercion_rules (optional), validation_rules (optional), and metadata (optional)",required:!0},{name:"include_metadata",type:"bool",description:"Whether to include metadata in the contract",required:!1,default:"True"},{name:"include_ownership",type:"bool",description:"Whether to include ownership information",required:!1,default:"True"},{name:"include_governance",type:"bool",description:"Whether to include governance rules",required:!1,default:"True"}],returns:{type:"Dict[str, Any]",description:"Consolidated contract dictionary ready for runtime validation, containing schema (with merged coercion/validation rules), coercion_rules, validation_rules, metadata (if included), and versions tracking dictionary"}},{id:"build_contract_from_store",title:"Contract Builder - From Store",description:"Build a consolidated contract from artifacts stored in metadata store with individual version control for each component",method:"build_contract_from_store(store, schema_title, schema_version=None, coercion_rules_title=None, coercion_rules_version=None, validation_rules_title=None, validation_rules_version=None, metadata_title=None, metadata_version=None)",apiEndpoint:"/api/v1/contracts/build",apiMethod:"POST",exampleRequest:{schema_title:"user_schema",schema_version:"1.0.0",coercion_rules_title:"user_schema",coercion_rules_version:"1.0.0",validation_rules_title:"user_schema",validation_rules_version:"1.0.0",metadata_title:"user_schema",metadata_version:"1.0.0"},exampleCode:`from pycharter import build_contract_from_store
|
|
18
|
+
|
|
19
|
+
store = PostgresMetadataStore(connection_string)
|
|
20
|
+
store.connect()
|
|
21
|
+
contract = build_contract_from_store(
|
|
22
|
+
store=store,
|
|
23
|
+
schema_title="user_schema",
|
|
24
|
+
schema_version="1.0.0",
|
|
25
|
+
coercion_rules_title="user_schema",
|
|
26
|
+
coercion_rules_version="1.0.0",
|
|
27
|
+
validation_rules_title="user_schema",
|
|
28
|
+
validation_rules_version="1.0.0",
|
|
29
|
+
metadata_title="user_schema",
|
|
30
|
+
metadata_version="1.0.0"
|
|
31
|
+
)`,arguments:[{name:"store",type:"MetadataStoreClient",description:"MetadataStoreClient instance connected to the metadata store",required:!0},{name:"schema_title",type:"str",description:"Schema title/identifier",required:!0},{name:"schema_version",type:"Optional[str]",description:"Optional schema version (if None, uses latest version)",required:!1,default:"None"},{name:"coercion_rules_title",type:"Optional[str]",description:"Optional coercion rules title/identifier (if None, uses schema_title)",required:!1,default:"None"},{name:"coercion_rules_version",type:"Optional[str]",description:"Optional coercion rules version (if None, uses latest version or schema_version)",required:!1,default:"None"},{name:"validation_rules_title",type:"Optional[str]",description:"Optional validation rules title/identifier (if None, uses schema_title)",required:!1,default:"None"},{name:"validation_rules_version",type:"Optional[str]",description:"Optional validation rules version (if None, uses latest version or schema_version)",required:!1,default:"None"},{name:"metadata_title",type:"Optional[str]",description:"Optional metadata title/identifier (if None, uses schema_title)",required:!1,default:"None"},{name:"metadata_version",type:"Optional[str]",description:"Optional metadata version (if None, uses latest version or schema_version)",required:!1,default:"None"}],returns:{type:"Dict[str, Any]",description:"Consolidated contract dictionary ready for runtime validation, containing schema (with merged coercion/validation rules), coercion_rules, validation_rules, metadata (if included), and versions tracking dictionary"}},{id:"store_schema",title:"Metadata Store - Store Schema",description:"Store a JSON Schema in the metadata store",method:"store.store_schema(schema_name, schema, version)",apiEndpoint:"/api/v1/metadata/schemas",apiMethod:"POST",exampleRequest:{schema_name:"user_schema",schema:{type:"object",properties:{name:{type:"string"},age:{type:"integer"}}},version:"1.0.0"},exampleCode:`from pycharter import MetadataStoreClient
|
|
32
|
+
|
|
33
|
+
store = MetadataStoreClient(database_url)
|
|
34
|
+
store.store_schema(schema_id, schema, version)
|
|
35
|
+
store.get_schema(schema_id, version)
|
|
36
|
+
store.store_metadata(schema_id, metadata, version)`,arguments:[{name:"schema_name",type:"str",description:"Name/identifier for the schema (used as data_contract name)",required:!0},{name:"schema",type:"Dict[str, Any]",description:'JSON Schema dictionary (must contain "version" field or it will be added)',required:!0},{name:"version",type:"str",description:'Required version string (must match schema["version"] if present)',required:!0}],returns:{type:"str",description:"Schema ID or identifier"}},{id:"get_schema",title:"Metadata Store - Get Schema",description:"Retrieve a schema from the metadata store",method:"store.get_schema(schema_id, version=None)",apiEndpoint:"/api/v1/metadata/schemas/{schema_id}",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import MetadataStoreClient
|
|
37
|
+
|
|
38
|
+
store = MetadataStoreClient(database_url)
|
|
39
|
+
store.get_schema(schema_id, version)`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, returns latest version)",required:!1,default:"None"}],returns:{type:"Optional[Dict[str, Any]]",description:"Schema dictionary with version included, or None if not found"}},{id:"list_schemas",title:"Metadata Store - List Schemas",description:"Retrieve a list of all schemas stored in the metadata store",method:"store.list_schemas()",apiEndpoint:"/api/v1/metadata/schemas",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import PostgresMetadataStore
|
|
40
|
+
|
|
41
|
+
store = PostgresMetadataStore(connection_string)
|
|
42
|
+
store.connect()
|
|
43
|
+
|
|
44
|
+
# List all schemas
|
|
45
|
+
schemas = store.list_schemas()
|
|
46
|
+
for schema in schemas:
|
|
47
|
+
print(f"Schema: {schema.get('name')}, Version: {schema.get('version')}")`,arguments:[],returns:{type:"List[Dict[str, Any]]",description:"List of schema metadata dictionaries, each containing id, name, title, and version"}},{id:"store_metadata",title:"Metadata Store - Store Metadata",description:"Store metadata (ownership, governance rules, etc.) for a schema",method:"store.store_metadata(schema_id, metadata, version=None)",apiEndpoint:"/api/v1/metadata/metadata",apiMethod:"POST",exampleRequest:{schema_id:"user_schema",metadata:{title:"user_schema_metadata",description:"Metadata for user schema",business_owners:["owner@example.com"],team:"data-engineering",governance_rules:{data_retention:{days:2555},access_control:{level:"public"}}},version:"1.0.0"},exampleCode:`from pycharter import PostgresMetadataStore
|
|
48
|
+
|
|
49
|
+
store = PostgresMetadataStore(connection_string)
|
|
50
|
+
store.connect()
|
|
51
|
+
|
|
52
|
+
# Store metadata for a schema
|
|
53
|
+
metadata_id = store.store_metadata(
|
|
54
|
+
schema_id='user_schema',
|
|
55
|
+
metadata={
|
|
56
|
+
'title': 'user_schema_metadata',
|
|
57
|
+
'description': 'Metadata for user schema',
|
|
58
|
+
'business_owners': ['owner@example.com'],
|
|
59
|
+
'team': 'data-engineering',
|
|
60
|
+
'governance_rules': {
|
|
61
|
+
'data_retention': {'days': 2555},
|
|
62
|
+
'access_control': {'level': 'public'}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
version='1.0.0'
|
|
66
|
+
)`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"metadata",type:"Dict[str, Any]",description:"Metadata dictionary containing ownership, governance_rules, and other metadata",required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, uses schema version)",required:!1,default:"None"}],returns:{type:"str",description:"Metadata record ID"}},{id:"get_metadata",title:"Metadata Store - Get Metadata",description:"Retrieve metadata for a schema from the metadata store",method:"store.get_metadata(schema_id, version=None)",apiEndpoint:"/api/v1/metadata/metadata/{schema_id}",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import PostgresMetadataStore
|
|
67
|
+
|
|
68
|
+
store = PostgresMetadataStore(connection_string)
|
|
69
|
+
store.connect()
|
|
70
|
+
|
|
71
|
+
# Get metadata for a schema
|
|
72
|
+
metadata = store.get_metadata(
|
|
73
|
+
schema_id='user_schema',
|
|
74
|
+
version='1.0.0' # Optional, defaults to latest
|
|
75
|
+
)`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, uses latest version)",required:!1,default:"None"}],returns:{type:"Optional[Dict[str, Any]]",description:"Metadata dictionary or None if not found"}},{id:"get_complete_schema",title:"Metadata Store - Get Complete Schema",description:"Retrieve a complete schema with coercion and validation rules merged",method:"store.get_complete_schema(schema_id, version=None)",apiEndpoint:"/api/v1/metadata/schemas/{schema_id}/complete",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import PostgresMetadataStore
|
|
76
|
+
|
|
77
|
+
store = PostgresMetadataStore(connection_string)
|
|
78
|
+
store.connect()
|
|
79
|
+
|
|
80
|
+
# Get complete schema with rules merged
|
|
81
|
+
complete_schema = store.get_complete_schema(
|
|
82
|
+
schema_id='user_schema',
|
|
83
|
+
version='1.0.0' # Optional, defaults to latest
|
|
84
|
+
)
|
|
85
|
+
# The schema now includes coercion and validation rules
|
|
86
|
+
# merged into the properties`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, defaults to latest)",required:!1,default:"None"}],returns:{type:"Optional[Dict[str, Any]]",description:"Complete schema dictionary with coercion and validation rules merged into the properties, or None if not found"}},{id:"store_coercion_rules",title:"Metadata Store - Store Coercion Rules",description:"Store coercion rules that define how data should be transformed before validation",method:"store.store_coercion_rules(schema_id, coercion_rules, version=None)",apiEndpoint:"/api/v1/metadata/coercion-rules",apiMethod:"POST",exampleRequest:{schema_id:"user_schema",coercion_rules:{age:"coerce_to_integer",email:"coerce_to_lowercase",price:"coerce_to_float",name:"coerce_to_stripped_string"},version:"1.0.0"},exampleCode:`from pycharter import PostgresMetadataStore
|
|
87
|
+
|
|
88
|
+
store = PostgresMetadataStore(connection_string)
|
|
89
|
+
store.connect()
|
|
90
|
+
|
|
91
|
+
# Store coercion rules for a schema
|
|
92
|
+
rule_id = store.store_coercion_rules(
|
|
93
|
+
schema_id='user_schema',
|
|
94
|
+
coercion_rules={
|
|
95
|
+
'age': 'coerce_to_integer',
|
|
96
|
+
'email': 'coerce_to_lowercase',
|
|
97
|
+
'name': 'coerce_to_stripped_string'
|
|
98
|
+
},
|
|
99
|
+
version='1.0.0'
|
|
100
|
+
)`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"coercion_rules",type:"Dict[str, Any]",description:'Dictionary mapping field names to coercion rule types (e.g., "coerce_to_integer", "coerce_to_lowercase")',required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, uses schema version)",required:!1,default:"None"}],returns:{type:"str",description:"Coercion rule record ID"}},{id:"get_coercion_rules",title:"Metadata Store - Get Coercion Rules",description:"Retrieve coercion rules for a schema from the metadata store",method:"store.get_coercion_rules(schema_id, version=None)",apiEndpoint:"/api/v1/metadata/coercion-rules/{schema_id}",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import PostgresMetadataStore
|
|
101
|
+
|
|
102
|
+
store = PostgresMetadataStore(connection_string)
|
|
103
|
+
store.connect()
|
|
104
|
+
|
|
105
|
+
# Get coercion rules for a schema
|
|
106
|
+
coercion_rules = store.get_coercion_rules(
|
|
107
|
+
schema_id='user_schema',
|
|
108
|
+
version='1.0.0' # Optional, defaults to latest
|
|
109
|
+
)`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, defaults to latest)",required:!1,default:"None"}],returns:{type:"Optional[Dict[str, Any]]",description:"Coercion rules dictionary mapping field names to coercion types, or None if not found"}},{id:"store_validation_rules",title:"Metadata Store - Store Validation Rules",description:"Store validation rules that define custom validation logic beyond JSON Schema",method:"store.store_validation_rules(schema_id, validation_rules, version=None)",apiEndpoint:"/api/v1/metadata/validation-rules",apiMethod:"POST",exampleRequest:{schema_id:"user_schema",validation_rules:{age:{greater_than_or_equal_to:{threshold:0},less_than_or_equal_to:{threshold:150}},email:{min_length:{threshold:5},matches_pattern:{pattern:"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"}}},version:"1.0.0"},exampleCode:`from pycharter import PostgresMetadataStore
|
|
110
|
+
|
|
111
|
+
store = PostgresMetadataStore(connection_string)
|
|
112
|
+
store.connect()
|
|
113
|
+
|
|
114
|
+
# Store validation rules for a schema
|
|
115
|
+
rule_id = store.store_validation_rules(
|
|
116
|
+
schema_id='user_schema',
|
|
117
|
+
validation_rules={
|
|
118
|
+
'age': {
|
|
119
|
+
'greater_than_or_equal_to': {'threshold': 0},
|
|
120
|
+
'less_than_or_equal_to': {'threshold': 150}
|
|
121
|
+
},
|
|
122
|
+
'email': {
|
|
123
|
+
'min_length': {'threshold': 5},
|
|
124
|
+
'matches_pattern': {'pattern': '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
version='1.0.0'
|
|
128
|
+
)`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"validation_rules",type:"Dict[str, Any]",description:'Dictionary mapping field names to validation rule dictionaries (e.g., {"age": {"greater_than_or_equal_to": {"threshold": 0}}})',required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, uses schema version)",required:!1,default:"None"}],returns:{type:"str",description:"Validation rule record ID"}},{id:"get_validation_rules",title:"Metadata Store - Get Validation Rules",description:"Retrieve validation rules for a schema from the metadata store",method:"store.get_validation_rules(schema_id, version=None)",apiEndpoint:"/api/v1/metadata/validation-rules/{schema_id}",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import PostgresMetadataStore
|
|
129
|
+
|
|
130
|
+
store = PostgresMetadataStore(connection_string)
|
|
131
|
+
store.connect()
|
|
132
|
+
|
|
133
|
+
# Get validation rules for a schema
|
|
134
|
+
validation_rules = store.get_validation_rules(
|
|
135
|
+
schema_id='user_schema',
|
|
136
|
+
version='1.0.0' # Optional, defaults to latest
|
|
137
|
+
)`,arguments:[{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"version",type:"Optional[str]",description:"Optional version string (if None, defaults to latest)",required:!1,default:"None"}],returns:{type:"Optional[Dict[str, Any]]",description:"Validation rules dictionary mapping field names to validation rule dictionaries, or None if not found"}},{id:"generate_model",title:"Pydantic Generator",description:"Generate Pydantic models from JSON Schema",method:'generate_model(schema, model_name="DynamicModel")',apiEndpoint:"/api/v1/schemas/generate",apiMethod:"POST",exampleRequest:{schema:{type:"object",properties:{name:{type:"string"},age:{type:"integer"}}},model_name:"User"},exampleCode:`from pycharter import generate_model, generate_model_file, from_dict, from_file, from_json, from_url
|
|
138
|
+
|
|
139
|
+
# Advanced: More control
|
|
140
|
+
UserModel = generate_model(schema_dict, model_name="User")
|
|
141
|
+
|
|
142
|
+
# Quick helpers: Generate and return model
|
|
143
|
+
UserModel = from_dict(schema_dict) # From dictionary
|
|
144
|
+
UserModel = from_file("schema.json") # From file
|
|
145
|
+
UserModel = from_json(json_string) # From JSON string
|
|
146
|
+
UserModel = from_url("https://example.com/schema.json") # From URL
|
|
147
|
+
|
|
148
|
+
# Generate model and save to file
|
|
149
|
+
generate_model_file(schema_dict, "models.py", model_name="User")`,arguments:[{name:"schema",type:"Dict[str, Any]",description:"JSON Schema dictionary",required:!0},{name:"model_name",type:"str",description:"Name for the generated Pydantic model class",required:!1,default:'"DynamicModel"'}],returns:{type:"Type[BaseModel]",description:"A Pydantic model class generated from the schema"}},{id:"from_dict",title:"Generate Model from Dict",description:"Quick helper: Generate Pydantic model from JSON Schema dictionary",method:"from_dict(schema_dict)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import from_dict
|
|
150
|
+
|
|
151
|
+
schema = {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {
|
|
154
|
+
"name": {"type": "string"},
|
|
155
|
+
"age": {"type": "integer"}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
UserModel = from_dict(schema)
|
|
160
|
+
user = UserModel(name="Alice", age=30)`,arguments:[{name:"schema_dict",type:"Dict[str, Any]",description:"JSON Schema dictionary",required:!0}],returns:{type:"Type[BaseModel]",description:"Pydantic model class generated from the schema"}},{id:"from_file",title:"Generate Model from File",description:"Quick helper: Generate Pydantic model from JSON Schema file",method:"from_file(file_path)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import from_file
|
|
161
|
+
|
|
162
|
+
UserModel = from_file("schema.json")
|
|
163
|
+
# or
|
|
164
|
+
UserModel = from_file("schema.yaml")`,arguments:[{name:"file_path",type:"str",description:"Path to JSON Schema file (JSON or YAML)",required:!0}],returns:{type:"Type[BaseModel]",description:"Pydantic model class generated from the schema file"}},{id:"from_json",title:"Generate Model from JSON String",description:"Quick helper: Generate Pydantic model from JSON Schema JSON string",method:"from_json(json_string)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import from_json
|
|
165
|
+
|
|
166
|
+
json_schema = '{"type": "object", "properties": {"name": {"type": "string"}}}'
|
|
167
|
+
UserModel = from_json(json_schema)`,arguments:[{name:"json_string",type:"str",description:"JSON Schema as JSON string",required:!0}],returns:{type:"Type[BaseModel]",description:"Pydantic model class generated from the JSON string"}},{id:"from_url",title:"Generate Model from URL",description:"Quick helper: Generate Pydantic model from JSON Schema URL",method:"from_url(url)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import from_url
|
|
168
|
+
|
|
169
|
+
UserModel = from_url("https://example.com/schema.json")`,arguments:[{name:"url",type:"str",description:"URL to JSON Schema file",required:!0}],returns:{type:"Type[BaseModel]",description:"Pydantic model class generated from the URL"}},{id:"generate_model_file",title:"Generate Model File",description:"Generate Pydantic model and save to Python file",method:'generate_model_file(schema, output_file, model_name="DynamicModel")',apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import generate_model_file
|
|
170
|
+
|
|
171
|
+
schema = {
|
|
172
|
+
"type": "object",
|
|
173
|
+
"properties": {
|
|
174
|
+
"name": {"type": "string"},
|
|
175
|
+
"age": {"type": "integer"}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
generate_model_file(
|
|
180
|
+
schema=schema,
|
|
181
|
+
output_file="models.py",
|
|
182
|
+
model_name="User"
|
|
183
|
+
)`,arguments:[{name:"schema",type:"Dict[str, Any]",description:"JSON Schema dictionary",required:!0},{name:"output_file",type:"str",description:"Path to output Python file",required:!0},{name:"model_name",type:"str",description:"Name for the generated Pydantic model class",required:!1,default:'"DynamicModel"'}],returns:{type:"None",description:"Saves the generated model to the specified file"}},{id:"model_to_schema",title:"JSON Schema Converter (Advanced)",description:"Convert Pydantic models to JSON Schema - core conversion function",method:"model_to_schema(model_class)",apiEndpoint:"/api/v1/schemas/convert",apiMethod:"POST",exampleRequest:{model_class:"pydantic.BaseModel"},exampleCode:`from pycharter import model_to_schema
|
|
184
|
+
from pydantic import BaseModel
|
|
185
|
+
|
|
186
|
+
class UserModel(BaseModel):
|
|
187
|
+
name: str
|
|
188
|
+
age: int
|
|
189
|
+
|
|
190
|
+
schema = model_to_schema(UserModel)
|
|
191
|
+
print(schema)`,arguments:[{name:"model_class",type:"Type[BaseModel] | str",description:'Pydantic model class or fully qualified class name (e.g., "mymodule.UserModel")',required:!0}],returns:{type:"Dict[str, Any]",description:"JSON Schema dictionary with optional title and version fields"}},{id:"to_dict",title:"Convert Model to Dict",description:"Quick helper: Convert Pydantic model to JSON Schema dictionary",method:"to_dict(model_class)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import to_dict
|
|
192
|
+
from pydantic import BaseModel
|
|
193
|
+
|
|
194
|
+
class UserModel(BaseModel):
|
|
195
|
+
name: str
|
|
196
|
+
age: int
|
|
197
|
+
|
|
198
|
+
schema = to_dict(UserModel)`,arguments:[{name:"model_class",type:"Type[BaseModel] | str",description:"Pydantic model class or fully qualified class name",required:!0}],returns:{type:"Dict[str, Any]",description:"JSON Schema dictionary"}},{id:"to_json",title:"Convert Model to JSON String",description:"Quick helper: Convert Pydantic model to JSON Schema JSON string",method:"to_json(model_class)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import to_json
|
|
199
|
+
from pydantic import BaseModel
|
|
200
|
+
|
|
201
|
+
class UserModel(BaseModel):
|
|
202
|
+
name: str
|
|
203
|
+
age: int
|
|
204
|
+
|
|
205
|
+
json_schema = to_json(UserModel)
|
|
206
|
+
print(json_schema)`,arguments:[{name:"model_class",type:"Type[BaseModel] | str",description:"Pydantic model class or fully qualified class name",required:!0}],returns:{type:"str",description:"JSON Schema as JSON string"}},{id:"to_file",title:"Convert Model to File",description:"Quick helper: Convert Pydantic model to JSON Schema file",method:"to_file(model_class, file_path)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import to_file
|
|
207
|
+
from pydantic import BaseModel
|
|
208
|
+
|
|
209
|
+
class UserModel(BaseModel):
|
|
210
|
+
name: str
|
|
211
|
+
age: int
|
|
212
|
+
|
|
213
|
+
to_file(UserModel, "schema.json")
|
|
214
|
+
# or
|
|
215
|
+
to_file(UserModel, "schema.yaml")`,arguments:[{name:"model_class",type:"Type[BaseModel] | str",description:"Pydantic model class or fully qualified class name",required:!0},{name:"file_path",type:"str",description:"Path to output file (JSON or YAML)",required:!0}],returns:{type:"None",description:"Saves the JSON Schema to the specified file"}},{id:"validator_class",title:"Validator Class (PRIMARY INTERFACE)",description:"⭐ PRIMARY: Use Validator class for all validation - best performance and flexibility",method:"Validator(contract_dir=None, contract_file=None, contract_dict=None, contract_metadata=None, store=None, schema_id=None, schema_version=None)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import Validator, ValidatorBuilder, create_validator
|
|
216
|
+
from pycharter.metadata_store import SQLiteMetadataStore
|
|
217
|
+
|
|
218
|
+
# From contract directory
|
|
219
|
+
validator = Validator(contract_dir="data/contracts/user")
|
|
220
|
+
result = validator.validate({"name": "Alice", "age": 30})
|
|
221
|
+
|
|
222
|
+
# From metadata store
|
|
223
|
+
store = SQLiteMetadataStore("metadata.db")
|
|
224
|
+
store.connect()
|
|
225
|
+
validator = Validator(store=store, schema_id="user_schema")
|
|
226
|
+
result = validator.validate({"name": "Alice", "age": 30})
|
|
227
|
+
|
|
228
|
+
# Using ValidatorBuilder (fluent API)
|
|
229
|
+
validator = (
|
|
230
|
+
ValidatorBuilder()
|
|
231
|
+
.from_directory("data/contracts/user")
|
|
232
|
+
.strict()
|
|
233
|
+
.with_quality_checks({"completeness": 0.95})
|
|
234
|
+
.build()
|
|
235
|
+
)
|
|
236
|
+
result = validator.validate({"name": "Alice", "age": 30})
|
|
237
|
+
print(result.quality.completeness) # Quality metrics included
|
|
238
|
+
|
|
239
|
+
# Batch validation
|
|
240
|
+
results = validator.validate_batch([
|
|
241
|
+
{"name": "Alice", "age": 30},
|
|
242
|
+
{"name": "Bob", "age": 25}
|
|
243
|
+
])
|
|
244
|
+
|
|
245
|
+
# Factory function
|
|
246
|
+
validator = create_validator(contract_file="contract.yaml")`,arguments:[{name:"contract_dir",type:"Optional[str]",description:"Directory containing contract files (schema.yaml, coercion_rules.yaml, validation_rules.yaml)",required:!1},{name:"contract_file",type:"Optional[str]",description:"Path to complete contract file (YAML/JSON)",required:!1},{name:"contract_dict",type:"Optional[Dict[str, Any]]",description:"Contract as dictionary with schema, coercion_rules, validation_rules keys",required:!1},{name:"contract_metadata",type:"Optional[ContractMetadata]",description:"ContractMetadata object (from parse_contract)",required:!1},{name:"store",type:"Optional[MetadataStoreClient]",description:"MetadataStoreClient instance (for loading from metadata store)",required:!1},{name:"schema_id",type:"Optional[str]",description:"Schema identifier (required when using store)",required:!1},{name:"schema_version",type:"Optional[str]",description:"Optional schema version (defaults to latest when using store)",required:!1}],returns:{type:"Validator",description:"Validator instance with validate() and validate_batch() methods"}},{id:"validator_builder",title:"ValidatorBuilder (Fluent API)",description:"Fluent builder pattern for constructing validators with configuration options like strict mode and quality checks",method:"ValidatorBuilder().from_directory(path).strict().with_quality_checks(thresholds).build()",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import ValidatorBuilder
|
|
247
|
+
|
|
248
|
+
# Basic usage
|
|
249
|
+
validator = (
|
|
250
|
+
ValidatorBuilder()
|
|
251
|
+
.from_directory("data/contracts/user")
|
|
252
|
+
.build()
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# With strict mode (raises exceptions on errors)
|
|
256
|
+
validator = (
|
|
257
|
+
ValidatorBuilder()
|
|
258
|
+
.from_file("contracts/user.yaml")
|
|
259
|
+
.strict()
|
|
260
|
+
.build()
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# With quality checks
|
|
264
|
+
validator = (
|
|
265
|
+
ValidatorBuilder()
|
|
266
|
+
.from_dict(contract_dict)
|
|
267
|
+
.with_quality_checks({"completeness": 0.95, "validity_rate": 0.99})
|
|
268
|
+
.build()
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# From metadata store
|
|
272
|
+
validator = (
|
|
273
|
+
ValidatorBuilder()
|
|
274
|
+
.from_store(store, "user_schema", version="1.0.0")
|
|
275
|
+
.lenient()
|
|
276
|
+
.with_quality_checks()
|
|
277
|
+
.build()
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# Validate with quality metrics
|
|
281
|
+
result = validator.validate(data, include_quality=True)
|
|
282
|
+
if result.quality:
|
|
283
|
+
print(f"Completeness: {result.quality.completeness}")
|
|
284
|
+
print(f"Validity rate: {result.quality.validity_rate}")`,arguments:[{name:"from_directory(path)",type:"method",description:"Load contract from directory containing schema.yaml, coercion_rules.yaml, validation_rules.yaml",required:!1},{name:"from_file(path)",type:"method",description:"Load contract from a single file (YAML/JSON)",required:!1},{name:"from_dict(contract_dict)",type:"method",description:"Load contract from dictionary",required:!1},{name:"from_store(store, schema_id, version)",type:"method",description:"Load contract from metadata store",required:!1},{name:"strict()",type:"method",description:"Enable strict mode - raises exceptions on validation errors",required:!1},{name:"lenient()",type:"method",description:"Enable lenient mode (default) - returns errors in ValidationResult",required:!1},{name:"with_quality_checks(thresholds)",type:"method",description:"Enable quality metrics calculation during validation. Optional thresholds dict for pass/fail criteria.",required:!1},{name:"build()",type:"method",description:"Build and return the configured Validator instance",required:!0}],returns:{type:"Validator",description:"Configured Validator instance with the specified options"}},{id:"validation_quality_metrics",title:"ValidationResult Quality Metrics",description:"Quality metrics included in ValidationResult when quality checks are enabled",method:"result.quality (QualityMetrics)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import Validator, ValidatorBuilder
|
|
285
|
+
|
|
286
|
+
# Enable quality checks via builder
|
|
287
|
+
validator = (
|
|
288
|
+
ValidatorBuilder()
|
|
289
|
+
.from_directory("data/contracts/user")
|
|
290
|
+
.with_quality_checks()
|
|
291
|
+
.build()
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Single validation with quality
|
|
295
|
+
result = validator.validate(data, include_quality=True)
|
|
296
|
+
if result.is_valid:
|
|
297
|
+
print(f"Valid! Quality score: {result.quality.completeness:.2%}")
|
|
298
|
+
else:
|
|
299
|
+
print(f"Invalid. Errors: {result.errors}")
|
|
300
|
+
|
|
301
|
+
# Batch validation with quality
|
|
302
|
+
results = validator.validate_batch(data_list, include_quality=True)
|
|
303
|
+
last_result = results[-1] # Quality metrics on last result
|
|
304
|
+
print(f"Valid: {last_result.quality.valid_count}/{last_result.quality.record_count}")
|
|
305
|
+
print(f"Validity rate: {last_result.quality.validity_rate:.2%}")
|
|
306
|
+
|
|
307
|
+
# Check against thresholds
|
|
308
|
+
thresholds = {"completeness": 0.95, "validity_rate": 0.99}
|
|
309
|
+
if last_result.quality.passes_thresholds(thresholds):
|
|
310
|
+
print("Quality thresholds passed!")`,arguments:[{name:"completeness",type:"float",description:"Ratio of non-null fields (0.0 to 1.0)",required:!1},{name:"field_completeness",type:"Dict[str, float]",description:"Per-field completeness ratios",required:!1},{name:"record_count",type:"int",description:"Total number of records validated",required:!1},{name:"valid_count",type:"int",description:"Number of valid records",required:!1},{name:"error_count",type:"int",description:"Number of records with errors",required:!1},{name:"validity_rate",type:"float (property)",description:"Ratio of valid records (valid_count / record_count)",required:!1}],returns:{type:"QualityMetrics",description:"Quality metrics object with completeness, validity rate, and per-field metrics"}},{id:"error_handling",title:"Error Handling Modes",description:"Standardized error handling with STRICT, LENIENT, and COLLECT modes for consistent behavior across pycharter",method:"ErrorMode, StrictMode, LenientMode, set_error_mode()",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import ErrorMode, StrictMode, LenientMode, set_error_mode
|
|
311
|
+
|
|
312
|
+
# Set global error mode
|
|
313
|
+
set_error_mode(ErrorMode.STRICT) # Raise exceptions
|
|
314
|
+
set_error_mode(ErrorMode.LENIENT) # Log warnings (default)
|
|
315
|
+
set_error_mode(ErrorMode.COLLECT) # Collect errors
|
|
316
|
+
|
|
317
|
+
# Context manager for temporary strict mode
|
|
318
|
+
from pycharter import Validator
|
|
319
|
+
|
|
320
|
+
validator = Validator(contract_dir="data/contracts/user")
|
|
321
|
+
|
|
322
|
+
with StrictMode():
|
|
323
|
+
# Errors will raise exceptions in this block
|
|
324
|
+
result = validator.validate(data) # Raises on error
|
|
325
|
+
|
|
326
|
+
# Back to default lenient mode
|
|
327
|
+
result = validator.validate(data) # Returns ValidationResult with errors
|
|
328
|
+
|
|
329
|
+
# Context manager for lenient mode
|
|
330
|
+
with LenientMode():
|
|
331
|
+
# Errors are logged as warnings
|
|
332
|
+
result = validator.validate(data)
|
|
333
|
+
|
|
334
|
+
# Using ErrorContext for collecting errors
|
|
335
|
+
from pycharter.shared import ErrorContext, ErrorMode
|
|
336
|
+
|
|
337
|
+
ctx = ErrorContext(mode=ErrorMode.COLLECT)
|
|
338
|
+
ctx.handle_error("Field 'name' is missing", category="validation")
|
|
339
|
+
ctx.handle_error("Field 'age' must be positive", category="validation")
|
|
340
|
+
|
|
341
|
+
print(f"Has errors: {ctx.has_errors}")
|
|
342
|
+
print(f"Errors: {ctx.errors}")
|
|
343
|
+
ctx.raise_if_errors() # Raises ValueError with all errors`,arguments:[{name:"ErrorMode.STRICT",type:"enum",description:"Raise exceptions immediately on any error",required:!1},{name:"ErrorMode.LENIENT",type:"enum",description:"Log warnings and continue with best effort (default)",required:!1},{name:"ErrorMode.COLLECT",type:"enum",description:"Collect errors and return them with results",required:!1},{name:"StrictMode",type:"context manager",description:"Context manager for temporarily enabling strict mode",required:!1},{name:"LenientMode",type:"context manager",description:"Context manager for temporarily enabling lenient mode",required:!1},{name:"set_error_mode(mode)",type:"function",description:"Set the default error handling mode globally",required:!1}],returns:{type:"None / ErrorContext",description:"Context managers return None; ErrorContext for collecting errors"}},{id:"validate_with_store",title:"Validate with Store (Convenience)",description:"Quick validation using schema from metadata store",method:"validate_with_store(store, schema_id, data, version=None, strict=False)",apiEndpoint:"/api/v1/validation/validate",apiMethod:"POST",exampleRequest:{schema_id:"user_schema",data:{name:"Alice",age:30},version:"1.0.0",strict:!1},exampleCode:`from pycharter import validate_with_store
|
|
344
|
+
from pycharter.metadata_store import SQLiteMetadataStore
|
|
345
|
+
|
|
346
|
+
store = SQLiteMetadataStore("metadata.db")
|
|
347
|
+
store.connect()
|
|
348
|
+
|
|
349
|
+
result = validate_with_store(
|
|
350
|
+
store=store,
|
|
351
|
+
schema_id="user_schema",
|
|
352
|
+
data={"name": "Alice", "age": 30},
|
|
353
|
+
version="1.0.0"
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
if result.is_valid:
|
|
357
|
+
print("Valid data:", result.data)
|
|
358
|
+
else:
|
|
359
|
+
print("Errors:", result.errors)`,arguments:[{name:"store",type:"MetadataStoreClient",description:"MetadataStoreClient instance",required:!0},{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"data",type:"Dict[str, Any]",description:"Data dictionary to validate",required:!0},{name:"version",type:"Optional[str]",description:"Optional schema version (if None, uses latest)",required:!1,default:"None"},{name:"strict",type:"bool",description:"If True, raise exceptions on validation errors",required:!1,default:"False"}],returns:{type:"ValidationResult",description:"ValidationResult object with is_valid flag, validated data (if valid), and list of errors (if invalid)"}},{id:"validate_with_contract",title:"Validate with Contract (Convenience)",description:"Quick validation using contract dictionary or file",method:"validate_with_contract(contract, data, strict=False)",apiEndpoint:"/api/v1/validation/validate",apiMethod:"POST",exampleRequest:{contract:{schema:{type:"object",properties:{name:{type:"string"},age:{type:"integer"}}}},data:{name:"Alice",age:30},strict:!1},exampleCode:`from pycharter import validate_with_contract
|
|
360
|
+
|
|
361
|
+
contract = {
|
|
362
|
+
"schema": {
|
|
363
|
+
"type": "object",
|
|
364
|
+
"properties": {
|
|
365
|
+
"name": {"type": "string"},
|
|
366
|
+
"age": {"type": "integer"}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
result = validate_with_contract(
|
|
372
|
+
contract=contract,
|
|
373
|
+
data={"name": "Alice", "age": 30}
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
# Or from file
|
|
377
|
+
result = validate_with_contract(
|
|
378
|
+
contract="contracts/user.yaml",
|
|
379
|
+
data={"name": "Alice", "age": 30}
|
|
380
|
+
)`,arguments:[{name:"contract",type:"Dict[str, Any] | ContractMetadata | str",description:"Contract dictionary, ContractMetadata object, or file path",required:!0},{name:"data",type:"Dict[str, Any]",description:"Data dictionary to validate",required:!0},{name:"strict",type:"bool",description:"If True, raise exceptions on validation errors",required:!1,default:"False"}],returns:{type:"ValidationResult",description:"ValidationResult object with is_valid flag, validated data (if valid), and list of errors (if invalid)"}},{id:"validate_batch_with_store",title:"Batch Validate with Store",description:"Validate multiple records using schema from metadata store",method:"validate_batch_with_store(store, schema_id, data_list, version=None, strict=False)",apiEndpoint:"/api/v1/validation/validate-batch",apiMethod:"POST",exampleRequest:{schema_id:"user_schema",data_list:[{name:"Alice",age:30},{name:"Bob",age:25}],version:"1.0.0",strict:!1},exampleCode:`from pycharter import validate_batch_with_store
|
|
381
|
+
from pycharter.metadata_store import SQLiteMetadataStore
|
|
382
|
+
|
|
383
|
+
store = SQLiteMetadataStore("metadata.db")
|
|
384
|
+
store.connect()
|
|
385
|
+
|
|
386
|
+
results = validate_batch_with_store(
|
|
387
|
+
store=store,
|
|
388
|
+
schema_id="user_schema",
|
|
389
|
+
data_list=[
|
|
390
|
+
{"name": "Alice", "age": 30},
|
|
391
|
+
{"name": "Bob", "age": 25}
|
|
392
|
+
],
|
|
393
|
+
version="1.0.0"
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
print(f"Valid: {results.total_count - len(results.errors)}/{results.total_count}")`,arguments:[{name:"store",type:"MetadataStoreClient",description:"MetadataStoreClient instance",required:!0},{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"data_list",type:"List[Dict[str, Any]]",description:"List of data dictionaries to validate",required:!0},{name:"version",type:"Optional[str]",description:"Optional schema version (if None, uses latest)",required:!1,default:"None"},{name:"strict",type:"bool",description:"If True, raise exceptions on validation errors",required:!1,default:"False"}],returns:{type:"ValidationBatchResponse",description:"Batch validation results with total_count, valid_count, error_count, and results list"}},{id:"validate_batch_with_contract",title:"Batch Validate with Contract",description:"Validate multiple records using contract dictionary or file",method:"validate_batch_with_contract(contract, data_list, strict=False)",apiEndpoint:"/api/v1/validation/validate-batch",apiMethod:"POST",exampleRequest:{contract:{schema:{type:"object",properties:{name:{type:"string"},age:{type:"integer"}}}},data_list:[{name:"Alice",age:30},{name:"Bob",age:25}],strict:!1},exampleCode:`from pycharter import validate_batch_with_contract
|
|
397
|
+
|
|
398
|
+
contract = {
|
|
399
|
+
"schema": {
|
|
400
|
+
"type": "object",
|
|
401
|
+
"properties": {
|
|
402
|
+
"name": {"type": "string"},
|
|
403
|
+
"age": {"type": "integer"}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
results = validate_batch_with_contract(
|
|
409
|
+
contract=contract,
|
|
410
|
+
data_list=[
|
|
411
|
+
{"name": "Alice", "age": 30},
|
|
412
|
+
{"name": "Bob", "age": 25}
|
|
413
|
+
]
|
|
414
|
+
)`,arguments:[{name:"contract",type:"Dict[str, Any] | ContractMetadata | str",description:"Contract dictionary, ContractMetadata object, or file path",required:!0},{name:"data_list",type:"List[Dict[str, Any]]",description:"List of data dictionaries to validate",required:!0},{name:"strict",type:"bool",description:"If True, raise exceptions on validation errors",required:!1,default:"False"}],returns:{type:"ValidationBatchResponse",description:"Batch validation results with total_count, valid_count, error_count, and results list"}},{id:"get_model_from_store",title:"Get Model from Store",description:"Get Pydantic model class from schema stored in metadata store",method:"get_model_from_store(store, schema_id, version=None)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import get_model_from_store
|
|
415
|
+
from pycharter.metadata_store import SQLiteMetadataStore
|
|
416
|
+
|
|
417
|
+
store = SQLiteMetadataStore("metadata.db")
|
|
418
|
+
store.connect()
|
|
419
|
+
|
|
420
|
+
# Get Pydantic model class
|
|
421
|
+
UserModel = get_model_from_store(
|
|
422
|
+
store=store,
|
|
423
|
+
schema_id="user_schema",
|
|
424
|
+
version="1.0.0"
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
# Use the model directly
|
|
428
|
+
user = UserModel(name="Alice", age=30)
|
|
429
|
+
print(user.model_dump())`,arguments:[{name:"store",type:"MetadataStoreClient",description:"MetadataStoreClient instance",required:!0},{name:"schema_id",type:"str",description:"Schema identifier",required:!0},{name:"version",type:"Optional[str]",description:"Optional schema version (if None, uses latest)",required:!1,default:"None"}],returns:{type:"Type[BaseModel]",description:"Pydantic model class generated from the schema"}},{id:"get_model_from_contract",title:"Get Model from Contract",description:"Get Pydantic model class from contract dictionary or file",method:"get_model_from_contract(contract)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import get_model_from_contract
|
|
430
|
+
|
|
431
|
+
contract = {
|
|
432
|
+
"schema": {
|
|
433
|
+
"type": "object",
|
|
434
|
+
"properties": {
|
|
435
|
+
"name": {"type": "string"},
|
|
436
|
+
"age": {"type": "integer"}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
# Get Pydantic model class
|
|
442
|
+
UserModel = get_model_from_contract(contract)
|
|
443
|
+
|
|
444
|
+
# Use the model directly
|
|
445
|
+
user = UserModel(name="Alice", age=30)
|
|
446
|
+
print(user.model_dump())
|
|
447
|
+
|
|
448
|
+
# Or from file
|
|
449
|
+
UserModel = get_model_from_contract("contracts/user.yaml")`,arguments:[{name:"contract",type:"Dict[str, Any] | ContractMetadata | str",description:"Contract dictionary, ContractMetadata object, or file path",required:!0}],returns:{type:"Type[BaseModel]",description:"Pydantic model class generated from the contract schema"}},{id:"validate",title:"Validate (Low-level)",description:"Low-level validation with existing Pydantic model",method:"validate(data, model, coercion_rules=None, validation_rules=None, strict=False)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import validate
|
|
450
|
+
from pydantic import BaseModel
|
|
451
|
+
|
|
452
|
+
# Define model manually or get from contract
|
|
453
|
+
class UserModel(BaseModel):
|
|
454
|
+
name: str
|
|
455
|
+
age: int
|
|
456
|
+
|
|
457
|
+
# Validate with model
|
|
458
|
+
result = validate(
|
|
459
|
+
data={"name": "Alice", "age": 30},
|
|
460
|
+
model=UserModel,
|
|
461
|
+
coercion_rules=None,
|
|
462
|
+
validation_rules=None
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
if result.is_valid:
|
|
466
|
+
print("Valid:", result.data)
|
|
467
|
+
else:
|
|
468
|
+
print("Errors:", result.errors)`,arguments:[{name:"data",type:"Dict[str, Any]",description:"Data dictionary to validate",required:!0},{name:"model",type:"Type[BaseModel]",description:"Pydantic model class",required:!0},{name:"coercion_rules",type:"Optional[Dict[str, Any]]",description:"Optional coercion rules dictionary",required:!1,default:"None"},{name:"validation_rules",type:"Optional[Dict[str, Any]]",description:"Optional validation rules dictionary",required:!1,default:"None"},{name:"strict",type:"bool",description:"If True, raise exceptions on validation errors",required:!1,default:"False"}],returns:{type:"ValidationResult",description:"ValidationResult object with is_valid flag, validated data (if valid), and list of errors (if invalid)"}},{id:"validate_batch",title:"Batch Validate (Low-level)",description:"Low-level batch validation with existing Pydantic model",method:"validate_batch(data_list, model, coercion_rules=None, validation_rules=None, strict=False)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import validate_batch
|
|
469
|
+
from pydantic import BaseModel
|
|
470
|
+
|
|
471
|
+
# Define model manually or get from contract
|
|
472
|
+
class UserModel(BaseModel):
|
|
473
|
+
name: str
|
|
474
|
+
age: int
|
|
475
|
+
|
|
476
|
+
# Batch validate with model
|
|
477
|
+
results = validate_batch(
|
|
478
|
+
data_list=[
|
|
479
|
+
{"name": "Alice", "age": 30},
|
|
480
|
+
{"name": "Bob", "age": 25}
|
|
481
|
+
],
|
|
482
|
+
model=UserModel
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
print(f"Valid: {results.valid_count}/{results.total_count}")`,arguments:[{name:"data_list",type:"List[Dict[str, Any]]",description:"List of data dictionaries to validate",required:!0},{name:"model",type:"Type[BaseModel]",description:"Pydantic model class",required:!0},{name:"coercion_rules",type:"Optional[Dict[str, Any]]",description:"Optional coercion rules dictionary",required:!1,default:"None"},{name:"validation_rules",type:"Optional[Dict[str, Any]]",description:"Optional validation rules dictionary",required:!1,default:"None"},{name:"strict",type:"bool",description:"If True, raise exceptions on validation errors",required:!1,default:"False"}],returns:{type:"ValidationBatchResponse",description:"Batch validation results with total_count, valid_count, error_count, and results list"}},{id:"quality_check",title:"QualityCheck Class (PRIMARY INTERFACE)",description:"⭐ PRIMARY: Use QualityCheck class for quality assurance - monitor data quality, calculate metrics, and track violations",method:"QualityCheck(store=None, db_session=None).run(schema_id=None, contract=None, data=None, options=None)",apiEndpoint:"/api/v1/quality/check",apiMethod:"POST",exampleRequest:{schema_id:"user_schema",data:[{name:"Alice",age:30},{name:"Bob",age:25}],calculate_metrics:!0,record_violations:!0},exampleCode:`from pycharter import QualityCheck, QualityCheckOptions, QualityReport, QualityThresholds
|
|
486
|
+
from pycharter.metadata_store import SQLiteMetadataStore
|
|
487
|
+
from sqlalchemy.orm import Session
|
|
488
|
+
|
|
489
|
+
# Create quality check instance
|
|
490
|
+
store = SQLiteMetadataStore("metadata.db")
|
|
491
|
+
store.connect()
|
|
492
|
+
db_session = Session() # Your database session
|
|
493
|
+
|
|
494
|
+
check = QualityCheck(store=store, db_session=db_session)
|
|
495
|
+
|
|
496
|
+
# Configure options
|
|
497
|
+
options = QualityCheckOptions(
|
|
498
|
+
record_violations=True,
|
|
499
|
+
calculate_metrics=True,
|
|
500
|
+
check_thresholds=True,
|
|
501
|
+
include_field_metrics=True,
|
|
502
|
+
sample_size=None # Process all data
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
# Set thresholds (optional)
|
|
506
|
+
thresholds = QualityThresholds(
|
|
507
|
+
overall_score_min=80.0,
|
|
508
|
+
accuracy_min=95.0,
|
|
509
|
+
completeness_min=90.0
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
# Run quality check
|
|
513
|
+
report = check.run(
|
|
514
|
+
schema_id='user_schema',
|
|
515
|
+
data="data/users.json", # File path, list, or callable
|
|
516
|
+
options=options
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
# Access results
|
|
520
|
+
print(f"Quality Score: {report.quality_score.overall_score:.2f}/100")
|
|
521
|
+
print(f"Passed: {report.passed}")
|
|
522
|
+
print(f"Metrics: {report.metrics}")
|
|
523
|
+
print(f"Violations: {len(report.violations)}")`,arguments:[{name:"store",type:"Optional[MetadataStoreClient]",description:"Optional metadata store for retrieving contracts and storing violations",required:!1,default:"None"},{name:"db_session",type:"Optional[Session]",description:"Optional SQLAlchemy database session for persisting metrics and violations",required:!1,default:"None"},{name:"schema_id",type:"Optional[str]",description:"Schema ID (if using store-based validation)",required:!1},{name:"contract",type:"Optional[Dict[str, Any] | str]",description:"Contract dictionary or file path (if using contract-based validation)",required:!1},{name:"data",type:"List[Dict[str, Any]] | str | Callable",description:"Data to validate. Can be a list of dictionaries, file path (JSON/CSV), or callable that returns data",required:!0},{name:"options",type:"Optional[QualityCheckOptions]",description:"Quality check options including record_violations, calculate_metrics, check_thresholds, include_field_metrics, sample_size, data_source, data_version, etc.",required:!1,default:"None"}],returns:{type:"QualityReport",description:"QualityReport object containing validation results, quality score (QualityScore), field metrics (FieldQualityMetrics), violations (List[ViolationRecord]), and threshold breaches"}},{id:"quality_check_options",title:"QualityCheckOptions",description:"Configuration options for quality checks",method:"QualityCheckOptions(record_violations=True, calculate_metrics=True, check_thresholds=False, include_field_metrics=True, sample_size=None, data_source=None, data_version=None, skip_if_unchanged=False)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import QualityCheckOptions
|
|
524
|
+
|
|
525
|
+
options = QualityCheckOptions(
|
|
526
|
+
record_violations=True, # Record violations to database
|
|
527
|
+
calculate_metrics=True, # Calculate quality metrics
|
|
528
|
+
check_thresholds=False, # Check against quality thresholds
|
|
529
|
+
include_field_metrics=True, # Include field-level metrics
|
|
530
|
+
sample_size=1000, # Sample size for large datasets
|
|
531
|
+
data_source="users.csv", # Data source identifier
|
|
532
|
+
data_version="v1.0", # Data version identifier
|
|
533
|
+
skip_if_unchanged=True # Skip if data hasn't changed
|
|
534
|
+
)`,arguments:[{name:"record_violations",type:"bool",description:"Whether to record violations to database",required:!1,default:"True"},{name:"calculate_metrics",type:"bool",description:"Whether to calculate quality metrics",required:!1,default:"True"},{name:"check_thresholds",type:"bool",description:"Whether to check against quality thresholds",required:!1,default:"False"},{name:"include_field_metrics",type:"bool",description:"Whether to include field-level quality metrics",required:!1,default:"True"},{name:"sample_size",type:"Optional[int]",description:"Sample size for large datasets (None = process all)",required:!1,default:"None"},{name:"data_source",type:"Optional[str]",description:"Data source identifier (e.g., file name)",required:!1,default:"None"},{name:"data_version",type:"Optional[str]",description:"Data version identifier",required:!1,default:"None"},{name:"skip_if_unchanged",type:"bool",description:"Skip quality check if data fingerprint hasn't changed",required:!1,default:"False"}],returns:{type:"QualityCheckOptions",description:"QualityCheckOptions instance for configuring quality checks"}},{id:"quality_thresholds",title:"QualityThresholds",description:"Define quality thresholds for monitoring and alerting",method:"QualityThresholds(overall_score_min=None, accuracy_min=None, completeness_min=None, violation_rate_max=None, field_thresholds=None)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import QualityThresholds
|
|
535
|
+
|
|
536
|
+
thresholds = QualityThresholds(
|
|
537
|
+
overall_score_min=80.0, # Minimum overall quality score
|
|
538
|
+
accuracy_min=95.0, # Minimum accuracy percentage
|
|
539
|
+
completeness_min=90.0, # Minimum completeness percentage
|
|
540
|
+
violation_rate_max=0.05, # Maximum violation rate (5%)
|
|
541
|
+
field_thresholds={ # Field-specific thresholds
|
|
542
|
+
"email": {"completeness_min": 98.0},
|
|
543
|
+
"age": {"accuracy_min": 99.0}
|
|
544
|
+
}
|
|
545
|
+
)`,arguments:[{name:"overall_score_min",type:"Optional[float]",description:"Minimum overall quality score (0-100)",required:!1,default:"None"},{name:"accuracy_min",type:"Optional[float]",description:"Minimum accuracy percentage (0-100)",required:!1,default:"None"},{name:"completeness_min",type:"Optional[float]",description:"Minimum completeness percentage (0-100)",required:!1,default:"None"},{name:"violation_rate_max",type:"Optional[float]",description:"Maximum violation rate (0-1)",required:!1,default:"None"},{name:"field_thresholds",type:"Optional[Dict[str, Dict[str, float]]]",description:'Field-specific thresholds (e.g., {"email": {"completeness_min": 98.0}})',required:!1,default:"None"}],returns:{type:"QualityThresholds",description:"QualityThresholds instance for defining quality requirements"}},{id:"pipeline_class",title:"Pipeline Class (NEW - PRIMARY)",description:"⭐ NEW: Build ETL pipelines with | operator for fluent, composable pipelines. Supports both programmatic and config-driven approaches.",method:"Pipeline(extractor) | transformer | loader",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import (
|
|
546
|
+
Pipeline, PipelineBuilder, PipelineContext,
|
|
547
|
+
HTTPExtractor, PostgresLoader,
|
|
548
|
+
Rename, AddField, Filter, Convert, Drop
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
# Programmatic pipeline with | operator
|
|
552
|
+
pipeline = (
|
|
553
|
+
Pipeline(HTTPExtractor(url="https://api.example.com/users"))
|
|
554
|
+
| Rename({"userName": "name", "userAge": "age"})
|
|
555
|
+
| AddField("processed_at", lambda r: datetime.now().isoformat())
|
|
556
|
+
| Filter(lambda r: r["age"] >= 18)
|
|
557
|
+
| Convert({"age": int, "salary": float})
|
|
558
|
+
| PostgresLoader(connection_string="...", table="users")
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
# Run the pipeline
|
|
562
|
+
result = await pipeline.run()
|
|
563
|
+
print(f"Loaded {result.total_loaded} records")
|
|
564
|
+
|
|
565
|
+
# Config-driven pipeline (from YAML files)
|
|
566
|
+
pipeline = Pipeline.from_config("data/pipelines/users")
|
|
567
|
+
result = await pipeline.run()
|
|
568
|
+
|
|
569
|
+
# With context for variable substitution
|
|
570
|
+
context = PipelineContext(extra={"API_KEY": "secret123"})
|
|
571
|
+
pipeline = Pipeline.from_config("configs/api_pipeline", context=context)
|
|
572
|
+
result = await pipeline.run()`,arguments:[{name:"extractor",type:"Extractor",description:"Extractor instance (HTTPExtractor, FileExtractor, DatabaseExtractor, CloudStorageExtractor)",required:!0},{name:"| transformer",type:"Transformer",description:"Chain transformers using | operator (Rename, AddField, Filter, Convert, Drop, Select, Map, FlatMap)",required:!1},{name:"| loader",type:"Loader",description:"Chain loader at the end (PostgresLoader, FileLoader, CloudStorageLoader)",required:!0}],returns:{type:"PipelineResult",description:"Result with total_extracted, total_transformed, total_loaded, batches, errors, duration_seconds"}},{id:"pipeline_builder",title:"PipelineBuilder (Fluent API)",description:"Alternative fluent API for building pipelines with method chaining",method:"PipelineBuilder().extract(extractor).transform(transformer).load(loader).build()",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import PipelineBuilder, HTTPExtractor, PostgresLoader, Rename, Filter
|
|
573
|
+
|
|
574
|
+
pipeline = (
|
|
575
|
+
PipelineBuilder()
|
|
576
|
+
.extract(HTTPExtractor(url="https://api.example.com/data"))
|
|
577
|
+
.transform(Rename({"old_name": "new_name"}))
|
|
578
|
+
.transform(Filter(lambda r: r["active"]))
|
|
579
|
+
.load(PostgresLoader(connection_string="...", table="users"))
|
|
580
|
+
.build()
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
result = await pipeline.run()`,arguments:[{name:"extract(extractor)",type:"method",description:"Set the extractor for the pipeline",required:!0},{name:"transform(transformer)",type:"method",description:"Add a transformer (can be called multiple times)",required:!1},{name:"load(loader)",type:"method",description:"Set the loader for the pipeline",required:!0},{name:"build()",type:"method",description:"Build and return the Pipeline instance",required:!0}],returns:{type:"Pipeline",description:"Configured Pipeline instance ready to run"}},{id:"etl_transformers",title:"ETL Transformers",description:"Built-in transformers for data manipulation, chainable with | operator",method:"Rename, AddField, Drop, Select, Filter, Convert, Default, Map, FlatMap, CustomFunction",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import (
|
|
584
|
+
Rename, AddField, Drop, Select, Filter,
|
|
585
|
+
Convert, Default, Map, FlatMap, CustomFunction
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
# Rename fields
|
|
589
|
+
rename = Rename({"old_name": "new_name", "userName": "user_name"})
|
|
590
|
+
|
|
591
|
+
# Add computed fields
|
|
592
|
+
add = AddField("full_name", lambda r: f"{r['first']} {r['last']}")
|
|
593
|
+
|
|
594
|
+
# Drop fields
|
|
595
|
+
drop = Drop(["temp_field", "internal_id"])
|
|
596
|
+
|
|
597
|
+
# Select specific fields only
|
|
598
|
+
select = Select(["id", "name", "email"])
|
|
599
|
+
|
|
600
|
+
# Filter records
|
|
601
|
+
filter_active = Filter(lambda r: r.get("active", False))
|
|
602
|
+
|
|
603
|
+
# Convert types
|
|
604
|
+
convert = Convert({"age": int, "price": float, "active": bool})
|
|
605
|
+
|
|
606
|
+
# Set defaults for missing/null values
|
|
607
|
+
defaults = Default({"status": "pending", "count": 0})
|
|
608
|
+
|
|
609
|
+
# Map - transform each record
|
|
610
|
+
map_transform = Map(lambda r: {**r, "name": r["name"].upper()})
|
|
611
|
+
|
|
612
|
+
# FlatMap - expand records (one-to-many)
|
|
613
|
+
flatmap = FlatMap(lambda r: [{"item": i} for i in r.get("items", [])])
|
|
614
|
+
|
|
615
|
+
# Custom function
|
|
616
|
+
def my_transform(records, **kwargs):
|
|
617
|
+
return [r for r in records if r.get("valid")]
|
|
618
|
+
custom = CustomFunction(my_transform)
|
|
619
|
+
|
|
620
|
+
# Chain transformers
|
|
621
|
+
chain = Rename({"a": "b"}) | Filter(lambda r: r["x"] > 0) | Convert({"x": int})`,arguments:[{name:"Rename(mapping)",type:"Transformer",description:"Rename fields according to mapping dict",required:!1},{name:"AddField(name, value_or_func)",type:"Transformer",description:"Add a new field with static value or computed from record",required:!1},{name:"Drop(fields)",type:"Transformer",description:"Remove specified fields from records",required:!1},{name:"Select(fields)",type:"Transformer",description:"Keep only specified fields",required:!1},{name:"Filter(predicate)",type:"Transformer",description:"Keep only records matching predicate function",required:!1},{name:"Convert(type_mapping)",type:"Transformer",description:"Convert field types (int, float, str, bool)",required:!1},{name:"Default(defaults)",type:"Transformer",description:"Set default values for missing/null fields",required:!1},{name:"Map(func)",type:"Transformer",description:"Transform each record with function",required:!1},{name:"FlatMap(func)",type:"Transformer",description:"Expand records (one-to-many transformation)",required:!1}],returns:{type:"Transformer / TransformerChain",description:"Transformer instance, chainable with | operator"}},{id:"etl_extractors",title:"ETL Extractors",description:"Built-in extractors for different data sources",method:"HTTPExtractor, FileExtractor, DatabaseExtractor, CloudStorageExtractor",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import (
|
|
622
|
+
HTTPExtractor, FileExtractor,
|
|
623
|
+
DatabaseExtractor, CloudStorageExtractor
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
# HTTP API extraction
|
|
627
|
+
http = HTTPExtractor(
|
|
628
|
+
url="https://api.example.com/data",
|
|
629
|
+
method="GET",
|
|
630
|
+
headers={"Authorization": "Bearer token"},
|
|
631
|
+
params={"limit": 100}
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
# File extraction (JSON, CSV, Parquet)
|
|
635
|
+
file = FileExtractor(
|
|
636
|
+
file_path="data/input.json",
|
|
637
|
+
file_format="json"
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
# Database extraction
|
|
641
|
+
db = DatabaseExtractor(
|
|
642
|
+
connection_string="postgresql://user:pass@host/db",
|
|
643
|
+
query="SELECT * FROM users WHERE active = true"
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
# Cloud storage extraction (S3, GCS, Azure)
|
|
647
|
+
cloud = CloudStorageExtractor(
|
|
648
|
+
provider="s3",
|
|
649
|
+
bucket="my-bucket",
|
|
650
|
+
key="data/users.json",
|
|
651
|
+
credentials={"aws_access_key_id": "...", "aws_secret_access_key": "..."}
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
# Config-driven extraction
|
|
655
|
+
http_from_config = HTTPExtractor.from_config({
|
|
656
|
+
"base_url": "https://api.example.com",
|
|
657
|
+
"api_endpoint": "/v1/users",
|
|
658
|
+
"method": "GET"
|
|
659
|
+
})`,arguments:[{name:"HTTPExtractor",type:"class",description:"Extract from HTTP APIs with pagination support",required:!1},{name:"FileExtractor",type:"class",description:"Extract from local files (JSON, CSV, Parquet, JSONL)",required:!1},{name:"DatabaseExtractor",type:"class",description:"Extract from databases via SQL query",required:!1},{name:"CloudStorageExtractor",type:"class",description:"Extract from cloud storage (S3, GCS, Azure Blob)",required:!1}],returns:{type:"Extractor",description:"Extractor instance implementing the Extractor protocol"}},{id:"etl_loaders",title:"ETL Loaders",description:"Built-in loaders for different destinations",method:"PostgresLoader, DatabaseLoader, FileLoader, CloudStorageLoader",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import PostgresLoader, FileLoader, CloudStorageLoader
|
|
660
|
+
|
|
661
|
+
# PostgreSQL/Database loading
|
|
662
|
+
postgres = PostgresLoader(
|
|
663
|
+
connection_string="postgresql://user:pass@host/db",
|
|
664
|
+
table="users",
|
|
665
|
+
schema="public",
|
|
666
|
+
if_exists="append", # 'append', 'replace', 'fail'
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
# File loading
|
|
670
|
+
file = FileLoader(
|
|
671
|
+
file_path="output/users.json",
|
|
672
|
+
file_format="json",
|
|
673
|
+
mode="w"
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
# Cloud storage loading
|
|
677
|
+
cloud = CloudStorageLoader(
|
|
678
|
+
provider="s3",
|
|
679
|
+
bucket="my-bucket",
|
|
680
|
+
key="output/users.parquet",
|
|
681
|
+
file_format="parquet"
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
# Use in pipeline
|
|
685
|
+
pipeline = (
|
|
686
|
+
Pipeline(HTTPExtractor(url="..."))
|
|
687
|
+
| Rename({"old": "new"})
|
|
688
|
+
| PostgresLoader(connection_string="...", table="users")
|
|
689
|
+
)`,arguments:[{name:"PostgresLoader",type:"class",description:"Load to PostgreSQL database",required:!1},{name:"DatabaseLoader",type:"class",description:"Generic database loader (supports various databases)",required:!1},{name:"FileLoader",type:"class",description:"Load to local files (JSON, CSV, Parquet)",required:!1},{name:"CloudStorageLoader",type:"class",description:"Load to cloud storage (S3, GCS, Azure Blob)",required:!1}],returns:{type:"Loader",description:"Loader instance implementing the Loader protocol"}},{id:"etl_orchestrator",title:"ETL Orchestrator (Legacy)",description:"Config-driven ETL orchestration from contract directories. Use Pipeline class for new projects.",method:"ETLOrchestrator(contract_dir=None, contract_file=None, extract_config=None, transform_config=None, load_config=None, config_context=None, ...)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator import ETLOrchestrator
|
|
690
|
+
|
|
691
|
+
orchestrator = ETLOrchestrator(contract_dir="path/to/contract_dir")
|
|
692
|
+
result = await orchestrator.run()
|
|
693
|
+
|
|
694
|
+
# With config overrides
|
|
695
|
+
orchestrator = ETLOrchestrator(
|
|
696
|
+
contract_dir="contracts/user",
|
|
697
|
+
extract_config={"base_url": "https://api.example.com", "api_endpoint": "/v1/data"},
|
|
698
|
+
transform_config={"rename": {"oldName": "new_name"}},
|
|
699
|
+
load_config={"target_table": "users", "schema_name": "public"}
|
|
700
|
+
)
|
|
701
|
+
result = await orchestrator.run(dry_run=False)`,arguments:[{name:"contract_dir",type:"Optional[str]",description:"Directory containing schema and extract/transform/load configs",required:!1},{name:"contract_file",type:"Optional[str]",description:"Path to a complete contract file (YAML or JSON)",required:!1},{name:"extract_config",type:"Optional[Dict[str, Any]]",description:"Extract configuration dictionary (overrides extract.yaml when provided)",required:!1},{name:"transform_config",type:"Optional[Dict[str, Any]]",description:"Transform configuration dictionary (overrides transform.yaml when provided)",required:!1},{name:"load_config",type:"Optional[Dict[str, Any]]",description:"Load configuration dictionary (overrides load.yaml when provided)",required:!1},{name:"config_context",type:"Optional[Dict[str, Any]]",description:"Context for resolving ${VAR} placeholders in config files",required:!1}],returns:{type:"ETLOrchestrator",description:"Orchestrator instance; call .run(**kwargs) to execute the pipeline"}},{id:"create_orchestrator",title:"Create Orchestrator",description:"Factory helper that creates an ETLOrchestrator instance from a contract directory.",method:"create_orchestrator(contract_dir=None, **kwargs) -> ETLOrchestrator",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator import create_orchestrator
|
|
702
|
+
|
|
703
|
+
orchestrator = create_orchestrator(contract_dir="configs/user_pipeline")
|
|
704
|
+
result = await orchestrator.run()`,arguments:[{name:"contract_dir",type:"Optional[str]",description:"Directory containing ETL configs (extract.yaml, transform.yaml, load.yaml)",required:!1},{name:"**kwargs",type:"Any",description:"Additional arguments passed through to ETLOrchestrator",required:!1}],returns:{type:"ETLOrchestrator",description:"Orchestrator instance configured for the given contract directory"}},{id:"pipeline_factory",title:"Pipeline Factory",description:"Discover pipelines by scanning a config root for subdirectories that contain extract.yaml, transform.yaml, and load.yaml, and create orchestrators by pipeline name.",method:'PipelineFactory(config_root="configs", excluded_dirs=None, required_files=None)',apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator import PipelineFactory
|
|
705
|
+
|
|
706
|
+
factory = PipelineFactory(config_root="configs")
|
|
707
|
+
names = factory.get_pipeline_names()
|
|
708
|
+
orchestrator = factory.create_orchestrator(
|
|
709
|
+
pipeline_name="fmp_key_metrics",
|
|
710
|
+
config_context={"FMP_API_KEY": "your_key"}
|
|
711
|
+
)
|
|
712
|
+
result = await orchestrator.run(symbol="AAPL")`,arguments:[{name:"config_root",type:"Union[str, Path]",description:"Root directory to scan for pipeline config directories",required:!1,default:'"configs"'},{name:"excluded_dirs",type:"Optional[List[str]]",description:"Directory names to skip during discovery (e.g. old, templates)",required:!1},{name:"required_files",type:"Optional[List[str]]",description:"Files each pipeline directory must contain (default: extract.yaml, transform.yaml, load.yaml)",required:!1}],returns:{type:"PipelineFactory",description:"Factory with get_pipeline_names(), get_contract_dir(name), and create_orchestrator(name, ...)"}},{id:"extract_with_pagination_streaming",title:"Extract with Pagination Streaming",description:"Async generator that yields batches of records. Dispatches to the appropriate extractor by source_type (http, file, database, cloud_storage) via ExtractorFactory.",method:"extract_with_pagination_streaming(extract_config, params, headers, contract_dir=None, batch_size=1000, max_records=None, config_context=None)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator.extractors import extract_with_pagination_streaming
|
|
713
|
+
|
|
714
|
+
async for batch in extract_with_pagination_streaming(
|
|
715
|
+
extract_config={"source_type": "file", "file_path": "data.json"},
|
|
716
|
+
params={},
|
|
717
|
+
headers={},
|
|
718
|
+
batch_size=500
|
|
719
|
+
):
|
|
720
|
+
print(len(batch))`,arguments:[{name:"extract_config",type:"Dict[str, Any]",description:"Extract configuration (source_type is auto-detected if omitted)",required:!0},{name:"params",type:"Dict[str, Any]",description:"Request or query parameters (e.g. for HTTP extractions)",required:!0},{name:"headers",type:"Dict[str, Any]",description:"Request headers (e.g. for HTTP extractions)",required:!0},{name:"contract_dir",type:"Optional[Any]",description:"Contract directory used for variable resolution in configs",required:!1},{name:"batch_size",type:"int",description:"Number of records to yield per batch",required:!1,default:"1000"},{name:"max_records",type:"Optional[int]",description:"Maximum total records to extract (None for no limit)",required:!1},{name:"config_context",type:"Optional[Dict[str, Any]]",description:"Context for resolving ${VAR} placeholders in configs",required:!1}],returns:{type:"AsyncIterator[List[Dict[str, Any]]]",description:"Async iterator yielding batches of record dictionaries"}},{id:"apply_transforms",title:"Apply Transforms",description:"Run the transform pipeline on a list of records. Order: simple operations (rename, convert, defaults, add, select, drop) → JSONata → custom function.",method:"apply_transforms(data, transform_config, **kwargs) -> List[Dict[str, Any]]",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator.transformers import apply_transforms
|
|
721
|
+
|
|
722
|
+
config = {
|
|
723
|
+
"transform": {"rename": {"oldName": "new_name"}, "convert": {"price": "float"}},
|
|
724
|
+
"jsonata": {"expression": "$.{\\"x\\": x * 2}", "mode": "record"}
|
|
725
|
+
}
|
|
726
|
+
out = apply_transforms(records, config)`,arguments:[{name:"data",type:"List[Dict[str, Any]]",description:"Input list of record dictionaries to transform",required:!0},{name:"transform_config",type:"Dict[str, Any]",description:"Transform configuration (transform, jsonata, and/or custom_function)",required:!0},{name:"**kwargs",type:"Any",description:"Additional keyword arguments passed to the custom_function step when configured",required:!1}],returns:{type:"List[Dict[str, Any]]",description:"Transformed list of record dictionaries"}},{id:"extractor_factory",title:"Extractor Factory",description:"Resolve source_type from extract config and return the appropriate extractor (HTTPExtractor, FileExtractor, DatabaseExtractor, or CloudStorageExtractor).",method:"ExtractorFactory.get_extractor(extract_config) -> BaseExtractor",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator.extractors import ExtractorFactory, get_extractor
|
|
727
|
+
|
|
728
|
+
extractor = get_extractor({"source_type": "http", "base_url": "https://api.example.com", "api_endpoint": "/v1/data"})
|
|
729
|
+
# or
|
|
730
|
+
extractor = ExtractorFactory.get_extractor(extract_config)
|
|
731
|
+
# Register a custom extractor
|
|
732
|
+
ExtractorFactory.register_extractor("kafka", KafkaExtractor)`,arguments:[{name:"extract_config",type:"Dict[str, Any]",description:"Extract configuration; source_type is auto-detected from config if not specified",required:!0}],returns:{type:"BaseExtractor",description:"Extractor instance (HTTPExtractor, FileExtractor, DatabaseExtractor, or CloudStorageExtractor)"}},{id:"load_to_file",title:"Load to File and Cloud Storage",description:"Write transformed data to a local file (JSON, CSV, Parquet, JSONL) or to cloud storage (S3, GCS, Azure). Used when load_config has destination_type file or cloud_storage.",method:"load_to_file(data, load_config, contract_dir=None, config_context=None)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator.loaders import load_to_file, load_to_cloud_storage
|
|
733
|
+
|
|
734
|
+
# Local file
|
|
735
|
+
result = load_to_file(
|
|
736
|
+
data=transformed_records,
|
|
737
|
+
load_config={"destination_type": "file", "file_path": "out.json", "format": "json"}
|
|
738
|
+
)
|
|
739
|
+
# Cloud (S3 / GCS / Azure)
|
|
740
|
+
result = load_to_cloud_storage(data, load_config, contract_dir=contract_dir)`,arguments:[{name:"data",type:"List[Dict[str, Any]]",description:"List of record dictionaries to write",required:!0},{name:"load_config",type:"Dict[str, Any]",description:"Load configuration (destination_type, file_path or storage, format, etc.)",required:!0},{name:"contract_dir",type:"Optional[Any]",description:"Contract directory used for variable resolution in load_config",required:!1},{name:"config_context",type:"Optional[Dict[str, Any]]",description:"Context for resolving ${VAR} placeholders in load_config",required:!1}],returns:{type:"Dict[str, Any]",description:"Result dictionary with keys such as written and total"}},{id:"generate_etl_config",title:"Generate ETL Config",description:"Generate ETL config dictionaries (extract, transform, load) from contract artifacts or from the metadata store. Use generate_etl_config_from_contract or generate_etl_config_from_store.",method:"generate_etl_config_from_contract(contract_dict, extraction_config=None, ...)",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter.etl_generator import generate_etl_config_from_contract, generate_etl_config_from_store
|
|
741
|
+
|
|
742
|
+
# From contract dictionary
|
|
743
|
+
config = generate_etl_config_from_contract(
|
|
744
|
+
contract_dict,
|
|
745
|
+
extraction_config={"provider_name": "fmp", "api_endpoint": "/api/v3/profile/AAPL"}
|
|
746
|
+
)
|
|
747
|
+
# From metadata store
|
|
748
|
+
config = generate_etl_config_from_store(store, schema_title="user_schema", ...)`,arguments:[{name:"contract_dict",type:"Dict[str, Any]",description:"Contract dictionary (used by generate_etl_config_from_contract)",required:!1},{name:"store",type:"MetadataStoreClient",description:"Metadata store client (used by generate_etl_config_from_store)",required:!1},{name:"schema_title",type:"str",description:"Schema or title identifier in the store",required:!1},{name:"extraction_config",type:"Optional[Dict[str, Any]]",description:"Extraction hints such as provider name and API endpoint",required:!1}],returns:{type:"Dict[str, Any]",description:"Dictionary containing extract, transform, and load configuration sections"}},{id:"docs_generator",title:"DocsGenerator Class",description:"Generate human-readable documentation from data contracts. Supports Markdown and HTML output formats.",method:"DocsGenerator(renderer=MarkdownRenderer())",apiEndpoint:"/api/v1/docs/generate",apiMethod:"POST",exampleRequest:{contract:{schema:{type:"object",title:"UserProfile",version:"1.0.0",properties:{name:{type:"string",description:"User name"},email:{type:"string",format:"email"}},required:["name"]}},format:"markdown"},exampleCode:`from pycharter import DocsGenerator, generate_docs, MarkdownRenderer, HTMLRenderer
|
|
749
|
+
|
|
750
|
+
# Quick generation
|
|
751
|
+
contract = parse_contract_file("contract.yaml")
|
|
752
|
+
markdown = generate_docs(contract)
|
|
753
|
+
html = generate_docs(contract, format="html")
|
|
754
|
+
|
|
755
|
+
# Custom generator
|
|
756
|
+
generator = DocsGenerator(renderer=MarkdownRenderer())
|
|
757
|
+
docs = generator.generate(contract)
|
|
758
|
+
schema_section = generator.generate_schema_section(contract.schema)`,arguments:[{name:"renderer",type:"DocsRenderer",description:"Renderer for output format (MarkdownRenderer or HTMLRenderer)",required:!1,default:"MarkdownRenderer()"}],returns:{type:"DocsGenerator",description:"DocsGenerator instance for generating documentation"}},{id:"generate_docs",title:"generate_docs() Function",description:"Convenience function to generate documentation from a contract in one call",method:'generate_docs(contract, format="markdown", **kwargs)',apiEndpoint:"/api/v1/docs/generate",apiMethod:"POST",exampleRequest:{contract:{schema:{type:"object",title:"Product",version:"1.0.0",properties:{id:{type:"string"},price:{type:"number",minimum:0}}},coercion_rules:{price:"to_float"}},format:"html",include_schema:!0,include_coercions:!0},exampleCode:`from pycharter import generate_docs, parse_contract_file
|
|
759
|
+
|
|
760
|
+
contract = parse_contract_file("contract.yaml")
|
|
761
|
+
|
|
762
|
+
# Generate Markdown
|
|
763
|
+
markdown = generate_docs(contract)
|
|
764
|
+
|
|
765
|
+
# Generate HTML
|
|
766
|
+
html = generate_docs(contract, format="html")
|
|
767
|
+
|
|
768
|
+
# Control sections included
|
|
769
|
+
docs = generate_docs(
|
|
770
|
+
contract,
|
|
771
|
+
format="markdown",
|
|
772
|
+
include_schema=True,
|
|
773
|
+
include_coercions=True,
|
|
774
|
+
include_validations=False,
|
|
775
|
+
include_metadata=True
|
|
776
|
+
)`,arguments:[{name:"contract",type:"ContractMetadata | Dict",description:"ContractMetadata object or contract dictionary",required:!0},{name:"format",type:"str",description:'Output format: "markdown" or "html"',required:!1,default:'"markdown"'},{name:"include_schema",type:"bool",description:"Include schema fields section",required:!1,default:"True"},{name:"include_coercions",type:"bool",description:"Include coercion rules section",required:!1,default:"True"},{name:"include_validations",type:"bool",description:"Include validation rules section",required:!1,default:"True"},{name:"include_metadata",type:"bool",description:"Include metadata/ownership section",required:!1,default:"True"}],returns:{type:"str",description:"Generated documentation as string"}},{id:"metrics_collector",title:"MetricsCollector Class",description:"Collect and query validation metrics over time. Track quality trends and aggregate statistics.",method:"MetricsCollector(store=InMemoryMetricsStore())",apiEndpoint:"/api/v1/quality/tracking",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import MetricsCollector, InMemoryMetricsStore, SQLiteMetricsStore
|
|
777
|
+
|
|
778
|
+
# Create collector with in-memory store (development)
|
|
779
|
+
store = InMemoryMetricsStore()
|
|
780
|
+
collector = MetricsCollector(store)
|
|
781
|
+
|
|
782
|
+
# Or use SQLite for persistence
|
|
783
|
+
store = SQLiteMetricsStore("metrics.db")
|
|
784
|
+
collector = MetricsCollector(store)
|
|
785
|
+
|
|
786
|
+
# Record validation results
|
|
787
|
+
result = validator.validate(data)
|
|
788
|
+
collector.record(result, schema_name="users", version="1.0.0", duration_ms=50.0)
|
|
789
|
+
|
|
790
|
+
# Query metrics
|
|
791
|
+
metrics = collector.query(schema_name="users", limit=100)
|
|
792
|
+
|
|
793
|
+
# Get aggregated summary
|
|
794
|
+
summary = collector.get_summary("users", window_hours=24)
|
|
795
|
+
print(f"Avg validity rate: {summary.avg_validity_rate}")`,arguments:[{name:"store",type:"MetricsStore",description:"Storage backend (InMemoryMetricsStore or SQLiteMetricsStore)",required:!1,default:"InMemoryMetricsStore()"}],returns:{type:"MetricsCollector",description:"MetricsCollector instance for tracking validation metrics"}},{id:"validation_metric",title:"ValidationMetric Model",description:"Data model for a single validation run metric. Contains all metrics captured from validation.",method:"ValidationMetric(schema_name, version, ...)",apiEndpoint:"/api/v1/quality/tracking",apiMethod:"POST",exampleRequest:{schema_name:"users",version:"1.0.0",record_count:100,valid_count:95,error_count:5,completeness:.98,duration_ms:150.5},exampleCode:`from pycharter import ValidationMetric
|
|
796
|
+
from datetime import datetime
|
|
797
|
+
|
|
798
|
+
# Metrics are typically created automatically by MetricsCollector
|
|
799
|
+
# but can be created manually:
|
|
800
|
+
metric = ValidationMetric(
|
|
801
|
+
schema_name="users",
|
|
802
|
+
version="1.0.0",
|
|
803
|
+
timestamp=datetime.utcnow(),
|
|
804
|
+
record_count=100,
|
|
805
|
+
valid_count=95,
|
|
806
|
+
error_count=5,
|
|
807
|
+
validity_rate=0.95,
|
|
808
|
+
completeness=0.98,
|
|
809
|
+
field_completeness={"email": 1.0, "phone": 0.85},
|
|
810
|
+
duration_ms=150.5,
|
|
811
|
+
errors_by_type={"missing_required": 3, "type_error": 2}
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
# Convert to dict for API/storage
|
|
815
|
+
data = metric.to_dict()`,arguments:[{name:"schema_name",type:"str",description:"Name of the schema validated against",required:!0},{name:"version",type:"str",description:"Version of the schema",required:!0},{name:"record_count",type:"int",description:"Number of records validated",required:!1,default:"0"},{name:"valid_count",type:"int",description:"Number of valid records",required:!1,default:"0"},{name:"validity_rate",type:"float",description:"Ratio of valid records (0.0 to 1.0)",required:!1,default:"1.0"},{name:"completeness",type:"float",description:"Overall data completeness (0.0 to 1.0)",required:!1,default:"1.0"},{name:"duration_ms",type:"float",description:"Validation duration in milliseconds",required:!1,default:"0.0"}],returns:{type:"ValidationMetric",description:"ValidationMetric dataclass instance"}},{id:"metrics_summary",title:"MetricsSummary Model",description:"Aggregated metrics summary for a schema over a time period. Used for trend analysis.",method:"collector.get_summary(schema_name, window_hours=24)",apiEndpoint:"/api/v1/quality/tracking/{schema_name}/summary",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter import MetricsCollector, InMemoryMetricsStore
|
|
816
|
+
|
|
817
|
+
collector = MetricsCollector(InMemoryMetricsStore())
|
|
818
|
+
|
|
819
|
+
# Get summary for last 24 hours
|
|
820
|
+
summary = collector.get_summary("users", window_hours=24)
|
|
821
|
+
|
|
822
|
+
print(f"Total validations: {summary.total_validations}")
|
|
823
|
+
print(f"Average validity rate: {summary.avg_validity_rate:.2%}")
|
|
824
|
+
print(f"Min validity rate: {summary.min_validity_rate:.2%}")
|
|
825
|
+
print(f"Max validity rate: {summary.max_validity_rate:.2%}")
|
|
826
|
+
print(f"Total records: {summary.total_records}")
|
|
827
|
+
print(f"Top errors: {summary.top_error_types}")`,arguments:[{name:"schema_name",type:"str",description:"Name of the schema to summarize",required:!0},{name:"window_hours",type:"int",description:"Number of hours to look back",required:!1,default:"24"}],returns:{type:"MetricsSummary",description:"MetricsSummary with aggregated statistics"}},{id:"metrics_export",title:"Export Metrics",description:"Export validation metrics in various formats: JSON, Prometheus, or CSV.",method:"export_json(metrics) | export_prometheus(metrics) | export_csv(metrics)",apiEndpoint:"/api/v1/quality/tracking/export",apiMethod:"GET",exampleRequest:null,exampleCode:`from pycharter.quality.tracking import (
|
|
828
|
+
export_json, export_prometheus, export_csv, MetricsCollector
|
|
829
|
+
)
|
|
830
|
+
|
|
831
|
+
collector = MetricsCollector()
|
|
832
|
+
metrics = collector.query(schema_name="users")
|
|
833
|
+
|
|
834
|
+
# Export as JSON
|
|
835
|
+
json_data = export_json(metrics, pretty=True)
|
|
836
|
+
|
|
837
|
+
# Export as Prometheus text format (for scraping)
|
|
838
|
+
prom_data = export_prometheus(metrics, prefix="pycharter")
|
|
839
|
+
|
|
840
|
+
# Export as CSV
|
|
841
|
+
csv_data = export_csv(metrics, include_header=True)
|
|
842
|
+
|
|
843
|
+
# Via API
|
|
844
|
+
# GET /api/v1/quality/tracking/export?format=prometheus&schema_name=users`,arguments:[{name:"metrics",type:"List[ValidationMetric]",description:"List of metrics to export",required:!0},{name:"format",type:"str",description:'Export format: "json", "prometheus", or "csv"',required:!1,default:'"json"'}],returns:{type:"str",description:"Exported metrics as string in specified format"}},{id:"validator_with_tracking",title:"Validator with Tracking",description:"Integrate metrics tracking into validators using ValidatorBuilder.with_tracking()",method:"ValidatorBuilder().with_tracking(collector).build()",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import ValidatorBuilder
|
|
845
|
+
from pycharter.quality.tracking import MetricsCollector, InMemoryMetricsStore
|
|
846
|
+
|
|
847
|
+
# Create metrics collector
|
|
848
|
+
store = InMemoryMetricsStore()
|
|
849
|
+
collector = MetricsCollector(store)
|
|
850
|
+
|
|
851
|
+
# Build validator with automatic tracking
|
|
852
|
+
validator = (
|
|
853
|
+
ValidatorBuilder()
|
|
854
|
+
.from_directory("contracts/users")
|
|
855
|
+
.with_tracking(collector) # Enable tracking
|
|
856
|
+
.with_quality_checks()
|
|
857
|
+
.build()
|
|
858
|
+
)
|
|
859
|
+
|
|
860
|
+
# Each validation automatically records metrics
|
|
861
|
+
result = validator.validate({"name": "Alice", "email": "alice@example.com"})
|
|
862
|
+
|
|
863
|
+
# Batch validation also tracks
|
|
864
|
+
results = validator.validate_batch([...])
|
|
865
|
+
|
|
866
|
+
# Query the recorded metrics
|
|
867
|
+
metrics = collector.query(schema_name="users")
|
|
868
|
+
summary = collector.get_summary("users")`,arguments:[{name:"collector",type:"MetricsCollector",description:"MetricsCollector instance for recording metrics",required:!0}],returns:{type:"ValidatorBuilder",description:"Self for method chaining"}},{id:"check_compatibility",title:"check_compatibility() Function",description:"Check if two schemas are compatible according to the specified mode (backward, forward, or full).",method:'check_compatibility(old_schema, new_schema, mode="backward")',apiEndpoint:"/api/v1/evolution/check",apiMethod:"POST",exampleRequest:{old_schema:{type:"object",properties:{name:{type:"string"}},required:["name"]},new_schema:{type:"object",properties:{name:{type:"string"},email:{type:"string"}},required:["name"]},mode:"backward"},exampleCode:`from pycharter import check_compatibility, CompatibilityMode
|
|
869
|
+
|
|
870
|
+
old_schema = {
|
|
871
|
+
"type": "object",
|
|
872
|
+
"properties": {"name": {"type": "string"}},
|
|
873
|
+
"required": ["name"]
|
|
874
|
+
}
|
|
875
|
+
new_schema = {
|
|
876
|
+
"type": "object",
|
|
877
|
+
"properties": {
|
|
878
|
+
"name": {"type": "string"},
|
|
879
|
+
"email": {"type": "string"} # New optional field
|
|
880
|
+
},
|
|
881
|
+
"required": ["name"]
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
# Check backward compatibility (new consumer, old data)
|
|
885
|
+
result = check_compatibility(old_schema, new_schema, mode="backward")
|
|
886
|
+
print(f"Compatible: {result.compatible}")
|
|
887
|
+
|
|
888
|
+
if not result.compatible:
|
|
889
|
+
print(f"Issues: {result.issues}")
|
|
890
|
+
|
|
891
|
+
# Check forward compatibility (old consumer, new data)
|
|
892
|
+
result = check_compatibility(old_schema, new_schema, mode="forward")
|
|
893
|
+
|
|
894
|
+
# Check full compatibility (both directions)
|
|
895
|
+
result = check_compatibility(old_schema, new_schema, mode="full")`,arguments:[{name:"old_schema",type:"Dict[str, Any]",description:"The existing/original schema",required:!0},{name:"new_schema",type:"Dict[str, Any]",description:"The new schema to check",required:!0},{name:"mode",type:"str | CompatibilityMode",description:'Compatibility mode: "backward", "forward", or "full"',required:!1,default:'"backward"'}],returns:{type:"CompatibilityResult",description:"CompatibilityResult with compatible status, diff, issues, and warnings"}},{id:"compute_diff",title:"compute_diff() Function",description:"Compute detailed diff between two JSON Schema versions. Returns all changes categorized by type.",method:"compute_diff(old_schema, new_schema)",apiEndpoint:"/api/v1/evolution/diff",apiMethod:"POST",exampleRequest:{old_schema:{type:"object",properties:{name:{type:"string"},age:{type:"integer",minimum:0}}},new_schema:{type:"object",properties:{name:{type:"string"},age:{type:"integer",minimum:18},email:{type:"string"}}}},exampleCode:`from pycharter import compute_diff, ChangeType
|
|
896
|
+
|
|
897
|
+
old_schema = {
|
|
898
|
+
"type": "object",
|
|
899
|
+
"properties": {
|
|
900
|
+
"name": {"type": "string"},
|
|
901
|
+
"age": {"type": "integer", "minimum": 0}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
new_schema = {
|
|
905
|
+
"type": "object",
|
|
906
|
+
"properties": {
|
|
907
|
+
"name": {"type": "string"},
|
|
908
|
+
"age": {"type": "integer", "minimum": 18}, # Changed
|
|
909
|
+
"email": {"type": "string"} # Added
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
diff = compute_diff(old_schema, new_schema)
|
|
914
|
+
|
|
915
|
+
print(f"Total changes: {len(diff.changes)}")
|
|
916
|
+
print(f"Breaking changes: {len(diff.breaking_changes)}")
|
|
917
|
+
|
|
918
|
+
for change in diff.changes:
|
|
919
|
+
status = "BREAKING" if change.breaking else "OK"
|
|
920
|
+
print(f"[{status}] {change.change_type.value}: {change.path}")
|
|
921
|
+
print(f" {change.message}")
|
|
922
|
+
|
|
923
|
+
# Access specific change types
|
|
924
|
+
for addition in diff.additions:
|
|
925
|
+
print(f"Added: {addition.path}")`,arguments:[{name:"old_schema",type:"Dict[str, Any]",description:"Original schema",required:!0},{name:"new_schema",type:"Dict[str, Any]",description:"New schema",required:!0}],returns:{type:"SchemaDiff",description:"SchemaDiff with changes, breaking_changes, additions, removals, modifications"}},{id:"compatibility_modes",title:"Compatibility Modes",description:"Understanding the three compatibility modes: backward, forward, and full.",method:"CompatibilityMode.BACKWARD | FORWARD | FULL",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import CompatibilityMode, check_compatibility
|
|
926
|
+
|
|
927
|
+
# BACKWARD: New schema can read old data
|
|
928
|
+
# Use when: Upgrading consumers before producers
|
|
929
|
+
# Safe: Add optional fields, remove fields, widen types
|
|
930
|
+
# Breaking: Add required fields, narrow types, remove enum values
|
|
931
|
+
result = check_compatibility(old, new, mode=CompatibilityMode.BACKWARD)
|
|
932
|
+
|
|
933
|
+
# FORWARD: Old schema can read new data
|
|
934
|
+
# Use when: Upgrading producers before consumers
|
|
935
|
+
# Safe: Remove optional fields, add fields
|
|
936
|
+
# Breaking: Remove required fields, add enum values, widen types
|
|
937
|
+
result = check_compatibility(old, new, mode=CompatibilityMode.FORWARD)
|
|
938
|
+
|
|
939
|
+
# FULL: Both backward and forward compatible
|
|
940
|
+
# Use when: No control over upgrade order
|
|
941
|
+
# Safe: Only metadata changes, add fields with defaults
|
|
942
|
+
# Breaking: Most schema changes
|
|
943
|
+
result = check_compatibility(old, new, mode=CompatibilityMode.FULL)`,arguments:[{name:"BACKWARD",type:"CompatibilityMode",description:"New consumers can read data from old producers",required:!1},{name:"FORWARD",type:"CompatibilityMode",description:"Old consumers can read data from new producers",required:!1},{name:"FULL",type:"CompatibilityMode",description:"Both backward and forward compatible",required:!1}],returns:{type:"CompatibilityMode",description:"Enum for specifying compatibility checking mode"}},{id:"change_types",title:"Change Types",description:"All schema change types detected by compute_diff()",method:"ChangeType enum values",apiEndpoint:null,apiMethod:"N/A",exampleRequest:null,exampleCode:`from pycharter import ChangeType, compute_diff
|
|
944
|
+
|
|
945
|
+
diff = compute_diff(old_schema, new_schema)
|
|
946
|
+
|
|
947
|
+
# Field changes
|
|
948
|
+
# ChangeType.FIELD_ADDED - New field added
|
|
949
|
+
# ChangeType.FIELD_REMOVED - Field removed
|
|
950
|
+
|
|
951
|
+
# Type changes
|
|
952
|
+
# ChangeType.TYPE_CHANGED - Type completely changed
|
|
953
|
+
# ChangeType.TYPE_WIDENED - Type widened (int -> number) - safe for backward
|
|
954
|
+
# ChangeType.TYPE_NARROWED - Type narrowed (number -> int) - breaking
|
|
955
|
+
|
|
956
|
+
# Constraint changes
|
|
957
|
+
# ChangeType.CONSTRAINT_ADDED - New constraint (min, max, pattern, etc.)
|
|
958
|
+
# ChangeType.CONSTRAINT_REMOVED - Constraint removed
|
|
959
|
+
# ChangeType.CONSTRAINT_MODIFIED - Constraint value changed
|
|
960
|
+
|
|
961
|
+
# Required/optional changes
|
|
962
|
+
# ChangeType.REQUIRED_ADDED - Field became required - breaking
|
|
963
|
+
# ChangeType.REQUIRED_REMOVED - Field became optional - safe
|
|
964
|
+
|
|
965
|
+
# Enum changes
|
|
966
|
+
# ChangeType.ENUM_VALUE_ADDED - New enum value
|
|
967
|
+
# ChangeType.ENUM_VALUE_REMOVED - Enum value removed - breaking
|
|
968
|
+
|
|
969
|
+
# Filter by type
|
|
970
|
+
type_changes = [c for c in diff.changes if c.change_type == ChangeType.TYPE_CHANGED]`,arguments:[],returns:{type:"ChangeType",description:"Enum with all possible schema change types"}}];function x({method:o}){let[d,l]=(0,r.useState)(o.exampleRequest?JSON.stringify(o.exampleRequest,null,2):""),[m,p]=(0,r.useState)(null),[u,_]=(0,r.useState)(null),[h,f]=(0,r.useState)(!1),[y,g]=(0,r.useState)(!1);if(!o.apiEndpoint)return null;let v=o.apiEndpoint?.includes("/upload")??!1,x=async()=>{f(!0),_(null);try{let t,r,{getApiBaseUrl:a}=await e.A(36909),i=a(),n=o.apiEndpoint;if(!n){_({success:!1,error:"This method does not have an API endpoint (Python-only)"}),f(!1);return}n.includes("{schema_id}")&&(n=n.replace("{schema_id}","user_schema"));let s=`${i}${n}`;if("GET"===o.apiMethod)t=await fetch(s);else if(v){if(!m){_({success:!1,error:"Please select a file to upload"}),f(!1);return}let e=new FormData;e.append("file",m),n.includes("/contracts/parse/upload")&&e.append("validate","true"),t=await fetch(s,{method:o.apiMethod,body:e})}else{let e=d?JSON.parse(d):{};t=await fetch(s,{method:o.apiMethod,headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})}let c=t.headers.get("content-type");r=c&&c.includes("application/json")?await t.json():{message:await t.text()},t.ok?_({success:!0,data:r}):_({success:!1,error:r.detail||r.message||`HTTP ${t.status}: ${t.statusText}`})}catch(t){let e=t.message;e.includes("JSON")&&(e="Invalid JSON in request body. Please check your input."),_({success:!1,error:e||"Failed to test API"})}finally{f(!1)}};return(0,t.jsxs)("div",{className:"border rounded-lg p-4 bg-muted/30",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,t.jsx)("h5",{className:"text-sm font-semibold",children:"Test API"}),o.apiEndpoint&&(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)(a.Button,{size:"sm",variant:"outline",onClick:()=>{var e;return o.apiEndpoint&&(e=o.apiEndpoint,void(navigator.clipboard.writeText(e),g(!0),setTimeout(()=>g(!1),2e3)))},className:"h-7",disabled:!o.apiEndpoint,children:y?(0,t.jsx)(c,{className:"h-3 w-3"}):(0,t.jsx)(s,{className:"h-3 w-3"})}),(0,t.jsx)(a.Button,{size:"sm",onClick:x,disabled:h||"GET"!==o.apiMethod&&!v&&!d||v&&!m,className:"h-7",children:h?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{className:"mr-1",children:(0,t.jsx)(i.default,{size:"sm"})}),"Testing..."]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n,{className:"h-3 w-3 mr-1"}),"Test"]})})]})]}),o.apiEndpoint&&"GET"!==o.apiMethod&&(0,t.jsx)("div",{className:"mb-3",children:v?(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"block text-xs font-medium mb-1",children:"Upload File"}),(0,t.jsx)("input",{type:"file",accept:".yaml,.yml,.json",onChange:e=>p(e.target.files?.[0]||null),className:"w-full px-2 py-1 border rounded text-xs bg-background"}),m&&(0,t.jsxs)("div",{className:"mt-1 text-xs text-muted-foreground",children:["Selected: ",m.name," (",(m.size/1024).toFixed(2)," KB)"]})]}):(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"block text-xs font-medium mb-1",children:"Request Body (JSON)"}),(0,t.jsx)("textarea",{value:d,onChange:e=>l(e.target.value),rows:6,className:"w-full px-2 py-1 border rounded text-xs font-mono bg-background",placeholder:"Enter JSON request body..."})]})}),o.apiEndpoint&&(0,t.jsxs)("div",{className:"text-xs text-muted-foreground mb-2",children:[(0,t.jsx)("span",{className:"font-mono font-semibold",children:o.apiMethod})," ",o.apiEndpoint]}),u&&(0,t.jsx)("div",{className:"mt-3",children:u.success?(0,t.jsxs)("div",{className:"bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded p-2",children:[(0,t.jsx)("div",{className:"text-xs font-semibold text-green-800 dark:text-green-200 mb-1",children:"Success"}),(0,t.jsx)("pre",{className:"text-xs overflow-x-auto text-green-700 dark:text-green-300",children:JSON.stringify(u.data,null,2)})]}):(0,t.jsxs)("div",{className:"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded p-2",children:[(0,t.jsx)("div",{className:"text-xs font-semibold text-red-800 dark:text-red-200 mb-1",children:"Error"}),(0,t.jsx)("div",{className:"text-xs text-red-700 dark:text-red-300",children:u.error})]})})]})}function b(){let[e,a]=(0,r.useState)("contract-management"),i={"contract-management":["parse_contract","parse_contract_file","build_contract","build_contract_from_store"],"metadata-store":["store_schema","get_schema","list_schemas","store_metadata","get_metadata","store_coercion_rules","get_coercion_rules","store_validation_rules","get_validation_rules","get_complete_schema"],"model-generator":["generate_model","generate_model_file","from_dict","from_file","from_json","from_url","model_to_schema","to_dict","to_json","to_file"],validation:["validator_class","validator_builder","validation_quality_metrics","error_handling","validate_with_store","validate_with_contract","validate_batch_with_store","validate_batch_with_contract","get_model_from_store","get_model_from_contract","validate","validate_batch"],"quality-assurance":["quality_check","quality_check_options","quality_thresholds"],"quality-tracking":["metrics_collector","validation_metric","metrics_summary","metrics_export","validator_with_tracking"],"docs-generation":["docs_generator","generate_docs"],"schema-evolution":["check_compatibility","compute_diff","compatibility_modes","change_types"],"etl-generator":["pipeline_class","pipeline_builder","etl_transformers","etl_extractors","etl_loaders","etl_orchestrator","create_orchestrator","pipeline_factory","extract_with_pagination_streaming","apply_transforms","extractor_factory","load_to_file","generate_etl_config"]},o=e=>{let t=Object.keys(i).find(t=>i[t].includes(e));if(t)a(t),setTimeout(()=>{let t=document.getElementById(`method-${e}`);t&&t.scrollIntoView({behavior:"smooth",block:"start"})},150);else{let t=document.getElementById(`method-${e}`);t&&t.scrollIntoView({behavior:"smooth",block:"start"})}},n=[{id:"contract-management",title:"Contract Management",icon:d.FileText,items:[{id:"parse_contract",label:"Parse Contract",onClick:()=>o("parse_contract")},{id:"build_contract",label:"Build Contract",onClick:()=>o("build_contract")}]},{id:"metadata-store",title:"Metadata Store Client",icon:l.Database,items:[{id:"store_schema",label:"Store Schema",onClick:()=>o("store_schema")},{id:"get_schema",label:"Get Schema",onClick:()=>o("get_schema")},{id:"list_schemas",label:"List Schemas",onClick:()=>o("list_schemas")},{id:"store_metadata",label:"Store Metadata",onClick:()=>o("store_metadata")},{id:"get_metadata",label:"Get Metadata",onClick:()=>o("get_metadata")},{id:"store_coercion_rules",label:"Store Coercion Rules",onClick:()=>o("store_coercion_rules")},{id:"get_coercion_rules",label:"Get Coercion Rules",onClick:()=>o("get_coercion_rules")},{id:"store_validation_rules",label:"Store Validation Rules",onClick:()=>o("store_validation_rules")},{id:"get_validation_rules",label:"Get Validation Rules",onClick:()=>o("get_validation_rules")},{id:"get_complete_schema",label:"Get Complete Schema",onClick:()=>o("get_complete_schema")}]},{id:"model-generator",title:"Model Generator",icon:m,items:[{id:"generate_model",label:"Generate Model",onClick:()=>o("generate_model")},{id:"generate_model_file",label:"Generate Model File",onClick:()=>o("generate_model_file")},{id:"from_dict",label:"From Dict",onClick:()=>o("from_dict")},{id:"from_file",label:"From File",onClick:()=>o("from_file")},{id:"from_json",label:"From JSON",onClick:()=>o("from_json")},{id:"from_url",label:"From URL",onClick:()=>o("from_url")},{id:"model_to_schema",label:"Model to Schema",onClick:()=>o("model_to_schema")},{id:"to_dict",label:"To Dict",onClick:()=>o("to_dict")},{id:"to_json",label:"To JSON",onClick:()=>o("to_json")},{id:"to_file",label:"To File",onClick:()=>o("to_file")}]},{id:"validation",title:"Validation",icon:p,items:[{id:"validator_class",label:"⭐ Validator Class",onClick:()=>o("validator_class")},{id:"validator_builder",label:"ValidatorBuilder",onClick:()=>o("validator_builder")},{id:"validation_quality_metrics",label:"Quality Metrics",onClick:()=>o("validation_quality_metrics")},{id:"error_handling",label:"Error Handling",onClick:()=>o("error_handling")},{id:"validate_with_store",label:"Validate with Store",onClick:()=>o("validate_with_store")},{id:"validate_with_contract",label:"Validate with Contract",onClick:()=>o("validate_with_contract")},{id:"validate_batch_with_store",label:"Batch Validate (Store)",onClick:()=>o("validate_batch_with_store")},{id:"validate_batch_with_contract",label:"Batch Validate (Contract)",onClick:()=>o("validate_batch_with_contract")},{id:"get_model_from_store",label:"Get Model (Store)",onClick:()=>o("get_model_from_store")},{id:"get_model_from_contract",label:"Get Model (Contract)",onClick:()=>o("get_model_from_contract")},{id:"validate",label:"Validate (Low-level)",onClick:()=>o("validate")},{id:"validate_batch",label:"Batch Validate (Low-level)",onClick:()=>o("validate_batch")}]},{id:"quality-assurance",title:"Quality Assurance",icon:u.Award,items:[{id:"quality_check",label:"⭐ QualityCheck Class",onClick:()=>o("quality_check")},{id:"quality_check_options",label:"QualityCheckOptions",onClick:()=>o("quality_check_options")},{id:"quality_thresholds",label:"QualityThresholds",onClick:()=>o("quality_thresholds")}]},{id:"quality-tracking",title:"Quality Tracking",icon:f,items:[{id:"metrics_collector",label:"⭐ MetricsCollector",onClick:()=>o("metrics_collector")},{id:"validation_metric",label:"ValidationMetric",onClick:()=>o("validation_metric")},{id:"metrics_summary",label:"MetricsSummary",onClick:()=>o("metrics_summary")},{id:"metrics_export",label:"Export Metrics",onClick:()=>o("metrics_export")},{id:"validator_with_tracking",label:"Validator + Tracking",onClick:()=>o("validator_with_tracking")}]},{id:"docs-generation",title:"Documentation Generation",icon:h,items:[{id:"docs_generator",label:"⭐ DocsGenerator",onClick:()=>o("docs_generator")},{id:"generate_docs",label:"generate_docs()",onClick:()=>o("generate_docs")}]},{id:"schema-evolution",title:"Schema Evolution",icon:y,items:[{id:"check_compatibility",label:"⭐ check_compatibility()",onClick:()=>o("check_compatibility")},{id:"compute_diff",label:"compute_diff()",onClick:()=>o("compute_diff")},{id:"compatibility_modes",label:"Compatibility Modes",onClick:()=>o("compatibility_modes")},{id:"change_types",label:"Change Types",onClick:()=>o("change_types")}]},{id:"etl-generator",title:"ETL Generator",icon:_,items:[{id:"pipeline_class",label:"⭐ Pipeline (NEW)",onClick:()=>o("pipeline_class")},{id:"pipeline_builder",label:"PipelineBuilder",onClick:()=>o("pipeline_builder")},{id:"etl_transformers",label:"Transformers",onClick:()=>o("etl_transformers")},{id:"etl_extractors",label:"Extractors",onClick:()=>o("etl_extractors")},{id:"etl_loaders",label:"Loaders",onClick:()=>o("etl_loaders")},{id:"etl_orchestrator",label:"ETL Orchestrator (Legacy)",onClick:()=>o("etl_orchestrator")},{id:"create_orchestrator",label:"Create Orchestrator",onClick:()=>o("create_orchestrator")},{id:"pipeline_factory",label:"Pipeline Factory",onClick:()=>o("pipeline_factory")},{id:"extract_with_pagination_streaming",label:"Extract Streaming",onClick:()=>o("extract_with_pagination_streaming")},{id:"apply_transforms",label:"Apply Transforms",onClick:()=>o("apply_transforms")},{id:"extractor_factory",label:"Extractor Factory",onClick:()=>o("extractor_factory")},{id:"load_to_file",label:"Load to File / Cloud",onClick:()=>o("load_to_file")},{id:"generate_etl_config",label:"Generate ETL Config",onClick:()=>o("generate_etl_config")}]}],s=i[e]?v.filter(t=>i[e].includes(t.id)):v;return(0,t.jsxs)("div",{className:"flex h-full bg-background",style:{height:"calc(100vh - 4rem)",overflow:"hidden"},children:[(0,t.jsx)("div",{className:"flex-shrink-0",style:{height:"100%",overflow:"hidden"},children:(0,t.jsx)(g.CollapsibleSidebar,{sections:n,defaultCollapsed:!1,headerTitle:"Documentation",selectedSection:e,onSectionClick:e=>{a(e),setTimeout(()=>{let t=document.getElementById(`section-${e}`);t&&t.scrollIntoView({behavior:"smooth",block:"start"})},100)}})}),(0,t.jsx)("div",{className:"flex-1 min-w-0",style:{height:"100%",overflowY:"auto",overflowX:"hidden"},"data-content-area":!0,children:(0,t.jsx)("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:(0,t.jsxs)("div",{className:"space-y-8",children:[(0,t.jsxs)("div",{id:`section-${e}`,className:"scroll-mt-4 mb-4",children:[(0,t.jsx)("h2",{className:"text-2xl font-bold text-foreground mb-1",children:n.find(t=>t.id===e)?.title||"Documentation"}),(0,t.jsxs)("p",{className:"text-sm text-muted-foreground",children:["contract-management"===e&&"Manage and work with data contracts","metadata-store"===e&&"Store and retrieve schemas, metadata, coercion rules, and validation rules","model-generator"===e&&"Generate Pydantic models from schemas","validation"===e&&"Validate data against schemas and contracts","quality-assurance"===e&&"Monitor data quality and track violations","quality-tracking"===e&&"Track validation metrics over time with trend analysis and export capabilities","docs-generation"===e&&"Generate human-readable documentation from data contracts in Markdown or HTML","schema-evolution"===e&&"Check schema compatibility and compute detailed diffs between versions","etl-generator"===e&&"Execute ETL pipelines from contract configs: extract, transform, and load"]})]}),(0,t.jsx)("div",{className:"space-y-6",children:s.map(e=>(0,t.jsx)("div",{id:`method-${e.id}`,className:"border rounded-lg overflow-hidden scroll-mt-4",children:(0,t.jsxs)("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4 p-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("h4",{className:"font-semibold mb-2",children:e.title}),(0,t.jsx)("p",{className:"text-sm text-muted-foreground mb-3",children:e.description}),e.arguments&&e.arguments.length>0&&(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)("h5",{className:"text-sm font-semibold mb-2",children:"Arguments"}),(0,t.jsx)("div",{className:"space-y-2",children:e.arguments.map((e,r)=>(0,t.jsxs)("div",{className:"text-xs border-l-2 border-primary/20 pl-2",children:[(0,t.jsxs)("div",{className:"font-mono font-semibold text-foreground",children:[e.name,!e.required&&(0,t.jsx)("span",{className:"text-muted-foreground ml-1",children:"(optional)"})]}),(0,t.jsxs)("div",{className:"text-muted-foreground mt-0.5",children:[(0,t.jsx)("span",{className:"font-mono",children:e.type}),e.default&&(0,t.jsxs)("span",{className:"ml-1",children:["default: ",e.default]})]}),(0,t.jsx)("div",{className:"text-muted-foreground mt-1",children:e.description})]},r))})]}),e.returns&&(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)("h5",{className:"text-sm font-semibold mb-2",children:"Returns"}),(0,t.jsxs)("div",{className:"text-xs border-l-2 border-green-500/20 pl-2",children:[(0,t.jsx)("div",{className:"font-mono font-semibold text-foreground mb-0.5",children:e.returns.type}),(0,t.jsx)("div",{className:"text-muted-foreground",children:e.returns.description})]})]}),(0,t.jsx)("div",{className:"bg-muted p-3 rounded font-mono text-xs overflow-x-auto mb-3",children:(0,t.jsx)("pre",{className:"whitespace-pre-wrap",children:e.exampleCode})}),(0,t.jsxs)("div",{className:"text-xs text-muted-foreground",children:[(0,t.jsx)("span",{className:"font-semibold",children:"Method:"})," ",e.method]})]}),(0,t.jsx)("div",{children:(0,t.jsx)(x,{method:e})})]})},e.id))}),(0,t.jsxs)("div",{className:"border rounded-lg p-4 bg-primary/5",children:[(0,t.jsx)("h4",{className:"font-semibold mb-2",children:"Additional Resources"}),(0,t.jsxs)("ul",{className:"text-sm space-y-1 text-muted-foreground",children:[(0,t.jsx)("li",{children:"• Full documentation: See README.md and REFERENCE.md"}),(0,t.jsx)("li",{children:"• ETL Generator interfaces: pycharter/etl_generator/INTERFACES.md"}),(0,t.jsx)("li",{children:"• Examples: Check the examples/ directory (including examples/etl_pyoptima/)"}),(0,t.jsx)("li",{children:"• API Documentation: Available at /docs when running the API server"})]})]})]})})})]})}e.s(["default",()=>b],33558)}]);
|