etlplus 0.16.3__tar.gz → 0.16.4__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.16.3 → etlplus-0.16.4}/CONTRIBUTING.md +1 -1
- {etlplus-0.16.3/etlplus.egg-info → etlplus-0.16.4}/PKG-INFO +1 -1
- {etlplus-0.16.3 → etlplus-0.16.4}/docs/pipeline-guide.md +2 -2
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/README.md +22 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/__init__.py +2 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/commands.py +22 -22
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/handlers.py +8 -9
- etlplus-0.16.3/etlplus/workflow/pipeline.py → etlplus-0.16.4/etlplus/config.py +17 -37
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/run.py +2 -2
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/types.py +2 -1
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/workflow/README.md +0 -24
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/workflow/__init__.py +0 -4
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/workflow/jobs.py +0 -2
- {etlplus-0.16.3 → etlplus-0.16.4/etlplus.egg-info}/PKG-INFO +1 -1
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus.egg-info/SOURCES.txt +4 -4
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/conftest.py +13 -13
- etlplus-0.16.3/tests/integration/test_i_pipeline_yaml_load.py → etlplus-0.16.4/tests/integration/test_i_config_load.py +9 -9
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/test_i_pagination_strategy.py +2 -2
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/test_i_run.py +3 -3
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/test_i_run_profile_pagination_defaults.py +3 -3
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/test_i_run_profile_rate_limit_defaults.py +2 -2
- etlplus-0.16.3/tests/unit/api/test_u_config.py → etlplus-0.16.4/tests/unit/api/test_u_api_config.py +1 -1
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/cli/conftest.py +3 -3
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/cli/test_u_cli_handlers.py +19 -19
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/conftest.py +12 -7
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/ops/test_u_ops_run.py +24 -24
- etlplus-0.16.3/tests/unit/workflow/test_u_workflow_pipeline.py → etlplus-0.16.4/tests/unit/test_u_config.py +25 -25
- {etlplus-0.16.3 → etlplus-0.16.4}/.coveragerc +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/.editorconfig +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/.gitattributes +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/.github/actions/python-bootstrap/action.yml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/.github/workflows/ci.yml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/.gitignore +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/.pre-commit-config.yaml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/.ruff.toml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/CODE_OF_CONDUCT.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/DEMO.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/LICENSE +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/MANIFEST.in +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/Makefile +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/REFERENCES.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/SECURITY.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/SUPPORT.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/docs/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/docs/snippets/installation_version.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/__main__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/__version__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/auth.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/config.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/endpoint_client.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/errors.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/pagination/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/pagination/client.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/pagination/config.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/pagination/paginator.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/rate_limiting/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/rate_limiting/config.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/rate_limiting/rate_limiter.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/request_manager.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/retry_manager.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/transport.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/types.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/api/utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/constants.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/io.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/main.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/options.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/state.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/cli/types.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/api.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/connector.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/core.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/database.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/file.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/types.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/connector/utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/database/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/database/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/database/ddl.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/database/engine.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/database/orm.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/database/schema.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/database/types.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/_imports.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/_io.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/accdb.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/arrow.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/avro.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/bson.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/cbor.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/cfg.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/conf.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/core.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/csv.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/dat.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/dta.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/duckdb.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/feather.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/fwf.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/gz.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/hbs.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/hdf5.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/ini.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/ion.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/jinja2.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/json.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/log.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/mat.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/mdb.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/msgpack.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/mustache.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/nc.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/ndjson.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/numbers.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/ods.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/orc.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/parquet.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/pb.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/pbf.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/properties.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/proto.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/psv.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/rda.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/rds.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/sas7bdat.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/sav.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/sqlite.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/stub.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/sylk.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/tab.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/toml.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/tsv.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/txt.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/vm.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/wks.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/xls.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/xlsm.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/xlsx.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/xml.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/xpt.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/yaml.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/zip.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/file/zsav.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/mixins.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/extract.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/load.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/transform.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/types.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/ops/validate.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/py.typed +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/templates/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/templates/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/templates/ddl.sql.j2 +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/templates/view.sql.j2 +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/workflow/dag.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus/workflow/profile.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus.egg-info/dependency_links.txt +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus.egg-info/entry_points.txt +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus.egg-info/requires.txt +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/etlplus.egg-info/top_level.txt +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/README.md +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/configs/ddl_spec.yml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/configs/pipeline.yml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/data/sample.csv +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/data/sample.json +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/data/sample.xml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/data/sample.xsd +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/data/sample.yaml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/examples/quickstart.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/pyproject.toml +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/pytest.ini +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/setup.cfg +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/setup.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/__init__.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/conftest.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/test_i_cli.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/test_i_examples_data_parity.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/integration/test_i_pipeline_smoke.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/conftest.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_api_enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_api_utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_auth.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_endpoint_client.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_mocks.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_pagination_client.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_pagination_config.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_paginator.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_rate_limit_config.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_rate_limiter.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_request_manager.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_retry_manager.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_transport.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/api/test_u_types.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/cli/test_u_cli_io.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/cli/test_u_cli_main.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/cli/test_u_cli_state.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/connector/test_u_connector_enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/connector/test_u_connector_utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/database/test_u_database_ddl.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/database/test_u_database_engine.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/database/test_u_database_orm.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/database/test_u_database_schema.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/file/test_u_file_core.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/file/test_u_file_enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/file/test_u_file_yaml.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/ops/test_u_ops_enums.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/ops/test_u_ops_extract.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/ops/test_u_ops_load.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/ops/test_u_ops_transform.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/ops/test_u_ops_utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/ops/test_u_ops_validate.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/test_u_main.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/test_u_mixins.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/test_u_utils.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/test_u_version.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tests/unit/workflow/test_u_workflow_jobs.py +0 -0
- {etlplus-0.16.3 → etlplus-0.16.4}/tools/update_demo_snippets.py +0 -0
|
@@ -133,5 +133,5 @@ If a test calls `etlplus.cli.main()` or `etlplus.ops.run.run()`, it is integrati
|
|
|
133
133
|
- CLI tests: monkeypatch `sys.argv` and call `etlplus.cli.main()`; capture output with `capsys`.
|
|
134
134
|
- File I/O: use `tmp_path` / `TemporaryDirectory()`; never write to the repo tree.
|
|
135
135
|
- API flows: stub `EndpointClient` or transport layer via `monkeypatch` to avoid real HTTP.
|
|
136
|
-
- Runner tests: monkeypatch `
|
|
136
|
+
- Runner tests: monkeypatch `load_config` to inject an in-memory `Config`.
|
|
137
137
|
- Keep tests small and focused; prefer one behavior per test with clear assertions.
|
|
@@ -497,8 +497,8 @@ For the HTTP client and pagination API, see `etlplus/api/README.md`.
|
|
|
497
497
|
|
|
498
498
|
## Design notes: Mapping inputs, dict outputs
|
|
499
499
|
|
|
500
|
-
ETLPlus config constructors (e.g., `ApiConfig.from_obj`, `
|
|
501
|
-
|
|
500
|
+
ETLPlus config constructors (e.g., `ApiConfig.from_obj`, `Config.from_dict`) accept `Mapping[str,
|
|
501
|
+
Any]` rather than `dict[str, Any]` for inputs. Why?
|
|
502
502
|
|
|
503
503
|
- Flexibility: callers can pass any mapping-like object (e.g., YAML loaders that return custom
|
|
504
504
|
mappings) without copying into a `dict` first.
|
|
@@ -31,6 +31,28 @@ assert validate(filtered, {"age": {"type": "number", "min": 0}})["valid"]
|
|
|
31
31
|
load(filtered, "file", "output.json", file_format="json")
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Loading and Validating Configs
|
|
35
|
+
|
|
36
|
+
Use the provided classes to load and validate configuration files:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from etlplus.workflow import Config
|
|
40
|
+
|
|
41
|
+
cfg = Config.from_yaml("pipeline.yml")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- Supports YAML and JSON formats
|
|
45
|
+
- Validates against expected schema
|
|
46
|
+
|
|
47
|
+
## Example: Loading a Pipeline Config
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from etlplus.workflow import Config
|
|
51
|
+
|
|
52
|
+
config = Config.from_yaml("configs/pipeline.yml")
|
|
53
|
+
print(config)
|
|
54
|
+
```
|
|
55
|
+
|
|
34
56
|
## See Also
|
|
35
57
|
|
|
36
58
|
- [Top-level project README](../README.md)
|
|
@@ -5,6 +5,7 @@ Top-level facade for the ETLPlus toolkit.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from .__version__ import __version__
|
|
8
|
+
from .config import Config
|
|
8
9
|
|
|
9
10
|
__author__ = 'ETLPlus Team'
|
|
10
11
|
|
|
@@ -15,4 +16,5 @@ __author__ = 'ETLPlus Team'
|
|
|
15
16
|
__all__ = [
|
|
16
17
|
'__author__',
|
|
17
18
|
'__version__',
|
|
19
|
+
'Config',
|
|
18
20
|
]
|
|
@@ -62,6 +62,16 @@ __all__ = ['app']
|
|
|
62
62
|
# SECTION: TYPE ALIASES ==================================================== #
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
ConfigOption = Annotated[
|
|
66
|
+
str,
|
|
67
|
+
typer.Option(
|
|
68
|
+
...,
|
|
69
|
+
'--config',
|
|
70
|
+
metavar='PATH',
|
|
71
|
+
help='Path to YAML-formatted configuration file.',
|
|
72
|
+
),
|
|
73
|
+
]
|
|
74
|
+
|
|
65
75
|
JobOption = Annotated[
|
|
66
76
|
str | None,
|
|
67
77
|
typer.Option(
|
|
@@ -97,16 +107,6 @@ OutputOption = Annotated[
|
|
|
97
107
|
),
|
|
98
108
|
]
|
|
99
109
|
|
|
100
|
-
PipelineConfigOption = Annotated[
|
|
101
|
-
str,
|
|
102
|
-
typer.Option(
|
|
103
|
-
...,
|
|
104
|
-
'--config',
|
|
105
|
-
metavar='PATH',
|
|
106
|
-
help='Path to pipeline YAML configuration file.',
|
|
107
|
-
),
|
|
108
|
-
]
|
|
109
|
-
|
|
110
110
|
PipelineOption = Annotated[
|
|
111
111
|
str | None,
|
|
112
112
|
typer.Option(
|
|
@@ -407,7 +407,7 @@ def _root(
|
|
|
407
407
|
@app.command('check')
|
|
408
408
|
def check_cmd(
|
|
409
409
|
ctx: typer.Context,
|
|
410
|
-
config:
|
|
410
|
+
config: ConfigOption,
|
|
411
411
|
jobs: JobsOption = False,
|
|
412
412
|
pipelines: PipelinesOption = False,
|
|
413
413
|
sources: SourcesOption = False,
|
|
@@ -422,20 +422,20 @@ def check_cmd(
|
|
|
422
422
|
----------
|
|
423
423
|
ctx : typer.Context
|
|
424
424
|
The Typer context.
|
|
425
|
-
config :
|
|
425
|
+
config : ConfigOption
|
|
426
426
|
Path to pipeline YAML configuration file.
|
|
427
|
-
jobs :
|
|
427
|
+
jobs : JobsOption, optional
|
|
428
428
|
List available job names and exit. Default is ``False``.
|
|
429
|
-
pipelines :
|
|
429
|
+
pipelines : PipelinesOption, optional
|
|
430
430
|
List ETL pipelines. Default is ``False``.
|
|
431
|
-
sources :
|
|
431
|
+
sources : SourcesOption, optional
|
|
432
432
|
List data sources. Default is ``False``.
|
|
433
|
-
summary :
|
|
433
|
+
summary : SummaryOption, optional
|
|
434
434
|
Show pipeline summary (name, version, sources, targets, jobs). Default
|
|
435
435
|
is ``False``.
|
|
436
|
-
targets :
|
|
436
|
+
targets : TargetsOption, optional
|
|
437
437
|
List data targets. Default is ``False``.
|
|
438
|
-
transforms :
|
|
438
|
+
transforms : TransformsOption, optional
|
|
439
439
|
List data transforms. Default is ``False``.
|
|
440
440
|
|
|
441
441
|
Returns
|
|
@@ -725,7 +725,7 @@ def render_cmd(
|
|
|
725
725
|
@app.command('run')
|
|
726
726
|
def run_cmd(
|
|
727
727
|
ctx: typer.Context,
|
|
728
|
-
config:
|
|
728
|
+
config: ConfigOption,
|
|
729
729
|
job: JobOption = None,
|
|
730
730
|
pipeline: PipelineOption = None,
|
|
731
731
|
) -> int:
|
|
@@ -736,11 +736,11 @@ def run_cmd(
|
|
|
736
736
|
----------
|
|
737
737
|
ctx : typer.Context
|
|
738
738
|
The Typer context.
|
|
739
|
-
config :
|
|
739
|
+
config : ConfigOption
|
|
740
740
|
Path to pipeline YAML configuration file.
|
|
741
|
-
job :
|
|
741
|
+
job : JobOption, optional
|
|
742
742
|
Name of the job to run. Default is ``None``.
|
|
743
|
-
pipeline :
|
|
743
|
+
pipeline : PipelineOption, optional
|
|
744
744
|
Name of the pipeline to run. Default is ``None``.
|
|
745
745
|
|
|
746
746
|
Returns
|
|
@@ -14,6 +14,7 @@ from typing import Any
|
|
|
14
14
|
from typing import Literal
|
|
15
15
|
from typing import cast
|
|
16
16
|
|
|
17
|
+
from .. import Config
|
|
17
18
|
from ..database import load_table_spec
|
|
18
19
|
from ..database import render_tables
|
|
19
20
|
from ..file import File
|
|
@@ -26,8 +27,6 @@ from ..ops import validate
|
|
|
26
27
|
from ..ops.validate import FieldRules
|
|
27
28
|
from ..types import JSONData
|
|
28
29
|
from ..types import TemplateKey
|
|
29
|
-
from ..workflow import PipelineConfig
|
|
30
|
-
from ..workflow import load_pipeline_config
|
|
31
30
|
from . import io as cli_io
|
|
32
31
|
|
|
33
32
|
# SECTION: EXPORTS ========================================================== #
|
|
@@ -73,14 +72,14 @@ def _collect_table_specs(
|
|
|
73
72
|
specs.append(dict(load_table_spec(Path(spec_path))))
|
|
74
73
|
|
|
75
74
|
if config_path:
|
|
76
|
-
cfg =
|
|
75
|
+
cfg = Config.from_yaml(config_path, substitute=True)
|
|
77
76
|
specs.extend(getattr(cfg, 'table_schemas', []))
|
|
78
77
|
|
|
79
78
|
return specs
|
|
80
79
|
|
|
81
80
|
|
|
82
81
|
def _check_sections(
|
|
83
|
-
cfg:
|
|
82
|
+
cfg: Config,
|
|
84
83
|
*,
|
|
85
84
|
jobs: bool,
|
|
86
85
|
pipelines: bool,
|
|
@@ -93,7 +92,7 @@ def _check_sections(
|
|
|
93
92
|
|
|
94
93
|
Parameters
|
|
95
94
|
----------
|
|
96
|
-
cfg :
|
|
95
|
+
cfg : Config
|
|
97
96
|
The loaded pipeline configuration.
|
|
98
97
|
jobs : bool
|
|
99
98
|
Whether to include job metadata.
|
|
@@ -133,14 +132,14 @@ def _check_sections(
|
|
|
133
132
|
|
|
134
133
|
|
|
135
134
|
def _pipeline_summary(
|
|
136
|
-
cfg:
|
|
135
|
+
cfg: Config,
|
|
137
136
|
) -> dict[str, Any]:
|
|
138
137
|
"""
|
|
139
138
|
Return a human-friendly snapshot of a pipeline config.
|
|
140
139
|
|
|
141
140
|
Parameters
|
|
142
141
|
----------
|
|
143
|
-
cfg :
|
|
142
|
+
cfg : Config
|
|
144
143
|
The loaded pipeline configuration.
|
|
145
144
|
|
|
146
145
|
Returns
|
|
@@ -229,7 +228,7 @@ def check_handler(
|
|
|
229
228
|
Zero on success.
|
|
230
229
|
|
|
231
230
|
"""
|
|
232
|
-
cfg =
|
|
231
|
+
cfg = Config.from_yaml(config, substitute=substitute)
|
|
233
232
|
if summary:
|
|
234
233
|
cli_io.emit_json(_pipeline_summary(cfg), pretty=True)
|
|
235
234
|
return 0
|
|
@@ -514,7 +513,7 @@ def run_handler(
|
|
|
514
513
|
int
|
|
515
514
|
Zero on success.
|
|
516
515
|
"""
|
|
517
|
-
cfg =
|
|
516
|
+
cfg = Config.from_yaml(config, substitute=True)
|
|
518
517
|
|
|
519
518
|
job_name = job or pipeline
|
|
520
519
|
if job_name:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
|
-
:mod:`etlplus.
|
|
2
|
+
:mod:`etlplus.config` module.
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Configuration model and helpers for job pipeline orchestration.
|
|
5
5
|
|
|
6
6
|
Notes
|
|
7
7
|
-----
|
|
@@ -24,26 +24,24 @@ from pathlib import Path
|
|
|
24
24
|
from typing import Any
|
|
25
25
|
from typing import Self
|
|
26
26
|
|
|
27
|
-
from
|
|
28
|
-
from
|
|
29
|
-
from
|
|
30
|
-
from
|
|
31
|
-
from
|
|
32
|
-
from
|
|
33
|
-
from
|
|
34
|
-
from
|
|
35
|
-
from
|
|
36
|
-
from .jobs import JobConfig
|
|
37
|
-
from .profile import ProfileConfig
|
|
27
|
+
from .api import ApiConfig
|
|
28
|
+
from .connector import Connector
|
|
29
|
+
from .connector import parse_connector
|
|
30
|
+
from .file import File
|
|
31
|
+
from .file import FileFormat
|
|
32
|
+
from .types import StrAnyMap
|
|
33
|
+
from .utils import coerce_dict
|
|
34
|
+
from .utils import deep_substitute
|
|
35
|
+
from .utils import maybe_mapping
|
|
36
|
+
from .workflow.jobs import JobConfig
|
|
37
|
+
from .workflow.profile import ProfileConfig
|
|
38
38
|
|
|
39
39
|
# SECTION: EXPORTS ========================================================== #
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
__all__ = [
|
|
43
43
|
# Data Classes
|
|
44
|
-
'
|
|
45
|
-
# Functions
|
|
46
|
-
'load_pipeline_config',
|
|
44
|
+
'Config',
|
|
47
45
|
]
|
|
48
46
|
|
|
49
47
|
|
|
@@ -126,29 +124,11 @@ def _parse_connector_entry(
|
|
|
126
124
|
return None
|
|
127
125
|
|
|
128
126
|
|
|
129
|
-
# SECTION: FUNCTIONS ======================================================== #
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def load_pipeline_config(
|
|
133
|
-
path: Path | str,
|
|
134
|
-
*,
|
|
135
|
-
substitute: bool = False,
|
|
136
|
-
env: Mapping[str, str] | None = None,
|
|
137
|
-
) -> PipelineConfig:
|
|
138
|
-
"""
|
|
139
|
-
Load a pipeline YAML file into a ``PipelineConfig`` instance.
|
|
140
|
-
|
|
141
|
-
Delegates to ``PipelineConfig.from_yaml`` for construction and optional
|
|
142
|
-
variable substitution.
|
|
143
|
-
"""
|
|
144
|
-
return PipelineConfig.from_yaml(path, substitute=substitute, env=env)
|
|
145
|
-
|
|
146
|
-
|
|
147
127
|
# SECTION: DATA CLASSES ===================================================== #
|
|
148
128
|
|
|
149
129
|
|
|
150
130
|
@dataclass(kw_only=True, slots=True)
|
|
151
|
-
class
|
|
131
|
+
class Config:
|
|
152
132
|
"""
|
|
153
133
|
Configuration for the data processing pipeline.
|
|
154
134
|
|
|
@@ -211,7 +191,7 @@ class PipelineConfig:
|
|
|
211
191
|
env: Mapping[str, str] | None = None,
|
|
212
192
|
) -> Self:
|
|
213
193
|
"""
|
|
214
|
-
Parse a YAML file into a ``
|
|
194
|
+
Parse a YAML file into a ``Config`` instance.
|
|
215
195
|
|
|
216
196
|
Parameters
|
|
217
197
|
----------
|
|
@@ -259,7 +239,7 @@ class PipelineConfig:
|
|
|
259
239
|
raw: StrAnyMap,
|
|
260
240
|
) -> Self:
|
|
261
241
|
"""
|
|
262
|
-
Parse a mapping into a ``
|
|
242
|
+
Parse a mapping into a ``Config`` instance.
|
|
263
243
|
|
|
264
244
|
Parameters
|
|
265
245
|
----------
|
|
@@ -11,6 +11,7 @@ from typing import Final
|
|
|
11
11
|
from typing import cast
|
|
12
12
|
|
|
13
13
|
from ..api import HttpMethod
|
|
14
|
+
from ..config import Config
|
|
14
15
|
from ..connector import DataConnectorType
|
|
15
16
|
from ..file import FileFormat
|
|
16
17
|
from ..ops.types import PipelineConfig
|
|
@@ -18,7 +19,6 @@ from ..types import JSONData
|
|
|
18
19
|
from ..types import JSONDict
|
|
19
20
|
from ..types import StrPath
|
|
20
21
|
from ..utils import print_json
|
|
21
|
-
from ..workflow import load_pipeline_config
|
|
22
22
|
from .extract import extract
|
|
23
23
|
from .extract import extract_from_api_source
|
|
24
24
|
from .load import load
|
|
@@ -176,7 +176,7 @@ def run(
|
|
|
176
176
|
If the job is not found or if there are configuration issues.
|
|
177
177
|
"""
|
|
178
178
|
cfg_path = config_path or DEFAULT_CONFIG_PATH
|
|
179
|
-
cfg =
|
|
179
|
+
cfg = Config.from_yaml(cfg_path, substitute=True)
|
|
180
180
|
|
|
181
181
|
# Lookup job by name
|
|
182
182
|
if not (job_obj := next((j for j in cfg.jobs if j.name == job), None)):
|
|
@@ -16,7 +16,8 @@ See Also
|
|
|
16
16
|
|
|
17
17
|
Examples
|
|
18
18
|
--------
|
|
19
|
-
>>> from etlplus.types import JSONDict
|
|
19
|
+
>>> from etlplus.types import JSONDict
|
|
20
|
+
>>> from etlplus.ops.types import PipelineConfig
|
|
20
21
|
>>> payload: JSONDict = {'id': 1, 'name': 'Ada'}
|
|
21
22
|
>>> isinstance(payload, dict)
|
|
22
23
|
True
|
|
@@ -12,8 +12,6 @@ Back to project overview: see the top-level [README](../../README.md).
|
|
|
12
12
|
|
|
13
13
|
- [`etlplus.workflow` Subpackage](#etlplusworkflow-subpackage)
|
|
14
14
|
- [Supported Configuration Types](#supported-configuration-types)
|
|
15
|
-
- [Loading and Validating Configs](#loading-and-validating-configs)
|
|
16
|
-
- [Example: Loading a Pipeline Config](#example-loading-a-pipeline-config)
|
|
17
15
|
- [See Also](#see-also)
|
|
18
16
|
|
|
19
17
|
## Supported Configuration Types
|
|
@@ -23,28 +21,6 @@ Back to project overview: see the top-level [README](../../README.md).
|
|
|
23
21
|
- **Pipeline**: End-to-end pipeline configuration
|
|
24
22
|
- **Profile**: User or environment-specific settings
|
|
25
23
|
|
|
26
|
-
## Loading and Validating Configs
|
|
27
|
-
|
|
28
|
-
Use the provided classes to load and validate configuration files:
|
|
29
|
-
|
|
30
|
-
```python
|
|
31
|
-
from etlplus.workflow import PipelineConfig
|
|
32
|
-
|
|
33
|
-
cfg = PipelineConfig.from_yaml("pipeline.yml")
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
- Supports YAML and JSON formats
|
|
37
|
-
- Validates against expected schema
|
|
38
|
-
|
|
39
|
-
## Example: Loading a Pipeline Config
|
|
40
|
-
|
|
41
|
-
```python
|
|
42
|
-
from etlplus.workflow import PipelineConfig
|
|
43
|
-
|
|
44
|
-
pipeline = PipelineConfig.from_yaml("configs/pipeline.yml")
|
|
45
|
-
print(pipeline)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
24
|
## See Also
|
|
49
25
|
|
|
50
26
|
- Top-level CLI and library usage in the main [README](../../README.md)
|
|
@@ -12,8 +12,6 @@ from .jobs import JobConfig
|
|
|
12
12
|
from .jobs import LoadRef
|
|
13
13
|
from .jobs import TransformRef
|
|
14
14
|
from .jobs import ValidationRef
|
|
15
|
-
from .pipeline import PipelineConfig
|
|
16
|
-
from .pipeline import load_pipeline_config
|
|
17
15
|
from .profile import ProfileConfig
|
|
18
16
|
|
|
19
17
|
# SECTION: EXPORTS ========================================================== #
|
|
@@ -24,11 +22,9 @@ __all__ = [
|
|
|
24
22
|
'ExtractRef',
|
|
25
23
|
'JobConfig',
|
|
26
24
|
'LoadRef',
|
|
27
|
-
'PipelineConfig',
|
|
28
25
|
'ProfileConfig',
|
|
29
26
|
'TransformRef',
|
|
30
27
|
'ValidationRef',
|
|
31
28
|
# Functions
|
|
32
|
-
'load_pipeline_config',
|
|
33
29
|
'topological_sort_jobs',
|
|
34
30
|
]
|
|
@@ -26,6 +26,7 @@ etlplus/README.md
|
|
|
26
26
|
etlplus/__init__.py
|
|
27
27
|
etlplus/__main__.py
|
|
28
28
|
etlplus/__version__.py
|
|
29
|
+
etlplus/config.py
|
|
29
30
|
etlplus/enums.py
|
|
30
31
|
etlplus/mixins.py
|
|
31
32
|
etlplus/py.typed
|
|
@@ -163,7 +164,6 @@ etlplus/workflow/README.md
|
|
|
163
164
|
etlplus/workflow/__init__.py
|
|
164
165
|
etlplus/workflow/dag.py
|
|
165
166
|
etlplus/workflow/jobs.py
|
|
166
|
-
etlplus/workflow/pipeline.py
|
|
167
167
|
etlplus/workflow/profile.py
|
|
168
168
|
examples/README.md
|
|
169
169
|
examples/quickstart.py
|
|
@@ -178,23 +178,24 @@ tests/__init__.py
|
|
|
178
178
|
tests/conftest.py
|
|
179
179
|
tests/integration/conftest.py
|
|
180
180
|
tests/integration/test_i_cli.py
|
|
181
|
+
tests/integration/test_i_config_load.py
|
|
181
182
|
tests/integration/test_i_examples_data_parity.py
|
|
182
183
|
tests/integration/test_i_pagination_strategy.py
|
|
183
184
|
tests/integration/test_i_pipeline_smoke.py
|
|
184
|
-
tests/integration/test_i_pipeline_yaml_load.py
|
|
185
185
|
tests/integration/test_i_run.py
|
|
186
186
|
tests/integration/test_i_run_profile_pagination_defaults.py
|
|
187
187
|
tests/integration/test_i_run_profile_rate_limit_defaults.py
|
|
188
188
|
tests/unit/conftest.py
|
|
189
|
+
tests/unit/test_u_config.py
|
|
189
190
|
tests/unit/test_u_main.py
|
|
190
191
|
tests/unit/test_u_mixins.py
|
|
191
192
|
tests/unit/test_u_utils.py
|
|
192
193
|
tests/unit/test_u_version.py
|
|
193
194
|
tests/unit/api/conftest.py
|
|
195
|
+
tests/unit/api/test_u_api_config.py
|
|
194
196
|
tests/unit/api/test_u_api_enums.py
|
|
195
197
|
tests/unit/api/test_u_api_utils.py
|
|
196
198
|
tests/unit/api/test_u_auth.py
|
|
197
|
-
tests/unit/api/test_u_config.py
|
|
198
199
|
tests/unit/api/test_u_endpoint_client.py
|
|
199
200
|
tests/unit/api/test_u_mocks.py
|
|
200
201
|
tests/unit/api/test_u_pagination_client.py
|
|
@@ -228,5 +229,4 @@ tests/unit/ops/test_u_ops_transform.py
|
|
|
228
229
|
tests/unit/ops/test_u_ops_utils.py
|
|
229
230
|
tests/unit/ops/test_u_ops_validate.py
|
|
230
231
|
tests/unit/workflow/test_u_workflow_jobs.py
|
|
231
|
-
tests/unit/workflow/test_u_workflow_pipeline.py
|
|
232
232
|
tools/update_demo_snippets.py
|
|
@@ -19,6 +19,7 @@ from typing import Protocol
|
|
|
19
19
|
|
|
20
20
|
import pytest
|
|
21
21
|
|
|
22
|
+
from etlplus import Config
|
|
22
23
|
from etlplus.api import ApiConfig
|
|
23
24
|
from etlplus.api import ApiProfileConfig
|
|
24
25
|
from etlplus.api import EndpointConfig
|
|
@@ -30,7 +31,6 @@ from etlplus.connector import ConnectorFile
|
|
|
30
31
|
from etlplus.workflow import ExtractRef
|
|
31
32
|
from etlplus.workflow import JobConfig
|
|
32
33
|
from etlplus.workflow import LoadRef
|
|
33
|
-
from etlplus.workflow import PipelineConfig
|
|
34
34
|
|
|
35
35
|
# SECTION: HELPERS ========================================================== #
|
|
36
36
|
|
|
@@ -173,7 +173,7 @@ def fake_endpoint_client_fixture() -> tuple[
|
|
|
173
173
|
def file_to_api_pipeline_factory_fixture(
|
|
174
174
|
tmp_path: pathlib.Path,
|
|
175
175
|
base_url: str,
|
|
176
|
-
) -> Callable[...,
|
|
176
|
+
) -> Callable[..., Config]:
|
|
177
177
|
"""Build a pipeline wiring a JSON file source to an API target."""
|
|
178
178
|
|
|
179
179
|
def _make(
|
|
@@ -187,7 +187,7 @@ def file_to_api_pipeline_factory_fixture(
|
|
|
187
187
|
headers: dict[str, str] | None = None,
|
|
188
188
|
job_name: str = 'send',
|
|
189
189
|
target_name: str = 'ingest_out',
|
|
190
|
-
) ->
|
|
190
|
+
) -> Config:
|
|
191
191
|
source_path = tmp_path / f'{job_name}_input.json'
|
|
192
192
|
effective_payload = payload if payload is not None else {'ok': True}
|
|
193
193
|
text = (
|
|
@@ -226,7 +226,7 @@ def file_to_api_pipeline_factory_fixture(
|
|
|
226
226
|
headers=headers or {},
|
|
227
227
|
)
|
|
228
228
|
|
|
229
|
-
return
|
|
229
|
+
return Config(
|
|
230
230
|
apis={'svc': api},
|
|
231
231
|
sources=[src],
|
|
232
232
|
targets=[tgt],
|
|
@@ -246,9 +246,9 @@ def file_to_api_pipeline_factory_fixture(
|
|
|
246
246
|
def pipeline_cfg_factory_fixture(
|
|
247
247
|
tmp_path: pathlib.Path,
|
|
248
248
|
base_url: str,
|
|
249
|
-
) -> Callable[...,
|
|
249
|
+
) -> Callable[..., Config]:
|
|
250
250
|
"""
|
|
251
|
-
Factory to build a minimal
|
|
251
|
+
Factory to build a minimal Config for runner tests.
|
|
252
252
|
|
|
253
253
|
Accepts optional pagination and rate limit defaults at the API profile
|
|
254
254
|
level. Creates a single job named 'job' with a source that references
|
|
@@ -263,8 +263,8 @@ def pipeline_cfg_factory_fixture(
|
|
|
263
263
|
|
|
264
264
|
Returns
|
|
265
265
|
-------
|
|
266
|
-
Callable[...,
|
|
267
|
-
Factory function to create :class:`
|
|
266
|
+
Callable[..., Config]
|
|
267
|
+
Factory function to create :class:`Config` instances.
|
|
268
268
|
"""
|
|
269
269
|
|
|
270
270
|
def _make(
|
|
@@ -272,7 +272,7 @@ def pipeline_cfg_factory_fixture(
|
|
|
272
272
|
pagination_defaults: PaginationConfig | None = None,
|
|
273
273
|
rate_limit_defaults: RateLimitConfig | None = None,
|
|
274
274
|
extract_options: dict[str, Any] | None = None,
|
|
275
|
-
) ->
|
|
275
|
+
) -> Config:
|
|
276
276
|
prof = ApiProfileConfig(
|
|
277
277
|
base_url=base_url,
|
|
278
278
|
headers={},
|
|
@@ -306,7 +306,7 @@ def pipeline_cfg_factory_fixture(
|
|
|
306
306
|
raise ValueError(msg)
|
|
307
307
|
job.extract.options = extract_options
|
|
308
308
|
|
|
309
|
-
return
|
|
309
|
+
return Config(
|
|
310
310
|
apis={'svc': api},
|
|
311
311
|
sources=[src],
|
|
312
312
|
targets=[tgt],
|
|
@@ -341,7 +341,7 @@ def run_patched_fixture(
|
|
|
341
341
|
extract_mod = importlib.import_module('etlplus.ops.extract')
|
|
342
342
|
|
|
343
343
|
def _run(
|
|
344
|
-
cfg:
|
|
344
|
+
cfg: Config,
|
|
345
345
|
endpoint_client_cls: type,
|
|
346
346
|
*,
|
|
347
347
|
sleep_seconds: float | None = None,
|
|
@@ -350,8 +350,8 @@ def run_patched_fixture(
|
|
|
350
350
|
|
|
351
351
|
# Patch config loader and EndpointClient.
|
|
352
352
|
monkeypatch.setattr(
|
|
353
|
-
run_mod,
|
|
354
|
-
'
|
|
353
|
+
run_mod.Config,
|
|
354
|
+
'from_yaml',
|
|
355
355
|
lambda *_a, **_k: cfg,
|
|
356
356
|
)
|
|
357
357
|
monkeypatch.setattr(
|
|
@@ -7,7 +7,7 @@ variable substitution enabled.
|
|
|
7
7
|
|
|
8
8
|
Notes
|
|
9
9
|
-----
|
|
10
|
-
- Uses ``
|
|
10
|
+
- Uses ``Config.from_yaml`` on the repo's example config.
|
|
11
11
|
- Asserts basic API modeling and presence of expected endpoints.
|
|
12
12
|
"""
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ from collections.abc import Mapping
|
|
|
17
17
|
|
|
18
18
|
import pytest
|
|
19
19
|
|
|
20
|
-
from etlplus
|
|
20
|
+
from etlplus import Config
|
|
21
21
|
|
|
22
22
|
# SECTION: HELPERS ========================================================== #
|
|
23
23
|
|
|
@@ -28,8 +28,8 @@ pytestmark = pytest.mark.integration
|
|
|
28
28
|
# SECTION: TESTS ============================================================ #
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class
|
|
32
|
-
"""Integration test suite for
|
|
31
|
+
class TestConfigLoad:
|
|
32
|
+
"""Integration test suite for configuration loading."""
|
|
33
33
|
|
|
34
34
|
@pytest.mark.parametrize('substitute', [False, True])
|
|
35
35
|
def test_load_repo_pipeline_yaml(
|
|
@@ -37,16 +37,16 @@ class TestPipelineYamlLoad:
|
|
|
37
37
|
substitute: bool,
|
|
38
38
|
) -> None:
|
|
39
39
|
"""
|
|
40
|
-
Test loading the
|
|
41
|
-
|
|
40
|
+
Test loading the configuration file with optional environment variable
|
|
41
|
+
substitution.
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
-
# Ensure the
|
|
45
|
-
cfg =
|
|
44
|
+
# Ensure the configuration file parses under current models.
|
|
45
|
+
cfg = Config.from_yaml(
|
|
46
46
|
'examples/configs/pipeline.yml',
|
|
47
47
|
substitute=substitute,
|
|
48
48
|
)
|
|
49
|
-
assert isinstance(cfg,
|
|
49
|
+
assert isinstance(cfg, Config)
|
|
50
50
|
|
|
51
51
|
# Basic sanity checks on REST API modeling.
|
|
52
52
|
assert 'github' in cfg.apis
|
|
@@ -32,8 +32,8 @@ import pytest
|
|
|
32
32
|
|
|
33
33
|
import etlplus.api.request_manager as rm_module
|
|
34
34
|
import etlplus.cli.handlers as cli_handlers
|
|
35
|
+
from etlplus import Config
|
|
35
36
|
from etlplus.cli import main
|
|
36
|
-
from etlplus.workflow.pipeline import PipelineConfig
|
|
37
37
|
from tests.integration.conftest import FakeEndpointClientProtocol
|
|
38
38
|
|
|
39
39
|
# SECTION: HELPERS ========================================================== #
|
|
@@ -527,7 +527,7 @@ class TestPaginationStrategies:
|
|
|
527
527
|
def test_pagination_edge_cases(
|
|
528
528
|
self,
|
|
529
529
|
scenario: PaginationEdgeCase,
|
|
530
|
-
pipeline_cfg_factory: Callable[...,
|
|
530
|
+
pipeline_cfg_factory: Callable[..., Config],
|
|
531
531
|
fake_endpoint_client: tuple[
|
|
532
532
|
type[FakeEndpointClientProtocol],
|
|
533
533
|
list[FakeEndpointClientProtocol],
|