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
|
@@ -2,33 +2,27 @@
|
|
|
2
2
|
Configuration validation for ETL pipelines.
|
|
3
3
|
|
|
4
4
|
Provides validation of extract, transform, and load configurations
|
|
5
|
-
with clear, actionable error messages.
|
|
5
|
+
using Pydantic models with clear, actionable error messages.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
8
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
import jsonschema
|
|
14
|
-
from jsonschema import Draft7Validator, ValidationError as JsonschemaValidationError
|
|
15
|
-
HAS_JSONSCHEMA = True
|
|
16
|
-
except ImportError:
|
|
17
|
-
HAS_JSONSCHEMA = False
|
|
18
|
-
JsonschemaValidationError = Exception # type: ignore[misc, assignment]
|
|
10
|
+
from pydantic import ValidationError as PydanticValidationError
|
|
19
11
|
|
|
20
12
|
from pycharter.shared.errors import ConfigValidationError
|
|
21
|
-
from pycharter.etl_generator.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
from pycharter.etl_generator.config_models import (
|
|
14
|
+
parse_extract_config,
|
|
15
|
+
parse_load_config,
|
|
16
|
+
parse_transform_config,
|
|
17
|
+
parse_settings_config,
|
|
18
|
+
SettingsConfig,
|
|
19
|
+
TransformConfig,
|
|
26
20
|
)
|
|
27
21
|
|
|
28
22
|
|
|
29
23
|
class ConfigValidator:
|
|
30
24
|
"""
|
|
31
|
-
Validates ETL pipeline configurations
|
|
25
|
+
Validates ETL pipeline configurations using Pydantic models.
|
|
32
26
|
|
|
33
27
|
Provides clear error messages to help users fix configuration issues.
|
|
34
28
|
|
|
@@ -56,146 +50,80 @@ class ConfigValidator:
|
|
|
56
50
|
If False, return errors without raising.
|
|
57
51
|
"""
|
|
58
52
|
self.strict = strict
|
|
59
|
-
self._extract_schema = None
|
|
60
|
-
self._transform_schema = None
|
|
61
|
-
self._load_schema = None
|
|
62
|
-
self._pipeline_schema = None
|
|
63
53
|
|
|
64
|
-
|
|
65
|
-
def extract_schema(self) -> Dict[str, Any]:
|
|
66
|
-
if self._extract_schema is None:
|
|
67
|
-
self._extract_schema = get_extract_schema()
|
|
68
|
-
return self._extract_schema
|
|
69
|
-
|
|
70
|
-
@property
|
|
71
|
-
def transform_schema(self) -> Dict[str, Any]:
|
|
72
|
-
if self._transform_schema is None:
|
|
73
|
-
self._transform_schema = get_transform_schema()
|
|
74
|
-
return self._transform_schema
|
|
75
|
-
|
|
76
|
-
@property
|
|
77
|
-
def load_schema(self) -> Dict[str, Any]:
|
|
78
|
-
if self._load_schema is None:
|
|
79
|
-
self._load_schema = get_load_schema()
|
|
80
|
-
return self._load_schema
|
|
81
|
-
|
|
82
|
-
@property
|
|
83
|
-
def pipeline_schema(self) -> Dict[str, Any]:
|
|
84
|
-
if self._pipeline_schema is None:
|
|
85
|
-
self._pipeline_schema = get_pipeline_schema()
|
|
86
|
-
return self._pipeline_schema
|
|
87
|
-
|
|
88
|
-
def _validate(
|
|
89
|
-
self,
|
|
90
|
-
config: Dict[str, Any],
|
|
91
|
-
schema: Dict[str, Any],
|
|
92
|
-
config_type: str,
|
|
93
|
-
config_path: Optional[str] = None,
|
|
94
|
-
) -> Tuple[bool, List[Dict[str, Any]]]:
|
|
95
|
-
"""
|
|
96
|
-
Validate config against schema.
|
|
97
|
-
|
|
98
|
-
Returns:
|
|
99
|
-
Tuple of (is_valid, list of error dicts)
|
|
100
|
-
"""
|
|
101
|
-
if not HAS_JSONSCHEMA:
|
|
102
|
-
# If jsonschema not installed, do basic validation
|
|
103
|
-
return self._basic_validate(config, config_type)
|
|
104
|
-
|
|
105
|
-
errors = []
|
|
106
|
-
validator = Draft7Validator(schema)
|
|
107
|
-
|
|
108
|
-
for error in sorted(validator.iter_errors(config), key=lambda e: str(e.path)):
|
|
109
|
-
error_dict = {
|
|
110
|
-
"path": ".".join(str(p) for p in error.absolute_path) or "(root)",
|
|
111
|
-
"message": self._format_error_message(error, config_type),
|
|
112
|
-
"validator": error.validator,
|
|
113
|
-
"schema_path": list(error.schema_path),
|
|
114
|
-
}
|
|
115
|
-
errors.append(error_dict)
|
|
116
|
-
|
|
117
|
-
return len(errors) == 0, errors
|
|
118
|
-
|
|
119
|
-
def _basic_validate(
|
|
54
|
+
def _format_pydantic_errors(
|
|
120
55
|
self,
|
|
121
|
-
|
|
56
|
+
error: PydanticValidationError,
|
|
122
57
|
config_type: str,
|
|
123
|
-
) ->
|
|
124
|
-
"""
|
|
58
|
+
) -> List[Dict[str, Any]]:
|
|
59
|
+
"""Convert Pydantic validation errors to our format."""
|
|
125
60
|
errors = []
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
errors.append({
|
|
135
|
-
"path": "type",
|
|
136
|
-
"message": f"Invalid type '{config['type']}'. Must be one of: http, file, database, cloud_storage",
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
elif config_type == "load":
|
|
140
|
-
if "type" not in config:
|
|
141
|
-
errors.append({
|
|
142
|
-
"path": "type",
|
|
143
|
-
"message": "Missing required field 'type'. Must be one of: postgres, sqlite, file, cloud_storage",
|
|
144
|
-
})
|
|
145
|
-
elif config["type"] not in ("postgres", "postgresql", "sqlite", "database", "file", "cloud_storage"):
|
|
146
|
-
errors.append({
|
|
147
|
-
"path": "type",
|
|
148
|
-
"message": f"Invalid type '{config['type']}'. Must be one of: postgres, sqlite, file, cloud_storage",
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
elif config_type == "pipeline":
|
|
152
|
-
if "extract" not in config:
|
|
153
|
-
errors.append({
|
|
154
|
-
"path": "extract",
|
|
155
|
-
"message": "Missing required section 'extract'",
|
|
156
|
-
})
|
|
157
|
-
if "load" not in config:
|
|
158
|
-
errors.append({
|
|
159
|
-
"path": "load",
|
|
160
|
-
"message": "Missing required section 'load'",
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
return len(errors) == 0, errors
|
|
61
|
+
for err in error.errors():
|
|
62
|
+
path = ".".join(str(p) for p in err["loc"]) or "(root)"
|
|
63
|
+
errors.append({
|
|
64
|
+
"path": path,
|
|
65
|
+
"message": self._format_error_message(err, config_type),
|
|
66
|
+
"type": err["type"],
|
|
67
|
+
})
|
|
68
|
+
return errors
|
|
164
69
|
|
|
165
|
-
def _format_error_message(self, error:
|
|
166
|
-
"""Format a
|
|
167
|
-
|
|
70
|
+
def _format_error_message(self, error: Dict[str, Any], config_type: str) -> str:
|
|
71
|
+
"""Format a Pydantic error into a user-friendly message."""
|
|
72
|
+
error_type = error["type"]
|
|
73
|
+
msg = error["msg"]
|
|
168
74
|
|
|
169
75
|
# Improve common error messages
|
|
170
|
-
if
|
|
171
|
-
|
|
172
|
-
if "type"
|
|
76
|
+
if error_type == "missing":
|
|
77
|
+
field = error["loc"][-1] if error["loc"] else "unknown"
|
|
78
|
+
if field == "type":
|
|
173
79
|
valid_types = {
|
|
174
80
|
"extract": "http, file, database, cloud_storage",
|
|
175
|
-
"load": "postgres, sqlite, file, cloud_storage",
|
|
81
|
+
"load": "postgres, postgresql, sqlite, file, cloud_storage",
|
|
176
82
|
}
|
|
177
83
|
types = valid_types.get(config_type, "")
|
|
178
84
|
if types:
|
|
179
85
|
return f"Missing required 'type' field. Must be one of: {types}"
|
|
180
|
-
return f"Missing required field
|
|
86
|
+
return f"Missing required field: {field}"
|
|
181
87
|
|
|
182
|
-
elif
|
|
183
|
-
allowed
|
|
184
|
-
|
|
88
|
+
elif error_type == "enum":
|
|
89
|
+
# Extract allowed values from the input
|
|
90
|
+
ctx = error.get("ctx", {})
|
|
91
|
+
expected = ctx.get("expected", "")
|
|
92
|
+
return f"Invalid value. Allowed values: {expected}"
|
|
185
93
|
|
|
186
|
-
elif
|
|
187
|
-
expected =
|
|
188
|
-
|
|
189
|
-
return f"Expected {expected}, got {actual}"
|
|
94
|
+
elif error_type in ("string_type", "int_type", "float_type", "bool_type"):
|
|
95
|
+
expected = error_type.replace("_type", "")
|
|
96
|
+
return f"Expected {expected}"
|
|
190
97
|
|
|
191
|
-
elif
|
|
192
|
-
|
|
98
|
+
elif error_type == "extra_forbidden":
|
|
99
|
+
field = error["loc"][-1] if error["loc"] else "unknown"
|
|
100
|
+
return f"Unknown field: '{field}'"
|
|
193
101
|
|
|
194
|
-
elif
|
|
195
|
-
return
|
|
102
|
+
elif error_type == "value_error":
|
|
103
|
+
return str(msg)
|
|
196
104
|
|
|
197
105
|
return msg
|
|
198
106
|
|
|
107
|
+
def _validate_with_pydantic(
|
|
108
|
+
self,
|
|
109
|
+
config: Dict[str, Any],
|
|
110
|
+
config_type: str,
|
|
111
|
+
parse_func,
|
|
112
|
+
) -> Tuple[bool, List[Dict[str, Any]]]:
|
|
113
|
+
"""Validate config using Pydantic model."""
|
|
114
|
+
try:
|
|
115
|
+
parse_func(config)
|
|
116
|
+
return True, []
|
|
117
|
+
except PydanticValidationError as e:
|
|
118
|
+
return False, self._format_pydantic_errors(e, config_type)
|
|
119
|
+
except ValueError as e:
|
|
120
|
+
# Handle parse_* function ValueErrors (e.g., unknown type)
|
|
121
|
+
return False, [{
|
|
122
|
+
"path": "(root)",
|
|
123
|
+
"message": str(e),
|
|
124
|
+
"type": "value_error",
|
|
125
|
+
}]
|
|
126
|
+
|
|
199
127
|
def validate_extract(
|
|
200
128
|
self,
|
|
201
129
|
config: Dict[str, Any],
|
|
@@ -211,11 +139,13 @@ class ConfigValidator:
|
|
|
211
139
|
Raises:
|
|
212
140
|
ConfigValidationError: If validation fails and strict=True
|
|
213
141
|
"""
|
|
214
|
-
is_valid, errors = self.
|
|
142
|
+
is_valid, errors = self._validate_with_pydantic(
|
|
143
|
+
config, "extract", parse_extract_config
|
|
144
|
+
)
|
|
215
145
|
|
|
216
146
|
if not is_valid and self.strict:
|
|
217
147
|
raise ConfigValidationError(
|
|
218
|
-
|
|
148
|
+
"Invalid extract configuration",
|
|
219
149
|
errors=errors,
|
|
220
150
|
config_type="extract",
|
|
221
151
|
config_path=config_path,
|
|
@@ -240,11 +170,13 @@ class ConfigValidator:
|
|
|
240
170
|
if not config:
|
|
241
171
|
return
|
|
242
172
|
|
|
243
|
-
is_valid, errors = self.
|
|
173
|
+
is_valid, errors = self._validate_with_pydantic(
|
|
174
|
+
config, "transform", lambda c: TransformConfig(**c)
|
|
175
|
+
)
|
|
244
176
|
|
|
245
177
|
if not is_valid and self.strict:
|
|
246
178
|
raise ConfigValidationError(
|
|
247
|
-
|
|
179
|
+
"Invalid transform configuration",
|
|
248
180
|
errors=errors,
|
|
249
181
|
config_type="transform",
|
|
250
182
|
config_path=config_path,
|
|
@@ -265,16 +197,45 @@ class ConfigValidator:
|
|
|
265
197
|
Raises:
|
|
266
198
|
ConfigValidationError: If validation fails and strict=True
|
|
267
199
|
"""
|
|
268
|
-
is_valid, errors = self.
|
|
200
|
+
is_valid, errors = self._validate_with_pydantic(
|
|
201
|
+
config, "load", parse_load_config
|
|
202
|
+
)
|
|
269
203
|
|
|
270
204
|
if not is_valid and self.strict:
|
|
271
205
|
raise ConfigValidationError(
|
|
272
|
-
|
|
206
|
+
"Invalid load configuration",
|
|
273
207
|
errors=errors,
|
|
274
208
|
config_type="load",
|
|
275
209
|
config_path=config_path,
|
|
276
210
|
)
|
|
277
211
|
|
|
212
|
+
def validate_settings(
|
|
213
|
+
self,
|
|
214
|
+
config: Dict[str, Any],
|
|
215
|
+
config_path: Optional[str] = None,
|
|
216
|
+
) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Validate settings configuration.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
config: Settings configuration dict
|
|
222
|
+
config_path: Optional path to config file (for error messages)
|
|
223
|
+
|
|
224
|
+
Raises:
|
|
225
|
+
ConfigValidationError: If validation fails and strict=True
|
|
226
|
+
"""
|
|
227
|
+
is_valid, errors = self._validate_with_pydantic(
|
|
228
|
+
config, "settings", parse_settings_config
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
if not is_valid and self.strict:
|
|
232
|
+
raise ConfigValidationError(
|
|
233
|
+
"Invalid settings configuration",
|
|
234
|
+
errors=errors,
|
|
235
|
+
config_type="settings",
|
|
236
|
+
config_path=config_path,
|
|
237
|
+
)
|
|
238
|
+
|
|
278
239
|
def validate_pipeline(
|
|
279
240
|
self,
|
|
280
241
|
config: Dict[str, Any],
|
|
@@ -290,47 +251,50 @@ class ConfigValidator:
|
|
|
290
251
|
Raises:
|
|
291
252
|
ConfigValidationError: If validation fails and strict=True
|
|
292
253
|
"""
|
|
293
|
-
# Basic structure validation
|
|
294
254
|
errors = []
|
|
295
255
|
|
|
256
|
+
# Validate extract (required)
|
|
296
257
|
if "extract" not in config:
|
|
297
258
|
errors.append({
|
|
298
259
|
"path": "extract",
|
|
299
260
|
"message": "Missing required 'extract' section",
|
|
261
|
+
"type": "missing",
|
|
300
262
|
})
|
|
301
263
|
else:
|
|
302
|
-
is_valid, extract_errors = self.
|
|
303
|
-
config["extract"],
|
|
264
|
+
is_valid, extract_errors = self._validate_with_pydantic(
|
|
265
|
+
config["extract"], "extract", parse_extract_config
|
|
304
266
|
)
|
|
305
267
|
for e in extract_errors:
|
|
306
268
|
e["path"] = f"extract.{e['path']}" if e["path"] != "(root)" else "extract"
|
|
307
269
|
errors.extend(extract_errors)
|
|
308
270
|
|
|
271
|
+
# Validate transform (optional)
|
|
309
272
|
if "transform" in config and config["transform"]:
|
|
310
|
-
# Validate transform if present
|
|
311
273
|
transform_config = config["transform"]
|
|
312
|
-
#
|
|
274
|
+
# Wrap if it's just simple ops
|
|
313
275
|
if isinstance(transform_config, (list, dict)):
|
|
314
276
|
if isinstance(transform_config, list) or not any(
|
|
315
277
|
k in transform_config for k in ("transform", "jsonata", "custom_function")
|
|
316
278
|
):
|
|
317
279
|
transform_config = {"transform": transform_config}
|
|
318
280
|
|
|
319
|
-
is_valid, transform_errors = self.
|
|
320
|
-
transform_config,
|
|
281
|
+
is_valid, transform_errors = self._validate_with_pydantic(
|
|
282
|
+
transform_config, "transform", lambda c: TransformConfig(**c)
|
|
321
283
|
)
|
|
322
284
|
for e in transform_errors:
|
|
323
285
|
e["path"] = f"transform.{e['path']}" if e["path"] != "(root)" else "transform"
|
|
324
286
|
errors.extend(transform_errors)
|
|
325
287
|
|
|
288
|
+
# Validate load (required)
|
|
326
289
|
if "load" not in config:
|
|
327
290
|
errors.append({
|
|
328
291
|
"path": "load",
|
|
329
292
|
"message": "Missing required 'load' section",
|
|
293
|
+
"type": "missing",
|
|
330
294
|
})
|
|
331
295
|
else:
|
|
332
|
-
is_valid, load_errors = self.
|
|
333
|
-
config["load"],
|
|
296
|
+
is_valid, load_errors = self._validate_with_pydantic(
|
|
297
|
+
config["load"], "load", parse_load_config
|
|
334
298
|
)
|
|
335
299
|
for e in load_errors:
|
|
336
300
|
e["path"] = f"load.{e['path']}" if e["path"] != "(root)" else "load"
|
|
@@ -338,7 +302,7 @@ class ConfigValidator:
|
|
|
338
302
|
|
|
339
303
|
if errors and self.strict:
|
|
340
304
|
raise ConfigValidationError(
|
|
341
|
-
|
|
305
|
+
"Invalid pipeline configuration",
|
|
342
306
|
errors=errors,
|
|
343
307
|
config_type="pipeline",
|
|
344
308
|
config_path=config_path,
|
|
@@ -349,7 +313,7 @@ class ConfigValidator:
|
|
|
349
313
|
config: Dict[str, Any],
|
|
350
314
|
) -> Tuple[bool, List[Dict[str, Any]]]:
|
|
351
315
|
"""Check extract config without raising. Returns (is_valid, errors)."""
|
|
352
|
-
return self.
|
|
316
|
+
return self._validate_with_pydantic(config, "extract", parse_extract_config)
|
|
353
317
|
|
|
354
318
|
def check_transform(
|
|
355
319
|
self,
|
|
@@ -358,14 +322,23 @@ class ConfigValidator:
|
|
|
358
322
|
"""Check transform config without raising. Returns (is_valid, errors)."""
|
|
359
323
|
if not config:
|
|
360
324
|
return True, []
|
|
361
|
-
return self.
|
|
325
|
+
return self._validate_with_pydantic(
|
|
326
|
+
config, "transform", lambda c: TransformConfig(**c)
|
|
327
|
+
)
|
|
362
328
|
|
|
363
329
|
def check_load(
|
|
364
330
|
self,
|
|
365
331
|
config: Dict[str, Any],
|
|
366
332
|
) -> Tuple[bool, List[Dict[str, Any]]]:
|
|
367
333
|
"""Check load config without raising. Returns (is_valid, errors)."""
|
|
368
|
-
return self.
|
|
334
|
+
return self._validate_with_pydantic(config, "load", parse_load_config)
|
|
335
|
+
|
|
336
|
+
def check_settings(
|
|
337
|
+
self,
|
|
338
|
+
config: Dict[str, Any],
|
|
339
|
+
) -> Tuple[bool, List[Dict[str, Any]]]:
|
|
340
|
+
"""Check settings config without raising. Returns (is_valid, errors)."""
|
|
341
|
+
return self._validate_with_pydantic(config, "settings", parse_settings_config)
|
|
369
342
|
|
|
370
343
|
|
|
371
344
|
def validate_config(
|
|
@@ -379,7 +352,7 @@ def validate_config(
|
|
|
379
352
|
|
|
380
353
|
Args:
|
|
381
354
|
config: Configuration dict
|
|
382
|
-
config_type: One of "extract", "transform", "load", "pipeline"
|
|
355
|
+
config_type: One of "extract", "transform", "load", "settings", "pipeline"
|
|
383
356
|
config_path: Optional path to config file
|
|
384
357
|
strict: If True, raise on validation failure
|
|
385
358
|
|
|
@@ -400,6 +373,9 @@ def validate_config(
|
|
|
400
373
|
elif config_type == "load":
|
|
401
374
|
validator.validate_load(config, config_path)
|
|
402
375
|
return validator.check_load(config)
|
|
376
|
+
elif config_type == "settings":
|
|
377
|
+
validator.validate_settings(config, config_path)
|
|
378
|
+
return validator.check_settings(config)
|
|
403
379
|
elif config_type == "pipeline":
|
|
404
380
|
validator.validate_pipeline(config, config_path)
|
|
405
381
|
# Return combined check
|
|
@@ -10,8 +10,11 @@ from dataclasses import dataclass, field
|
|
|
10
10
|
from typing import Any, Dict, Optional
|
|
11
11
|
|
|
12
12
|
# Variable pattern: ${VAR_NAME} or ${VAR_NAME:-default} or ${VAR_NAME:?error}
|
|
13
|
+
# This is the canonical definition - import from here in other modules
|
|
13
14
|
VARIABLE_PATTERN = re.compile(r'\$\{([^}:]+)(?::([?-])([^}]*))?\}')
|
|
14
15
|
|
|
16
|
+
__all__ = ["PipelineContext", "VARIABLE_PATTERN"]
|
|
17
|
+
|
|
15
18
|
|
|
16
19
|
@dataclass
|
|
17
20
|
class PipelineContext:
|
|
@@ -39,6 +39,7 @@ DB_MYSQL = "mysql"
|
|
|
39
39
|
DB_SQLITE = "sqlite"
|
|
40
40
|
DB_MSSQL = "mssql"
|
|
41
41
|
DB_ORACLE = "oracle"
|
|
42
|
+
DB_MONGODB = "mongodb"
|
|
42
43
|
|
|
43
44
|
# Default ports for SSH tunnel
|
|
44
45
|
DEFAULT_POSTGRES_PORT = 5432
|
|
@@ -86,10 +87,13 @@ def detect_database_type(db_url: str) -> str:
|
|
|
86
87
|
# Check for Oracle
|
|
87
88
|
elif base_url.startswith("oracle://"):
|
|
88
89
|
return DB_ORACLE
|
|
90
|
+
# Check for MongoDB
|
|
91
|
+
elif base_url.startswith(("mongodb://", "mongodb+srv://")):
|
|
92
|
+
return DB_MONGODB
|
|
89
93
|
else:
|
|
90
94
|
raise ValueError(
|
|
91
95
|
f"Cannot detect database type from connection string. "
|
|
92
|
-
f"Supported formats: postgresql://, mysql://, sqlite://, mssql://, oracle:// "
|
|
96
|
+
f"Supported formats: postgresql://, mysql://, sqlite://, mssql://, oracle://, mongodb:// "
|
|
93
97
|
f"(async variants like postgresql+asyncpg:// are also supported). "
|
|
94
98
|
f"Got: {db_url[:50]}..."
|
|
95
99
|
)
|
|
@@ -5,6 +5,7 @@ This module provides a modular architecture for data extraction from various sou
|
|
|
5
5
|
- HTTP/API extraction
|
|
6
6
|
- File-based extraction (CSV, JSON, Parquet, Excel, TSV, XML)
|
|
7
7
|
- Database extraction (PostgreSQL, MySQL, SQLite, MSSQL, Oracle)
|
|
8
|
+
- MongoDB extraction (queries and aggregation pipelines)
|
|
8
9
|
- Cloud storage extraction (S3, GCS, Azure Blob)
|
|
9
10
|
|
|
10
11
|
Entry point for orchestration: extract_with_pagination_streaming().
|
|
@@ -14,17 +15,18 @@ from pycharter.etl_generator.extractors.base import BaseExtractor
|
|
|
14
15
|
from pycharter.etl_generator.extractors.cloud_storage import CloudStorageExtractor
|
|
15
16
|
from pycharter.etl_generator.extractors.database import DatabaseExtractor
|
|
16
17
|
from pycharter.etl_generator.extractors.file import FileExtractor
|
|
17
|
-
from pycharter.etl_generator.extractors.factory import ExtractorFactory
|
|
18
|
+
from pycharter.etl_generator.extractors.factory import ExtractorFactory
|
|
18
19
|
from pycharter.etl_generator.extractors.http import HTTPExtractor
|
|
20
|
+
from pycharter.etl_generator.extractors.mongodb import MongoDBExtractor
|
|
19
21
|
from pycharter.etl_generator.extractors.streaming import extract_with_pagination_streaming
|
|
20
22
|
|
|
21
23
|
__all__ = [
|
|
22
24
|
"BaseExtractor",
|
|
23
25
|
"ExtractorFactory",
|
|
24
|
-
"get_extractor",
|
|
25
26
|
"HTTPExtractor",
|
|
26
27
|
"FileExtractor",
|
|
27
28
|
"DatabaseExtractor",
|
|
29
|
+
"MongoDBExtractor",
|
|
28
30
|
"CloudStorageExtractor",
|
|
29
31
|
"extract_with_pagination_streaming",
|
|
30
32
|
]
|
|
@@ -125,10 +125,10 @@ class CloudStorageExtractor(BaseExtractor):
|
|
|
125
125
|
|
|
126
126
|
def validate_config(self, extract_config: Dict[str, Any]) -> None:
|
|
127
127
|
"""Validate cloud storage extractor configuration."""
|
|
128
|
-
if '
|
|
128
|
+
if 'type' in extract_config and extract_config['type'] != 'cloud_storage':
|
|
129
129
|
raise ValueError(
|
|
130
|
-
f"CloudStorageExtractor requires
|
|
131
|
-
f"got '{extract_config.get('
|
|
130
|
+
f"CloudStorageExtractor requires type='cloud_storage', "
|
|
131
|
+
f"got '{extract_config.get('type')}'"
|
|
132
132
|
)
|
|
133
133
|
|
|
134
134
|
storage_config = extract_config.get('storage', {})
|
|
@@ -266,7 +266,7 @@ class CloudStorageExtractor(BaseExtractor):
|
|
|
266
266
|
# Use FileExtractor to process the file
|
|
267
267
|
file_extractor = FileExtractor()
|
|
268
268
|
file_config = {
|
|
269
|
-
'
|
|
269
|
+
'type': 'file',
|
|
270
270
|
'file_path': str(tmp_path),
|
|
271
271
|
'format': file_format,
|
|
272
272
|
}
|
|
@@ -292,7 +292,7 @@ class CloudStorageExtractor(BaseExtractor):
|
|
|
292
292
|
# Use FileExtractor to process the file
|
|
293
293
|
file_extractor = FileExtractor()
|
|
294
294
|
file_config = {
|
|
295
|
-
'
|
|
295
|
+
'type': 'file',
|
|
296
296
|
'file_path': str(tmp_path),
|
|
297
297
|
'format': file_format,
|
|
298
298
|
}
|
|
@@ -369,7 +369,7 @@ class CloudStorageExtractor(BaseExtractor):
|
|
|
369
369
|
# Use FileExtractor
|
|
370
370
|
file_extractor = FileExtractor()
|
|
371
371
|
file_config = {
|
|
372
|
-
'
|
|
372
|
+
'type': 'file',
|
|
373
373
|
'file_path': str(tmp_path),
|
|
374
374
|
'format': file_format,
|
|
375
375
|
}
|
|
@@ -395,7 +395,7 @@ class CloudStorageExtractor(BaseExtractor):
|
|
|
395
395
|
# Use FileExtractor
|
|
396
396
|
file_extractor = FileExtractor()
|
|
397
397
|
file_config = {
|
|
398
|
-
'
|
|
398
|
+
'type': 'file',
|
|
399
399
|
'file_path': str(tmp_path),
|
|
400
400
|
'format': file_format,
|
|
401
401
|
}
|
|
@@ -473,7 +473,7 @@ class CloudStorageExtractor(BaseExtractor):
|
|
|
473
473
|
# Use FileExtractor
|
|
474
474
|
file_extractor = FileExtractor()
|
|
475
475
|
file_config = {
|
|
476
|
-
'
|
|
476
|
+
'type': 'file',
|
|
477
477
|
'file_path': str(tmp_path),
|
|
478
478
|
'format': file_format,
|
|
479
479
|
}
|
|
@@ -500,7 +500,7 @@ class CloudStorageExtractor(BaseExtractor):
|
|
|
500
500
|
# Use FileExtractor
|
|
501
501
|
file_extractor = FileExtractor()
|
|
502
502
|
file_config = {
|
|
503
|
-
'
|
|
503
|
+
'type': 'file',
|
|
504
504
|
'file_path': str(tmp_path),
|
|
505
505
|
'format': file_format,
|
|
506
506
|
}
|
|
@@ -102,8 +102,8 @@ class DatabaseExtractor(BaseExtractor):
|
|
|
102
102
|
|
|
103
103
|
def validate_config(self, extract_config: Dict[str, Any]) -> None:
|
|
104
104
|
"""Validate database extractor configuration."""
|
|
105
|
-
if '
|
|
106
|
-
raise ValueError(f"DatabaseExtractor requires
|
|
105
|
+
if 'type' in extract_config and extract_config['type'] != 'database':
|
|
106
|
+
raise ValueError(f"DatabaseExtractor requires type='database', got '{extract_config.get('type')}'")
|
|
107
107
|
|
|
108
108
|
db_config = extract_config.get('database', {})
|
|
109
109
|
if not db_config.get('url'):
|