data-validation-engine 0.7.5__tar.gz → 0.8.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.
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/PKG-INFO +22 -18
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/README.md +8 -5
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/pyproject.toml +28 -29
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/reader.py +15 -2
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/exceptions.py +27 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/readers/csv.py +85 -56
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/readers/json.py +17 -4
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/readers/xml.py +12 -5
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/rules.py +1 -1
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/readers/csv.py +27 -10
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/readers/json.py +6 -1
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/readers/xml.py +6 -1
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/metadata/contract.py +2 -2
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/readers/csv.py +42 -0
- data_validation_engine-0.8.0/src/dve/core_engine/backends/readers/utilities.py +75 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/readers/xml.py +1 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/utilities.py +1 -1
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/configuration/v1/__init__.py +9 -9
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/engine.py +10 -10
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/type_hints.py +1 -1
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/domain_types.py +1 -1
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/models.py +5 -5
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/helpers.py +2 -2
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/pipeline/duckdb_pipeline.py +1 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/pipeline/pipeline.py +20 -4
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/pipeline/utils.py +10 -3
- data_validation_engine-0.7.5/src/dve/core_engine/backends/readers/utilities.py +0 -21
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/LICENSE +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/common/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/common/error_utils.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/auditing.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/backend.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/contract.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/core.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/reference_data.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/rules.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/base/utilities.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/auditing.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/contract.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/duckdb_helpers.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/readers/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/reference_data.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/types.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/duckdb/utilities.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/auditing.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/backend.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/contract.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/readers/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/reference_data.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/rules.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/spark_helpers.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/types.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/implementations/spark/utilities.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/metadata/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/metadata/reporting.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/metadata/rules.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/readers/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/readers/xml_linting.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/backends/types.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/configuration/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/configuration/base.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/configuration/v1/filters.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/configuration/v1/rule_stores/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/configuration/v1/rule_stores/models.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/configuration/v1/steps.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/constants.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/exceptions.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/functions/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/functions/implementations.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/loggers.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/message.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/models.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/templating.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/core_engine/validation.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/exc.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/function_library.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/function_wrapper.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/model_generator.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/metadata_parser/utilities.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/exceptions.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/implementations/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/implementations/base.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/implementations/dbfs.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/implementations/file.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/implementations/s3.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/log_handler.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/service.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/file_handling/utilities.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/type_hints.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/parser/utilities.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/pipeline/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/pipeline/foundry_ddb_pipeline.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/pipeline/spark_pipeline.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/reporting/__init__.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/reporting/error_report.py +0 -0
- {data_validation_engine-0.7.5 → data_validation_engine-0.8.0}/src/dve/reporting/excel_report.py +0 -0
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: data-validation-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: `nhs data validation engine` is a framework used to validate data
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Author: NHS England
|
|
8
8
|
Author-email: england.contactus@nhs.net
|
|
9
|
-
Requires-Python: >=3.10,<3.
|
|
9
|
+
Requires-Python: >=3.10,<3.13
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Topic :: Software Development :: Libraries
|
|
15
15
|
Classifier: Typing :: Typed
|
|
16
|
-
Requires-Dist: Jinja2 (==3.1
|
|
16
|
+
Requires-Dist: Jinja2 (==3.1.6)
|
|
17
17
|
Requires-Dist: boto3 (>=1.34.162,<1.36)
|
|
18
18
|
Requires-Dist: botocore (>=1.34.162,<1.36)
|
|
19
|
-
Requires-Dist: delta-spark (==2.
|
|
20
|
-
Requires-Dist: duckdb (==1.1
|
|
21
|
-
Requires-Dist: lxml (
|
|
19
|
+
Requires-Dist: delta-spark (==3.2.0)
|
|
20
|
+
Requires-Dist: duckdb (==1.1.3)
|
|
21
|
+
Requires-Dist: lxml (==4.9.4)
|
|
22
22
|
Requires-Dist: numpy (==1.26.4)
|
|
23
|
-
Requires-Dist: openpyxl (
|
|
24
|
-
Requires-Dist: pandas (
|
|
25
|
-
Requires-Dist: polars (==0.20
|
|
26
|
-
Requires-Dist: pyarrow (
|
|
27
|
-
Requires-Dist: pydantic (==1.10.
|
|
28
|
-
Requires-Dist: pyspark (==3.
|
|
29
|
-
Requires-Dist: typing_extensions (
|
|
23
|
+
Requires-Dist: openpyxl (==3.1.5)
|
|
24
|
+
Requires-Dist: pandas (==2.3.3)
|
|
25
|
+
Requires-Dist: polars (==0.20.31)
|
|
26
|
+
Requires-Dist: pyarrow (==17.0.0)
|
|
27
|
+
Requires-Dist: pydantic (==1.10.19)
|
|
28
|
+
Requires-Dist: pyspark (==3.5.2)
|
|
29
|
+
Requires-Dist: typing_extensions (==4.15.0)
|
|
30
|
+
Requires-Dist: urllib3 (==2.7.0)
|
|
30
31
|
Project-URL: Changelog, https://github.com/NHSDigital/data-validation-engine/blob/main/CHANGELOG.md
|
|
31
32
|
Project-URL: Documentation, https://nhsdigital.github.io/data-validation-engine/
|
|
32
33
|
Project-URL: Homepage, https://github.com/NHSDigital/data-validation-engine
|
|
@@ -96,13 +97,16 @@ Below is a list of features that we would like to implement or have been request
|
|
|
96
97
|
| ------------------------------------------------------------------------------- | ----------------- | --------- |
|
|
97
98
|
| Open source release | 0.1.0 | Yes |
|
|
98
99
|
| Uplift to Python 3.11 | 0.2.0 | Yes |
|
|
99
|
-
| Uplift Pyspark to 3.5 |
|
|
100
|
-
| Allow DVE to run on Python 3.12+ |
|
|
101
|
-
| Upgrade to Pydantic 2.0 |
|
|
100
|
+
| Uplift Pyspark to 3.5 | 0.8.0 | Yes |
|
|
101
|
+
| Allow DVE to run on Python 3.12+ | 0.8.0 | Yes |
|
|
102
|
+
| Upgrade to Pydantic 2.0 | 0.9.0 | No |
|
|
102
103
|
| Uplift Pyspark to 4.0+ | TBA | No |
|
|
103
|
-
|
|
|
104
|
+
| Polars upgrade to v1+ | TBA | No |
|
|
105
|
+
| DuckDB upgrade to v1.5+ | TBA | No |
|
|
106
|
+
| Python 3.13 & 3.14 upgrade | TBA | No |
|
|
107
|
+
| Create a more user friendly interface for building and modifying dischema files | TBA | No |
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
If you are interested in getting any of the unreleased features listed above available, then please read the [Contributing](#Contributing) section and then submit us a pull request.
|
|
106
110
|
|
|
107
111
|
## Contributing
|
|
108
112
|
Please see guidance [here](https://github.com/NHSDigital/data-validation-engine/blob/main/CONTRIBUTE.md).
|
|
@@ -60,13 +60,16 @@ Below is a list of features that we would like to implement or have been request
|
|
|
60
60
|
| ------------------------------------------------------------------------------- | ----------------- | --------- |
|
|
61
61
|
| Open source release | 0.1.0 | Yes |
|
|
62
62
|
| Uplift to Python 3.11 | 0.2.0 | Yes |
|
|
63
|
-
| Uplift Pyspark to 3.5 |
|
|
64
|
-
| Allow DVE to run on Python 3.12+ |
|
|
65
|
-
| Upgrade to Pydantic 2.0 |
|
|
63
|
+
| Uplift Pyspark to 3.5 | 0.8.0 | Yes |
|
|
64
|
+
| Allow DVE to run on Python 3.12+ | 0.8.0 | Yes |
|
|
65
|
+
| Upgrade to Pydantic 2.0 | 0.9.0 | No |
|
|
66
66
|
| Uplift Pyspark to 4.0+ | TBA | No |
|
|
67
|
-
|
|
|
67
|
+
| Polars upgrade to v1+ | TBA | No |
|
|
68
|
+
| DuckDB upgrade to v1.5+ | TBA | No |
|
|
69
|
+
| Python 3.13 & 3.14 upgrade | TBA | No |
|
|
70
|
+
| Create a more user friendly interface for building and modifying dischema files | TBA | No |
|
|
68
71
|
|
|
69
|
-
|
|
72
|
+
If you are interested in getting any of the unreleased features listed above available, then please read the [Contributing](#Contributing) section and then submit us a pull request.
|
|
70
73
|
|
|
71
74
|
## Contributing
|
|
72
75
|
Please see guidance [here](https://github.com/NHSDigital/data-validation-engine/blob/main/CONTRIBUTE.md).
|
|
@@ -24,27 +24,28 @@ Issues = "https://github.com/NHSDigital/data-validation-engine/issues"
|
|
|
24
24
|
Changelog = "https://github.com/NHSDigital/data-validation-engine/blob/main/CHANGELOG.md"
|
|
25
25
|
|
|
26
26
|
[tool.poetry]
|
|
27
|
-
version = "0.
|
|
27
|
+
version = "0.8.0"
|
|
28
28
|
packages = [
|
|
29
29
|
{ include = "dve", from = "src" },
|
|
30
30
|
]
|
|
31
31
|
|
|
32
32
|
[tool.poetry.dependencies]
|
|
33
|
-
python = ">=3.10,<3.12
|
|
33
|
+
python = ">=3.10,<3.13" # breaking changes beyond 3.12
|
|
34
34
|
boto3 = ">=1.34.162,<1.36" # breaking change beyond 1.36
|
|
35
35
|
botocore = ">=1.34.162,<1.36" # breaking change beyond 1.36
|
|
36
|
-
delta-spark = "2.
|
|
37
|
-
duckdb = "1.1
|
|
38
|
-
Jinja2 = "3.1
|
|
39
|
-
lxml = "
|
|
36
|
+
delta-spark = "3.2.0"
|
|
37
|
+
duckdb = "1.1.3" # breaking changes beyond 1.1
|
|
38
|
+
Jinja2 = "3.1.6"
|
|
39
|
+
lxml = "4.9.4"
|
|
40
40
|
numpy = "1.26.4"
|
|
41
|
-
openpyxl = "
|
|
42
|
-
pandas = "
|
|
43
|
-
polars = "0.20
|
|
44
|
-
pyarrow = "
|
|
45
|
-
pydantic = "1.10.
|
|
46
|
-
pyspark = "3.
|
|
47
|
-
typing_extensions = "
|
|
41
|
+
openpyxl = "3.1.5"
|
|
42
|
+
pandas = "2.3.3"
|
|
43
|
+
polars = "0.20.31"
|
|
44
|
+
pyarrow = "17.0.0"
|
|
45
|
+
pydantic = "1.10.19"
|
|
46
|
+
pyspark = "3.5.2"
|
|
47
|
+
typing_extensions = "4.15.0"
|
|
48
|
+
urllib3 = "2.7.0" # dependency of boto3 & botocore
|
|
48
49
|
|
|
49
50
|
[tool.poetry.group.dev]
|
|
50
51
|
optional = true
|
|
@@ -58,30 +59,30 @@ commitizen = "4.9.1"
|
|
|
58
59
|
pre-commit = "4.3.0"
|
|
59
60
|
charset-normalizer = "3.4.6"
|
|
60
61
|
python-discovery = "1.2.0"
|
|
61
|
-
|
|
62
|
+
idna = "3.15" # dependency of requests
|
|
62
63
|
|
|
63
64
|
[tool.poetry.group.test]
|
|
64
65
|
optional = true
|
|
65
66
|
|
|
66
67
|
[tool.poetry.group.test.dependencies]
|
|
67
|
-
faker = "18.11.1"
|
|
68
68
|
behave = "1.3.3"
|
|
69
69
|
coverage = "7.11.0"
|
|
70
|
-
moto = {extras = ["s3"], version = "4.
|
|
70
|
+
moto = {extras = ["s3"], version = "4.2.14"}
|
|
71
|
+
requests = "2.33.0" # dependency of `moto`
|
|
71
72
|
Werkzeug = "3.1.6"
|
|
72
|
-
pytest = "
|
|
73
|
+
pytest = "9.0.3"
|
|
73
74
|
pytest-lazy-fixtures = "1.4.0" # switched from https://github.com/TvoroG/pytest-lazy-fixture as it's no longer supported
|
|
74
|
-
xlsx2csv = "0.8.
|
|
75
|
+
xlsx2csv = "0.8.4" # polars requirement
|
|
75
76
|
|
|
76
77
|
[tool.poetry.group.lint]
|
|
77
78
|
optional = true
|
|
78
79
|
|
|
79
80
|
[tool.poetry.group.lint.dependencies]
|
|
80
81
|
black = "24.3.0"
|
|
81
|
-
astroid = "
|
|
82
|
-
isort = "5.
|
|
83
|
-
pylint = "
|
|
84
|
-
mypy = "
|
|
82
|
+
astroid = "3.3.9"
|
|
83
|
+
isort = "5.13.2"
|
|
84
|
+
pylint = "3.3.9"
|
|
85
|
+
mypy = "1.11.2"
|
|
85
86
|
boto3-stubs = {extras = ["essential"], version = "1.26.72"}
|
|
86
87
|
botocore-stubs = "1.29.72"
|
|
87
88
|
pandas-stubs = "1.2.0.62"
|
|
@@ -100,10 +101,10 @@ optional = true
|
|
|
100
101
|
|
|
101
102
|
[tool.poetry.group.docs.dependencies]
|
|
102
103
|
click = "8.2.1"
|
|
103
|
-
mkdocs = "
|
|
104
|
+
mkdocs = "1.6.1"
|
|
104
105
|
mkdocstrings = { version = "1.0.3", extras = ["python"] }
|
|
105
106
|
griffelib = "2.0.1"
|
|
106
|
-
pymdown-extensions = "10.21.
|
|
107
|
+
pymdown-extensions = "10.21.3"
|
|
107
108
|
zensical = "0.0.31"
|
|
108
109
|
|
|
109
110
|
[tool.ruff]
|
|
@@ -142,10 +143,6 @@ source_pkgs = [
|
|
|
142
143
|
[tool.coverage.report]
|
|
143
144
|
show_missing = true
|
|
144
145
|
|
|
145
|
-
[tool.pylint]
|
|
146
|
-
init-hook = "import sys; sys.path.append('./pylint_checkers')"
|
|
147
|
-
load-plugins = "check_typing_imports"
|
|
148
|
-
|
|
149
146
|
[tool.pylint.main]
|
|
150
147
|
extension-pkg-allow-list = ["pyspark", "lxml", "pydantic"]
|
|
151
148
|
fail-under = 10.0
|
|
@@ -194,7 +191,7 @@ max-statements = 50
|
|
|
194
191
|
min-public-methods = 2
|
|
195
192
|
|
|
196
193
|
[tool.pylint.exceptions]
|
|
197
|
-
overgeneral-exceptions = ["BaseException", "Exception"]
|
|
194
|
+
overgeneral-exceptions = ["builtins.BaseException", "builtins.Exception"]
|
|
198
195
|
|
|
199
196
|
[tool.pylint.format]
|
|
200
197
|
ignore-long-lines = "^\\s*(# )?<?https?://\\S+>?$"
|
|
@@ -229,6 +226,8 @@ disable = [
|
|
|
229
226
|
"use-symbolic-message-instead",
|
|
230
227
|
"logging-fstring-interpolation",
|
|
231
228
|
"fixme",
|
|
229
|
+
"too-many-positional-arguments",
|
|
230
|
+
"too-many-arguments",
|
|
232
231
|
]
|
|
233
232
|
enable = ["c-extension-no-member"]
|
|
234
233
|
|
|
@@ -90,6 +90,7 @@ class BaseFileReader(ABC):
|
|
|
90
90
|
resource: URI,
|
|
91
91
|
entity_name: EntityName,
|
|
92
92
|
schema: type[BaseModel],
|
|
93
|
+
all_model_fields: Optional[set[str]] = None,
|
|
93
94
|
) -> Iterator[dict[str, Any]]:
|
|
94
95
|
"""Iterate through the contents of the resource, yielding dicts
|
|
95
96
|
representing each record.
|
|
@@ -107,6 +108,7 @@ class BaseFileReader(ABC):
|
|
|
107
108
|
resource: URI,
|
|
108
109
|
entity_name: EntityName,
|
|
109
110
|
schema: type[BaseModel],
|
|
111
|
+
all_model_fields: Optional[set[str]] = None,
|
|
110
112
|
) -> EntityType:
|
|
111
113
|
"""Read to the specified entity type, if supported.
|
|
112
114
|
|
|
@@ -116,7 +118,12 @@ class BaseFileReader(ABC):
|
|
|
116
118
|
|
|
117
119
|
"""
|
|
118
120
|
if entity_name == Iterator[dict[str, Any]]:
|
|
119
|
-
return self.read_to_py_iterator(
|
|
121
|
+
return self.read_to_py_iterator(
|
|
122
|
+
resource,
|
|
123
|
+
entity_name,
|
|
124
|
+
schema, # type: ignore
|
|
125
|
+
all_model_fields
|
|
126
|
+
)
|
|
120
127
|
|
|
121
128
|
self.raise_if_not_sensible_file(resource, entity_name)
|
|
122
129
|
|
|
@@ -125,7 +132,13 @@ class BaseFileReader(ABC):
|
|
|
125
132
|
except KeyError as err:
|
|
126
133
|
raise ReaderLacksEntityTypeSupport(entity_type=entity_type) from err
|
|
127
134
|
|
|
128
|
-
return reader_func(
|
|
135
|
+
return reader_func(
|
|
136
|
+
self,
|
|
137
|
+
resource,
|
|
138
|
+
entity_name,
|
|
139
|
+
schema,
|
|
140
|
+
all_model_fields=all_model_fields # type: ignore
|
|
141
|
+
)
|
|
129
142
|
|
|
130
143
|
def add_record_index(self, entity: EntityType, **kwargs) -> EntityType:
|
|
131
144
|
"""Add a record index to the entity"""
|
|
@@ -33,6 +33,33 @@ class MessageBearingError(BackendError):
|
|
|
33
33
|
"""The messages to be returned as part of the error."""
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
class UnableToParseCSVError(MessageBearingError):
|
|
37
|
+
"""An error raised when unable to parse a CSV file"""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
entity_name: str,
|
|
42
|
+
field_check_error_message: str,
|
|
43
|
+
field_check_error_code: str
|
|
44
|
+
):
|
|
45
|
+
super().__init__(
|
|
46
|
+
messages=[
|
|
47
|
+
FeedbackMessage(
|
|
48
|
+
entity="csv_structure",
|
|
49
|
+
record={
|
|
50
|
+
entity_name: "Unable to parse file. Please check the structure of the file."
|
|
51
|
+
},
|
|
52
|
+
failure_type="submission",
|
|
53
|
+
is_informational=False,
|
|
54
|
+
error_type="csv read",
|
|
55
|
+
error_location=entity_name,
|
|
56
|
+
error_message=field_check_error_message,
|
|
57
|
+
error_code=field_check_error_code,
|
|
58
|
+
)
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
36
63
|
class BackendErrorMixin(ABC, BackendError):
|
|
37
64
|
"""A mixin used to create backend error type."""
|
|
38
65
|
|
|
@@ -9,21 +9,25 @@ import polars as pl
|
|
|
9
9
|
from duckdb import (
|
|
10
10
|
DuckDBPyConnection,
|
|
11
11
|
DuckDBPyRelation,
|
|
12
|
+
InvalidInputException,
|
|
12
13
|
StarExpression,
|
|
13
|
-
default_connection,
|
|
14
14
|
read_csv,
|
|
15
15
|
)
|
|
16
16
|
from pydantic import BaseModel
|
|
17
17
|
|
|
18
|
-
from dve.core_engine.backends.base.reader import
|
|
19
|
-
from dve.core_engine.backends.exceptions import
|
|
18
|
+
from dve.core_engine.backends.base.reader import read_function
|
|
19
|
+
from dve.core_engine.backends.exceptions import (
|
|
20
|
+
EmptyFileError,
|
|
21
|
+
MessageBearingError,
|
|
22
|
+
UnableToParseCSVError,
|
|
23
|
+
)
|
|
20
24
|
from dve.core_engine.backends.implementations.duckdb.duckdb_helpers import (
|
|
21
25
|
duckdb_record_index,
|
|
22
26
|
duckdb_write_parquet,
|
|
23
27
|
get_duckdb_type_from_annotation,
|
|
24
28
|
)
|
|
25
29
|
from dve.core_engine.backends.implementations.duckdb.types import SQLType
|
|
26
|
-
from dve.core_engine.backends.readers.
|
|
30
|
+
from dve.core_engine.backends.readers.csv import CSVFileReader
|
|
27
31
|
from dve.core_engine.backends.utilities import get_polars_type_from_annotation, polars_record_index
|
|
28
32
|
from dve.core_engine.constants import RECORD_INDEX_COLUMN_NAME
|
|
29
33
|
from dve.core_engine.message import FeedbackMessage
|
|
@@ -33,7 +37,7 @@ from dve.parser.file_handling import get_content_length
|
|
|
33
37
|
|
|
34
38
|
@duckdb_record_index
|
|
35
39
|
@duckdb_write_parquet
|
|
36
|
-
class DuckDBCSVReader(
|
|
40
|
+
class DuckDBCSVReader(CSVFileReader):
|
|
37
41
|
"""A reader for CSV files including the ability to compare the passed model
|
|
38
42
|
to the file header, if it exists.
|
|
39
43
|
|
|
@@ -53,66 +57,57 @@ class DuckDBCSVReader(BaseFileReader):
|
|
|
53
57
|
quotechar: str = '"',
|
|
54
58
|
connection: Optional[DuckDBPyConnection] = None,
|
|
55
59
|
field_check: bool = False,
|
|
56
|
-
field_check_error_code:
|
|
57
|
-
field_check_error_message:
|
|
60
|
+
field_check_error_code: str = "ExpectedVsActualFieldMismatch",
|
|
61
|
+
field_check_error_message: str = "The submitted header is missing fields",
|
|
58
62
|
null_empty_strings: bool = False,
|
|
59
63
|
**_,
|
|
60
64
|
):
|
|
61
|
-
self.
|
|
62
|
-
self.delim = delim
|
|
63
|
-
self.quotechar = quotechar
|
|
64
|
-
self._connection = connection if connection else default_connection
|
|
65
|
-
self.field_check = field_check
|
|
66
|
-
self.field_check_error_code = field_check_error_code
|
|
67
|
-
self.field_check_error_message = field_check_error_message
|
|
65
|
+
self._connection = connection if connection else ddb.connect(":memory:")
|
|
68
66
|
self.null_empty_strings = null_empty_strings
|
|
69
67
|
|
|
70
|
-
super().__init__(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if missing := check_csv_header_expected(resource, expected_schema, self.delim):
|
|
80
|
-
raise MessageBearingError(
|
|
81
|
-
"The CSV header doesn't match what is expected",
|
|
82
|
-
messages=[
|
|
83
|
-
FeedbackMessage(
|
|
84
|
-
entity=entity_name,
|
|
85
|
-
record={"missing_fields": missing},
|
|
86
|
-
failure_type="submission",
|
|
87
|
-
error_location="Whole File",
|
|
88
|
-
reporting_field="missing_fields",
|
|
89
|
-
error_code=self.field_check_error_code,
|
|
90
|
-
error_message=f"{self.field_check_error_message}", # pylint: disable=line-too-long
|
|
91
|
-
)
|
|
92
|
-
],
|
|
93
|
-
)
|
|
68
|
+
super().__init__(
|
|
69
|
+
header=header,
|
|
70
|
+
delimiter=delim,
|
|
71
|
+
quote_char=quotechar,
|
|
72
|
+
field_check=field_check,
|
|
73
|
+
field_check_error_code=field_check_error_code,
|
|
74
|
+
field_check_error_message=field_check_error_message
|
|
75
|
+
)
|
|
94
76
|
|
|
95
77
|
def read_to_py_iterator(
|
|
96
|
-
self,
|
|
78
|
+
self,
|
|
79
|
+
resource: URI,
|
|
80
|
+
entity_name: EntityName,
|
|
81
|
+
schema: type[BaseModel],
|
|
82
|
+
all_model_fields: Optional[set[str]] = None,
|
|
97
83
|
) -> Iterator[dict[str, Any]]:
|
|
98
84
|
"""Creates an iterable object of rows as dictionaries"""
|
|
99
|
-
yield from self.read_to_relation(
|
|
85
|
+
yield from self.read_to_relation(
|
|
86
|
+
resource,
|
|
87
|
+
entity_name,
|
|
88
|
+
schema,
|
|
89
|
+
all_model_fields,
|
|
90
|
+
).pl().iter_rows(named=True)
|
|
100
91
|
|
|
101
92
|
@read_function(DuckDBPyRelation)
|
|
102
93
|
def read_to_relation( # pylint: disable=unused-argument
|
|
103
|
-
self,
|
|
94
|
+
self,
|
|
95
|
+
resource: URI,
|
|
96
|
+
entity_name: EntityName,
|
|
97
|
+
schema: type[BaseModel],
|
|
98
|
+
all_model_fields: Optional[set[str]] = None,
|
|
104
99
|
) -> DuckDBPyRelation:
|
|
105
100
|
"""Returns a relation object from the source csv"""
|
|
106
101
|
if get_content_length(resource) == 0:
|
|
107
102
|
raise EmptyFileError(f"File at {resource} is empty.")
|
|
108
103
|
|
|
109
104
|
if self.field_check:
|
|
110
|
-
self.perform_field_check(resource, entity_name, schema)
|
|
105
|
+
self.perform_field_check(resource, entity_name, schema, all_model_fields)
|
|
111
106
|
|
|
112
107
|
reader_options: dict[str, Any] = {
|
|
113
108
|
"header": self.header,
|
|
114
|
-
"delimiter": self.
|
|
115
|
-
"quotechar": self.
|
|
109
|
+
"delimiter": self.delimiter,
|
|
110
|
+
"quotechar": self.quote_char,
|
|
116
111
|
}
|
|
117
112
|
|
|
118
113
|
ddb_schema: dict[str, SQLType] = {
|
|
@@ -122,7 +117,14 @@ class DuckDBCSVReader(BaseFileReader):
|
|
|
122
117
|
|
|
123
118
|
reader_options["columns"] = ddb_schema
|
|
124
119
|
|
|
125
|
-
|
|
120
|
+
try:
|
|
121
|
+
rel = self.add_record_index(read_csv(resource, **reader_options, parallel=False))
|
|
122
|
+
except InvalidInputException as exc:
|
|
123
|
+
raise UnableToParseCSVError(
|
|
124
|
+
entity_name="csv_structure",
|
|
125
|
+
field_check_error_message=self.field_check_error_message,
|
|
126
|
+
field_check_error_code=self.field_check_error_code,
|
|
127
|
+
) from exc
|
|
126
128
|
|
|
127
129
|
if self.null_empty_strings:
|
|
128
130
|
cleaned_cols = ",".join(
|
|
@@ -144,19 +146,23 @@ class PolarsToDuckDBCSVReader(DuckDBCSVReader):
|
|
|
144
146
|
|
|
145
147
|
@read_function(DuckDBPyRelation)
|
|
146
148
|
def read_to_relation( # pylint: disable=unused-argument
|
|
147
|
-
self,
|
|
149
|
+
self,
|
|
150
|
+
resource: URI,
|
|
151
|
+
entity_name: EntityName,
|
|
152
|
+
schema: type[BaseModel],
|
|
153
|
+
all_model_fields: Optional[set[str]] = None,
|
|
148
154
|
) -> DuckDBPyRelation:
|
|
149
155
|
"""Returns a relation object from the source csv"""
|
|
150
156
|
if get_content_length(resource) == 0:
|
|
151
157
|
raise EmptyFileError(f"File at {resource} is empty.")
|
|
152
158
|
|
|
153
159
|
if self.field_check:
|
|
154
|
-
self.perform_field_check(resource, entity_name, schema)
|
|
160
|
+
self.perform_field_check(resource, entity_name, schema, all_model_fields)
|
|
155
161
|
|
|
156
162
|
reader_options: dict[str, Any] = {
|
|
157
163
|
"has_header": self.header,
|
|
158
|
-
"separator": self.
|
|
159
|
-
"quote_char": self.
|
|
164
|
+
"separator": self.delimiter,
|
|
165
|
+
"quote_char": self.quote_char,
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
polars_types = {
|
|
@@ -167,11 +173,18 @@ class PolarsToDuckDBCSVReader(DuckDBCSVReader):
|
|
|
167
173
|
|
|
168
174
|
# there is a raise_if_empty arg for 0.18+. Future reference when upgrading. Makes L85
|
|
169
175
|
# redundant
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
try:
|
|
177
|
+
df = self.add_record_index( # pylint: disable=W0612
|
|
178
|
+
pl.scan_csv(resource, **reader_options).select( # type: ignore
|
|
179
|
+
list(polars_types.keys())
|
|
180
|
+
)
|
|
173
181
|
)
|
|
174
|
-
|
|
182
|
+
except pl.exceptions.PolarsError as exc:
|
|
183
|
+
raise UnableToParseCSVError(
|
|
184
|
+
entity_name="csv_structure",
|
|
185
|
+
field_check_error_message=self.field_check_error_message,
|
|
186
|
+
field_check_error_code=self.field_check_error_code,
|
|
187
|
+
) from exc
|
|
175
188
|
|
|
176
189
|
if self.null_empty_strings:
|
|
177
190
|
pl_exprs = [
|
|
@@ -181,7 +194,16 @@ class PolarsToDuckDBCSVReader(DuckDBCSVReader):
|
|
|
181
194
|
] + [pl.col(RECORD_INDEX_COLUMN_NAME)]
|
|
182
195
|
df = df.select(pl_exprs)
|
|
183
196
|
|
|
184
|
-
|
|
197
|
+
entity = self._connection.sql("SELECT * FROM df")
|
|
198
|
+
|
|
199
|
+
if entity.pl().shape[0] == 0:
|
|
200
|
+
raise UnableToParseCSVError(
|
|
201
|
+
entity_name="csv_structure",
|
|
202
|
+
field_check_error_message=self.field_check_error_message,
|
|
203
|
+
field_check_error_code=self.field_check_error_code,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
return entity
|
|
185
207
|
|
|
186
208
|
|
|
187
209
|
class DuckDBCSVRepeatingHeaderReader(PolarsToDuckDBCSVReader):
|
|
@@ -222,10 +244,17 @@ class DuckDBCSVRepeatingHeaderReader(PolarsToDuckDBCSVReader):
|
|
|
222
244
|
|
|
223
245
|
@read_function(DuckDBPyRelation)
|
|
224
246
|
def read_to_relation( # pylint: disable=unused-argument
|
|
225
|
-
self,
|
|
247
|
+
self,
|
|
248
|
+
resource: URI,
|
|
249
|
+
entity_name: EntityName,
|
|
250
|
+
schema: type[BaseModel],
|
|
251
|
+
all_model_fields: Optional[set[str]] = None,
|
|
226
252
|
) -> DuckDBPyRelation:
|
|
227
253
|
entity: DuckDBPyRelation = super().read_to_relation(
|
|
228
|
-
resource=resource,
|
|
254
|
+
resource=resource,
|
|
255
|
+
entity_name=entity_name,
|
|
256
|
+
schema=schema,
|
|
257
|
+
all_model_fields=all_model_fields
|
|
229
258
|
)
|
|
230
259
|
entity = entity.select(StarExpression(exclude=[RECORD_INDEX_COLUMN_NAME])).distinct()
|
|
231
260
|
no_records = entity.shape[0]
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
from collections.abc import Iterator
|
|
5
5
|
from typing import Any, Optional
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import duckdb
|
|
8
|
+
from duckdb import DuckDBPyConnection, DuckDBPyRelation
|
|
8
9
|
from pydantic import BaseModel
|
|
9
10
|
|
|
10
11
|
from dve.core_engine.backends.base.reader import BaseFileReader, read_function
|
|
@@ -26,21 +27,31 @@ class DuckDBJSONReader(BaseFileReader):
|
|
|
26
27
|
self,
|
|
27
28
|
*,
|
|
28
29
|
json_format: Optional[str] = "array",
|
|
30
|
+
connection: Optional[DuckDBPyConnection] = None,
|
|
29
31
|
**_,
|
|
30
32
|
):
|
|
31
33
|
self._json_format = json_format
|
|
34
|
+
self._connection = duckdb.connect(":memory:") if not connection else connection
|
|
32
35
|
|
|
33
36
|
super().__init__()
|
|
34
37
|
|
|
35
38
|
def read_to_py_iterator(
|
|
36
|
-
self,
|
|
39
|
+
self,
|
|
40
|
+
resource: URI,
|
|
41
|
+
entity_name: EntityName,
|
|
42
|
+
schema: type[BaseModel],
|
|
43
|
+
all_model_fields: Optional[set[str]] = None,
|
|
37
44
|
) -> Iterator[dict[str, Any]]:
|
|
38
45
|
"""Creates an iterable object of rows as dictionaries"""
|
|
39
46
|
return self.read_to_relation(resource, entity_name, schema).pl().iter_rows(named=True)
|
|
40
47
|
|
|
41
48
|
@read_function(DuckDBPyRelation)
|
|
42
49
|
def read_to_relation( # pylint: disable=unused-argument
|
|
43
|
-
self,
|
|
50
|
+
self,
|
|
51
|
+
resource: URI,
|
|
52
|
+
entity_name: EntityName,
|
|
53
|
+
schema: type[BaseModel],
|
|
54
|
+
**_,
|
|
44
55
|
) -> DuckDBPyRelation:
|
|
45
56
|
"""Returns a relation object from the source json"""
|
|
46
57
|
|
|
@@ -50,5 +61,7 @@ class DuckDBJSONReader(BaseFileReader):
|
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
return self.add_record_index(
|
|
53
|
-
read_json(
|
|
64
|
+
self._connection.read_json(
|
|
65
|
+
resource, columns=ddb_schema, format=self._json_format # type: ignore
|
|
66
|
+
)
|
|
54
67
|
)
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
+
import duckdb
|
|
6
7
|
import polars as pl
|
|
7
|
-
from duckdb import DuckDBPyConnection, DuckDBPyRelation
|
|
8
|
+
from duckdb import DuckDBPyConnection, DuckDBPyRelation
|
|
8
9
|
from pydantic import BaseModel
|
|
9
10
|
|
|
10
11
|
from dve.core_engine.backends.base.reader import read_function
|
|
@@ -24,12 +25,18 @@ from dve.core_engine.type_hints import URI
|
|
|
24
25
|
class DuckDBXMLStreamReader(XMLStreamReader):
|
|
25
26
|
"""A reader for XML files"""
|
|
26
27
|
|
|
27
|
-
def __init__(self, *,
|
|
28
|
-
self.
|
|
28
|
+
def __init__(self, *, connection: Optional[DuckDBPyConnection] = None, **kwargs):
|
|
29
|
+
self._connection = connection if connection else duckdb.connect(":memory:")
|
|
29
30
|
super().__init__(**kwargs)
|
|
30
31
|
|
|
31
32
|
@read_function(DuckDBPyRelation)
|
|
32
|
-
def read_to_relation(
|
|
33
|
+
def read_to_relation(
|
|
34
|
+
self,
|
|
35
|
+
resource: URI,
|
|
36
|
+
entity_name: str,
|
|
37
|
+
schema: type[BaseModel],
|
|
38
|
+
**_,
|
|
39
|
+
):
|
|
33
40
|
"""Returns a relation object from the source xml"""
|
|
34
41
|
if self.xsd_location:
|
|
35
42
|
msg = self._run_xmllint(file_uri=resource)
|
|
@@ -49,4 +56,4 @@ class DuckDBXMLStreamReader(XMLStreamReader):
|
|
|
49
56
|
data=self.read_to_py_iterator(resource, entity_name, schema), schema=polars_schema
|
|
50
57
|
)
|
|
51
58
|
)
|
|
52
|
-
return self.
|
|
59
|
+
return self._connection.sql("select * from _lazy_frame")
|
|
@@ -152,7 +152,7 @@ class DuckDBStepImplementations(BaseStepImplementations[DuckDBPyRelation]):
|
|
|
152
152
|
group_pl = entity.pl().pivot(
|
|
153
153
|
columns=[config.pivot_column],
|
|
154
154
|
values=agg_cols,
|
|
155
|
-
index=(group_cols or [const_fld]),
|
|
155
|
+
index=(group_cols or [const_fld]), # pylint: disable=E0606
|
|
156
156
|
aggregate_function=config.agg_function,
|
|
157
157
|
)
|
|
158
158
|
if const_fld in group_pl.columns:
|