etlplus 0.16.2__tar.gz → 0.16.3__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.2/etlplus.egg-info → etlplus-0.16.3}/PKG-INFO +1 -1
- etlplus-0.16.3/etlplus/enums.py +144 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/__init__.py +1 -0
- {etlplus-0.16.2/etlplus → etlplus-0.16.3/etlplus/ops}/enums.py +5 -108
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/run.py +1 -1
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/transform.py +16 -16
- etlplus-0.16.3/etlplus/ops/types.py +147 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/types.py +0 -99
- {etlplus-0.16.2 → etlplus-0.16.3/etlplus.egg-info}/PKG-INFO +1 -1
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus.egg-info/SOURCES.txt +4 -2
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/README.md +1 -1
- etlplus-0.16.2/examples/quickstart_python.py → etlplus-0.16.3/examples/quickstart.py +22 -1
- etlplus-0.16.2/tests/unit/test_u_enums.py → etlplus-0.16.3/tests/unit/ops/test_u_ops_enums.py +8 -8
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/ops/test_u_ops_transform.py +3 -3
- {etlplus-0.16.2 → etlplus-0.16.3}/.coveragerc +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/.editorconfig +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/.gitattributes +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/.github/actions/python-bootstrap/action.yml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/.github/workflows/ci.yml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/.gitignore +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/.pre-commit-config.yaml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/.ruff.toml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/CODE_OF_CONDUCT.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/CONTRIBUTING.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/DEMO.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/LICENSE +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/MANIFEST.in +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/Makefile +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/REFERENCES.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/SECURITY.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/SUPPORT.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/docs/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/docs/pipeline-guide.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/docs/snippets/installation_version.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/__main__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/__version__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/auth.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/config.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/endpoint_client.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/enums.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/errors.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/pagination/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/pagination/client.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/pagination/config.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/pagination/paginator.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/rate_limiting/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/rate_limiting/config.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/rate_limiting/rate_limiter.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/request_manager.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/retry_manager.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/transport.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/types.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/api/utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/commands.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/constants.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/handlers.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/io.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/main.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/options.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/state.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/cli/types.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/api.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/connector.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/core.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/database.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/enums.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/file.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/types.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/connector/utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/database/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/database/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/database/ddl.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/database/engine.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/database/orm.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/database/schema.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/database/types.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/_imports.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/_io.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/accdb.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/arrow.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/avro.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/bson.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/cbor.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/cfg.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/conf.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/core.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/csv.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/dat.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/dta.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/duckdb.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/enums.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/feather.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/fwf.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/gz.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/hbs.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/hdf5.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/ini.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/ion.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/jinja2.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/json.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/log.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/mat.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/mdb.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/msgpack.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/mustache.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/nc.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/ndjson.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/numbers.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/ods.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/orc.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/parquet.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/pb.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/pbf.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/properties.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/proto.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/psv.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/rda.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/rds.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/sas7bdat.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/sav.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/sqlite.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/stub.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/sylk.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/tab.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/toml.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/tsv.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/txt.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/vm.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/wks.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/xls.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/xlsm.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/xlsx.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/xml.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/xpt.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/yaml.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/zip.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/file/zsav.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/mixins.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/extract.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/load.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/ops/validate.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/py.typed +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/templates/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/templates/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/templates/ddl.sql.j2 +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/templates/view.sql.j2 +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/workflow/README.md +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/workflow/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/workflow/dag.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/workflow/jobs.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/workflow/pipeline.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus/workflow/profile.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus.egg-info/dependency_links.txt +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus.egg-info/entry_points.txt +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus.egg-info/requires.txt +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/etlplus.egg-info/top_level.txt +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/configs/ddl_spec.yml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/configs/pipeline.yml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/data/sample.csv +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/data/sample.json +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/data/sample.xml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/data/sample.xsd +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/examples/data/sample.yaml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/pyproject.toml +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/pytest.ini +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/setup.cfg +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/setup.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/__init__.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/conftest.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/conftest.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_cli.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_examples_data_parity.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_pagination_strategy.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_pipeline_smoke.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_pipeline_yaml_load.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_run.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_run_profile_pagination_defaults.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/integration/test_i_run_profile_rate_limit_defaults.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/conftest.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_api_enums.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_api_utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_auth.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_config.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_endpoint_client.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_mocks.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_pagination_client.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_pagination_config.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_paginator.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_rate_limit_config.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_rate_limiter.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_request_manager.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_retry_manager.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_transport.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/api/test_u_types.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/cli/conftest.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/cli/test_u_cli_handlers.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/cli/test_u_cli_io.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/cli/test_u_cli_main.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/cli/test_u_cli_state.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/conftest.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/connector/test_u_connector_enums.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/connector/test_u_connector_utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/database/test_u_database_ddl.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/database/test_u_database_engine.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/database/test_u_database_orm.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/database/test_u_database_schema.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/file/test_u_file_core.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/file/test_u_file_enums.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/file/test_u_file_yaml.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/ops/test_u_ops_extract.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/ops/test_u_ops_load.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/ops/test_u_ops_run.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/ops/test_u_ops_utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/ops/test_u_ops_validate.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/test_u_main.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/test_u_mixins.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/test_u_utils.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/test_u_version.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/workflow/test_u_workflow_jobs.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tests/unit/workflow/test_u_workflow_pipeline.py +0 -0
- {etlplus-0.16.2 → etlplus-0.16.3}/tools/update_demo_snippets.py +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.enums` module.
|
|
3
|
+
|
|
4
|
+
Shared enumeration base class.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import enum
|
|
10
|
+
from typing import Self
|
|
11
|
+
|
|
12
|
+
from .types import StrStrMap
|
|
13
|
+
|
|
14
|
+
# SECTION: EXPORTS ========================================================== #
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
# Enums
|
|
19
|
+
'CoercibleStrEnum',
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# SECTION: CLASSES ========================================================== #
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CoercibleStrEnum(enum.StrEnum):
|
|
27
|
+
"""
|
|
28
|
+
StrEnum with ergonomic helpers.
|
|
29
|
+
|
|
30
|
+
Provides a DRY, class-level :meth:`coerce` that normalizes inputs and
|
|
31
|
+
produces consistent, informative error messages. Also exposes
|
|
32
|
+
:meth:`choices` for UI/validation and :meth:`try_coerce` for soft parsing.
|
|
33
|
+
|
|
34
|
+
Notes
|
|
35
|
+
-----
|
|
36
|
+
- Values are normalized via ``str(value).strip().casefold()``.
|
|
37
|
+
- If value matching fails, the raw string is tried as a member name.
|
|
38
|
+
- Error messages enumerate allowed values for easier debugging.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
# -- Class Methods -- #
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def aliases(cls) -> StrStrMap:
|
|
45
|
+
"""
|
|
46
|
+
Return a mapping of common aliases for each enum member.
|
|
47
|
+
|
|
48
|
+
Subclasses may override this method to provide custom aliases.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
StrStrMap
|
|
53
|
+
A mapping of alias strings to their corresponding enum member
|
|
54
|
+
values or names.
|
|
55
|
+
|
|
56
|
+
Notes
|
|
57
|
+
-----
|
|
58
|
+
- Alias keys are normalized via ``str(key).strip().casefold()``.
|
|
59
|
+
- Alias values should be member values or member names.
|
|
60
|
+
"""
|
|
61
|
+
return {}
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def choices(cls) -> tuple[str, ...]:
|
|
65
|
+
"""
|
|
66
|
+
Return the allowed string values for this enum.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
tuple[str, ...]
|
|
71
|
+
A tuple of allowed string values for this enum.
|
|
72
|
+
"""
|
|
73
|
+
return tuple(member.value for member in cls)
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def coerce(cls, value: Self | str | object) -> Self:
|
|
77
|
+
"""
|
|
78
|
+
Convert an enum member or string-like input to a member of *cls*.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
value : Self | str | object
|
|
83
|
+
An existing enum member or a string-like value to normalize.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
Self
|
|
88
|
+
The corresponding enum member.
|
|
89
|
+
|
|
90
|
+
Raises
|
|
91
|
+
------
|
|
92
|
+
ValueError
|
|
93
|
+
If the value cannot be coerced into a valid member.
|
|
94
|
+
"""
|
|
95
|
+
if isinstance(value, cls):
|
|
96
|
+
return value
|
|
97
|
+
try:
|
|
98
|
+
raw = str(value).strip()
|
|
99
|
+
normalized = raw.casefold()
|
|
100
|
+
aliases = {
|
|
101
|
+
str(key).strip().casefold(): alias
|
|
102
|
+
for key, alias in cls.aliases().items()
|
|
103
|
+
}
|
|
104
|
+
resolved = aliases.get(normalized)
|
|
105
|
+
if resolved is None:
|
|
106
|
+
try:
|
|
107
|
+
return cls(normalized) # type: ignore[arg-type]
|
|
108
|
+
except (ValueError, TypeError):
|
|
109
|
+
return cls[raw] # type: ignore[index]
|
|
110
|
+
if isinstance(resolved, cls):
|
|
111
|
+
return resolved
|
|
112
|
+
try:
|
|
113
|
+
return cls(resolved) # type: ignore[arg-type]
|
|
114
|
+
except (ValueError, TypeError):
|
|
115
|
+
# Allow aliases to reference member names.
|
|
116
|
+
return cls[resolved] # type: ignore[index]
|
|
117
|
+
except (ValueError, TypeError, KeyError) as e:
|
|
118
|
+
allowed = ', '.join(cls.choices())
|
|
119
|
+
raise ValueError(
|
|
120
|
+
f'Invalid {cls.__name__} value: {value!r}. Allowed: {allowed}',
|
|
121
|
+
) from e
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def try_coerce(
|
|
125
|
+
cls,
|
|
126
|
+
value: Self | str | object,
|
|
127
|
+
) -> Self | None:
|
|
128
|
+
"""
|
|
129
|
+
Attempt to coerce a value into the enum; return ``None`` on failure.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
value : Self | str | object
|
|
134
|
+
An existing enum member or a string-like value to normalize.
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
Self | None
|
|
139
|
+
The corresponding enum member, or ``None`` if coercion fails.
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
return cls.coerce(value)
|
|
143
|
+
except (ValueError, TypeError, KeyError):
|
|
144
|
+
return None
|
|
@@ -1,133 +1,30 @@
|
|
|
1
1
|
"""
|
|
2
|
-
:mod:`etlplus.enums` module.
|
|
2
|
+
:mod:`etlplus.ops.enums` module.
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Operation-specific enums and helpers.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
import enum
|
|
10
9
|
import operator as _op
|
|
11
10
|
from statistics import fmean
|
|
12
|
-
from typing import Self
|
|
13
11
|
|
|
12
|
+
from ..enums import CoercibleStrEnum
|
|
13
|
+
from ..types import StrStrMap
|
|
14
14
|
from .types import AggregateFunc
|
|
15
15
|
from .types import OperatorFunc
|
|
16
|
-
from .types import StrStrMap
|
|
17
16
|
|
|
18
|
-
# SECTION: EXPORTS
|
|
17
|
+
# SECTION: EXPORTS ========================================================= #
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
__all__ = [
|
|
22
21
|
# Enums
|
|
23
22
|
'AggregateName',
|
|
24
|
-
'CoercibleStrEnum',
|
|
25
23
|
'OperatorName',
|
|
26
24
|
'PipelineStep',
|
|
27
25
|
]
|
|
28
26
|
|
|
29
27
|
|
|
30
|
-
# SECTION: CLASSES ========================================================== #
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class CoercibleStrEnum(enum.StrEnum):
|
|
34
|
-
"""
|
|
35
|
-
StrEnum with ergonomic helpers.
|
|
36
|
-
|
|
37
|
-
Provides a DRY, class-level :meth:`coerce` that normalizes inputs and
|
|
38
|
-
produces consistent, informative error messages. Also exposes
|
|
39
|
-
:meth:`choices` for UI/validation and :meth:`try_coerce` for soft parsing.
|
|
40
|
-
|
|
41
|
-
Notes
|
|
42
|
-
-----
|
|
43
|
-
- Values are normalized via ``str(value).strip().casefold()``.
|
|
44
|
-
- Error messages enumerate allowed values for easier debugging.
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
# -- Class Methods -- #
|
|
48
|
-
|
|
49
|
-
@classmethod
|
|
50
|
-
def aliases(cls) -> StrStrMap:
|
|
51
|
-
"""
|
|
52
|
-
Return a mapping of common aliases for each enum member.
|
|
53
|
-
|
|
54
|
-
Subclasses may override this method to provide custom aliases.
|
|
55
|
-
|
|
56
|
-
Returns
|
|
57
|
-
-------
|
|
58
|
-
StrStrMap
|
|
59
|
-
A mapping of alias names to their corresponding enum member names.
|
|
60
|
-
"""
|
|
61
|
-
return {}
|
|
62
|
-
|
|
63
|
-
@classmethod
|
|
64
|
-
def choices(cls) -> tuple[str, ...]:
|
|
65
|
-
"""
|
|
66
|
-
Return the allowed string values for this enum.
|
|
67
|
-
|
|
68
|
-
Returns
|
|
69
|
-
-------
|
|
70
|
-
tuple[str, ...]
|
|
71
|
-
A tuple of allowed string values for this enum.
|
|
72
|
-
"""
|
|
73
|
-
return tuple(member.value for member in cls)
|
|
74
|
-
|
|
75
|
-
@classmethod
|
|
76
|
-
def coerce(cls, value: Self | str | object) -> Self:
|
|
77
|
-
"""
|
|
78
|
-
Convert an enum member or string-like input to a member of *cls*.
|
|
79
|
-
|
|
80
|
-
Parameters
|
|
81
|
-
----------
|
|
82
|
-
value : Self | str | object
|
|
83
|
-
An existing enum member or a text value to normalize.
|
|
84
|
-
|
|
85
|
-
Returns
|
|
86
|
-
-------
|
|
87
|
-
Self
|
|
88
|
-
The corresponding enum member.
|
|
89
|
-
|
|
90
|
-
Raises
|
|
91
|
-
------
|
|
92
|
-
ValueError
|
|
93
|
-
If the value cannot be coerced into a valid member.
|
|
94
|
-
"""
|
|
95
|
-
if isinstance(value, cls):
|
|
96
|
-
return value
|
|
97
|
-
try:
|
|
98
|
-
normalized = str(value).strip().casefold()
|
|
99
|
-
resolved = cls.aliases().get(normalized, normalized)
|
|
100
|
-
return cls(resolved) # type: ignore[arg-type]
|
|
101
|
-
except (ValueError, TypeError) as e:
|
|
102
|
-
allowed = ', '.join(cls.choices())
|
|
103
|
-
raise ValueError(
|
|
104
|
-
f'Invalid {cls.__name__} value: {value!r}. Allowed: {allowed}',
|
|
105
|
-
) from e
|
|
106
|
-
|
|
107
|
-
@classmethod
|
|
108
|
-
def try_coerce(
|
|
109
|
-
cls,
|
|
110
|
-
value: object,
|
|
111
|
-
) -> Self | None:
|
|
112
|
-
"""
|
|
113
|
-
Best-effort parse; return ``None`` on failure instead of raising.
|
|
114
|
-
|
|
115
|
-
Parameters
|
|
116
|
-
----------
|
|
117
|
-
value : object
|
|
118
|
-
An existing enum member or a text value to normalize.
|
|
119
|
-
|
|
120
|
-
Returns
|
|
121
|
-
-------
|
|
122
|
-
Self | None
|
|
123
|
-
The corresponding enum member, or ``None`` if coercion fails.
|
|
124
|
-
"""
|
|
125
|
-
try:
|
|
126
|
-
return cls.coerce(value)
|
|
127
|
-
except ValueError:
|
|
128
|
-
return None
|
|
129
|
-
|
|
130
|
-
|
|
131
28
|
# SECTION: ENUMS ============================================================ #
|
|
132
29
|
|
|
133
30
|
|
|
@@ -13,9 +13,9 @@ from typing import cast
|
|
|
13
13
|
from ..api import HttpMethod
|
|
14
14
|
from ..connector import DataConnectorType
|
|
15
15
|
from ..file import FileFormat
|
|
16
|
+
from ..ops.types import PipelineConfig
|
|
16
17
|
from ..types import JSONData
|
|
17
18
|
from ..types import JSONDict
|
|
18
|
-
from ..types import PipelineConfig
|
|
19
19
|
from ..types import StrPath
|
|
20
20
|
from ..utils import print_json
|
|
21
21
|
from ..workflow import load_pipeline_config
|
|
@@ -44,28 +44,28 @@ from collections.abc import Sequence
|
|
|
44
44
|
from typing import Any
|
|
45
45
|
from typing import cast
|
|
46
46
|
|
|
47
|
-
from ..
|
|
48
|
-
from ..enums import OperatorName
|
|
49
|
-
from ..enums import PipelineStep
|
|
50
|
-
from ..types import AggregateFunc
|
|
51
|
-
from ..types import AggregateSpec
|
|
52
|
-
from ..types import FieldName
|
|
53
|
-
from ..types import Fields
|
|
54
|
-
from ..types import FilterSpec
|
|
47
|
+
from ..ops.types import PipelineConfig
|
|
55
48
|
from ..types import JSONData
|
|
56
49
|
from ..types import JSONDict
|
|
57
50
|
from ..types import JSONList
|
|
58
|
-
from ..types import MapSpec
|
|
59
|
-
from ..types import OperatorFunc
|
|
60
|
-
from ..types import PipelineConfig
|
|
61
|
-
from ..types import PipelineStepName
|
|
62
|
-
from ..types import SortKey
|
|
63
|
-
from ..types import StepApplier
|
|
64
|
-
from ..types import StepOrSteps
|
|
65
|
-
from ..types import StepSpec
|
|
66
51
|
from ..types import StrPath
|
|
67
52
|
from ..utils import to_number
|
|
53
|
+
from .enums import AggregateName
|
|
54
|
+
from .enums import OperatorName
|
|
55
|
+
from .enums import PipelineStep
|
|
68
56
|
from .load import load_data
|
|
57
|
+
from .types import AggregateFunc
|
|
58
|
+
from .types import AggregateSpec
|
|
59
|
+
from .types import FieldName
|
|
60
|
+
from .types import Fields
|
|
61
|
+
from .types import FilterSpec
|
|
62
|
+
from .types import MapSpec
|
|
63
|
+
from .types import OperatorFunc
|
|
64
|
+
from .types import PipelineStepName
|
|
65
|
+
from .types import SortKey
|
|
66
|
+
from .types import StepApplier
|
|
67
|
+
from .types import StepOrSteps
|
|
68
|
+
from .types import StepSpec
|
|
69
69
|
|
|
70
70
|
# SECTION: EXPORTS ========================================================== #
|
|
71
71
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.ops.types` module.
|
|
3
|
+
|
|
4
|
+
Shared type aliases leveraged across :mod:`etlplus.ops` modules.
|
|
5
|
+
|
|
6
|
+
Notes
|
|
7
|
+
-----
|
|
8
|
+
- Centralizes ops-focused aliases (functions, specs, and pipeline helpers).
|
|
9
|
+
- Relies on Python 3.13 ``type`` statements for readability and IDE support.
|
|
10
|
+
|
|
11
|
+
Examples
|
|
12
|
+
--------
|
|
13
|
+
>>> from etlplus.ops.types import AggregateFunc, OperatorFunc
|
|
14
|
+
>>> def total(xs: list[float], _: int) -> float:
|
|
15
|
+
... return sum(xs)
|
|
16
|
+
>>> agg: AggregateFunc = total
|
|
17
|
+
>>> op: OperatorFunc = lambda a, b: a == b
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from collections.abc import Callable
|
|
23
|
+
from collections.abc import Mapping
|
|
24
|
+
from collections.abc import Sequence
|
|
25
|
+
from typing import Any
|
|
26
|
+
from typing import Literal
|
|
27
|
+
|
|
28
|
+
from ..types import JSONList
|
|
29
|
+
from ..types import StrAnyMap
|
|
30
|
+
from ..types import StrSeqMap
|
|
31
|
+
from ..types import StrStrMap
|
|
32
|
+
|
|
33
|
+
# SECTION: EXPORTS ========================================================== #
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
# Type Aliases (Functions)
|
|
38
|
+
'AggregateFunc',
|
|
39
|
+
'OperatorFunc',
|
|
40
|
+
# Type Aliases (Records & Fields)
|
|
41
|
+
'FieldName',
|
|
42
|
+
'Fields',
|
|
43
|
+
# Type Aliases (Transform Specs)
|
|
44
|
+
'AggregateSpec',
|
|
45
|
+
'FilterSpec',
|
|
46
|
+
'MapSpec',
|
|
47
|
+
'SelectSpec',
|
|
48
|
+
'SortSpec',
|
|
49
|
+
# Type Aliases (Pipelines)
|
|
50
|
+
'StepOrSteps',
|
|
51
|
+
'StepSeq',
|
|
52
|
+
'StepSpec',
|
|
53
|
+
'PipelineConfig',
|
|
54
|
+
'PipelineStepName',
|
|
55
|
+
# Type Aliases (Helpers)
|
|
56
|
+
'StepApplier',
|
|
57
|
+
'SortKey',
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# SECTION: TYPE ALIASES ===================================================== #
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# -- Functions -- #
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# TODO: Consider redefining to use `functools.reduce` signature.
|
|
68
|
+
# TODO: Consider adding `**kwargs` to support richer aggregation functions.
|
|
69
|
+
# TODO: Consider constraining first argument to `Sequence[float]`.
|
|
70
|
+
# TODO: Consider constraining return type to `float | int | None`.
|
|
71
|
+
# Callable reducing numeric collections into a summary value.
|
|
72
|
+
type AggregateFunc = Callable[[list[float], int], Any]
|
|
73
|
+
|
|
74
|
+
# Binary predicate consumed by filter operations.
|
|
75
|
+
type OperatorFunc = Callable[[Any, Any], bool]
|
|
76
|
+
|
|
77
|
+
# -- Records & Fields -- #
|
|
78
|
+
|
|
79
|
+
# Individual field identifier referenced inside specs.
|
|
80
|
+
type FieldName = str
|
|
81
|
+
|
|
82
|
+
# Ordered list of :data:`FieldName` entries preserving projection order.
|
|
83
|
+
type Fields = list[FieldName]
|
|
84
|
+
|
|
85
|
+
# -- Transform Specs -- #
|
|
86
|
+
|
|
87
|
+
# Filtering spec expecting ``field``, ``op``, and ``value`` keys.
|
|
88
|
+
type FilterSpec = StrAnyMap
|
|
89
|
+
|
|
90
|
+
# Field renaming instructions mapping old keys to new ones.
|
|
91
|
+
type MapSpec = StrStrMap
|
|
92
|
+
|
|
93
|
+
# Projection spec as a field list or mapping with metadata.
|
|
94
|
+
#
|
|
95
|
+
# Examples
|
|
96
|
+
# --------
|
|
97
|
+
# >>> from etlplus.ops.types import SelectSpec
|
|
98
|
+
# >>> spec1: SelectSpec = ['a','b']
|
|
99
|
+
# >>> spec2: SelectSpec = {'fields': [...]}
|
|
100
|
+
type SelectSpec = Fields | StrSeqMap
|
|
101
|
+
|
|
102
|
+
# Sort directive expressed as a field string or mapping with flags.
|
|
103
|
+
#
|
|
104
|
+
# Examples
|
|
105
|
+
# --------
|
|
106
|
+
# >>> from etlplus.ops.types import SortSpec
|
|
107
|
+
# >>> spec1: SortSpec = 'field'
|
|
108
|
+
# >>> spec2: SortSpec = {'field': 'x', 'reverse': True}
|
|
109
|
+
type SortSpec = str | StrAnyMap
|
|
110
|
+
|
|
111
|
+
# Aggregate instruction covering ``field``, ``func``, and optional alias.
|
|
112
|
+
#
|
|
113
|
+
# Supported functions: ``avg``, ``count``, ``max``, ``min``, and ``sum``.
|
|
114
|
+
# Examples
|
|
115
|
+
# --------
|
|
116
|
+
# >>> from etlplus.ops.types import AggregateSpec
|
|
117
|
+
# >>> spec: AggregateSpec = \
|
|
118
|
+
# ... {'field': 'x', 'func': 'sum' | 'avg' | ..., 'alias'?: '...'}
|
|
119
|
+
type AggregateSpec = StrAnyMap
|
|
120
|
+
|
|
121
|
+
# -- Pipelines-- #
|
|
122
|
+
|
|
123
|
+
# Unified pipeline step spec consumed by :mod:`etlplus.ops.transform`.
|
|
124
|
+
type StepSpec = AggregateSpec | FilterSpec | MapSpec | SelectSpec | SortSpec
|
|
125
|
+
|
|
126
|
+
# Collections of steps
|
|
127
|
+
|
|
128
|
+
# Ordered collection of :data:`StepSpec` entries.
|
|
129
|
+
type StepSeq = Sequence[StepSpec]
|
|
130
|
+
|
|
131
|
+
# Accepts either a single :data:`StepSpec` or a sequence of them.
|
|
132
|
+
type StepOrSteps = StepSpec | StepSeq
|
|
133
|
+
|
|
134
|
+
# Canonical literal names for supported transform stages.
|
|
135
|
+
type PipelineStepName = Literal['aggregate', 'filter', 'map', 'select', 'sort']
|
|
136
|
+
|
|
137
|
+
# Mapping from step name to its associated specification payload.
|
|
138
|
+
# TODO: Consider replacing with etlplus.workflow.types.PipelineConfig.
|
|
139
|
+
type PipelineConfig = Mapping[PipelineStepName, StepOrSteps]
|
|
140
|
+
|
|
141
|
+
# -- Helpers -- #
|
|
142
|
+
|
|
143
|
+
# Callable that applies step configuration to a batch of records.
|
|
144
|
+
type StepApplier = Callable[[JSONList, Any], JSONList]
|
|
145
|
+
|
|
146
|
+
# Tuple combining stable sort index and computed sort value.
|
|
147
|
+
type SortKey = tuple[int, Any]
|
|
@@ -53,30 +53,10 @@ __all__ = [
|
|
|
53
53
|
'JSONRecords',
|
|
54
54
|
# Type Aliases (File System)
|
|
55
55
|
'StrPath',
|
|
56
|
-
# Type Aliases (Functions)
|
|
57
|
-
'AggregateFunc',
|
|
58
|
-
'OperatorFunc',
|
|
59
|
-
# Type Aliases (Records & Fields)
|
|
60
|
-
'FieldName',
|
|
61
|
-
'Fields',
|
|
62
56
|
# Type Aliases (Transform Specs)
|
|
63
57
|
'StrAnyMap',
|
|
64
58
|
'StrSeqMap',
|
|
65
59
|
'StrStrMap',
|
|
66
|
-
'AggregateSpec',
|
|
67
|
-
'FilterSpec',
|
|
68
|
-
'MapSpec',
|
|
69
|
-
'SelectSpec',
|
|
70
|
-
'SortSpec',
|
|
71
|
-
# Type Aliases (Pipelines)
|
|
72
|
-
'StepOrSteps',
|
|
73
|
-
'StepSeq',
|
|
74
|
-
'StepSpec',
|
|
75
|
-
'PipelineStepName',
|
|
76
|
-
'PipelineConfig',
|
|
77
|
-
# Type Aliases (Helpers)
|
|
78
|
-
'StepApplier',
|
|
79
|
-
'SortKey',
|
|
80
60
|
# Type Aliases (Networking / Runtime)
|
|
81
61
|
'Sleeper',
|
|
82
62
|
'Timeout',
|
|
@@ -126,22 +106,6 @@ type JSONRecords = list[JSONRecord]
|
|
|
126
106
|
# Path-like inputs accepted by file helpers.
|
|
127
107
|
type StrPath = str | Path | PathLike[str]
|
|
128
108
|
|
|
129
|
-
# -- Functions -- #
|
|
130
|
-
|
|
131
|
-
# Callable reducing numeric collections into a summary value.
|
|
132
|
-
type AggregateFunc = Callable[[list[float], int], Any]
|
|
133
|
-
|
|
134
|
-
# Binary predicate consumed by filter operations.
|
|
135
|
-
type OperatorFunc = Callable[[Any, Any], bool]
|
|
136
|
-
|
|
137
|
-
# -- Records & Fields -- #
|
|
138
|
-
|
|
139
|
-
# Individual field identifier referenced inside specs.
|
|
140
|
-
type FieldName = str
|
|
141
|
-
|
|
142
|
-
# Ordered list of :data:`FieldName` entries preserving projection order.
|
|
143
|
-
type Fields = list[FieldName]
|
|
144
|
-
|
|
145
109
|
# -- Transform Specs -- #
|
|
146
110
|
|
|
147
111
|
# Kept intentionally broad for runtime-friendly validation in transform.py.
|
|
@@ -157,69 +121,6 @@ type StrStrMap = Mapping[str, str]
|
|
|
157
121
|
# Mapping whose values are homogeneous sequences.
|
|
158
122
|
type StrSeqMap = Mapping[str, Sequence[Any]]
|
|
159
123
|
|
|
160
|
-
# Transform step specifications
|
|
161
|
-
|
|
162
|
-
# Filtering spec expecting ``field``, ``op``, and ``value`` keys.
|
|
163
|
-
type FilterSpec = StrAnyMap
|
|
164
|
-
|
|
165
|
-
# Field renaming instructions mapping old keys to new ones.
|
|
166
|
-
type MapSpec = StrStrMap
|
|
167
|
-
|
|
168
|
-
# Projection spec as a field list or mapping with metadata.
|
|
169
|
-
#
|
|
170
|
-
# Examples
|
|
171
|
-
# --------
|
|
172
|
-
# >>> from etlplus.types import SelectSpec
|
|
173
|
-
# >>> spec1: SelectSpec = ['a','b']
|
|
174
|
-
# >>> spec2: SelectSpec = {'fields': [...]}
|
|
175
|
-
type SelectSpec = Fields | StrSeqMap
|
|
176
|
-
|
|
177
|
-
# Sort directive expressed as a field string or mapping with flags.
|
|
178
|
-
#
|
|
179
|
-
# Examples
|
|
180
|
-
# --------
|
|
181
|
-
# >>> from etlplus.types import SortSpec
|
|
182
|
-
# >>> spec1: SortSpec = 'field'
|
|
183
|
-
# >>> spec2: SortSpec = {'field': 'x', 'reverse': True}
|
|
184
|
-
type SortSpec = str | StrAnyMap
|
|
185
|
-
|
|
186
|
-
# Aggregate instruction covering ``field``, ``func``, and optional alias.
|
|
187
|
-
#
|
|
188
|
-
# Supported functions: ``avg``, ``count``, ``max``, ``min``, and ``sum``.
|
|
189
|
-
# Examples
|
|
190
|
-
# --------
|
|
191
|
-
# >>> from etlplus.types import AggregateSpec
|
|
192
|
-
# >>> spec: AggregateSpec = \
|
|
193
|
-
# ... {'field': 'x', 'func': 'sum' | 'avg' | ..., 'alias'?: '...'}
|
|
194
|
-
type AggregateSpec = StrAnyMap
|
|
195
|
-
|
|
196
|
-
# -- Pipelines-- #
|
|
197
|
-
|
|
198
|
-
# Unified pipeline step spec consumed by :mod:`etlplus.ops.transform`.
|
|
199
|
-
type StepSpec = AggregateSpec | FilterSpec | MapSpec | SelectSpec | SortSpec
|
|
200
|
-
|
|
201
|
-
# Collections of steps
|
|
202
|
-
|
|
203
|
-
# Ordered collection of :data:`StepSpec` entries.
|
|
204
|
-
type StepSeq = Sequence[StepSpec]
|
|
205
|
-
|
|
206
|
-
# Accepts either a single :data:`StepSpec` or a sequence of them.
|
|
207
|
-
type StepOrSteps = StepSpec | StepSeq
|
|
208
|
-
|
|
209
|
-
# Canonical literal names for supported transform stages.
|
|
210
|
-
type PipelineStepName = Literal['filter', 'map', 'select', 'sort', 'aggregate']
|
|
211
|
-
|
|
212
|
-
# Mapping from step name to its associated specification payload.
|
|
213
|
-
type PipelineConfig = Mapping[PipelineStepName, StepOrSteps]
|
|
214
|
-
|
|
215
|
-
# -- Helpers -- #
|
|
216
|
-
|
|
217
|
-
# Callable that applies step configuration to a batch of records.
|
|
218
|
-
type StepApplier = Callable[[JSONList, Any], JSONList]
|
|
219
|
-
|
|
220
|
-
# Tuple combining stable sort index and computed sort value.
|
|
221
|
-
type SortKey = tuple[int, Any]
|
|
222
|
-
|
|
223
124
|
# -- Networking / Runtime -- #
|
|
224
125
|
|
|
225
126
|
# Sleep function used by retry helpers.
|
|
@@ -147,10 +147,12 @@ etlplus/file/zip.py
|
|
|
147
147
|
etlplus/file/zsav.py
|
|
148
148
|
etlplus/ops/README.md
|
|
149
149
|
etlplus/ops/__init__.py
|
|
150
|
+
etlplus/ops/enums.py
|
|
150
151
|
etlplus/ops/extract.py
|
|
151
152
|
etlplus/ops/load.py
|
|
152
153
|
etlplus/ops/run.py
|
|
153
154
|
etlplus/ops/transform.py
|
|
155
|
+
etlplus/ops/types.py
|
|
154
156
|
etlplus/ops/utils.py
|
|
155
157
|
etlplus/ops/validate.py
|
|
156
158
|
etlplus/templates/README.md
|
|
@@ -164,7 +166,7 @@ etlplus/workflow/jobs.py
|
|
|
164
166
|
etlplus/workflow/pipeline.py
|
|
165
167
|
etlplus/workflow/profile.py
|
|
166
168
|
examples/README.md
|
|
167
|
-
examples/
|
|
169
|
+
examples/quickstart.py
|
|
168
170
|
examples/configs/ddl_spec.yml
|
|
169
171
|
examples/configs/pipeline.yml
|
|
170
172
|
examples/data/sample.csv
|
|
@@ -184,7 +186,6 @@ tests/integration/test_i_run.py
|
|
|
184
186
|
tests/integration/test_i_run_profile_pagination_defaults.py
|
|
185
187
|
tests/integration/test_i_run_profile_rate_limit_defaults.py
|
|
186
188
|
tests/unit/conftest.py
|
|
187
|
-
tests/unit/test_u_enums.py
|
|
188
189
|
tests/unit/test_u_main.py
|
|
189
190
|
tests/unit/test_u_mixins.py
|
|
190
191
|
tests/unit/test_u_utils.py
|
|
@@ -219,6 +220,7 @@ tests/unit/database/test_u_database_schema.py
|
|
|
219
220
|
tests/unit/file/test_u_file_core.py
|
|
220
221
|
tests/unit/file/test_u_file_enums.py
|
|
221
222
|
tests/unit/file/test_u_file_yaml.py
|
|
223
|
+
tests/unit/ops/test_u_ops_enums.py
|
|
222
224
|
tests/unit/ops/test_u_ops_extract.py
|
|
223
225
|
tests/unit/ops/test_u_ops_load.py
|
|
224
226
|
tests/unit/ops/test_u_ops_run.py
|