pycharter 0.0.22__py3-none-any.whl → 0.0.24__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.
- api/main.py +27 -1
- api/models/docs.py +68 -0
- api/models/evolution.py +117 -0
- api/models/tracking.py +111 -0
- api/models/validation.py +46 -6
- api/routes/v1/__init__.py +14 -1
- api/routes/v1/docs.py +187 -0
- api/routes/v1/evolution.py +337 -0
- api/routes/v1/templates.py +211 -27
- api/routes/v1/tracking.py +301 -0
- api/routes/v1/validation.py +68 -31
- pycharter/__init__.py +268 -58
- pycharter/data/templates/contract/template_coercion_rules.yaml +57 -0
- pycharter/data/templates/contract/template_contract.yaml +122 -0
- pycharter/data/templates/contract/template_metadata.yaml +68 -0
- pycharter/data/templates/contract/template_schema.yaml +100 -0
- pycharter/data/templates/contract/template_validation_rules.yaml +75 -0
- pycharter/data/templates/etl/README.md +224 -0
- pycharter/data/templates/etl/extract_cloud_azure.yaml +24 -0
- pycharter/data/templates/etl/extract_cloud_gcs.yaml +25 -0
- pycharter/data/templates/etl/extract_cloud_s3.yaml +30 -0
- pycharter/data/templates/etl/extract_database.yaml +34 -0
- pycharter/data/templates/etl/extract_database_ssh.yaml +40 -0
- pycharter/data/templates/etl/extract_file_csv.yaml +21 -0
- pycharter/data/templates/etl/extract_file_glob.yaml +25 -0
- pycharter/data/templates/etl/extract_file_json.yaml +24 -0
- pycharter/data/templates/etl/extract_file_parquet.yaml +20 -0
- pycharter/data/templates/etl/extract_http_paginated.yaml +79 -0
- pycharter/data/templates/etl/extract_http_path_params.yaml +38 -0
- pycharter/data/templates/etl/extract_http_simple.yaml +62 -0
- pycharter/data/templates/etl/load_cloud_azure.yaml +24 -0
- pycharter/data/templates/etl/load_cloud_gcs.yaml +22 -0
- pycharter/data/templates/etl/load_cloud_s3.yaml +27 -0
- pycharter/data/templates/etl/load_file.yaml +34 -0
- pycharter/data/templates/etl/load_insert.yaml +18 -0
- pycharter/data/templates/etl/load_postgresql.yaml +39 -0
- pycharter/data/templates/etl/load_sqlite.yaml +21 -0
- pycharter/data/templates/etl/load_truncate_and_load.yaml +20 -0
- pycharter/data/templates/etl/load_upsert.yaml +25 -0
- pycharter/data/templates/etl/load_with_dlq.yaml +34 -0
- pycharter/data/templates/etl/load_with_ssh_tunnel.yaml +35 -0
- pycharter/data/templates/etl/pipeline_http_to_db.yaml +75 -0
- pycharter/data/templates/etl/transform_combined.yaml +48 -0
- pycharter/data/templates/etl/transform_custom_function.yaml +58 -0
- pycharter/data/templates/etl/transform_jsonata.yaml +51 -0
- pycharter/data/templates/etl/transform_simple.yaml +59 -0
- pycharter/db/schemas/.ipynb_checkpoints/data_contract-checkpoint.py +160 -0
- pycharter/docs_generator/__init__.py +43 -0
- pycharter/docs_generator/generator.py +465 -0
- pycharter/docs_generator/renderers.py +247 -0
- pycharter/etl_generator/__init__.py +168 -80
- pycharter/etl_generator/builder.py +121 -0
- pycharter/etl_generator/config_loader.py +394 -0
- pycharter/etl_generator/config_validator.py +418 -0
- pycharter/etl_generator/context.py +132 -0
- pycharter/etl_generator/expression.py +499 -0
- pycharter/etl_generator/extractors/__init__.py +30 -0
- pycharter/etl_generator/extractors/base.py +70 -0
- pycharter/etl_generator/extractors/cloud_storage.py +530 -0
- pycharter/etl_generator/extractors/database.py +221 -0
- pycharter/etl_generator/extractors/factory.py +185 -0
- pycharter/etl_generator/extractors/file.py +475 -0
- pycharter/etl_generator/extractors/http.py +895 -0
- pycharter/etl_generator/extractors/streaming.py +57 -0
- pycharter/etl_generator/loaders/__init__.py +41 -0
- pycharter/etl_generator/loaders/base.py +35 -0
- pycharter/etl_generator/loaders/cloud.py +87 -0
- pycharter/etl_generator/loaders/cloud_storage_loader.py +275 -0
- pycharter/etl_generator/loaders/database.py +274 -0
- pycharter/etl_generator/loaders/factory.py +180 -0
- pycharter/etl_generator/loaders/file.py +72 -0
- pycharter/etl_generator/loaders/file_loader.py +130 -0
- pycharter/etl_generator/pipeline.py +743 -0
- pycharter/etl_generator/protocols.py +54 -0
- pycharter/etl_generator/result.py +63 -0
- pycharter/etl_generator/schemas/__init__.py +49 -0
- pycharter/etl_generator/transformers/__init__.py +49 -0
- pycharter/etl_generator/transformers/base.py +63 -0
- pycharter/etl_generator/transformers/config.py +45 -0
- pycharter/etl_generator/transformers/custom_function.py +101 -0
- pycharter/etl_generator/transformers/jsonata_transformer.py +56 -0
- pycharter/etl_generator/transformers/operations.py +218 -0
- pycharter/etl_generator/transformers/pipeline.py +54 -0
- pycharter/etl_generator/transformers/simple_operations.py +131 -0
- pycharter/quality/__init__.py +25 -0
- pycharter/quality/tracking/__init__.py +64 -0
- pycharter/quality/tracking/collector.py +318 -0
- pycharter/quality/tracking/exporters.py +238 -0
- pycharter/quality/tracking/models.py +194 -0
- pycharter/quality/tracking/store.py +385 -0
- pycharter/runtime_validator/__init__.py +20 -7
- pycharter/runtime_validator/builder.py +328 -0
- pycharter/runtime_validator/validator.py +311 -7
- pycharter/runtime_validator/validator_core.py +61 -0
- pycharter/schema_evolution/__init__.py +61 -0
- pycharter/schema_evolution/compatibility.py +270 -0
- pycharter/schema_evolution/diff.py +496 -0
- pycharter/schema_evolution/models.py +201 -0
- pycharter/shared/__init__.py +56 -0
- pycharter/shared/errors.py +296 -0
- pycharter/shared/protocols.py +234 -0
- {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/METADATA +146 -26
- pycharter-0.0.24.dist-info/RECORD +543 -0
- {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/WHEEL +1 -1
- ui/static/404/index.html +1 -1
- ui/static/404.html +1 -1
- ui/static/__next.__PAGE__.txt +1 -1
- ui/static/__next._full.txt +1 -1
- ui/static/__next._head.txt +1 -1
- ui/static/__next._index.txt +1 -1
- ui/static/__next._tree.txt +1 -1
- ui/static/_next/static/chunks/26dfc590f7714c03.js +1 -0
- ui/static/_next/static/chunks/34d289e6db2ef551.js +1 -0
- ui/static/_next/static/chunks/99508d9d5869cc27.js +1 -0
- ui/static/_next/static/chunks/b313c35a6ba76574.js +1 -0
- ui/static/_not-found/__next._full.txt +1 -1
- ui/static/_not-found/__next._head.txt +1 -1
- ui/static/_not-found/__next._index.txt +1 -1
- ui/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
- ui/static/_not-found/__next._not-found.txt +1 -1
- ui/static/_not-found/__next._tree.txt +1 -1
- ui/static/_not-found/index.html +1 -1
- ui/static/_not-found/index.txt +1 -1
- ui/static/contracts/__next._full.txt +2 -2
- ui/static/contracts/__next._head.txt +1 -1
- ui/static/contracts/__next._index.txt +1 -1
- ui/static/contracts/__next._tree.txt +1 -1
- ui/static/contracts/__next.contracts.__PAGE__.txt +2 -2
- ui/static/contracts/__next.contracts.txt +1 -1
- ui/static/contracts/index.html +1 -1
- ui/static/contracts/index.txt +2 -2
- ui/static/documentation/__next._full.txt +1 -1
- ui/static/documentation/__next._head.txt +1 -1
- ui/static/documentation/__next._index.txt +1 -1
- ui/static/documentation/__next._tree.txt +1 -1
- ui/static/documentation/__next.documentation.__PAGE__.txt +1 -1
- ui/static/documentation/__next.documentation.txt +1 -1
- ui/static/documentation/index.html +2 -2
- ui/static/documentation/index.txt +1 -1
- ui/static/index.html +1 -1
- ui/static/index.txt +1 -1
- ui/static/metadata/__next._full.txt +1 -1
- ui/static/metadata/__next._head.txt +1 -1
- ui/static/metadata/__next._index.txt +1 -1
- ui/static/metadata/__next._tree.txt +1 -1
- ui/static/metadata/__next.metadata.__PAGE__.txt +1 -1
- ui/static/metadata/__next.metadata.txt +1 -1
- ui/static/metadata/index.html +1 -1
- ui/static/metadata/index.txt +1 -1
- ui/static/quality/__next._full.txt +2 -2
- ui/static/quality/__next._head.txt +1 -1
- ui/static/quality/__next._index.txt +1 -1
- ui/static/quality/__next._tree.txt +1 -1
- ui/static/quality/__next.quality.__PAGE__.txt +2 -2
- ui/static/quality/__next.quality.txt +1 -1
- ui/static/quality/index.html +2 -2
- ui/static/quality/index.txt +2 -2
- ui/static/rules/__next._full.txt +1 -1
- ui/static/rules/__next._head.txt +1 -1
- ui/static/rules/__next._index.txt +1 -1
- ui/static/rules/__next._tree.txt +1 -1
- ui/static/rules/__next.rules.__PAGE__.txt +1 -1
- ui/static/rules/__next.rules.txt +1 -1
- ui/static/rules/index.html +1 -1
- ui/static/rules/index.txt +1 -1
- ui/static/schemas/__next._full.txt +1 -1
- ui/static/schemas/__next._head.txt +1 -1
- ui/static/schemas/__next._index.txt +1 -1
- ui/static/schemas/__next._tree.txt +1 -1
- ui/static/schemas/__next.schemas.__PAGE__.txt +1 -1
- ui/static/schemas/__next.schemas.txt +1 -1
- ui/static/schemas/index.html +1 -1
- ui/static/schemas/index.txt +1 -1
- ui/static/settings/__next._full.txt +1 -1
- ui/static/settings/__next._head.txt +1 -1
- ui/static/settings/__next._index.txt +1 -1
- ui/static/settings/__next._tree.txt +1 -1
- ui/static/settings/__next.settings.__PAGE__.txt +1 -1
- ui/static/settings/__next.settings.txt +1 -1
- ui/static/settings/index.html +1 -1
- ui/static/settings/index.txt +1 -1
- ui/static/static/404/index.html +1 -1
- ui/static/static/404.html +1 -1
- ui/static/static/__next.__PAGE__.txt +1 -1
- ui/static/static/__next._full.txt +2 -2
- ui/static/static/__next._head.txt +1 -1
- ui/static/static/__next._index.txt +2 -2
- ui/static/static/__next._tree.txt +2 -2
- ui/static/static/_next/static/chunks/13d4a0fbd74c1ee4.js +1 -0
- ui/static/static/_next/static/chunks/2edb43b48432ac04.js +441 -0
- ui/static/static/_next/static/chunks/d2363397e1b2bcab.css +1 -0
- ui/static/static/_next/static/chunks/f7d1a90dd75d2572.js +1 -0
- ui/static/static/_not-found/__next._full.txt +2 -2
- ui/static/static/_not-found/__next._head.txt +1 -1
- ui/static/static/_not-found/__next._index.txt +2 -2
- ui/static/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
- ui/static/static/_not-found/__next._not-found.txt +1 -1
- ui/static/static/_not-found/__next._tree.txt +2 -2
- ui/static/static/_not-found/index.html +1 -1
- ui/static/static/_not-found/index.txt +2 -2
- ui/static/static/contracts/__next._full.txt +3 -3
- ui/static/static/contracts/__next._head.txt +1 -1
- ui/static/static/contracts/__next._index.txt +2 -2
- ui/static/static/contracts/__next._tree.txt +2 -2
- ui/static/static/contracts/__next.contracts.__PAGE__.txt +2 -2
- ui/static/static/contracts/__next.contracts.txt +1 -1
- ui/static/static/contracts/index.html +1 -1
- ui/static/static/contracts/index.txt +3 -3
- ui/static/static/documentation/__next._full.txt +3 -3
- ui/static/static/documentation/__next._head.txt +1 -1
- ui/static/static/documentation/__next._index.txt +2 -2
- ui/static/static/documentation/__next._tree.txt +2 -2
- ui/static/static/documentation/__next.documentation.__PAGE__.txt +2 -2
- ui/static/static/documentation/__next.documentation.txt +1 -1
- ui/static/static/documentation/index.html +2 -2
- ui/static/static/documentation/index.txt +3 -3
- ui/static/static/index.html +1 -1
- ui/static/static/index.txt +2 -2
- ui/static/static/metadata/__next._full.txt +2 -2
- ui/static/static/metadata/__next._head.txt +1 -1
- ui/static/static/metadata/__next._index.txt +2 -2
- ui/static/static/metadata/__next._tree.txt +2 -2
- ui/static/static/metadata/__next.metadata.__PAGE__.txt +1 -1
- ui/static/static/metadata/__next.metadata.txt +1 -1
- ui/static/static/metadata/index.html +1 -1
- ui/static/static/metadata/index.txt +2 -2
- ui/static/static/quality/__next._full.txt +2 -2
- ui/static/static/quality/__next._head.txt +1 -1
- ui/static/static/quality/__next._index.txt +2 -2
- ui/static/static/quality/__next._tree.txt +2 -2
- ui/static/static/quality/__next.quality.__PAGE__.txt +1 -1
- ui/static/static/quality/__next.quality.txt +1 -1
- ui/static/static/quality/index.html +2 -2
- ui/static/static/quality/index.txt +2 -2
- ui/static/static/rules/__next._full.txt +2 -2
- ui/static/static/rules/__next._head.txt +1 -1
- ui/static/static/rules/__next._index.txt +2 -2
- ui/static/static/rules/__next._tree.txt +2 -2
- ui/static/static/rules/__next.rules.__PAGE__.txt +1 -1
- ui/static/static/rules/__next.rules.txt +1 -1
- ui/static/static/rules/index.html +1 -1
- ui/static/static/rules/index.txt +2 -2
- ui/static/static/schemas/__next._full.txt +2 -2
- ui/static/static/schemas/__next._head.txt +1 -1
- ui/static/static/schemas/__next._index.txt +2 -2
- ui/static/static/schemas/__next._tree.txt +2 -2
- ui/static/static/schemas/__next.schemas.__PAGE__.txt +1 -1
- ui/static/static/schemas/__next.schemas.txt +1 -1
- ui/static/static/schemas/index.html +1 -1
- ui/static/static/schemas/index.txt +2 -2
- ui/static/static/settings/__next._full.txt +2 -2
- ui/static/static/settings/__next._head.txt +1 -1
- ui/static/static/settings/__next._index.txt +2 -2
- ui/static/static/settings/__next._tree.txt +2 -2
- ui/static/static/settings/__next.settings.__PAGE__.txt +1 -1
- ui/static/static/settings/__next.settings.txt +1 -1
- ui/static/static/settings/index.html +1 -1
- ui/static/static/settings/index.txt +2 -2
- ui/static/static/static/.gitkeep +0 -0
- ui/static/static/static/404/index.html +1 -0
- ui/static/static/static/404.html +1 -0
- ui/static/static/static/__next.__PAGE__.txt +10 -0
- ui/static/static/static/__next._full.txt +30 -0
- ui/static/static/static/__next._head.txt +7 -0
- ui/static/static/static/__next._index.txt +9 -0
- ui/static/static/static/__next._tree.txt +2 -0
- ui/static/static/static/_next/static/chunks/222442f6da32302a.js +1 -0
- ui/static/static/static/_next/static/chunks/247eb132b7f7b574.js +1 -0
- ui/static/static/static/_next/static/chunks/297d55555b71baba.js +1 -0
- ui/static/static/static/_next/static/chunks/2ab439ce003cd691.js +1 -0
- ui/static/static/static/_next/static/chunks/414e77373f8ff61c.js +1 -0
- ui/static/static/static/_next/static/chunks/49ca65abd26ae49e.js +1 -0
- ui/static/static/static/_next/static/chunks/652ad0aa26265c47.js +2 -0
- ui/static/static/static/_next/static/chunks/9667e7a3d359eb39.js +1 -0
- ui/static/static/static/_next/static/chunks/9c23f44fff36548a.js +1 -0
- ui/static/static/static/_next/static/chunks/a6dad97d9634a72d.js +1 -0
- ui/static/static/static/_next/static/chunks/b32a0963684b9933.js +4 -0
- ui/static/static/static/_next/static/chunks/c69f6cba366bd988.js +1 -0
- ui/static/static/static/_next/static/chunks/db913959c675cea6.js +1 -0
- ui/static/static/static/_next/static/chunks/f061a4be97bfc3b3.js +1 -0
- ui/static/static/static/_next/static/chunks/f2e7afeab1178138.js +1 -0
- ui/static/static/static/_next/static/chunks/ff1a16fafef87110.js +1 -0
- ui/static/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +3 -0
- ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_buildManifest.js +11 -0
- ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_ssgManifest.js +1 -0
- ui/static/static/static/_not-found/__next._full.txt +17 -0
- ui/static/static/static/_not-found/__next._head.txt +7 -0
- ui/static/static/static/_not-found/__next._index.txt +9 -0
- ui/static/static/static/_not-found/__next._not-found.__PAGE__.txt +5 -0
- ui/static/static/static/_not-found/__next._not-found.txt +4 -0
- ui/static/static/static/_not-found/__next._tree.txt +2 -0
- ui/static/static/static/_not-found/index.html +1 -0
- ui/static/static/static/_not-found/index.txt +17 -0
- ui/static/static/static/contracts/__next._full.txt +21 -0
- ui/static/static/static/contracts/__next._head.txt +7 -0
- ui/static/static/static/contracts/__next._index.txt +9 -0
- ui/static/static/static/contracts/__next._tree.txt +2 -0
- ui/static/static/static/contracts/__next.contracts.__PAGE__.txt +9 -0
- ui/static/static/static/contracts/__next.contracts.txt +4 -0
- ui/static/static/static/contracts/index.html +1 -0
- ui/static/static/static/contracts/index.txt +21 -0
- ui/static/static/static/documentation/__next._full.txt +21 -0
- ui/static/static/static/documentation/__next._head.txt +7 -0
- ui/static/static/static/documentation/__next._index.txt +9 -0
- ui/static/static/static/documentation/__next._tree.txt +2 -0
- ui/static/static/static/documentation/__next.documentation.__PAGE__.txt +9 -0
- ui/static/static/static/documentation/__next.documentation.txt +4 -0
- ui/static/static/static/documentation/index.html +93 -0
- ui/static/static/static/documentation/index.txt +21 -0
- ui/static/static/static/index.html +1 -0
- ui/static/static/static/index.txt +30 -0
- ui/static/static/static/metadata/__next._full.txt +21 -0
- ui/static/static/static/metadata/__next._head.txt +7 -0
- ui/static/static/static/metadata/__next._index.txt +9 -0
- ui/static/static/static/metadata/__next._tree.txt +2 -0
- ui/static/static/static/metadata/__next.metadata.__PAGE__.txt +9 -0
- ui/static/static/static/metadata/__next.metadata.txt +4 -0
- ui/static/static/static/metadata/index.html +1 -0
- ui/static/static/static/metadata/index.txt +21 -0
- ui/static/static/static/quality/__next._full.txt +21 -0
- ui/static/static/static/quality/__next._head.txt +7 -0
- ui/static/static/static/quality/__next._index.txt +9 -0
- ui/static/static/static/quality/__next._tree.txt +2 -0
- ui/static/static/static/quality/__next.quality.__PAGE__.txt +9 -0
- ui/static/static/static/quality/__next.quality.txt +4 -0
- ui/static/static/static/quality/index.html +2 -0
- ui/static/static/static/quality/index.txt +21 -0
- ui/static/static/static/rules/__next._full.txt +21 -0
- ui/static/static/static/rules/__next._head.txt +7 -0
- ui/static/static/static/rules/__next._index.txt +9 -0
- ui/static/static/static/rules/__next._tree.txt +2 -0
- ui/static/static/static/rules/__next.rules.__PAGE__.txt +9 -0
- ui/static/static/static/rules/__next.rules.txt +4 -0
- ui/static/static/static/rules/index.html +1 -0
- ui/static/static/static/rules/index.txt +21 -0
- ui/static/static/static/schemas/__next._full.txt +21 -0
- ui/static/static/static/schemas/__next._head.txt +7 -0
- ui/static/static/static/schemas/__next._index.txt +9 -0
- ui/static/static/static/schemas/__next._tree.txt +2 -0
- ui/static/static/static/schemas/__next.schemas.__PAGE__.txt +9 -0
- ui/static/static/static/schemas/__next.schemas.txt +4 -0
- ui/static/static/static/schemas/index.html +1 -0
- ui/static/static/static/schemas/index.txt +21 -0
- ui/static/static/static/settings/__next._full.txt +21 -0
- ui/static/static/static/settings/__next._head.txt +7 -0
- ui/static/static/static/settings/__next._index.txt +9 -0
- ui/static/static/static/settings/__next._tree.txt +2 -0
- ui/static/static/static/settings/__next.settings.__PAGE__.txt +9 -0
- ui/static/static/static/settings/__next.settings.txt +4 -0
- ui/static/static/static/settings/index.html +1 -0
- ui/static/static/static/settings/index.txt +21 -0
- ui/static/static/static/validation/__next._full.txt +21 -0
- ui/static/static/static/validation/__next._head.txt +7 -0
- ui/static/static/static/validation/__next._index.txt +9 -0
- ui/static/static/static/validation/__next._tree.txt +2 -0
- ui/static/static/static/validation/__next.validation.__PAGE__.txt +9 -0
- ui/static/static/static/validation/__next.validation.txt +4 -0
- ui/static/static/static/validation/index.html +1 -0
- ui/static/static/static/validation/index.txt +21 -0
- ui/static/static/validation/__next._full.txt +2 -2
- ui/static/static/validation/__next._head.txt +1 -1
- ui/static/static/validation/__next._index.txt +2 -2
- ui/static/static/validation/__next._tree.txt +2 -2
- ui/static/static/validation/__next.validation.__PAGE__.txt +1 -1
- ui/static/static/validation/__next.validation.txt +1 -1
- ui/static/static/validation/index.html +1 -1
- ui/static/static/validation/index.txt +2 -2
- ui/static/validation/__next._full.txt +2 -2
- ui/static/validation/__next._head.txt +1 -1
- ui/static/validation/__next._index.txt +1 -1
- ui/static/validation/__next._tree.txt +1 -1
- ui/static/validation/__next.validation.__PAGE__.txt +2 -2
- ui/static/validation/__next.validation.txt +1 -1
- ui/static/validation/index.html +1 -1
- ui/static/validation/index.txt +2 -2
- pycharter/data/templates/template_coercion_rules.yaml +0 -15
- pycharter/data/templates/template_contract.yaml +0 -587
- pycharter/data/templates/template_metadata.yaml +0 -38
- pycharter/data/templates/template_schema.yaml +0 -22
- pycharter/data/templates/template_transform_advanced.yaml +0 -50
- pycharter/data/templates/template_transform_simple.yaml +0 -59
- pycharter/data/templates/template_validation_rules.yaml +0 -29
- pycharter/etl_generator/extraction.py +0 -916
- pycharter/etl_generator/factory.py +0 -174
- pycharter/etl_generator/orchestrator.py +0 -1650
- pycharter/integrations/__init__.py +0 -19
- pycharter/integrations/kafka.py +0 -178
- pycharter/integrations/streaming.py +0 -100
- pycharter-0.0.22.dist-info/RECORD +0 -358
- {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/entry_points.txt +0 -0
- {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/licenses/LICENSE +0 -0
- {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/top_level.txt +0 -0
- /ui/static/_next/static/{0rYA78L88aUyD2Uh38hhX → 2gKjNv6YvE6BcIdFthBLs}/_buildManifest.js +0 -0
- /ui/static/_next/static/{0rYA78L88aUyD2Uh38hhX → 2gKjNv6YvE6BcIdFthBLs}/_ssgManifest.js +0 -0
- /ui/static/static/_next/static/{tNTkVW6puVXC4bAm4WrHl → 0rYA78L88aUyD2Uh38hhX}/_buildManifest.js +0 -0
- /ui/static/static/_next/static/{tNTkVW6puVXC4bAm4WrHl → 0rYA78L88aUyD2Uh38hhX}/_ssgManifest.js +0 -0
- /ui/static/{_next → static/_next}/static/chunks/c4fa4f4114b7c352.js +0 -0
- /ui/static/static/{_next → static/_next}/static/chunks/4e310fe5005770a3.css +0 -0
- /ui/static/{_next → static/static/_next}/static/chunks/5e04d10c4a7b58a3.js +0 -0
- /ui/static/static/{_next → static/_next}/static/chunks/5fc14c00a2779dc5.js +0 -0
- /ui/static/{_next → static/static/_next}/static/chunks/75d88a058d8ffaa6.js +0 -0
- /ui/static/{_next → static/static/_next}/static/chunks/8c89634cf6bad76f.js +0 -0
- /ui/static/static/{_next → static/_next}/static/chunks/b584574fdc8ab13e.js +0 -0
- /ui/static/static/{_next → static/_next}/static/chunks/d5989c94d3614b3a.js +0 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Documentation Generator - Core generation logic.
|
|
3
|
+
|
|
4
|
+
Transforms ContractMetadata into human-readable documentation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from typing import Any, Dict, List, Optional, Union
|
|
9
|
+
|
|
10
|
+
from pycharter.contract_parser import ContractMetadata
|
|
11
|
+
from pycharter.docs_generator.renderers import DocsRenderer, MarkdownRenderer
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DocsGenerator:
|
|
15
|
+
"""
|
|
16
|
+
Generate documentation from data contracts.
|
|
17
|
+
|
|
18
|
+
Transforms ContractMetadata objects into human-readable documentation
|
|
19
|
+
in various formats (Markdown, HTML, etc.).
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
>>> from pycharter import parse_contract_file
|
|
23
|
+
>>> from pycharter.docs_generator import DocsGenerator
|
|
24
|
+
>>>
|
|
25
|
+
>>> contract = parse_contract_file("contract.yaml")
|
|
26
|
+
>>> generator = DocsGenerator()
|
|
27
|
+
>>> docs = generator.generate(contract)
|
|
28
|
+
>>> print(docs)
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, renderer: Optional[DocsRenderer] = None):
|
|
32
|
+
"""
|
|
33
|
+
Initialize the documentation generator.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
renderer: Renderer to use for output format. Defaults to MarkdownRenderer.
|
|
37
|
+
"""
|
|
38
|
+
self.renderer = renderer or MarkdownRenderer()
|
|
39
|
+
|
|
40
|
+
def generate(
|
|
41
|
+
self,
|
|
42
|
+
contract: ContractMetadata,
|
|
43
|
+
include_schema: bool = True,
|
|
44
|
+
include_coercions: bool = True,
|
|
45
|
+
include_validations: bool = True,
|
|
46
|
+
include_metadata: bool = True,
|
|
47
|
+
) -> str:
|
|
48
|
+
"""
|
|
49
|
+
Generate full documentation for a contract.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
contract: ContractMetadata object to document
|
|
53
|
+
include_schema: Include schema field documentation
|
|
54
|
+
include_coercions: Include coercion rules documentation
|
|
55
|
+
include_validations: Include validation rules documentation
|
|
56
|
+
include_metadata: Include metadata/ownership documentation
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Generated documentation as string
|
|
60
|
+
"""
|
|
61
|
+
parts = []
|
|
62
|
+
|
|
63
|
+
# Get title from schema or metadata
|
|
64
|
+
title = self._get_title(contract)
|
|
65
|
+
version = contract.versions.get("schema") or contract.schema.get("version")
|
|
66
|
+
|
|
67
|
+
# Header
|
|
68
|
+
parts.append(self.renderer.render_header(title, version))
|
|
69
|
+
|
|
70
|
+
# Description
|
|
71
|
+
description = contract.schema.get("description") or contract.metadata.get(
|
|
72
|
+
"description"
|
|
73
|
+
)
|
|
74
|
+
if description:
|
|
75
|
+
parts.append(self.renderer.render_description(description))
|
|
76
|
+
|
|
77
|
+
# Schema section
|
|
78
|
+
if include_schema and contract.schema:
|
|
79
|
+
parts.append(self.generate_schema_section(contract.schema))
|
|
80
|
+
|
|
81
|
+
# Coercion rules section
|
|
82
|
+
if include_coercions and contract.coercion_rules:
|
|
83
|
+
parts.append(self.generate_coercion_section(contract.coercion_rules))
|
|
84
|
+
|
|
85
|
+
# Validation rules section
|
|
86
|
+
if include_validations and contract.validation_rules:
|
|
87
|
+
parts.append(self.generate_validation_section(contract.validation_rules))
|
|
88
|
+
|
|
89
|
+
# Metadata section
|
|
90
|
+
if include_metadata and contract.metadata:
|
|
91
|
+
parts.append(self.generate_metadata_section(contract))
|
|
92
|
+
|
|
93
|
+
# Footer for HTML
|
|
94
|
+
if hasattr(self.renderer, "render_footer"):
|
|
95
|
+
parts.append(self.renderer.render_footer())
|
|
96
|
+
|
|
97
|
+
return "".join(parts)
|
|
98
|
+
|
|
99
|
+
def generate_schema_section(self, schema: Dict[str, Any]) -> str:
|
|
100
|
+
"""
|
|
101
|
+
Generate documentation for schema fields.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
schema: JSON Schema dictionary
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Formatted schema documentation
|
|
108
|
+
"""
|
|
109
|
+
properties = schema.get("properties", {})
|
|
110
|
+
required = set(schema.get("required", []))
|
|
111
|
+
|
|
112
|
+
if not properties:
|
|
113
|
+
return ""
|
|
114
|
+
|
|
115
|
+
# Build table rows for fields
|
|
116
|
+
headers = ["Field", "Type", "Required", "Description", "Constraints"]
|
|
117
|
+
rows = []
|
|
118
|
+
|
|
119
|
+
for field_name, field_def in properties.items():
|
|
120
|
+
row = self._build_field_row(field_name, field_def, field_name in required)
|
|
121
|
+
rows.append(row)
|
|
122
|
+
|
|
123
|
+
table = self.renderer.render_table(headers, rows)
|
|
124
|
+
return self.renderer.render_section("Schema Fields", table)
|
|
125
|
+
|
|
126
|
+
def generate_coercion_section(self, rules: Dict[str, Any]) -> str:
|
|
127
|
+
"""
|
|
128
|
+
Generate documentation for coercion rules.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
rules: Coercion rules dictionary
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Formatted coercion documentation
|
|
135
|
+
"""
|
|
136
|
+
# Filter out version key
|
|
137
|
+
coercion_rules = {k: v for k, v in rules.items() if k != "version"}
|
|
138
|
+
|
|
139
|
+
if not coercion_rules:
|
|
140
|
+
return ""
|
|
141
|
+
|
|
142
|
+
headers = ["Field", "Coercion", "Description"]
|
|
143
|
+
rows = []
|
|
144
|
+
|
|
145
|
+
for field, coercion in coercion_rules.items():
|
|
146
|
+
if isinstance(coercion, str):
|
|
147
|
+
coercion_name = coercion
|
|
148
|
+
description = self._get_coercion_description(coercion_name)
|
|
149
|
+
elif isinstance(coercion, dict):
|
|
150
|
+
coercion_name = coercion.get("type", str(coercion))
|
|
151
|
+
description = coercion.get(
|
|
152
|
+
"description", self._get_coercion_description(coercion_name)
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
coercion_name = str(coercion)
|
|
156
|
+
description = ""
|
|
157
|
+
|
|
158
|
+
rows.append([f"`{field}`", f"`{coercion_name}`", description])
|
|
159
|
+
|
|
160
|
+
content = self.renderer.render_description(
|
|
161
|
+
"Coercions are applied before validation to transform incoming data."
|
|
162
|
+
)
|
|
163
|
+
content += self.renderer.render_table(headers, rows)
|
|
164
|
+
return self.renderer.render_section("Coercion Rules", content)
|
|
165
|
+
|
|
166
|
+
def generate_validation_section(self, rules: Dict[str, Any]) -> str:
|
|
167
|
+
"""
|
|
168
|
+
Generate documentation for validation rules.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
rules: Validation rules dictionary
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
Formatted validation documentation
|
|
175
|
+
"""
|
|
176
|
+
# Filter out version key
|
|
177
|
+
validation_rules = {k: v for k, v in rules.items() if k != "version"}
|
|
178
|
+
|
|
179
|
+
if not validation_rules:
|
|
180
|
+
return ""
|
|
181
|
+
|
|
182
|
+
headers = ["Field", "Validation", "Configuration"]
|
|
183
|
+
rows = []
|
|
184
|
+
|
|
185
|
+
for field, validations in validation_rules.items():
|
|
186
|
+
if isinstance(validations, dict):
|
|
187
|
+
for val_name, val_config in validations.items():
|
|
188
|
+
config_str = self._format_config(val_config)
|
|
189
|
+
rows.append([f"`{field}`", f"`{val_name}`", config_str])
|
|
190
|
+
elif isinstance(validations, str):
|
|
191
|
+
rows.append([f"`{field}`", f"`{validations}`", ""])
|
|
192
|
+
elif isinstance(validations, list):
|
|
193
|
+
for val in validations:
|
|
194
|
+
rows.append([f"`{field}`", f"`{val}`", ""])
|
|
195
|
+
|
|
196
|
+
content = self.renderer.render_description(
|
|
197
|
+
"Validations are applied after coercion to ensure data meets requirements."
|
|
198
|
+
)
|
|
199
|
+
content += self.renderer.render_table(headers, rows)
|
|
200
|
+
return self.renderer.render_section("Validation Rules", content)
|
|
201
|
+
|
|
202
|
+
def generate_metadata_section(self, contract: ContractMetadata) -> str:
|
|
203
|
+
"""
|
|
204
|
+
Generate documentation for contract metadata.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
contract: ContractMetadata object
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Formatted metadata documentation
|
|
211
|
+
"""
|
|
212
|
+
parts = []
|
|
213
|
+
|
|
214
|
+
# Ownership section
|
|
215
|
+
if contract.ownership:
|
|
216
|
+
ownership_content = self._format_ownership(contract.ownership)
|
|
217
|
+
parts.append(
|
|
218
|
+
self.renderer.render_section("Ownership", ownership_content)
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Governance rules
|
|
222
|
+
if contract.governance_rules:
|
|
223
|
+
governance_content = self._format_governance(contract.governance_rules)
|
|
224
|
+
parts.append(
|
|
225
|
+
self.renderer.render_section("Governance Rules", governance_content)
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# Version information
|
|
229
|
+
if contract.versions:
|
|
230
|
+
version_content = self._format_versions(contract.versions)
|
|
231
|
+
parts.append(
|
|
232
|
+
self.renderer.render_section("Version Information", version_content)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Other metadata
|
|
236
|
+
other_metadata = {
|
|
237
|
+
k: v
|
|
238
|
+
for k, v in contract.metadata.items()
|
|
239
|
+
if k not in ["ownership", "governance_rules", "version"]
|
|
240
|
+
}
|
|
241
|
+
if other_metadata:
|
|
242
|
+
other_content = self._format_metadata_dict(other_metadata)
|
|
243
|
+
parts.append(
|
|
244
|
+
self.renderer.render_section("Additional Metadata", other_content)
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
return "".join(parts)
|
|
248
|
+
|
|
249
|
+
def _get_title(self, contract: ContractMetadata) -> str:
|
|
250
|
+
"""Extract title from contract."""
|
|
251
|
+
# Try schema title
|
|
252
|
+
if "title" in contract.schema:
|
|
253
|
+
return contract.schema["title"]
|
|
254
|
+
# Try metadata title
|
|
255
|
+
if "title" in contract.metadata:
|
|
256
|
+
return contract.metadata["title"]
|
|
257
|
+
# Try schema $id
|
|
258
|
+
if "$id" in contract.schema:
|
|
259
|
+
return contract.schema["$id"]
|
|
260
|
+
return "Data Contract Documentation"
|
|
261
|
+
|
|
262
|
+
def _build_field_row(
|
|
263
|
+
self, field_name: str, field_def: Dict[str, Any], is_required: bool
|
|
264
|
+
) -> List[str]:
|
|
265
|
+
"""Build a table row for a schema field."""
|
|
266
|
+
# Type
|
|
267
|
+
field_type = self._get_field_type(field_def)
|
|
268
|
+
|
|
269
|
+
# Required badge
|
|
270
|
+
required_str = "Yes" if is_required else "No"
|
|
271
|
+
|
|
272
|
+
# Description
|
|
273
|
+
description = field_def.get("description", "")
|
|
274
|
+
|
|
275
|
+
# Constraints
|
|
276
|
+
constraints = self._get_field_constraints(field_def)
|
|
277
|
+
|
|
278
|
+
return [f"`{field_name}`", field_type, required_str, description, constraints]
|
|
279
|
+
|
|
280
|
+
def _get_field_type(self, field_def: Dict[str, Any]) -> str:
|
|
281
|
+
"""Extract field type from definition."""
|
|
282
|
+
if "type" in field_def:
|
|
283
|
+
base_type = field_def["type"]
|
|
284
|
+
if base_type == "array" and "items" in field_def:
|
|
285
|
+
items_type = self._get_field_type(field_def["items"])
|
|
286
|
+
return f"array[{items_type}]"
|
|
287
|
+
return base_type
|
|
288
|
+
if "anyOf" in field_def:
|
|
289
|
+
types = [self._get_field_type(t) for t in field_def["anyOf"]]
|
|
290
|
+
return " | ".join(types)
|
|
291
|
+
if "oneOf" in field_def:
|
|
292
|
+
types = [self._get_field_type(t) for t in field_def["oneOf"]]
|
|
293
|
+
return " | ".join(types)
|
|
294
|
+
if "$ref" in field_def:
|
|
295
|
+
return f"ref: {field_def['$ref']}"
|
|
296
|
+
return "any"
|
|
297
|
+
|
|
298
|
+
def _get_field_constraints(self, field_def: Dict[str, Any]) -> str:
|
|
299
|
+
"""Extract constraints from field definition."""
|
|
300
|
+
constraints = []
|
|
301
|
+
|
|
302
|
+
# String constraints
|
|
303
|
+
if "minLength" in field_def:
|
|
304
|
+
constraints.append(f"minLength: {field_def['minLength']}")
|
|
305
|
+
if "maxLength" in field_def:
|
|
306
|
+
constraints.append(f"maxLength: {field_def['maxLength']}")
|
|
307
|
+
if "pattern" in field_def:
|
|
308
|
+
constraints.append(f"pattern: `{field_def['pattern']}`")
|
|
309
|
+
if "format" in field_def:
|
|
310
|
+
constraints.append(f"format: {field_def['format']}")
|
|
311
|
+
|
|
312
|
+
# Number constraints
|
|
313
|
+
if "minimum" in field_def:
|
|
314
|
+
constraints.append(f"min: {field_def['minimum']}")
|
|
315
|
+
if "maximum" in field_def:
|
|
316
|
+
constraints.append(f"max: {field_def['maximum']}")
|
|
317
|
+
if "exclusiveMinimum" in field_def:
|
|
318
|
+
constraints.append(f"exclusiveMin: {field_def['exclusiveMinimum']}")
|
|
319
|
+
if "exclusiveMaximum" in field_def:
|
|
320
|
+
constraints.append(f"exclusiveMax: {field_def['exclusiveMaximum']}")
|
|
321
|
+
if "multipleOf" in field_def:
|
|
322
|
+
constraints.append(f"multipleOf: {field_def['multipleOf']}")
|
|
323
|
+
|
|
324
|
+
# Enum
|
|
325
|
+
if "enum" in field_def:
|
|
326
|
+
enum_vals = ", ".join(str(v) for v in field_def["enum"][:5])
|
|
327
|
+
if len(field_def["enum"]) > 5:
|
|
328
|
+
enum_vals += "..."
|
|
329
|
+
constraints.append(f"enum: [{enum_vals}]")
|
|
330
|
+
|
|
331
|
+
# Default
|
|
332
|
+
if "default" in field_def:
|
|
333
|
+
constraints.append(f"default: {field_def['default']}")
|
|
334
|
+
|
|
335
|
+
return "; ".join(constraints) if constraints else ""
|
|
336
|
+
|
|
337
|
+
def _get_coercion_description(self, coercion_name: str) -> str:
|
|
338
|
+
"""Get description for built-in coercion types."""
|
|
339
|
+
descriptions = {
|
|
340
|
+
"to_string": "Convert value to string",
|
|
341
|
+
"to_integer": "Convert value to integer",
|
|
342
|
+
"to_float": "Convert value to float",
|
|
343
|
+
"to_number": "Convert value to number",
|
|
344
|
+
"to_boolean": "Convert value to boolean",
|
|
345
|
+
"to_datetime": "Parse value as datetime",
|
|
346
|
+
"to_date": "Parse value as date",
|
|
347
|
+
"trim": "Remove leading/trailing whitespace",
|
|
348
|
+
"lowercase": "Convert to lowercase",
|
|
349
|
+
"uppercase": "Convert to uppercase",
|
|
350
|
+
"strip_html": "Remove HTML tags",
|
|
351
|
+
"normalize_whitespace": "Normalize whitespace characters",
|
|
352
|
+
}
|
|
353
|
+
return descriptions.get(coercion_name, "")
|
|
354
|
+
|
|
355
|
+
def _format_config(self, config: Any) -> str:
|
|
356
|
+
"""Format validation configuration for display."""
|
|
357
|
+
if config is None:
|
|
358
|
+
return ""
|
|
359
|
+
if isinstance(config, bool):
|
|
360
|
+
return "enabled" if config else "disabled"
|
|
361
|
+
if isinstance(config, (int, float, str)):
|
|
362
|
+
return str(config)
|
|
363
|
+
if isinstance(config, dict):
|
|
364
|
+
parts = [f"{k}={v}" for k, v in config.items()]
|
|
365
|
+
return ", ".join(parts)
|
|
366
|
+
if isinstance(config, list):
|
|
367
|
+
return ", ".join(str(v) for v in config)
|
|
368
|
+
return str(config)
|
|
369
|
+
|
|
370
|
+
def _format_ownership(self, ownership: Dict[str, Any]) -> str:
|
|
371
|
+
"""Format ownership information."""
|
|
372
|
+
headers = ["Role", "Contact"]
|
|
373
|
+
rows = []
|
|
374
|
+
|
|
375
|
+
role_labels = {
|
|
376
|
+
"business_owners": "Business Owners",
|
|
377
|
+
"bu_sme": "Business Unit SME",
|
|
378
|
+
"it_application_owners": "IT Application Owners",
|
|
379
|
+
"it_sme": "IT SME",
|
|
380
|
+
"support_lead": "Support Lead",
|
|
381
|
+
"owner": "Owner",
|
|
382
|
+
"team": "Team",
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for key, value in ownership.items():
|
|
386
|
+
label = role_labels.get(key, key.replace("_", " ").title())
|
|
387
|
+
if isinstance(value, list):
|
|
388
|
+
value_str = ", ".join(str(v) for v in value)
|
|
389
|
+
else:
|
|
390
|
+
value_str = str(value)
|
|
391
|
+
rows.append([label, value_str])
|
|
392
|
+
|
|
393
|
+
return self.renderer.render_table(headers, rows)
|
|
394
|
+
|
|
395
|
+
def _format_governance(self, governance: Dict[str, Any]) -> str:
|
|
396
|
+
"""Format governance rules."""
|
|
397
|
+
headers = ["Rule", "Configuration"]
|
|
398
|
+
rows = []
|
|
399
|
+
|
|
400
|
+
for rule, config in governance.items():
|
|
401
|
+
rule_label = rule.replace("_", " ").title()
|
|
402
|
+
config_str = self._format_config(config)
|
|
403
|
+
rows.append([rule_label, config_str])
|
|
404
|
+
|
|
405
|
+
return self.renderer.render_table(headers, rows)
|
|
406
|
+
|
|
407
|
+
def _format_versions(self, versions: Dict[str, str]) -> str:
|
|
408
|
+
"""Format version information."""
|
|
409
|
+
headers = ["Component", "Version"]
|
|
410
|
+
rows = [[comp.replace("_", " ").title(), ver] for comp, ver in versions.items()]
|
|
411
|
+
return self.renderer.render_table(headers, rows)
|
|
412
|
+
|
|
413
|
+
def _format_metadata_dict(self, metadata: Dict[str, Any]) -> str:
|
|
414
|
+
"""Format a metadata dictionary."""
|
|
415
|
+
headers = ["Property", "Value"]
|
|
416
|
+
rows = []
|
|
417
|
+
for key, value in metadata.items():
|
|
418
|
+
if isinstance(value, (dict, list)):
|
|
419
|
+
value_str = json.dumps(value, indent=2)
|
|
420
|
+
else:
|
|
421
|
+
value_str = str(value)
|
|
422
|
+
rows.append([key.replace("_", " ").title(), value_str])
|
|
423
|
+
return self.renderer.render_table(headers, rows)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def generate_docs(
|
|
427
|
+
contract: Union[ContractMetadata, Dict[str, Any]],
|
|
428
|
+
format: str = "markdown",
|
|
429
|
+
**kwargs,
|
|
430
|
+
) -> str:
|
|
431
|
+
"""
|
|
432
|
+
Convenience function to generate documentation from a contract.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
contract: ContractMetadata object or contract dictionary
|
|
436
|
+
format: Output format ('markdown' or 'html')
|
|
437
|
+
**kwargs: Additional options passed to DocsGenerator.generate()
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
Generated documentation as string
|
|
441
|
+
|
|
442
|
+
Example:
|
|
443
|
+
>>> from pycharter import parse_contract_file
|
|
444
|
+
>>> from pycharter.docs_generator import generate_docs
|
|
445
|
+
>>>
|
|
446
|
+
>>> contract = parse_contract_file("contract.yaml")
|
|
447
|
+
>>> markdown = generate_docs(contract)
|
|
448
|
+
>>> html = generate_docs(contract, format="html")
|
|
449
|
+
"""
|
|
450
|
+
from pycharter.docs_generator.renderers import HTMLRenderer, MarkdownRenderer
|
|
451
|
+
|
|
452
|
+
# Convert dict to ContractMetadata if needed
|
|
453
|
+
if isinstance(contract, dict):
|
|
454
|
+
from pycharter.contract_parser import parse_contract
|
|
455
|
+
|
|
456
|
+
contract = parse_contract(contract, validate=False)
|
|
457
|
+
|
|
458
|
+
# Select renderer
|
|
459
|
+
if format.lower() == "html":
|
|
460
|
+
renderer = HTMLRenderer()
|
|
461
|
+
else:
|
|
462
|
+
renderer = MarkdownRenderer()
|
|
463
|
+
|
|
464
|
+
generator = DocsGenerator(renderer=renderer)
|
|
465
|
+
return generator.generate(contract, **kwargs)
|