etlplus 0.14.3__tar.gz → 0.15.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {etlplus-0.14.3/etlplus.egg-info → etlplus-0.15.0}/PKG-INFO +1 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/README.md +1 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/README.md +2 -2
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/utils.py +5 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/README.md +2 -2
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/handlers.py +2 -2
- etlplus-0.15.0/etlplus/config/README.md +50 -0
- etlplus-0.15.0/etlplus/config/__init__.py +33 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/config/types.py +0 -64
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/database/README.md +2 -2
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/README.md +2 -2
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/run.py +14 -9
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/templates/README.md +2 -2
- {etlplus-0.14.3/etlplus/config → etlplus-0.15.0/etlplus/workflow}/README.md +6 -6
- {etlplus-0.14.3/etlplus/config → etlplus-0.15.0/etlplus/workflow}/__init__.py +10 -23
- {etlplus-0.14.3/etlplus/config → etlplus-0.15.0/etlplus/workflow}/connector.py +17 -16
- etlplus-0.15.0/etlplus/workflow/dag.py +105 -0
- {etlplus-0.14.3/etlplus/config → etlplus-0.15.0/etlplus/workflow}/jobs.py +17 -11
- {etlplus-0.14.3/etlplus/config → etlplus-0.15.0/etlplus/workflow}/pipeline.py +11 -3
- {etlplus-0.14.3/etlplus/config → etlplus-0.15.0/etlplus/workflow}/profile.py +8 -5
- etlplus-0.15.0/etlplus/workflow/types.py +115 -0
- {etlplus-0.14.3 → etlplus-0.15.0/etlplus.egg-info}/PKG-INFO +1 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus.egg-info/SOURCES.txt +13 -9
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/conftest.py +6 -6
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_pagination_strategy.py +11 -11
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_pipeline_yaml_load.py +1 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_run.py +1 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_run_profile_pagination_defaults.py +1 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_run_profile_rate_limit_defaults.py +1 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/cli/conftest.py +2 -2
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/cli/test_u_cli_handlers.py +3 -1
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/conftest.py +1 -1
- etlplus-0.14.3/tests/unit/config/test_u_connector.py → etlplus-0.15.0/tests/unit/workflow/test_u_workflow_connector.py +6 -6
- etlplus-0.14.3/tests/unit/config/test_u_jobs.py → etlplus-0.15.0/tests/unit/workflow/test_u_workflow_jobs.py +3 -3
- etlplus-0.14.3/tests/unit/config/test_u_pipeline.py → etlplus-0.15.0/tests/unit/workflow/test_u_workflow_pipeline.py +7 -7
- etlplus-0.14.3/tests/unit/config/test_u_config_utils.py → etlplus-0.15.0/tests/unit/workflow/test_u_workflow_utils.py +3 -3
- {etlplus-0.14.3 → etlplus-0.15.0}/.coveragerc +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/.editorconfig +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/.gitattributes +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/.github/actions/python-bootstrap/action.yml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/.github/workflows/ci.yml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/.gitignore +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/.pre-commit-config.yaml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/.ruff.toml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/CODE_OF_CONDUCT.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/CONTRIBUTING.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/DEMO.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/LICENSE +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/MANIFEST.in +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/Makefile +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/README.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/REFERENCES.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/SECURITY.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/SUPPORT.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/docs/README.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/docs/pipeline-guide.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/docs/snippets/installation_version.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/__main__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/__version__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/auth.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/config.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/endpoint_client.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/enums.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/errors.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/pagination/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/pagination/client.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/pagination/config.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/pagination/paginator.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/rate_limiting/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/rate_limiting/config.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/rate_limiting/rate_limiter.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/request_manager.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/retry_manager.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/transport.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/api/types.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/commands.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/constants.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/io.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/main.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/options.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/state.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/cli/types.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/dag.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/database/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/database/ddl.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/database/engine.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/database/orm.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/database/schema.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/database/types.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/enums.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/_imports.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/_io.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/accdb.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/arrow.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/avro.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/bson.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/cbor.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/cfg.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/conf.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/core.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/csv.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/dat.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/dta.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/duckdb.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/enums.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/feather.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/fwf.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/gz.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/hbs.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/hdf5.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/ini.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/ion.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/jinja2.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/json.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/log.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/mat.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/mdb.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/msgpack.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/mustache.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/nc.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/ndjson.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/numbers.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/ods.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/orc.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/parquet.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/pb.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/pbf.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/properties.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/proto.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/psv.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/rda.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/rds.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/sas7bdat.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/sav.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/sqlite.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/stub.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/sylk.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/tab.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/toml.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/tsv.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/txt.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/vm.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/wks.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/xls.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/xlsm.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/xlsx.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/xml.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/xpt.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/yaml.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/zip.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/file/zsav.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/mixins.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/README.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/extract.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/load.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/transform.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/utils.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/ops/validate.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/py.typed +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/templates/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/templates/ddl.sql.j2 +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/templates/view.sql.j2 +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/types.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus/utils.py +0 -0
- {etlplus-0.14.3/etlplus/config → etlplus-0.15.0/etlplus/workflow}/utils.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus.egg-info/dependency_links.txt +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus.egg-info/entry_points.txt +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus.egg-info/requires.txt +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/etlplus.egg-info/top_level.txt +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/README.md +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/configs/ddl_spec.yml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/configs/pipeline.yml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/data/sample.csv +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/data/sample.json +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/data/sample.xml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/data/sample.xsd +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/data/sample.yaml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/examples/quickstart_python.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/pyproject.toml +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/pytest.ini +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/setup.cfg +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/setup.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/__init__.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/conftest.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_cli.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_examples_data_parity.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/integration/test_i_pipeline_smoke.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/conftest.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_api_enums.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_api_utils.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_auth.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_config.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_endpoint_client.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_mocks.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_pagination_client.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_pagination_config.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_paginator.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_rate_limit_config.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_rate_limiter.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_request_manager.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_retry_manager.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_transport.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/api/test_u_types.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/cli/test_u_cli_io.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/cli/test_u_cli_main.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/cli/test_u_cli_state.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/database/test_u_database_ddl.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/database/test_u_database_engine.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/database/test_u_database_orm.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/database/test_u_database_schema.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/file/test_u_file_core.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/file/test_u_file_enums.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/file/test_u_file_yaml.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/ops/test_u_ops_extract.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/ops/test_u_ops_load.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/ops/test_u_ops_run.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/ops/test_u_ops_transform.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/ops/test_u_ops_utils.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/ops/test_u_ops_validate.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/test_u_enums.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/test_u_main.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/test_u_mixins.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/test_u_utils.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tests/unit/test_u_version.py +0 -0
- {etlplus-0.14.3 → etlplus-0.15.0}/tools/update_demo_snippets.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# etlplus.api
|
|
1
|
+
# `etlplus.api` Subpackage
|
|
2
2
|
|
|
3
3
|
Documentation for the `etlplus.api` subpackage: a lightweight HTTP client and helpers for paginated
|
|
4
4
|
REST endpoints.
|
|
@@ -12,7 +12,7 @@ REST endpoints.
|
|
|
12
12
|
|
|
13
13
|
Back to project overview: see the top-level [README](../../README.md).
|
|
14
14
|
|
|
15
|
-
- [etlplus.api
|
|
15
|
+
- [`etlplus.api` Subpackage](#etlplusapi-subpackage)
|
|
16
16
|
- [Installation](#installation)
|
|
17
17
|
- [Quickstart](#quickstart)
|
|
18
18
|
- [Overriding Rate Limits Per Call](#overriding-rate-limits-per-call)
|
|
@@ -892,4 +892,8 @@ def resolve_request(
|
|
|
892
892
|
'Session object must supply a callable '
|
|
893
893
|
f'"{http_method.value}" method',
|
|
894
894
|
)
|
|
895
|
-
|
|
895
|
+
typed_request_callable = cast(
|
|
896
|
+
Callable[..., requests.Response],
|
|
897
|
+
request_callable,
|
|
898
|
+
)
|
|
899
|
+
return typed_request_callable, request_timeout, http_method
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# etlplus.cli
|
|
1
|
+
# `etlplus.cli` Subpackage
|
|
2
2
|
|
|
3
3
|
Documentation for the `etlplus.cli` subpackage: command-line interface for ETLPlus workflows.
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ Documentation for the `etlplus.cli` subpackage: command-line interface for ETLPl
|
|
|
9
9
|
|
|
10
10
|
Back to project overview: see the top-level [README](../../README.md).
|
|
11
11
|
|
|
12
|
-
- [etlplus.cli
|
|
12
|
+
- [`etlplus.cli` Subpackage](#etlpluscli-subpackage)
|
|
13
13
|
- [Available Commands](#available-commands)
|
|
14
14
|
- [Command Options](#command-options)
|
|
15
15
|
- [Example: Running a Pipeline](#example-running-a-pipeline)
|
|
@@ -14,8 +14,6 @@ from typing import Any
|
|
|
14
14
|
from typing import Literal
|
|
15
15
|
from typing import cast
|
|
16
16
|
|
|
17
|
-
from ..config import PipelineConfig
|
|
18
|
-
from ..config import load_pipeline_config
|
|
19
17
|
from ..database import load_table_spec
|
|
20
18
|
from ..database import render_tables
|
|
21
19
|
from ..file import File
|
|
@@ -28,6 +26,8 @@ from ..ops import validate
|
|
|
28
26
|
from ..ops.validate import FieldRules
|
|
29
27
|
from ..types import JSONData
|
|
30
28
|
from ..types import TemplateKey
|
|
29
|
+
from ..workflow import PipelineConfig
|
|
30
|
+
from ..workflow import load_pipeline_config
|
|
31
31
|
from . import io as cli_io
|
|
32
32
|
|
|
33
33
|
# SECTION: EXPORTS ========================================================== #
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `etlplus.config` Subpackage
|
|
2
|
+
|
|
3
|
+
Documentation for the `etlplus.config` subpackage: type definitions and config shape helpers for
|
|
4
|
+
ETLPlus.
|
|
5
|
+
|
|
6
|
+
- Exposes TypedDict-based config schemas for API profiles and endpoints
|
|
7
|
+
- Provides exported type aliases for API configuration maps
|
|
8
|
+
- Designed for Python 3.13 typing and editor assistance (runtime parsing lives elsewhere)
|
|
9
|
+
|
|
10
|
+
Back to project overview: see the top-level [README](../../README.md).
|
|
11
|
+
|
|
12
|
+
- [`etlplus.config` Subpackage](#etlplusconfig-subpackage)
|
|
13
|
+
- [Modules](#modules)
|
|
14
|
+
- [Exported Types](#exported-types)
|
|
15
|
+
- [Example: Typing an API Config](#example-typing-an-api-config)
|
|
16
|
+
- [See Also](#see-also)
|
|
17
|
+
|
|
18
|
+
## Modules
|
|
19
|
+
|
|
20
|
+
- `etlplus.config.__init__`: package exports and high-level package notes
|
|
21
|
+
- `etlplus.config.types`: TypedDict-based config schemas
|
|
22
|
+
|
|
23
|
+
## Exported Types
|
|
24
|
+
|
|
25
|
+
- `ApiConfigMap`: top-level API config shape
|
|
26
|
+
- `ApiProfileConfigMap`: per-profile API config shape
|
|
27
|
+
- `ApiProfileDefaultsMap`: defaults block within a profile
|
|
28
|
+
- `EndpointMap`: endpoint config shape
|
|
29
|
+
|
|
30
|
+
## Example: Typing an API Config
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from etlplus.config import ApiConfigMap
|
|
34
|
+
|
|
35
|
+
api_cfg: ApiConfigMap = {
|
|
36
|
+
"base_url": "https://example.test",
|
|
37
|
+
"headers": {"Authorization": "Bearer token"},
|
|
38
|
+
"endpoints": {
|
|
39
|
+
"users": {
|
|
40
|
+
"path": "/users",
|
|
41
|
+
"method": "GET",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## See Also
|
|
48
|
+
|
|
49
|
+
- Top-level CLI and library usage in the main [README](../../README.md)
|
|
50
|
+
- Config type definitions in [types.py](types.py)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.config` package.
|
|
3
|
+
|
|
4
|
+
Configuration models and helpers for ETLPlus.
|
|
5
|
+
|
|
6
|
+
This package defines models for data sources/targets ("connectors"), APIs,
|
|
7
|
+
pagination/rate limits, pipeline orchestration, and related utilities. The
|
|
8
|
+
parsers are permissive (accepting ``Mapping[str, Any]``) and normalize to
|
|
9
|
+
concrete types without raising on unknown/optional fields.
|
|
10
|
+
|
|
11
|
+
Notes
|
|
12
|
+
-----
|
|
13
|
+
- The models use ``@dataclass(slots=True)`` and avoid mutating inputs.
|
|
14
|
+
- TypedDicts are editor/type-checking hints and are not enforced at runtime.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from .types import ApiConfigMap
|
|
20
|
+
from .types import ApiProfileConfigMap
|
|
21
|
+
from .types import ApiProfileDefaultsMap
|
|
22
|
+
from .types import EndpointMap
|
|
23
|
+
|
|
24
|
+
# SECTION: EXPORTS ========================================================== #
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
# Typed Dicts
|
|
29
|
+
'ApiConfigMap',
|
|
30
|
+
'ApiProfileConfigMap',
|
|
31
|
+
'ApiProfileDefaultsMap',
|
|
32
|
+
'EndpointMap',
|
|
33
|
+
]
|
|
@@ -33,7 +33,6 @@ from __future__ import annotations
|
|
|
33
33
|
|
|
34
34
|
from collections.abc import Mapping
|
|
35
35
|
from typing import Any
|
|
36
|
-
from typing import Literal
|
|
37
36
|
from typing import TypedDict
|
|
38
37
|
|
|
39
38
|
from ..api import PaginationConfigMap
|
|
@@ -44,26 +43,17 @@ from ..types import StrAnyMap
|
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
__all__ = [
|
|
47
|
-
# Type aliases
|
|
48
|
-
'ConnectorType',
|
|
49
|
-
# 'PaginationType',
|
|
50
46
|
# TypedDicts
|
|
51
47
|
'ApiProfileDefaultsMap',
|
|
52
48
|
'ApiProfileConfigMap',
|
|
53
49
|
'ApiConfigMap',
|
|
54
50
|
'EndpointMap',
|
|
55
|
-
'ConnectorApiConfigMap',
|
|
56
|
-
'ConnectorDbConfigMap',
|
|
57
|
-
'ConnectorFileConfigMap',
|
|
58
51
|
]
|
|
59
52
|
|
|
60
53
|
|
|
61
54
|
# SECTION: TYPE ALIASES ===================================================== #
|
|
62
55
|
|
|
63
56
|
|
|
64
|
-
# Literal type for supported connector kinds
|
|
65
|
-
type ConnectorType = Literal['api', 'database', 'file']
|
|
66
|
-
|
|
67
57
|
# Literal type for supported pagination kinds
|
|
68
58
|
# type PaginationType = Literal['page', 'offset', 'cursor']
|
|
69
59
|
|
|
@@ -129,60 +119,6 @@ class ApiProfileDefaultsMap(TypedDict, total=False):
|
|
|
129
119
|
rate_limit: RateLimitConfigMap | StrAnyMap
|
|
130
120
|
|
|
131
121
|
|
|
132
|
-
class ConnectorApiConfigMap(TypedDict, total=False):
|
|
133
|
-
"""
|
|
134
|
-
Shape accepted by ConnectorApi.from_obj (all keys optional).
|
|
135
|
-
|
|
136
|
-
See Also
|
|
137
|
-
--------
|
|
138
|
-
- etlplus.config.connector.ConnectorApi.from_obj
|
|
139
|
-
"""
|
|
140
|
-
|
|
141
|
-
name: str
|
|
142
|
-
type: ConnectorType
|
|
143
|
-
url: str
|
|
144
|
-
method: str
|
|
145
|
-
headers: StrAnyMap
|
|
146
|
-
query_params: StrAnyMap
|
|
147
|
-
pagination: PaginationConfigMap
|
|
148
|
-
rate_limit: RateLimitConfigMap
|
|
149
|
-
api: str
|
|
150
|
-
endpoint: str
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
class ConnectorDbConfigMap(TypedDict, total=False):
|
|
154
|
-
"""
|
|
155
|
-
Shape accepted by ConnectorDb.from_obj (all keys optional).
|
|
156
|
-
|
|
157
|
-
See Also
|
|
158
|
-
--------
|
|
159
|
-
- etlplus.config.connector.ConnectorDb.from_obj
|
|
160
|
-
"""
|
|
161
|
-
|
|
162
|
-
name: str
|
|
163
|
-
type: ConnectorType
|
|
164
|
-
connection_string: str
|
|
165
|
-
query: str
|
|
166
|
-
table: str
|
|
167
|
-
mode: str
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class ConnectorFileConfigMap(TypedDict, total=False):
|
|
171
|
-
"""
|
|
172
|
-
Shape accepted by ConnectorFile.from_obj (all keys optional).
|
|
173
|
-
|
|
174
|
-
See Also
|
|
175
|
-
--------
|
|
176
|
-
- etlplus.config.connector.ConnectorFile.from_obj
|
|
177
|
-
"""
|
|
178
|
-
|
|
179
|
-
name: str
|
|
180
|
-
type: ConnectorType
|
|
181
|
-
format: str
|
|
182
|
-
path: str
|
|
183
|
-
options: StrAnyMap
|
|
184
|
-
|
|
185
|
-
|
|
186
122
|
class EndpointMap(TypedDict, total=False):
|
|
187
123
|
"""
|
|
188
124
|
Shape accepted by EndpointConfig.from_obj.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# etlplus.database
|
|
1
|
+
# `etlplus.database` Subpackage
|
|
2
2
|
|
|
3
3
|
Documentation for the `etlplus.database` subpackage: database engine, schema, and ORM helpers.
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ Documentation for the `etlplus.database` subpackage: database engine, schema, an
|
|
|
9
9
|
|
|
10
10
|
Back to project overview: see the top-level [README](../../README.md).
|
|
11
11
|
|
|
12
|
-
- [etlplus.database
|
|
12
|
+
- [`etlplus.database` Subpackage](#etlplusdatabase-subpackage)
|
|
13
13
|
- [Database Engine and Connections](#database-engine-and-connections)
|
|
14
14
|
- [Schema and DDL Helpers](#schema-and-ddl-helpers)
|
|
15
15
|
- [ORM Utilities](#orm-utilities)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# etlplus.file
|
|
1
|
+
# `etlplus.file` Subpackage
|
|
2
2
|
|
|
3
3
|
Documentation for the `etlplus.file` subpackage: unified file format support and helpers for reading
|
|
4
4
|
and writing data files.
|
|
@@ -11,7 +11,7 @@ and writing data files.
|
|
|
11
11
|
|
|
12
12
|
Back to project overview: see the top-level [README](../../README.md).
|
|
13
13
|
|
|
14
|
-
- [etlplus.file
|
|
14
|
+
- [`etlplus.file` Subpackage](#etlplusfile-subpackage)
|
|
15
15
|
- [Supported File Formats](#supported-file-formats)
|
|
16
16
|
- [Inferring File Format and Compression](#inferring-file-format-and-compression)
|
|
17
17
|
- [Reading and Writing Files](#reading-and-writing-files)
|
|
@@ -20,7 +20,6 @@ from ..api import RequestOptions
|
|
|
20
20
|
from ..api import compose_api_request_env
|
|
21
21
|
from ..api import compose_api_target_env
|
|
22
22
|
from ..api import paginate_with_client
|
|
23
|
-
from ..config import load_pipeline_config
|
|
24
23
|
from ..enums import DataConnectorType
|
|
25
24
|
from ..file import FileFormat
|
|
26
25
|
from ..types import JSONData
|
|
@@ -29,6 +28,7 @@ from ..types import PipelineConfig
|
|
|
29
28
|
from ..types import StrPath
|
|
30
29
|
from ..types import Timeout
|
|
31
30
|
from ..utils import print_json
|
|
31
|
+
from ..workflow import load_pipeline_config
|
|
32
32
|
from .extract import extract
|
|
33
33
|
from .load import load
|
|
34
34
|
from .transform import transform
|
|
@@ -162,9 +162,12 @@ def run(
|
|
|
162
162
|
# can monkeypatch this class on etlplus.ops.run.
|
|
163
163
|
ClientClass = EndpointClient # noqa: N806
|
|
164
164
|
client = ClientClass(
|
|
165
|
-
base_url=cast(str, env
|
|
165
|
+
base_url=cast(str, env.get('base_url')),
|
|
166
166
|
base_path=cast(str | None, env.get('base_path')),
|
|
167
|
-
endpoints=cast(
|
|
167
|
+
endpoints=cast(
|
|
168
|
+
dict[str, str],
|
|
169
|
+
env.get('endpoints_map', {}),
|
|
170
|
+
),
|
|
168
171
|
retry=env.get('retry'),
|
|
169
172
|
retry_network_errors=bool(
|
|
170
173
|
env.get('retry_network_errors', False),
|
|
@@ -173,7 +176,7 @@ def run(
|
|
|
173
176
|
)
|
|
174
177
|
data = paginate_with_client(
|
|
175
178
|
client,
|
|
176
|
-
cast(str, env
|
|
179
|
+
cast(str, env.get('endpoint_key')),
|
|
177
180
|
env.get('params'),
|
|
178
181
|
env.get('headers'),
|
|
179
182
|
env.get('timeout'),
|
|
@@ -276,12 +279,14 @@ def run(
|
|
|
276
279
|
if not url_t:
|
|
277
280
|
raise ValueError('API target missing "url"')
|
|
278
281
|
kwargs_t: dict[str, Any] = {}
|
|
279
|
-
|
|
280
|
-
|
|
282
|
+
headers = env_t.get('headers')
|
|
283
|
+
if headers:
|
|
284
|
+
kwargs_t['headers'] = cast(dict[str, str], headers)
|
|
281
285
|
if env_t.get('timeout') is not None:
|
|
282
|
-
kwargs_t['timeout'] = env_t
|
|
283
|
-
|
|
284
|
-
|
|
286
|
+
kwargs_t['timeout'] = env_t.get('timeout')
|
|
287
|
+
session = env_t.get('session')
|
|
288
|
+
if session is not None:
|
|
289
|
+
kwargs_t['session'] = session
|
|
285
290
|
result = load(
|
|
286
291
|
data,
|
|
287
292
|
'api',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# etlplus.templates
|
|
1
|
+
# `etlplus.templates` Subpackage
|
|
2
2
|
|
|
3
3
|
Documentation for the `etlplus.templates` subpackage: SQL and DDL template helpers.
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ Documentation for the `etlplus.templates` subpackage: SQL and DDL template helpe
|
|
|
8
8
|
|
|
9
9
|
Back to project overview: see the top-level [README](../../README.md).
|
|
10
10
|
|
|
11
|
-
- [etlplus.templates
|
|
11
|
+
- [`etlplus.templates` Subpackage](#etlplus-templates-subpackage)
|
|
12
12
|
- [Available Templates](#available-templates)
|
|
13
13
|
- [Rendering Templates](#rendering-templates)
|
|
14
14
|
- [Example: Rendering a DDL Template](#example-rendering-a-ddl-template)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# etlplus.
|
|
1
|
+
# `etlplus.workflow` Subpackage
|
|
2
2
|
|
|
3
|
-
Documentation for the `etlplus.
|
|
4
|
-
jobs, and profiles.
|
|
3
|
+
Documentation for the `etlplus.workflow` subpackage: configuration helpers for connectors,
|
|
4
|
+
pipelines, jobs, and profiles.
|
|
5
5
|
|
|
6
6
|
- Provides classes and utilities for managing ETL pipeline configuration
|
|
7
7
|
- Supports YAML/JSON config loading and validation
|
|
@@ -10,7 +10,7 @@ jobs, and profiles.
|
|
|
10
10
|
|
|
11
11
|
Back to project overview: see the top-level [README](../../README.md).
|
|
12
12
|
|
|
13
|
-
- [etlplus.
|
|
13
|
+
- [`etlplus.workflow` Subpackage](#etlplusworkflow-subpackage)
|
|
14
14
|
- [Supported Configuration Types](#supported-configuration-types)
|
|
15
15
|
- [Loading and Validating Configs](#loading-and-validating-configs)
|
|
16
16
|
- [Example: Loading a Pipeline Config](#example-loading-a-pipeline-config)
|
|
@@ -28,7 +28,7 @@ Back to project overview: see the top-level [README](../../README.md).
|
|
|
28
28
|
Use the provided classes to load and validate configuration files:
|
|
29
29
|
|
|
30
30
|
```python
|
|
31
|
-
from etlplus.
|
|
31
|
+
from etlplus.workflow import PipelineConfig
|
|
32
32
|
|
|
33
33
|
cfg = PipelineConfig.from_yaml("pipeline.yml")
|
|
34
34
|
```
|
|
@@ -39,7 +39,7 @@ cfg = PipelineConfig.from_yaml("pipeline.yml")
|
|
|
39
39
|
## Example: Loading a Pipeline Config
|
|
40
40
|
|
|
41
41
|
```python
|
|
42
|
-
from etlplus.
|
|
42
|
+
from etlplus.workflow import PipelineConfig
|
|
43
43
|
|
|
44
44
|
pipeline = PipelineConfig.from_yaml("configs/pipeline.yml")
|
|
45
45
|
print(pipeline)
|
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
|
-
:mod:`etlplus.
|
|
2
|
+
:mod:`etlplus.workflow` package.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
This package defines models for data sources/targets ("connectors"), APIs,
|
|
7
|
-
pagination/rate limits, pipeline orchestration, and related utilities. The
|
|
8
|
-
parsers are permissive (accepting ``Mapping[str, Any]``) and normalize to
|
|
9
|
-
concrete types without raising on unknown/optional fields.
|
|
10
|
-
|
|
11
|
-
Notes
|
|
12
|
-
-----
|
|
13
|
-
- The models use ``@dataclass(slots=True)`` and avoid mutating inputs.
|
|
14
|
-
- TypedDicts are editor/type-checking hints and are not enforced at runtime.
|
|
4
|
+
Job workflow helpers.
|
|
15
5
|
"""
|
|
16
6
|
|
|
17
7
|
from __future__ import annotations
|
|
@@ -21,6 +11,7 @@ from .connector import ConnectorApi
|
|
|
21
11
|
from .connector import ConnectorDb
|
|
22
12
|
from .connector import ConnectorFile
|
|
23
13
|
from .connector import parse_connector
|
|
14
|
+
from .dag import topological_sort_jobs
|
|
24
15
|
from .jobs import ExtractRef
|
|
25
16
|
from .jobs import JobConfig
|
|
26
17
|
from .jobs import LoadRef
|
|
@@ -28,29 +19,25 @@ from .jobs import TransformRef
|
|
|
28
19
|
from .jobs import ValidationRef
|
|
29
20
|
from .pipeline import PipelineConfig
|
|
30
21
|
from .pipeline import load_pipeline_config
|
|
31
|
-
from .profile import ProfileConfig
|
|
32
|
-
from .types import ConnectorType
|
|
33
22
|
|
|
34
23
|
# SECTION: EXPORTS ========================================================== #
|
|
35
24
|
|
|
36
25
|
|
|
37
26
|
__all__ = [
|
|
38
|
-
#
|
|
39
|
-
'Connector',
|
|
40
|
-
'ConnectorType',
|
|
27
|
+
# Data Classes
|
|
41
28
|
'ConnectorApi',
|
|
42
29
|
'ConnectorDb',
|
|
43
30
|
'ConnectorFile',
|
|
44
|
-
'parse_connector',
|
|
45
|
-
# Jobs / Refs
|
|
46
31
|
'ExtractRef',
|
|
47
32
|
'JobConfig',
|
|
48
33
|
'LoadRef',
|
|
34
|
+
'PipelineConfig',
|
|
49
35
|
'TransformRef',
|
|
50
36
|
'ValidationRef',
|
|
51
|
-
#
|
|
52
|
-
'PipelineConfig',
|
|
37
|
+
# Functions
|
|
53
38
|
'load_pipeline_config',
|
|
54
|
-
|
|
55
|
-
'
|
|
39
|
+
'parse_connector',
|
|
40
|
+
'topological_sort_jobs',
|
|
41
|
+
# Type Aliases
|
|
42
|
+
'Connector',
|
|
56
43
|
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
:mod:`etlplus.
|
|
2
|
+
:mod:`etlplus.workflow.connector` module.
|
|
3
3
|
|
|
4
4
|
A module defining configuration types for data source/target connectors in ETL
|
|
5
5
|
pipelines. A "connector" is any I/O endpoint:
|
|
@@ -11,18 +11,19 @@ pipelines. A "connector" is any I/O endpoint:
|
|
|
11
11
|
|
|
12
12
|
Examples
|
|
13
13
|
--------
|
|
14
|
-
- Use
|
|
15
|
-
|
|
16
|
-
- Use the
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
- Use :class:`ConnectorApi`/:class:`ConnectorFile`/:class:`ConnectorDb` when
|
|
15
|
+
you want the concrete dataclasses.
|
|
16
|
+
- Use the :class:`Connector` union for typing a value that can be any
|
|
17
|
+
connector.
|
|
18
|
+
- Use :func:`parse_connector(obj)` to construct a connector instance from a
|
|
19
|
+
generic mapping that includes a *type* key.
|
|
19
20
|
|
|
20
21
|
Notes
|
|
21
22
|
-----
|
|
22
23
|
- TypedDict shapes are editor hints; runtime parsing remains permissive
|
|
23
|
-
|
|
24
|
+
(from_obj accepts Mapping[str, Any]).
|
|
24
25
|
- TypedDicts referenced in :mod:`etlplus.config.types` remain editor hints.
|
|
25
|
-
|
|
26
|
+
Runtime parsing stays permissive and tolerant.
|
|
26
27
|
|
|
27
28
|
See Also
|
|
28
29
|
--------
|
|
@@ -59,7 +60,7 @@ if TYPE_CHECKING: # Editor-only typing hints to avoid runtime imports
|
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
__all__ = [
|
|
62
|
-
# Classes
|
|
63
|
+
# Data Classes
|
|
63
64
|
'ConnectorApi',
|
|
64
65
|
'ConnectorDb',
|
|
65
66
|
'ConnectorFile',
|
|
@@ -83,12 +84,12 @@ class ConnectorApi:
|
|
|
83
84
|
name : str
|
|
84
85
|
Unique connector name.
|
|
85
86
|
type : ConnectorType
|
|
86
|
-
Connector kind literal, always ``
|
|
87
|
+
Connector kind literal, always ``'api'``.
|
|
87
88
|
url : str | None
|
|
88
89
|
Direct absolute URL (when not using ``service``/``endpoint`` refs).
|
|
89
90
|
method : str | None
|
|
90
91
|
Optional HTTP method; typically omitted for sources (defaults to
|
|
91
|
-
GET) and used for targets (e.g., ``
|
|
92
|
+
GET) and used for targets (e.g., ``'post'``).
|
|
92
93
|
headers : dict[str, str]
|
|
93
94
|
Additional request headers.
|
|
94
95
|
query_params : dict[str, Any]
|
|
@@ -111,7 +112,7 @@ class ConnectorApi:
|
|
|
111
112
|
|
|
112
113
|
# Direct form
|
|
113
114
|
url: str | None = None
|
|
114
|
-
# Optional HTTP method; typically omitted for sources (defaults to GET
|
|
115
|
+
# Optional HTTP method; typically omitted for sources (defaults to GET)
|
|
115
116
|
# at runtime) and used for targets (e.g., 'post', 'put').
|
|
116
117
|
method: str | None = None
|
|
117
118
|
headers: dict[str, str] = field(default_factory=dict)
|
|
@@ -185,7 +186,7 @@ class ConnectorDb:
|
|
|
185
186
|
name : str
|
|
186
187
|
Unique connector name.
|
|
187
188
|
type : ConnectorType
|
|
188
|
-
Connector kind literal, always ``
|
|
189
|
+
Connector kind literal, always ``'database'``.
|
|
189
190
|
connection_string : str | None
|
|
190
191
|
Connection string/DSN for the database.
|
|
191
192
|
query : str | None
|
|
@@ -193,7 +194,7 @@ class ConnectorDb:
|
|
|
193
194
|
table : str | None
|
|
194
195
|
Target/source table name (optional).
|
|
195
196
|
mode : str | None
|
|
196
|
-
Load mode hint (e.g., ``
|
|
197
|
+
Load mode hint (e.g., ``'append'``, ``'replace'``) — future use.
|
|
197
198
|
"""
|
|
198
199
|
|
|
199
200
|
# -- Attributes -- #
|
|
@@ -262,9 +263,9 @@ class ConnectorFile:
|
|
|
262
263
|
name : str
|
|
263
264
|
Unique connector name.
|
|
264
265
|
type : ConnectorType
|
|
265
|
-
Connector kind literal, always ``
|
|
266
|
+
Connector kind literal, always ``'file'``.
|
|
266
267
|
format : str | None
|
|
267
|
-
File format (e.g., ``
|
|
268
|
+
File format (e.g., ``'json'``, ``'csv'``).
|
|
268
269
|
path : str | None
|
|
269
270
|
File path or URI.
|
|
270
271
|
options : dict[str, Any]
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.workflow.dag` module.
|
|
3
|
+
|
|
4
|
+
Lightweight directed acyclic graph (DAG) helpers for ordering jobs based on
|
|
5
|
+
:attr:`depends_on`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections import deque
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
|
|
13
|
+
from .jobs import JobConfig
|
|
14
|
+
|
|
15
|
+
# SECTION: EXPORTS ========================================================== #
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
# Errors
|
|
20
|
+
'DagError',
|
|
21
|
+
# Functions
|
|
22
|
+
'topological_sort_jobs',
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# SECTION: ERRORS =========================================================== #
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(slots=True)
|
|
30
|
+
class DagError(ValueError):
|
|
31
|
+
"""
|
|
32
|
+
Raised when the job dependency graph is invalid.
|
|
33
|
+
|
|
34
|
+
Attributes
|
|
35
|
+
----------
|
|
36
|
+
message : str
|
|
37
|
+
Error message.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# -- Attributes -- #
|
|
41
|
+
|
|
42
|
+
message: str
|
|
43
|
+
|
|
44
|
+
# -- Magic Methods (Object Representation) -- #
|
|
45
|
+
|
|
46
|
+
def __str__(self) -> str:
|
|
47
|
+
return self.message
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# SECTION: FUNCTIONS ======================================================== #
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def topological_sort_jobs(
|
|
54
|
+
jobs: list[JobConfig],
|
|
55
|
+
) -> list[JobConfig]:
|
|
56
|
+
"""
|
|
57
|
+
Return jobs in topological order based on :attr:`depends_on`.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
jobs : list[JobConfig]
|
|
62
|
+
List of job configurations to sort.
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
list[JobConfig]
|
|
67
|
+
Jobs sorted in topological order.
|
|
68
|
+
|
|
69
|
+
Raises
|
|
70
|
+
------
|
|
71
|
+
DagError
|
|
72
|
+
If a dependency is missing, self-referential, or when a cycle is
|
|
73
|
+
detected.
|
|
74
|
+
"""
|
|
75
|
+
index = {job.name: job for job in jobs}
|
|
76
|
+
edges: dict[str, set[str]] = {name: set() for name in index}
|
|
77
|
+
indegree: dict[str, int] = {name: 0 for name in index}
|
|
78
|
+
|
|
79
|
+
for job in jobs:
|
|
80
|
+
for dep in job.depends_on:
|
|
81
|
+
if dep not in index:
|
|
82
|
+
raise DagError(
|
|
83
|
+
f'Unknown dependency "{dep}" in job "{job.name}"',
|
|
84
|
+
)
|
|
85
|
+
if dep == job.name:
|
|
86
|
+
raise DagError(f'Job "{job.name}" depends on itself')
|
|
87
|
+
if job.name not in edges[dep]:
|
|
88
|
+
edges[dep].add(job.name)
|
|
89
|
+
indegree[job.name] += 1
|
|
90
|
+
|
|
91
|
+
queue = deque(sorted(name for name, deg in indegree.items() if deg == 0))
|
|
92
|
+
ordered: list[str] = []
|
|
93
|
+
|
|
94
|
+
while queue:
|
|
95
|
+
name = queue.popleft()
|
|
96
|
+
ordered.append(name)
|
|
97
|
+
for child in sorted(edges[name]):
|
|
98
|
+
indegree[child] -= 1
|
|
99
|
+
if indegree[child] == 0:
|
|
100
|
+
queue.append(child)
|
|
101
|
+
|
|
102
|
+
if len(ordered) != len(jobs):
|
|
103
|
+
raise DagError('Dependency cycle detected')
|
|
104
|
+
|
|
105
|
+
return [index[name] for name in ordered]
|