etlplus 0.15.5__tar.gz → 0.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {etlplus-0.15.5/etlplus.egg-info → etlplus-0.16.0}/PKG-INFO +1 -1
- {etlplus-0.15.5 → etlplus-0.16.0}/docs/pipeline-guide.md +2 -2
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/constants.py +1 -1
- etlplus-0.16.0/etlplus/connector/__init__.py +43 -0
- etlplus-0.16.0/etlplus/connector/api.py +161 -0
- etlplus-0.16.0/etlplus/connector/connector.py +26 -0
- etlplus-0.16.0/etlplus/connector/core.py +132 -0
- etlplus-0.16.0/etlplus/connector/database.py +122 -0
- etlplus-0.16.0/etlplus/connector/enums.py +52 -0
- etlplus-0.16.0/etlplus/connector/file.py +120 -0
- etlplus-0.16.0/etlplus/connector/types.py +40 -0
- etlplus-0.16.0/etlplus/connector/utils.py +122 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/enums.py +0 -32
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/extract.py +1 -1
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/load.py +1 -1
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/run.py +1 -1
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/types.py +1 -1
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/workflow/__init__.py +0 -11
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/workflow/pipeline.py +2 -2
- {etlplus-0.15.5 → etlplus-0.16.0/etlplus.egg-info}/PKG-INFO +1 -1
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus.egg-info/SOURCES.txt +11 -3
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/conftest.py +2 -2
- etlplus-0.15.5/tests/unit/workflow/test_u_workflow_connector.py → etlplus-0.16.0/tests/unit/connector/test_u_connector_connector.py +6 -6
- etlplus-0.16.0/tests/unit/connector/test_u_connector_enums.py +47 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/ops/test_u_ops_load.py +1 -6
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/test_u_enums.py +0 -27
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/workflow/test_u_workflow_pipeline.py +3 -3
- 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.0}/.coveragerc +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/.editorconfig +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/.gitattributes +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/.github/actions/python-bootstrap/action.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/.github/workflows/ci.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/.gitignore +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/.pre-commit-config.yaml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/.ruff.toml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/CODE_OF_CONDUCT.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/CONTRIBUTING.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/DEMO.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/LICENSE +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/MANIFEST.in +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/Makefile +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/REFERENCES.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/SECURITY.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/SUPPORT.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/docs/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/docs/snippets/installation_version.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/__main__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/__version__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/auth.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/endpoint_client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/errors.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/pagination/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/pagination/client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/pagination/config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/pagination/paginator.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/rate_limiting/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/rate_limiting/config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/rate_limiting/rate_limiter.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/request_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/retry_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/transport.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/types.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/api/utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/commands.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/handlers.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/io.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/main.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/options.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/state.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/cli/types.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/database/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/database/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/database/ddl.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/database/engine.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/database/orm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/database/schema.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/database/types.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/_imports.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/_io.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/accdb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/arrow.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/avro.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/bson.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/cbor.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/cfg.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/conf.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/core.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/csv.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/dat.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/dta.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/duckdb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/feather.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/fwf.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/gz.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/hbs.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/hdf5.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/ini.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/ion.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/jinja2.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/json.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/log.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/mat.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/mdb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/msgpack.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/mustache.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/nc.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/ndjson.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/numbers.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/ods.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/orc.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/parquet.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/pb.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/pbf.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/properties.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/proto.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/psv.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/rda.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/rds.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/sas7bdat.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/sav.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/sqlite.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/stub.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/sylk.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/tab.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/toml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/tsv.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/txt.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/vm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/wks.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/xls.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/xlsm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/xlsx.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/xml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/xpt.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/yaml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/zip.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/file/zsav.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/mixins.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/transform.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/ops/validate.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/py.typed +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/templates/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/templates/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/templates/ddl.sql.j2 +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/templates/view.sql.j2 +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/workflow/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/workflow/dag.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/workflow/jobs.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus/workflow/profile.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus.egg-info/dependency_links.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus.egg-info/entry_points.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus.egg-info/requires.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/etlplus.egg-info/top_level.txt +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/README.md +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/configs/ddl_spec.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/configs/pipeline.yml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/data/sample.csv +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/data/sample.json +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/data/sample.xml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/data/sample.xsd +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/data/sample.yaml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/examples/quickstart_python.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/pyproject.toml +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/pytest.ini +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/setup.cfg +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/setup.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/__init__.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_cli.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_examples_data_parity.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_pagination_strategy.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_pipeline_smoke.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_pipeline_yaml_load.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_run.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_run_profile_pagination_defaults.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/integration/test_i_run_profile_rate_limit_defaults.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_api_enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_api_utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_auth.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_endpoint_client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_mocks.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_pagination_client.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_pagination_config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_paginator.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_rate_limit_config.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_rate_limiter.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_request_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_retry_manager.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_transport.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/api/test_u_types.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/cli/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/cli/test_u_cli_handlers.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/cli/test_u_cli_io.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/cli/test_u_cli_main.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/cli/test_u_cli_state.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/conftest.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/database/test_u_database_ddl.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/database/test_u_database_engine.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/database/test_u_database_orm.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/database/test_u_database_schema.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/file/test_u_file_core.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/file/test_u_file_enums.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/file/test_u_file_yaml.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/ops/test_u_ops_extract.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/ops/test_u_ops_run.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/ops/test_u_ops_transform.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/ops/test_u_ops_utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/ops/test_u_ops_validate.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/test_u_main.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/test_u_mixins.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/test_u_utils.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/test_u_version.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/tests/unit/workflow/test_u_workflow_jobs.py +0 -0
- {etlplus-0.15.5 → etlplus-0.16.0}/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
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:mod:`etlplus.connector.file` module.
|
|
3
|
+
|
|
4
|
+
File 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 ..types import StrAnyMap
|
|
25
|
+
from ..utils import coerce_dict
|
|
26
|
+
from .core import ConnectorBase
|
|
27
|
+
from .enums import DataConnectorType
|
|
28
|
+
from .types import ConnectorType
|
|
29
|
+
|
|
30
|
+
# SECTION: EXPORTS ========================================================== #
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
'ConnectorFile',
|
|
35
|
+
'ConnectorFileConfigMap',
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# SECTION: TYPED DICTS ====================================================== #
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ConnectorFileConfigMap(TypedDict, total=False):
|
|
43
|
+
"""
|
|
44
|
+
Shape accepted by :meth:`ConnectorFile.from_obj` (all keys optional).
|
|
45
|
+
|
|
46
|
+
See Also
|
|
47
|
+
--------
|
|
48
|
+
- :meth:`etlplus.connector.file.ConnectorFile.from_obj`
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
name: str
|
|
52
|
+
type: ConnectorType
|
|
53
|
+
format: str
|
|
54
|
+
path: str
|
|
55
|
+
options: StrAnyMap
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# SECTION: DATA CLASSES ===================================================== #
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(kw_only=True, slots=True)
|
|
62
|
+
class ConnectorFile(ConnectorBase):
|
|
63
|
+
"""
|
|
64
|
+
Configuration for a file-based data connector.
|
|
65
|
+
|
|
66
|
+
Attributes
|
|
67
|
+
----------
|
|
68
|
+
type : ConnectorType
|
|
69
|
+
Connector kind, always ``'file'``.
|
|
70
|
+
format : str | None
|
|
71
|
+
File format (e.g., ``'json'``, ``'csv'``).
|
|
72
|
+
path : str | None
|
|
73
|
+
File path or URI.
|
|
74
|
+
options : dict[str, Any]
|
|
75
|
+
Reader/writer format options.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
# -- Attributes -- #
|
|
79
|
+
|
|
80
|
+
type: ConnectorType = DataConnectorType.FILE
|
|
81
|
+
format: str | None = None
|
|
82
|
+
path: str | None = None
|
|
83
|
+
options: dict[str, Any] = field(default_factory=dict)
|
|
84
|
+
|
|
85
|
+
# -- Class Methods -- #
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
@overload
|
|
89
|
+
def from_obj(cls, obj: ConnectorFileConfigMap) -> Self: ...
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
@overload
|
|
93
|
+
def from_obj(cls, obj: StrAnyMap) -> Self: ...
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def from_obj(
|
|
97
|
+
cls,
|
|
98
|
+
obj: StrAnyMap,
|
|
99
|
+
) -> Self:
|
|
100
|
+
"""
|
|
101
|
+
Parse a mapping into a ``ConnectorFile`` instance.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
obj : StrAnyMap
|
|
106
|
+
Mapping with at least ``name``.
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
Self
|
|
111
|
+
Parsed connector instance.
|
|
112
|
+
"""
|
|
113
|
+
name = cls._require_name(obj, kind='File')
|
|
114
|
+
|
|
115
|
+
return cls(
|
|
116
|
+
name=name,
|
|
117
|
+
format=obj.get('format'),
|
|
118
|
+
path=obj.get('path'),
|
|
119
|
+
options=coerce_dict(obj.get('options')),
|
|
120
|
+
)
|