diff --git a/README.md b/README.md index 28d786d..f6e2724 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,9 @@ dbt-exasol: # Known isues +## >=1.3 Python model not yet supported - WIP +- Please follow [this pull request](https://github.com/tglunde/dbt-exasol/pull/59) + ## Breaking changes with release 1.2.2 - Timestamp format defaults to YYYY-MM-DDTHH:MI:SS.FF6 @@ -50,25 +53,6 @@ In order to support packages like dbt-utils and dbt-audit-helper, we needed to c # Reporting bugs and contributing code - Please report bugs using the issues -# Release History - -## Release 1.2.2 -- Added timestamp format parameter in profile.yml parameter file to set Exasol session parameter NLS_TIMESTAMP_FORMAT when opening a connection. Defaults to 'YYYY-MM-DDTHH:MI:SS.FF6' -- Adding row_separator (LF/CRLF) parameter in profile.yml parameter file to be used in seed csv import. Defaults to operating system default (os.linesep in python). -- bugfix #36 regarding column quotes and case sensitivity of column names. -- bugfix #42 regarding datatype change when using snapshot materialization. Added modify column statement in exasol__alter_column_type macro -- bugfix #17 number format datatype -- issue #24 - dbt-core v1.2.0 compatibility finished +# Releases -## Release 1.2.0 -- support for invalidate_hard_deletes option in snapshots added by jups23 -- added persist_docs support by sti0 -- added additional configuration keys that can be included in profiles.yml by johannes-becker-otto -- added cross-database macros introduced in 1.2 by sti0 -- added support for connection retries by sti0 -- added support for grants by sti0 -- added pytest functional adapter tests by tglunde -- tox testing for python 3.7.2 through 3.10 added by tglunde - -## Release 1.0.0 -- pyexasol HTTP import csv feature implemented. Optimal performance and compatibility with Exasol CSV parsing +[GitHub Releases](https://github.com/tglunde/dbt-exasol/releases) diff --git a/dbt/adapters/exasol/connections.py b/dbt/adapters/exasol/connections.py index c23058a..6973d01 100644 --- a/dbt/adapters/exasol/connections.py +++ b/dbt/adapters/exasol/connections.py @@ -258,6 +258,10 @@ def execute(self, query, bindings: Optional[Any] = None): """executing query""" if query.startswith("0CSV|"): self.import_from_file(bindings, query.split("|", 1)[1]) # type: ignore + elif query.__contains__("|SEPARATEMEPLEASE|"): + sqls = query.split("|SEPARATEMEPLEASE|") + for sql in sqls: + self.stmt = self.connection.execute(sql) else: self.stmt = self.connection.execute(query) return self diff --git a/dbt/adapters/exasol/impl.py b/dbt/adapters/exasol/impl.py index 0fd83a7..abbb5ea 100644 --- a/dbt/adapters/exasol/impl.py +++ b/dbt/adapters/exasol/impl.py @@ -8,7 +8,8 @@ from dbt.exceptions import raise_compiler_error from dbt.utils import filter_null_values -from dbt.adapters.exasol import ExasolColumn, ExasolConnectionManager, ExasolRelation +from dbt.adapters.exasol import (ExasolColumn, ExasolConnectionManager, + ExasolRelation) class ExasolAdapter(SQLAdapter): @@ -79,3 +80,9 @@ def quote_seed_column(self, column: str, quote_config: Optional[bool]) -> str: if quote_columns: return self.quote(column) return column + + def valid_incremental_strategies(self): + """The set of standard builtin strategies which this adapter supports out-of-the-box. + Not used to validate custom strategies defined by end users. + """ + return ["append", "delete+insert"] \ No newline at end of file diff --git a/dbt/include/exasol/macros/materializations/incremental.sql b/dbt/include/exasol/macros/materializations/incremental.sql index 6e8975d..c428807 100644 --- a/dbt/include/exasol/macros/materializations/incremental.sql +++ b/dbt/include/exasol/macros/materializations/incremental.sql @@ -1,91 +1,93 @@ -{% macro incremental_delete(target_relation, tmp_relation) -%} - {%- set unique_key = config.get('unique_key') -%} - - {% if unique_key %} - {% if unique_key is sequence and unique_key is not string %} - delete from {{ target_relation }} - where exists (select 1 from {{ tmp_relation }} - where - {% for key in unique_key %} - {{ tmp_relation }}.{{ key }} = {{ target_relation }}.{{ key }} - {{ "and " if not loop.last }} - {% endfor %} - ); - {% else %} - delete from {{ target_relation }} - where ( - {{ unique_key }}) in ( - select ({{ unique_key }}) - from {{ tmp_relation }} - ); - {% endif %} - {%endif%} -{%- endmacro %} -{% macro incremental_insert(tmp_relation, target_relation, unique_key=none, statement_name="main") %} - {%- set dest_columns = adapter.get_columns_in_relation(target_relation) -%} - {%- set dest_cols_csv = dest_columns | join(', ', attribute='name') -%} - - insert into {{ target_relation }} ({{ dest_cols_csv }}) - ( - select {{ dest_cols_csv }} - from {{ tmp_relation.schema }}.{{ tmp_relation.identifier }} - ); -{%- endmacro %} +{% materialization incremental, adapter='exasol' -%} + -- relations + {%- set existing_relation = load_relation(this) -%} -{% materialization incremental, adapter='exasol' -%} + {%- set target_relation = this.incorporate(type='table') -%} + {%- set temp_relation = make_temp_relation(target_relation)-%} + {%- set intermediate_relation = make_intermediate_relation(target_relation)-%} + {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%} + {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%} + -- configs {%- set unique_key = config.get('unique_key') -%} - {%- set full_refresh_mode = (flags.FULL_REFRESH == True) -%} - {%- set identifier = model['alias'] -%} - {%- set target_relation = api.Relation.create(identifier=identifier, schema=schema, database=database, type='table') -%} - {% set existing_relation = adapter.get_relation(database=database, schema=schema, identifier = identifier) %} - {% set tmp_relation = make_temp_relation(target_relation) %} + {%- set full_refresh_mode = (should_full_refresh() or existing_relation.is_view) -%} + {%- set on_schema_change = incremental_validate_on_schema_change(config.get('on_schema_change'), default='ignore') -%} + + -- the temp_ and backup_ relations should not already exist in the database; get_relation + -- will return None in that case. Otherwise, we get a relation that we can drop + -- later, before we try to use this name for the current operation. This has to happen before + -- BEGIN, in a separate transaction + {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation)-%} + {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%} + -- grab current tables grants config for comparision later on + {% set grant_config = config.get('grants') %} + {{ drop_relation_if_exists(preexisting_intermediate_relation) }} + {{ drop_relation_if_exists(preexisting_backup_relation) }} - -- grab current tables grants config for comparision later on - {%- set grant_config = config.get('grants') -%} - - -- setup {{ run_hooks(pre_hooks, inside_transaction=False) }} -- `BEGIN` happens here: {{ run_hooks(pre_hooks, inside_transaction=True) }} + {% set to_drop = [] %} + {% if existing_relation is none %} - {% set build_sql = create_table_as(False, target_relation, sql) %} - {% elif existing_relation.is_view %} - {% do adapter.drop_relation(existing_relation) %} - {% set build_sql = create_table_as(False, target_relation, sql) %} + {% set build_sql = get_create_table_as_sql(False, target_relation, sql) %} {% elif full_refresh_mode %} - {% do drop_relation(existing_relation) %} - {% set build_sql = create_table_as(False, target_relation, sql) %} + {% set build_sql = get_create_table_as_sql(False, intermediate_relation, sql) %} + {% set need_swap = true %} {% else %} - {% do run_query(create_table_as(True, tmp_relation, sql)) %} - {% do run_query(incremental_delete(target_relation, tmp_relation)) %} - {% set build_sql = incremental_insert(tmp_relation, target_relation) %} + {% do run_query(get_create_table_as_sql(True, temp_relation, sql)) %} + {% do adapter.expand_target_column_types( + from_relation=temp_relation, + to_relation=target_relation) %} + {#-- Process schema changes. Returns dict of changes if successful. Use source columns for upserting/merging --#} + {% set dest_columns = process_schema_changes(on_schema_change, temp_relation, existing_relation) %} + {% if not dest_columns %} + {% set dest_columns = adapter.get_columns_in_relation(existing_relation) %} + {% endif %} + + {#-- Get the incremental_strategy, the macro to use for the strategy, and build the sql --#} + {% set incremental_strategy = config.get('incremental_strategy') or 'default' %} + {% set incremental_predicates = config.get('predicates', none) or config.get('incremental_predicates', none) %} + {% set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) %} + {% set strategy_arg_dict = ({'target_relation': target_relation, 'temp_relation': temp_relation, 'unique_key': unique_key, 'dest_columns': dest_columns, 'incremental_predicates': incremental_predicates }) %} + {% set build_sql = strategy_sql_macro_func(strategy_arg_dict) %} + {% endif %} - - {%- call statement('main') -%} - {{ build_sql }} - {%- endcall -%} + {% call statement("main") %} + {{ build_sql }} + {% endcall %} - {% if tmp_relation is not none %} - {% do adapter.drop_relation(tmp_relation) %} + {% if need_swap %} + {% do adapter.rename_relation(existing_relation, backup_relation) %} + {% do adapter.rename_relation(intermediate_relation, target_relation) %} + {% do to_drop.append(backup_relation) %} {% endif %} - - {{ run_hooks(post_hooks, inside_transaction=True) }} - {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=full_refresh_mode) %} - {% do apply_grants(target_relation, grant_config, should_revoke) %} + {% set should_revoke = should_revoke(existing_relation, full_refresh_mode) %} + {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %} + + {% do persist_docs(target_relation, model) %} + + {% if existing_relation is none or existing_relation.is_view or should_full_refresh() %} + {% do create_indexes(target_relation) %} + {% endif %} + + {{ run_hooks(post_hooks, inside_transaction=True) }} -- `COMMIT` happens here - {{ adapter.commit() }} + {% do adapter.commit() %} - {{ run_hooks(post_hooks, inside_transaction=False) }} + {% for rel in to_drop %} + {% do adapter.drop_relation(rel) %} + {% endfor %} - {% do persist_docs(target_relation, model) %} + {{ run_hooks(post_hooks, inside_transaction=False) }} {{ return({'relations': [target_relation]}) }} -{%- endmaterialization %} + +{%- endmaterialization %} \ No newline at end of file diff --git a/dbt/include/exasol/macros/materializations/incremental_strategies.sql b/dbt/include/exasol/macros/materializations/incremental_strategies.sql new file mode 100644 index 0000000..1a08dfb --- /dev/null +++ b/dbt/include/exasol/macros/materializations/incremental_strategies.sql @@ -0,0 +1,9 @@ +{% macro exasol__get_incremental_default_sql(arg_dict) %} + + {% if arg_dict["unique_key"] %} + {% do return(get_incremental_delete_insert_sql(arg_dict)) %} + {% else %} + {% do return(get_incremental_append_sql(arg_dict)) %} + {% endif %} + +{% endmacro %} diff --git a/dbt/include/exasol/macros/materializations/merge.sql b/dbt/include/exasol/macros/materializations/merge.sql new file mode 100644 index 0000000..19e2b41 --- /dev/null +++ b/dbt/include/exasol/macros/materializations/merge.sql @@ -0,0 +1,34 @@ +{% macro exasol__get_delete_insert_merge_sql(target, source, unique_key, dest_columns) -%} + + {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute="name")) -%} + + {% if unique_key %} + {% if unique_key is sequence and unique_key is not string %} + delete from {{ target }} + where exists ( select 1 from {{ source }} + where + {% for key in unique_key %} + {{ source }}.{{ key }} = {{ target }}.{{ key }} + {{ "and " if not loop.last }} + {% endfor %} + ) + {% else %} + delete from {{ target }} + where ( + {{ unique_key }}) in ( + select ({{ unique_key }}) + from {{ source }} + ) + + {% endif %} + {% endif %} + + |SEPARATEMEPLEASE| + + insert into {{ target }} ({{ dest_cols_csv }}) + ( + select {{ dest_cols_csv }} + from {{ source }} + ) + +{%- endmacro %} diff --git a/dbt/include/exasol/macros/materializations/view.sql b/dbt/include/exasol/macros/materializations/view.sql deleted file mode 100644 index 7acfb65..0000000 --- a/dbt/include/exasol/macros/materializations/view.sql +++ /dev/null @@ -1,4 +0,0 @@ -{% materialization view, adapter='exasol' -%} - {{ return(create_or_replace_view()) }} - -{%- endmaterialization %} \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index a433476..ed57b67 100644 --- a/poetry.lock +++ b/poetry.lock @@ -27,19 +27,18 @@ test = ["PyICU (>=2.4.2)", "coverage (>=3.7.1)", "cssselect (>=0.9.1)", "lxml (> [[package]] name = "astroid" -version = "2.15.1" +version = "2.15.2" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "astroid-2.15.1-py3-none-any.whl", hash = "sha256:89860bda98fe2bbd1f5d262229be7629d778ce280de68d95d4a73d1f592ad268"}, - {file = "astroid-2.15.1.tar.gz", hash = "sha256:af4e0aff46e2868218502789898269ed95b663fba49e65d91c1e09c966266c34"}, + {file = "astroid-2.15.2-py3-none-any.whl", hash = "sha256:dea89d9f99f491c66ac9c04ebddf91e4acf8bd711722175fe6245c0725cc19bb"}, + {file = "astroid-2.15.2.tar.gz", hash = "sha256:6e61b85c891ec53b07471aec5878f4ac6446a41e590ede0f2ce095f39f7d49dd"}, ] [package.dependencies] lazy-object-proxy = ">=1.4.0" -typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} wrapt = [ {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, @@ -77,9 +76,6 @@ files = [ {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, ] -[package.dependencies] -pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} - [[package]] name = "black" version = "22.12.0" @@ -108,8 +104,6 @@ mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -305,7 +299,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" @@ -386,10 +379,7 @@ Jinja2 = "3.1.2" logbook = ">=1.5,<1.6" mashumaro = {version = "3.0.4", extras = ["msgpack"]} minimal-snowplow-tracker = "0.0.2" -networkx = [ - {version = ">=2.3,<2.8.1", markers = "python_version < \"3.8\""}, - {version = ">=2.3,<3", markers = "python_version >= \"3.8\""}, -] +networkx = {version = ">=2.3,<3", markers = "python_version >= \"3.8\""} packaging = ">=20.9,<22.0" pathspec = ">=0.9.0,<0.10.0" pytz = ">=2015.7" @@ -538,27 +528,6 @@ files = [ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] -[[package]] -name = "importlib-metadata" -version = "6.1.0" -description = "Read metadata from Python packages" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "importlib_metadata-6.1.0-py3-none-any.whl", hash = "sha256:ff80f3b5394912eb1b108fcfd444dc78b7f1f3e16b16188054bd01cb9cb86f09"}, - {file = "importlib_metadata-6.1.0.tar.gz", hash = "sha256:43ce9281e097583d758c2c708c4376371261a02c34682491a8e98352365aad20"}, -] - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] - [[package]] name = "iniconfig" version = "2.0.0" @@ -588,18 +557,18 @@ six = "*" [[package]] name = "isort" -version = "5.11.5" +version = "5.12.0" description = "A Python utility / library to sort Python imports." category = "dev" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"}, - {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"}, + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, ] [package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] +colors = ["colorama (>=0.4.3)"] pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] plugins = ["setuptools"] requirements-deprecated-finder = ["pip-api", "pipreqs"] @@ -636,7 +605,6 @@ files = [ [package.dependencies] attrs = ">=17.4.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} pyrsistent = ">=0.14.0" setuptools = "*" six = ">=1.11.0" @@ -928,25 +896,6 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -[[package]] -name = "networkx" -version = "2.6.3" -description = "Python package for creating and manipulating graphs and networks" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "networkx-2.6.3-py3-none-any.whl", hash = "sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef"}, - {file = "networkx-2.6.3.tar.gz", hash = "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51"}, -] - -[package.extras] -default = ["matplotlib (>=3.3)", "numpy (>=1.19)", "pandas (>=1.1)", "scipy (>=1.5,!=1.6.1)"] -developer = ["black (==21.5b1)", "pre-commit (>=2.12)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.1)", "pillow (>=8.2)", "pydata-sphinx-theme (>=0.6,<1.0)", "sphinx (>=4.0,<5.0)", "sphinx-gallery (>=0.9,<1.0)", "texext (>=0.6.6)"] -extra = ["lxml (>=4.5)", "pydot (>=1.4.1)", "pygraphviz (>=1.7)"] -test = ["codecov (>=2.1)", "pytest (>=6.2)", "pytest-cov (>=2.12)"] - [[package]] name = "networkx" version = "2.8.8" @@ -1020,9 +969,6 @@ files = [ {file = "platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.5", markers = "python_version < \"3.8\""} - [package.extras] docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] @@ -1039,9 +985,6 @@ files = [ {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] @@ -1109,18 +1052,18 @@ ujson = ["ujson"] [[package]] name = "pylint" -version = "2.17.1" +version = "2.17.2" description = "python code static checker" category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "pylint-2.17.1-py3-none-any.whl", hash = "sha256:8660a54e3f696243d644fca98f79013a959c03f979992c1ab59c24d3f4ec2700"}, - {file = "pylint-2.17.1.tar.gz", hash = "sha256:d4d009b0116e16845533bc2163493d6681846ac725eab8ca8014afb520178ddd"}, + {file = "pylint-2.17.2-py3-none-any.whl", hash = "sha256:001cc91366a7df2970941d7e6bbefcbf98694e00102c1f121c531a814ddc2ea8"}, + {file = "pylint-2.17.2.tar.gz", hash = "sha256:1b647da5249e7c279118f657ca28b6aaebb299f86bf92affc632acf199f7adbb"}, ] [package.dependencies] -astroid = ">=2.15.0,<=2.17.0-dev0" +astroid = ">=2.15.2,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, @@ -1131,7 +1074,6 @@ mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" -typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] spelling = ["pyenchant (>=3.2,<4.0)"] @@ -1224,7 +1166,6 @@ files = [ attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" @@ -1249,6 +1190,22 @@ files = [ pytest = ">=5.0.0" python-dotenv = ">=0.9.1" +[[package]] +name = "pytest-parallel" +version = "0.1.1" +description = "a pytest plugin for parallel and concurrent testing" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "pytest-parallel-0.1.1.tar.gz", hash = "sha256:9aac3fc199a168c0a8559b60249d9eb254de7af58c12cee0310b54d4affdbfab"}, + {file = "pytest_parallel-0.1.1-py3-none-any.whl", hash = "sha256:9e3703015b0eda52be9e07d2ba3498f09340a56d5c79a39b50f22fc5c38212fe"}, +] + +[package.dependencies] +pytest = ">=3.0.0" +tblib = "*" + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1266,14 +1223,14 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "0.21.1" +version = "1.0.0" description = "Read key-value pairs from a .env file and set them as environment variables" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "python-dotenv-0.21.1.tar.gz", hash = "sha256:1c93de8f636cde3ce377292818d0e440b6e45a82f215c3744979151fa8151c49"}, - {file = "python_dotenv-0.21.1-py3-none-any.whl", hash = "sha256:41e12e0318bebc859fcc4d97d4db8d20ad21721a6aa5047dd59f090391cb549a"}, + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, ] [package.extras] @@ -1449,6 +1406,18 @@ files = [ {file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"}, ] +[[package]] +name = "tblib" +version = "1.7.0" +description = "Traceback serialization library." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "tblib-1.7.0-py2.py3-none-any.whl", hash = "sha256:289fa7359e580950e7d9743eab36b0691f0310fce64dee7d9c31065b8f723e23"}, + {file = "tblib-1.7.0.tar.gz", hash = "sha256:059bd77306ea7b419d4f76016aef6d7027cc8a0785579b5aad198803435f882c"}, +] + [[package]] name = "text-unidecode" version = "1.3" @@ -1500,7 +1469,6 @@ files = [ [package.dependencies] colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} filelock = ">=3.0.0" -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} packaging = ">=14" pluggy = ">=0.12.0" py = ">=1.4.17" @@ -1512,40 +1480,6 @@ virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2, docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)"] -[[package]] -name = "typed-ast" -version = "1.5.4" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, -] - [[package]] name = "typing-extensions" version = "4.5.0" @@ -1590,7 +1524,6 @@ files = [ [package.dependencies] distlib = ">=0.3.6,<1" filelock = ">=3.4.1,<4" -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""} platformdirs = ">=2.4,<4" [package.extras] @@ -1717,23 +1650,7 @@ files = [ {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, ] -[[package]] -name = "zipp" -version = "3.15.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - [metadata] lock-version = "2.0" -python-versions = "^3.7.2, <4" -content-hash = "4a5ec6b029497091d99a0f7c08bbf8d711b4a632c847998cc9dc860e49db7fc9" +python-versions = "^3.10.9" +content-hash = "0a9fe95f6672cb642d25e1e4c1b1686ba34f55ab4e2c3271e08b81c382892269" diff --git a/pyproject.toml b/pyproject.toml index 9d0c2e8..3594de3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ license = "GPL3" readme = "README.md" [tool.poetry.dependencies] -python = "^3.7.2, <4" dbt-core = "^1.3, <1.4" pyexasol = "^0.25.0" dbt-tests-adapter = "^1.3, <1.4" @@ -28,6 +27,7 @@ tox = "^3.26.0" [tool.poetry.group.dev.dependencies] dbt-tests-adapter = "^1.3.2" pylint = "^2.15.8" +pytest-parallel = "^0.1.1" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tox.ini b/tox.ini index 89e6ae6..77eb7dc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] isolated_build = True -envlist = python3.7,py38,py39,py310 +env_list = py{37,38,39,310} [testenv] passenv = * @@ -8,4 +8,4 @@ allowlist_externals = poetry pytest commands = poetry install -v - pytest --junitxml=report.xml tests + pytest --workers=auto --junitxml=report.xml tests