etlplus 0.15.5__tar.gz → 0.16.2__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.15.5/etlplus.egg-info → etlplus-0.16.2}/PKG-INFO +1 -1
- {etlplus-0.15.5 → etlplus-0.16.2}/docs/pipeline-guide.md +2 -2
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/types.py +32 -11
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/constants.py +1 -1
- etlplus-0.16.2/etlplus/connector/__init__.py +43 -0
- etlplus-0.16.2/etlplus/connector/api.py +161 -0
- etlplus-0.16.2/etlplus/connector/connector.py +26 -0
- etlplus-0.16.2/etlplus/connector/core.py +132 -0
- etlplus-0.16.2/etlplus/connector/database.py +122 -0
- etlplus-0.16.2/etlplus/connector/enums.py +52 -0
- etlplus-0.16.2/etlplus/connector/file.py +120 -0
- etlplus-0.16.2/etlplus/connector/types.py +40 -0
- etlplus-0.16.2/etlplus/connector/utils.py +122 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/enums.py +0 -32
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/extract.py +210 -23
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/load.py +141 -35
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/run.py +86 -101
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/transform.py +30 -11
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/types.py +3 -2
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/workflow/__init__.py +2 -11
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/workflow/dag.py +23 -1
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/workflow/jobs.py +15 -26
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/workflow/pipeline.py +39 -56
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/workflow/profile.py +4 -2
- {etlplus-0.15.5 → etlplus-0.16.2/etlplus.egg-info}/PKG-INFO +1 -1
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus.egg-info/SOURCES.txt +11 -3
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/conftest.py +22 -25
- etlplus-0.16.2/tests/unit/connector/test_u_connector_enums.py +47 -0
- etlplus-0.15.5/tests/unit/workflow/test_u_workflow_connector.py → etlplus-0.16.2/tests/unit/connector/test_u_connector_utils.py +6 -6
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/ops/test_u_ops_load.py +1 -6
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/ops/test_u_ops_run.py +16 -13
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/test_u_enums.py +0 -27
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/workflow/test_u_workflow_pipeline.py +4 -5
- etlplus-0.15.5/etlplus/workflow/connector.py +0 -386
- etlplus-0.15.5/etlplus/workflow/types.py +0 -115
- {etlplus-0.15.5 → etlplus-0.16.2}/.coveragerc +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/.editorconfig +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/.gitattributes +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/.github/actions/python-bootstrap/action.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/.github/workflows/ci.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/.gitignore +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/.pre-commit-config.yaml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/.ruff.toml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/CODE_OF_CONDUCT.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/CONTRIBUTING.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/DEMO.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/LICENSE +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/MANIFEST.in +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/Makefile +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/REFERENCES.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/SECURITY.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/SUPPORT.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/docs/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/docs/snippets/installation_version.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/__main__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/__version__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/auth.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/endpoint_client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/errors.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/pagination/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/pagination/client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/pagination/config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/pagination/paginator.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/rate_limiting/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/rate_limiting/config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/rate_limiting/rate_limiter.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/request_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/retry_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/transport.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/api/utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/commands.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/handlers.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/io.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/main.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/options.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/state.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/cli/types.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/database/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/database/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/database/ddl.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/database/engine.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/database/orm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/database/schema.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/database/types.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/_imports.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/_io.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/accdb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/arrow.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/avro.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/bson.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/cbor.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/cfg.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/conf.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/core.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/csv.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/dat.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/dta.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/duckdb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/feather.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/fwf.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/gz.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/hbs.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/hdf5.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/ini.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/ion.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/jinja2.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/json.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/log.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/mat.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/mdb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/msgpack.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/mustache.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/nc.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/ndjson.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/numbers.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/ods.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/orc.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/parquet.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/pb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/pbf.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/properties.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/proto.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/psv.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/rda.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/rds.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/sas7bdat.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/sav.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/sqlite.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/stub.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/sylk.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/tab.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/toml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/tsv.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/txt.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/vm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/wks.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/xls.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/xlsm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/xlsx.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/xml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/xpt.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/yaml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/zip.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/file/zsav.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/mixins.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/ops/validate.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/py.typed +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/templates/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/templates/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/templates/ddl.sql.j2 +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/templates/view.sql.j2 +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus/workflow/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus.egg-info/dependency_links.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus.egg-info/entry_points.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus.egg-info/requires.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/etlplus.egg-info/top_level.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/configs/ddl_spec.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/configs/pipeline.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/data/sample.csv +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/data/sample.json +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/data/sample.xml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/data/sample.xsd +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/data/sample.yaml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/examples/quickstart_python.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/pyproject.toml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/pytest.ini +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/setup.cfg +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/setup.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_cli.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_examples_data_parity.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_pagination_strategy.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_pipeline_smoke.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_pipeline_yaml_load.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_run.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_run_profile_pagination_defaults.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/integration/test_i_run_profile_rate_limit_defaults.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_api_enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_api_utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_auth.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_endpoint_client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_mocks.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_pagination_client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_pagination_config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_paginator.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_rate_limit_config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_rate_limiter.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_request_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_retry_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_transport.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/api/test_u_types.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/cli/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/cli/test_u_cli_handlers.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/cli/test_u_cli_io.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/cli/test_u_cli_main.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/cli/test_u_cli_state.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/database/test_u_database_ddl.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/database/test_u_database_engine.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/database/test_u_database_orm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/database/test_u_database_schema.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/file/test_u_file_core.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/file/test_u_file_enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/file/test_u_file_yaml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/ops/test_u_ops_extract.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/ops/test_u_ops_transform.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/ops/test_u_ops_utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/ops/test_u_ops_validate.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/test_u_main.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/test_u_mixins.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/test_u_utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/test_u_version.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tests/unit/workflow/test_u_workflow_jobs.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.2}/tools/update_demo_snippets.py +0 -0
|
@@ -377,9 +377,9 @@ Details:
|
|
|
377
377
|
- Unknown or malformed entries are skipped rather than failing the whole load (keeping pipeline
|
|
378
378
|
authoring permissive).
|
|
379
379
|
- The connector kind is also available as a type-safe literal in code as
|
|
380
|
-
`etlplus.
|
|
380
|
+
`etlplus.connector.ConnectorType` (values: `"file" | "database" | "api"`).
|
|
381
381
|
|
|
382
|
-
To add new connector kinds in the future, implement a new dataclass in `etlplus.
|
|
382
|
+
To add new connector kinds in the future, implement a new dataclass in `etlplus.connector`
|
|
383
383
|
and extend the internal parser to handle its `type` value.
|
|
384
384
|
|
|
385
385
|
## Jobs
|
|
@@ -53,7 +53,31 @@ __all__ = [
|
|
|
53
53
|
# SECTION: CONSTANTS ======================================================== #
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
_UNSET = object()
|
|
56
|
+
_UNSET: object = object()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# SECTION: INTERNAL FUNCTIONS =============================================== #
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _to_dict(
|
|
63
|
+
value: Mapping[str, Any] | object | None,
|
|
64
|
+
) -> dict[str, Any] | None:
|
|
65
|
+
"""
|
|
66
|
+
Return a defensive ``dict`` copy for mapping inputs.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
value : Mapping[str, Any] | object | None
|
|
71
|
+
Mapping to copy, or ``None``.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
dict[str, Any] | None
|
|
76
|
+
New ``dict`` instance or ``None`` when the input is ``None``.
|
|
77
|
+
"""
|
|
78
|
+
if value is None:
|
|
79
|
+
return None
|
|
80
|
+
return cast(dict[str, Any], value)
|
|
57
81
|
|
|
58
82
|
|
|
59
83
|
# SECTION: TYPED DICTS ====================================================== #
|
|
@@ -176,9 +200,9 @@ class RequestOptions:
|
|
|
176
200
|
|
|
177
201
|
def __post_init__(self) -> None:
|
|
178
202
|
if self.params is not None:
|
|
179
|
-
object.__setattr__(self, 'params',
|
|
203
|
+
object.__setattr__(self, 'params', _to_dict(self.params))
|
|
180
204
|
if self.headers is not None:
|
|
181
|
-
object.__setattr__(self, 'headers',
|
|
205
|
+
object.__setattr__(self, 'headers', _to_dict(self.headers))
|
|
182
206
|
|
|
183
207
|
# -- Instance Methods -- #
|
|
184
208
|
|
|
@@ -224,23 +248,20 @@ class RequestOptions:
|
|
|
224
248
|
|
|
225
249
|
Returns
|
|
226
250
|
-------
|
|
227
|
-
|
|
251
|
+
Self
|
|
228
252
|
New snapshot reflecting the provided overrides.
|
|
229
253
|
"""
|
|
230
254
|
if params is _UNSET:
|
|
231
255
|
next_params = self.params
|
|
232
|
-
elif params is None:
|
|
233
|
-
next_params = None
|
|
234
256
|
else:
|
|
235
|
-
next_params =
|
|
257
|
+
# next_params = _to_dict(params) if params is not None else None
|
|
258
|
+
next_params = _to_dict(params)
|
|
236
259
|
|
|
237
260
|
if headers is _UNSET:
|
|
238
261
|
next_headers = self.headers
|
|
239
|
-
elif headers is None:
|
|
240
|
-
next_headers = None
|
|
241
262
|
else:
|
|
242
|
-
next_headers =
|
|
243
|
-
|
|
263
|
+
# next_headers = _to_dict(headers) if headers is not None else None
|
|
264
|
+
next_headers = _to_dict(headers)
|
|
244
265
|
if timeout is _UNSET:
|
|
245
266
|
next_timeout = self.timeout
|
|
246
267
|
else:
|
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
from typing import Final
|
|
10
10
|
|
|
11
|
-
from ..
|
|
11
|
+
from ..connector import DataConnectorType
|
|
12
12
|
from ..file import FileFormat
|
|
13
13
|
|
|
14
14
|
# SECTION: EXPORTS ========================================================== #
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.connector` package.
|
|
3
|
+
|
|
4
|
+
Connector configuration types and enums.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from .api import ConnectorApi
|
|
10
|
+
from .api import ConnectorApiConfigMap
|
|
11
|
+
from .connector import Connector
|
|
12
|
+
from .core import ConnectorBase
|
|
13
|
+
from .core import ConnectorProtocol
|
|
14
|
+
from .database import ConnectorDb
|
|
15
|
+
from .database import ConnectorDbConfigMap
|
|
16
|
+
from .enums import DataConnectorType
|
|
17
|
+
from .file import ConnectorFile
|
|
18
|
+
from .file import ConnectorFileConfigMap
|
|
19
|
+
from .types import ConnectorType
|
|
20
|
+
from .utils import parse_connector
|
|
21
|
+
|
|
22
|
+
# SECTION: EXPORTS ========================================================== #
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
# Data Classes
|
|
27
|
+
'ConnectorApi',
|
|
28
|
+
'ConnectorDb',
|
|
29
|
+
'ConnectorFile',
|
|
30
|
+
# Enums
|
|
31
|
+
'DataConnectorType',
|
|
32
|
+
# Functions
|
|
33
|
+
'parse_connector',
|
|
34
|
+
# Type Aliases
|
|
35
|
+
'Connector',
|
|
36
|
+
'ConnectorBase',
|
|
37
|
+
'ConnectorProtocol',
|
|
38
|
+
'ConnectorType',
|
|
39
|
+
# Typed Dicts
|
|
40
|
+
'ConnectorApiConfigMap',
|
|
41
|
+
'ConnectorDbConfigMap',
|
|
42
|
+
'ConnectorFileConfigMap',
|
|
43
|
+
]
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.connector.api` module.
|
|
3
|
+
|
|
4
|
+
API connector configuration dataclass.
|
|
5
|
+
|
|
6
|
+
Notes
|
|
7
|
+
-----
|
|
8
|
+
- TypedDicts in this module are intentionally ``total=False`` and are not
|
|
9
|
+
enforced at runtime.
|
|
10
|
+
- :meth:`*.from_obj` constructors accept :class:`Mapping[str, Any]` and perform
|
|
11
|
+
tolerant parsing and light casting. This keeps the runtime permissive while
|
|
12
|
+
improving autocomplete and static analysis for contributors.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from dataclasses import field
|
|
19
|
+
from typing import Any
|
|
20
|
+
from typing import Self
|
|
21
|
+
from typing import TypedDict
|
|
22
|
+
from typing import overload
|
|
23
|
+
|
|
24
|
+
from ..api import PaginationConfig
|
|
25
|
+
from ..api import PaginationConfigMap
|
|
26
|
+
from ..api import RateLimitConfig
|
|
27
|
+
from ..api import RateLimitConfigMap
|
|
28
|
+
from ..types import StrAnyMap
|
|
29
|
+
from ..types import StrStrMap
|
|
30
|
+
from ..utils import cast_str_dict
|
|
31
|
+
from ..utils import coerce_dict
|
|
32
|
+
from ..utils import maybe_mapping
|
|
33
|
+
from .core import ConnectorBase
|
|
34
|
+
from .enums import DataConnectorType
|
|
35
|
+
from .types import ConnectorType
|
|
36
|
+
|
|
37
|
+
# SECTION: EXPORTS ========================================================== #
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
'ConnectorApi',
|
|
42
|
+
'ConnectorApiConfigMap',
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# SECTION: TYPED DICTS ====================================================== #
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ConnectorApiConfigMap(TypedDict, total=False):
|
|
50
|
+
"""
|
|
51
|
+
Shape accepted by :meth:`ConnectorApi.from_obj` (all keys optional).
|
|
52
|
+
|
|
53
|
+
See Also
|
|
54
|
+
--------
|
|
55
|
+
- :meth:`etlplus.connector.api.ConnectorApi.from_obj`
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
name: str
|
|
59
|
+
type: ConnectorType
|
|
60
|
+
url: str
|
|
61
|
+
method: str
|
|
62
|
+
headers: StrStrMap
|
|
63
|
+
query_params: StrAnyMap
|
|
64
|
+
pagination: PaginationConfigMap
|
|
65
|
+
rate_limit: RateLimitConfigMap
|
|
66
|
+
api: str
|
|
67
|
+
endpoint: str
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# SECTION: DATA CLASSES ===================================================== #
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(kw_only=True, slots=True)
|
|
74
|
+
class ConnectorApi(ConnectorBase):
|
|
75
|
+
"""
|
|
76
|
+
Configuration for an API-based data connector.
|
|
77
|
+
|
|
78
|
+
Attributes
|
|
79
|
+
----------
|
|
80
|
+
type : ConnectorType
|
|
81
|
+
Connector kind, always ``'api'``.
|
|
82
|
+
url : str | None
|
|
83
|
+
Direct absolute URL (when not using ``service``/``endpoint`` refs).
|
|
84
|
+
method : str | None
|
|
85
|
+
Optional HTTP method; typically omitted for sources (defaults to
|
|
86
|
+
GET) and used for targets (e.g., ``'post'``).
|
|
87
|
+
headers : dict[str, str]
|
|
88
|
+
Additional request headers.
|
|
89
|
+
query_params : dict[str, Any]
|
|
90
|
+
Default query parameters.
|
|
91
|
+
pagination : PaginationConfig | None
|
|
92
|
+
Pagination settings (optional).
|
|
93
|
+
rate_limit : RateLimitConfig | None
|
|
94
|
+
Rate limiting settings (optional).
|
|
95
|
+
api : str | None
|
|
96
|
+
Service reference into the pipeline ``apis`` block (a.k.a.
|
|
97
|
+
``service``).
|
|
98
|
+
endpoint : str | None
|
|
99
|
+
Endpoint name within the referenced service.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
# -- Attributes -- #
|
|
103
|
+
|
|
104
|
+
type: ConnectorType = DataConnectorType.API
|
|
105
|
+
|
|
106
|
+
# Direct form
|
|
107
|
+
url: str | None = None
|
|
108
|
+
# Optional HTTP method; typically omitted for sources (defaults to GET)
|
|
109
|
+
# at runtime) and used for targets (e.g., 'post', 'put').
|
|
110
|
+
method: str | None = None
|
|
111
|
+
headers: dict[str, str] = field(default_factory=dict)
|
|
112
|
+
query_params: dict[str, Any] = field(default_factory=dict)
|
|
113
|
+
pagination: PaginationConfig | None = None
|
|
114
|
+
rate_limit: RateLimitConfig | None = None
|
|
115
|
+
|
|
116
|
+
# Reference form (to top-level APIs/endpoints)
|
|
117
|
+
api: str | None = None
|
|
118
|
+
endpoint: str | None = None
|
|
119
|
+
|
|
120
|
+
# -- Class Methods -- #
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
@overload
|
|
124
|
+
def from_obj(cls, obj: ConnectorApiConfigMap) -> Self: ...
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
@overload
|
|
128
|
+
def from_obj(cls, obj: StrAnyMap) -> Self: ...
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def from_obj(
|
|
132
|
+
cls,
|
|
133
|
+
obj: StrAnyMap,
|
|
134
|
+
) -> Self:
|
|
135
|
+
"""
|
|
136
|
+
Parse a mapping into a ``ConnectorApi`` instance.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
obj : StrAnyMap
|
|
141
|
+
Mapping with at least ``name``.
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
Self
|
|
146
|
+
Parsed connector instance.
|
|
147
|
+
"""
|
|
148
|
+
name = cls._require_name(obj, kind='Api')
|
|
149
|
+
headers = cast_str_dict(maybe_mapping(obj.get('headers')))
|
|
150
|
+
|
|
151
|
+
return cls(
|
|
152
|
+
name=name,
|
|
153
|
+
url=obj.get('url'),
|
|
154
|
+
method=obj.get('method'),
|
|
155
|
+
headers=headers,
|
|
156
|
+
query_params=coerce_dict(obj.get('query_params')),
|
|
157
|
+
pagination=PaginationConfig.from_obj(obj.get('pagination')),
|
|
158
|
+
rate_limit=RateLimitConfig.from_obj(obj.get('rate_limit')),
|
|
159
|
+
api=obj.get('api') or obj.get('service'),
|
|
160
|
+
endpoint=obj.get('endpoint'),
|
|
161
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.connector.connector` module.
|
|
3
|
+
|
|
4
|
+
Compatibility re-exports for connector configuration classes.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from .api import ConnectorApi
|
|
10
|
+
from .database import ConnectorDb
|
|
11
|
+
from .file import ConnectorFile
|
|
12
|
+
|
|
13
|
+
# SECTION: EXPORTS ========================================================== #
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
# Type aliases
|
|
18
|
+
'Connector',
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# SECTION: TYPED ALIASES ==================================================== #
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Type alias representing any supported connector
|
|
26
|
+
type Connector = ConnectorApi | ConnectorDb | ConnectorFile
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.connector.core` module.
|
|
3
|
+
|
|
4
|
+
Protocols and base classes for connector implementations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from abc import ABC
|
|
10
|
+
from abc import abstractmethod
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Protocol
|
|
13
|
+
from typing import Self
|
|
14
|
+
from typing import runtime_checkable
|
|
15
|
+
|
|
16
|
+
from ..types import StrAnyMap
|
|
17
|
+
from .types import ConnectorType
|
|
18
|
+
|
|
19
|
+
# SECTION: EXPORTS ========================================================== #
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
'ConnectorBase',
|
|
24
|
+
'ConnectorProtocol',
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# SECTION: PROTOCOLS ======================================================== #
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@runtime_checkable
|
|
32
|
+
class ConnectorProtocol(Protocol):
|
|
33
|
+
"""
|
|
34
|
+
Structural contract for connector implementations.
|
|
35
|
+
|
|
36
|
+
Attributes
|
|
37
|
+
----------
|
|
38
|
+
name : str
|
|
39
|
+
Unique connector name.
|
|
40
|
+
type : ConnectorType
|
|
41
|
+
Connector kind.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
# -- Attributes -- #
|
|
45
|
+
|
|
46
|
+
name: str
|
|
47
|
+
type: ConnectorType
|
|
48
|
+
|
|
49
|
+
# -- Class Methods -- #
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def from_obj(cls, obj: StrAnyMap) -> Self:
|
|
53
|
+
"""
|
|
54
|
+
Parse a mapping into a connector instance.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
obj : StrAnyMap
|
|
59
|
+
Mapping with at least ``name``.
|
|
60
|
+
|
|
61
|
+
Returns
|
|
62
|
+
-------
|
|
63
|
+
Self
|
|
64
|
+
Parsed connector instance.
|
|
65
|
+
"""
|
|
66
|
+
...
|
|
67
|
+
|
|
68
|
+
# -- Internal Static Methods -- #
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def _require_name(obj: StrAnyMap, *, kind: str) -> str:
|
|
72
|
+
"""
|
|
73
|
+
Extract and validate the ``name`` field from connector mappings.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
obj : StrAnyMap
|
|
78
|
+
Connector mapping with a ``name`` entry.
|
|
79
|
+
kind : str
|
|
80
|
+
Connector kind used in the error message.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
str
|
|
85
|
+
Valid connector name.
|
|
86
|
+
|
|
87
|
+
Raises
|
|
88
|
+
------
|
|
89
|
+
TypeError
|
|
90
|
+
If ``name`` is missing or not a string.
|
|
91
|
+
"""
|
|
92
|
+
name = obj.get('name')
|
|
93
|
+
if not isinstance(name, str):
|
|
94
|
+
raise TypeError(f'Connector{kind} requires a "name" (str)')
|
|
95
|
+
return name
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# SECTION: ABSTRACT BASE DATA CLASSES ======================================= #
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@dataclass(kw_only=True, slots=True)
|
|
102
|
+
class ConnectorBase(ABC, ConnectorProtocol):
|
|
103
|
+
"""
|
|
104
|
+
Abstract base class for connector implementations.
|
|
105
|
+
|
|
106
|
+
Attributes
|
|
107
|
+
----------
|
|
108
|
+
name : str
|
|
109
|
+
Unique connector name.
|
|
110
|
+
type : ConnectorType
|
|
111
|
+
Connector kind.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
name: str
|
|
115
|
+
type: ConnectorType
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
@abstractmethod
|
|
119
|
+
def from_obj(cls, obj: StrAnyMap) -> Self:
|
|
120
|
+
"""
|
|
121
|
+
Parse a mapping into a connector instance.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
obj : StrAnyMap
|
|
126
|
+
Mapping with at least ``name``.
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
Self
|
|
131
|
+
Parsed connector instance.
|
|
132
|
+
"""
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.connector.database` module.
|
|
3
|
+
|
|
4
|
+
Database connector configuration dataclass.
|
|
5
|
+
|
|
6
|
+
Notes
|
|
7
|
+
-----
|
|
8
|
+
- TypedDicts in this module are intentionally ``total=False`` and are not
|
|
9
|
+
enforced at runtime.
|
|
10
|
+
- :meth:`*.from_obj` constructors accept :class:`Mapping[str, Any]` and perform
|
|
11
|
+
tolerant parsing and light casting. This keeps the runtime permissive while
|
|
12
|
+
improving autocomplete and static analysis for contributors.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from typing import Self
|
|
19
|
+
from typing import TypedDict
|
|
20
|
+
from typing import overload
|
|
21
|
+
|
|
22
|
+
from ..types import StrAnyMap
|
|
23
|
+
from .core import ConnectorBase
|
|
24
|
+
from .enums import DataConnectorType
|
|
25
|
+
from .types import ConnectorType
|
|
26
|
+
|
|
27
|
+
# SECTION: EXPORTS ========================================================== #
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
'ConnectorDb',
|
|
32
|
+
'ConnectorDbConfigMap',
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# SECTION: TYPED DICTS ====================================================== #
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ConnectorDbConfigMap(TypedDict, total=False):
|
|
40
|
+
"""
|
|
41
|
+
Shape accepted by :meth:`ConnectorDb.from_obj` (all keys optional).
|
|
42
|
+
|
|
43
|
+
See Also
|
|
44
|
+
--------
|
|
45
|
+
- :meth:`etlplus.connector.database.ConnectorDb.from_obj`
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
name: str
|
|
49
|
+
type: ConnectorType
|
|
50
|
+
connection_string: str
|
|
51
|
+
query: str
|
|
52
|
+
table: str
|
|
53
|
+
mode: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# SECTION: DATA CLASSES ===================================================== #
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(kw_only=True, slots=True)
|
|
60
|
+
class ConnectorDb(ConnectorBase):
|
|
61
|
+
"""
|
|
62
|
+
Configuration for a database-based data connector.
|
|
63
|
+
|
|
64
|
+
Attributes
|
|
65
|
+
----------
|
|
66
|
+
type : ConnectorType
|
|
67
|
+
Connector kind, always ``'database'``.
|
|
68
|
+
connection_string : str | None
|
|
69
|
+
Connection string/DSN for the database.
|
|
70
|
+
query : str | None
|
|
71
|
+
Query to execute for extraction (optional).
|
|
72
|
+
table : str | None
|
|
73
|
+
Target/source table name (optional).
|
|
74
|
+
mode : str | None
|
|
75
|
+
Load mode hint (e.g., ``'append'``, ``'replace'``) - future use.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
# -- Attributes -- #
|
|
79
|
+
|
|
80
|
+
type: ConnectorType = DataConnectorType.DATABASE
|
|
81
|
+
connection_string: str | None = None
|
|
82
|
+
query: str | None = None
|
|
83
|
+
table: str | None = None
|
|
84
|
+
mode: str | None = None # append|replace|upsert (future)
|
|
85
|
+
|
|
86
|
+
# -- Class Methods -- #
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
@overload
|
|
90
|
+
def from_obj(cls, obj: ConnectorDbConfigMap) -> Self: ...
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
@overload
|
|
94
|
+
def from_obj(cls, obj: StrAnyMap) -> Self: ...
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def from_obj(
|
|
98
|
+
cls,
|
|
99
|
+
obj: StrAnyMap,
|
|
100
|
+
) -> Self:
|
|
101
|
+
"""
|
|
102
|
+
Parse a mapping into a ``ConnectorDb`` instance.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
obj : StrAnyMap
|
|
107
|
+
Mapping with at least ``name``.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
Self
|
|
112
|
+
Parsed connector instance.
|
|
113
|
+
"""
|
|
114
|
+
name = cls._require_name(obj, kind='Db')
|
|
115
|
+
|
|
116
|
+
return cls(
|
|
117
|
+
name=name,
|
|
118
|
+
connection_string=obj.get('connection_string'),
|
|
119
|
+
query=obj.get('query'),
|
|
120
|
+
table=obj.get('table'),
|
|
121
|
+
mode=obj.get('mode'),
|
|
122
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.connector.enums` module.
|
|
3
|
+
|
|
4
|
+
Connector enums and helpers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ..enums import CoercibleStrEnum
|
|
10
|
+
from ..types import StrStrMap
|
|
11
|
+
|
|
12
|
+
# SECTION: EXPORTS ========================================================= #
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
# Enums
|
|
17
|
+
'DataConnectorType',
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# SECTION: ENUMS ============================================================ #
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DataConnectorType(CoercibleStrEnum):
|
|
25
|
+
"""Supported data connector types."""
|
|
26
|
+
|
|
27
|
+
# -- Constants -- #
|
|
28
|
+
|
|
29
|
+
API = 'api'
|
|
30
|
+
DATABASE = 'database'
|
|
31
|
+
FILE = 'file'
|
|
32
|
+
|
|
33
|
+
# -- Class Methods -- #
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def aliases(cls) -> StrStrMap:
|
|
37
|
+
"""
|
|
38
|
+
Return a mapping of common aliases for each enum member.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
StrStrMap
|
|
43
|
+
A mapping of alias names to their corresponding enum member names.
|
|
44
|
+
"""
|
|
45
|
+
return {
|
|
46
|
+
'http': 'api',
|
|
47
|
+
'https': 'api',
|
|
48
|
+
'rest': 'api',
|
|
49
|
+
'db': 'database',
|
|
50
|
+
'filesystem': 'file',
|
|
51
|
+
'fs': 'file',
|
|
52
|
+
}
|