From 2bd762105396b11d70bd155e12f6c61824c66c9d Mon Sep 17 00:00:00 2001 From: Danny Meijer Date: Mon, 10 Jun 2024 15:38:46 +0200 Subject: [PATCH 1/6] Create codeql.yml (#47) Adding codeql as workflow --- .github/workflows/codeql.yml | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..fa9f5f1 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,93 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '36 17 * * 6' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # πŸ“š See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From 4c4d06287cc33caf318295539a44d4d9646d685f Mon Sep 17 00:00:00 2001 From: riccamini Date: Mon, 10 Jun 2024 15:56:07 +0200 Subject: [PATCH 2/6] Add missing merge clauses in DeltaTableWriter (#46) DeltaTableWriter provides the option to configure the writer in MERGE mode using the output_mode_params field by providing in it a list of merge clauses in the merge_builder key. This is especially useful in case the Delta table or the DataFrame to be merged are not available upfront. Not all merge clauses were supported: the merge clause provided was being validated against a list of valid clauses which did not include whenMatchedUpdateAll and whenNotMatchedInsertAll clauses. As part of this PR: - validation of the clauses now happens in the output_mode_params field validator (currently this is happening only when the merge is being executed) - the list of available merge clauses is sourced directly from available methods in DeltaMergeBuilder class and now includes all of them ## Related Issue https://github.com/Nike-Inc/koheesio/issues/43 ## Motivation and Context Now it's possible to use all merge clauses when configuring the DeltaTableWriter --------- Co-authored-by: riacom_nike --- .github/workflows/test.yml | 3 +- src/koheesio/spark/writers/delta/batch.py | 32 ++++++++++++------- .../spark/writers/delta/test_delta_writer.py | 25 ++++++++------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5aae361..1f72446 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,8 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - ref: ${{ github.head_ref }} + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} - name: Fetch main branch run: git fetch origin main:main - name: Check changes diff --git a/src/koheesio/spark/writers/delta/batch.py b/src/koheesio/spark/writers/delta/batch.py index dc04d7c..7334f27 100644 --- a/src/koheesio/spark/writers/delta/batch.py +++ b/src/koheesio/spark/writers/delta/batch.py @@ -233,7 +233,7 @@ def __merge_all(self) -> Union[DeltaMergeBuilder, DataFrameWriter]: return self.__merge(merge_builder=builder) - def _get_merge_builder(self, provided_merge_builder=None): + def _get_merge_builder(self, provided_merge_builder=None) -> DeltaMergeBuilder: """Resolves the merge builder. If provided, it will be used, otherwise it will be created from the args""" # A merge builder has been already created - case for merge_all @@ -274,19 +274,8 @@ def _merge_builder_from_args(self): .merge(self.df.alias(source_alias), merge_cond) ) - valid_clauses = [ - "whenMatchedUpdate", - "whenNotMatchedInsert", - "whenMatchedDelete", - "whenNotMatchedBySourceUpdate", - "whenNotMatchedBySourceDelete", - ] - for merge_clause in merge_clauses: clause_type = merge_clause.pop("clause", None) - if clause_type not in valid_clauses: - raise ValueError(f"Invalid merge clause '{clause_type}' provided") - method = getattr(builder, clause_type) builder = method(**merge_clause) @@ -314,6 +303,25 @@ def _validate_table(cls, table): return DeltaTableStep(table=table) return table + @field_validator("params") + def _validate_params(cls, params): + """Validates params. If an array of merge clauses is provided, they will be validated against the available + ones in DeltaMergeBuilder""" + + valid_clauses = {m for m in dir(DeltaMergeBuilder) if m.startswith("when")} + + if "merge_builder" in params: + merge_builder = params["merge_builder"] + if isinstance(merge_builder, list): + for merge_conf in merge_builder: + clause = merge_conf.get("clause") + if clause not in valid_clauses: + raise ValueError(f"Invalid merge clause '{clause}' provided") + elif not isinstance(merge_builder, DeltaMergeBuilder): + raise ValueError("merge_builder must be a list or merge clauses or a DeltaMergeBuilder instance") + + return params + @classmethod def get_output_mode(cls, choice: str, options: Set[Type]) -> Union[BatchOutputMode, StreamingOutputMode]: """Retrieve an OutputMode by validating `choice` against a set of option OutputModes. diff --git a/tests/spark/writers/delta/test_delta_writer.py b/tests/spark/writers/delta/test_delta_writer.py index 4a36069..66306de 100644 --- a/tests/spark/writers/delta/test_delta_writer.py +++ b/tests/spark/writers/delta/test_delta_writer.py @@ -308,24 +308,25 @@ def test_merge_from_args(spark, dummy_df): ) -def test_merge_from_args_raise_value_error(spark, dummy_df): - table_name = "test_table_merge_from_args_value_error" - dummy_df.write.format("delta").saveAsTable(table_name) - - writer = DeltaTableWriter( - df=dummy_df, - table=table_name, - output_mode=BatchOutputMode.MERGE, - output_mode_params={ +@pytest.mark.parametrize( + "output_mode_params", + [ + { "merge_builder": [ {"clause": "NOT-SUPPORTED-MERGE-CLAUSE", "set": {"id": "source.id"}, "condition": "source.id=target.id"} ], "merge_cond": "source.id=target.id", }, - ) - + {"merge_builder": MagicMock()}, + ], +) +def test_merge_from_args_raise_value_error(spark, output_mode_params): with pytest.raises(ValueError): - writer._merge_builder_from_args() + DeltaTableWriter( + table="test_table_merge", + output_mode=BatchOutputMode.MERGE, + output_mode_params=output_mode_params, + ) def test_merge_no_table(spark): From 2f040f061f983444c5e37a3b1bd6967f3af711b7 Mon Sep 17 00:00:00 2001 From: Brend Braeckmans <72923643+BrendBraeckmans@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:20:22 +0200 Subject: [PATCH 3/6] Make it possible to set explicit schema i.s.o letting AutoLoader infer the schema (#40) Make it possible to set explicit schema i.s.o letting AutoLoader infer the schema. Optional `schema` argument has been added ## Related Issue [koheesio-39](https://github.com/Nike-Inc/koheesio/issues/39) ## Motivation and Context The previous implementation of AutoLoader within koheesio would always infer the schema from the files it reads. In a lot of cases this was unnecessary and might even give issues if the input data doesn't contain the required fields. ## How Has This Been Tested? - Through UTs - On DBX --- .../spark/readers/databricks/autoloader.py | 23 ++++++-- tests/spark/readers/test_auto_loader.py | 55 ++++++++++++++++++- 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/koheesio/spark/readers/databricks/autoloader.py b/src/koheesio/spark/readers/databricks/autoloader.py index 6b26e20..8444a54 100644 --- a/src/koheesio/spark/readers/databricks/autoloader.py +++ b/src/koheesio/spark/readers/databricks/autoloader.py @@ -3,9 +3,12 @@ Autoloader can ingest JSON, CSV, PARQUET, AVRO, ORC, TEXT, and BINARYFILE file formats. """ -from typing import Dict, Optional, Union +from typing import Any, Dict, List, Optional, Tuple, Union from enum import Enum +from pyspark.sql.streaming import DataStreamReader +from pyspark.sql.types import AtomicType, StructType + from koheesio.models import Field, field_validator from koheesio.spark.readers import Reader @@ -53,7 +56,7 @@ class AutoLoader(Reader): Example ------- ```python - from koheesio.spark.readers.databricks import AutoLoader, AutoLoaderFormat + from koheesio.steps.readers.databricks import AutoLoader, AutoLoaderFormat result_df = AutoLoader( format=AutoLoaderFormat.JSON, @@ -82,11 +85,16 @@ class AutoLoader(Reader): description="The location for storing inferred schema and supporting schema evolution, " "used in `cloudFiles.schemaLocation`.", ) - options: Optional[Dict[str, str]] = Field( + options: Optional[Dict[str, Any]] = Field( default_factory=dict, description="Extra inputs to provide to the autoloader. For a full list of inputs, " "see https://docs.databricks.com/ingestion/auto-loader/options.html", ) + schema_: Optional[Union[str, StructType, List[str], Tuple[str, ...], AtomicType]] = Field( + default=None, + description="Explicit schema to apply to the input files.", + alias="schema", + ) @field_validator("format") def validate_format(cls, format_specified): @@ -107,9 +115,12 @@ def get_options(self): return self.options # @property - def reader(self): - """Return the reader for the autoloader""" - return self.spark.readStream.format("cloudFiles").options(**self.get_options()) + def reader(self) -> DataStreamReader: + reader = self.spark.readStream.format("cloudFiles") + if self.schema_ is not None: + reader = reader.schema(self.schema_) + reader = reader.options(**self.get_options()) + return reader def execute(self): """Reads from the given location with the given options using Autoloader""" diff --git a/tests/spark/readers/test_auto_loader.py b/tests/spark/readers/test_auto_loader.py index ca07f55..8f2b168 100644 --- a/tests/spark/readers/test_auto_loader.py +++ b/tests/spark/readers/test_auto_loader.py @@ -21,10 +21,13 @@ def test_invalid_format(bad_format): def mock_reader(self): - return self.spark.read.format("json").options(**self.options) + reader = self.spark.read.format("json") + if self.schema_ is not None: + reader = reader.schema(self.schema_) + return reader.options(**self.options) -def test_read_json(spark, mocker, data_path): +def test_read_json_infer_schema(spark, mocker, data_path): mocker.patch("koheesio.spark.readers.databricks.autoloader.AutoLoader.reader", mock_reader) options = {"multiLine": "true"} @@ -49,3 +52,51 @@ def test_read_json(spark, mocker, data_path): ] expected_df = spark.createDataFrame(data_expected, schema_expected) assert_df_equality(result, expected_df, ignore_column_order=True) + + +def test_read_json_exact_explicit_schema_struct(spark, mocker, data_path): + mocker.patch("koheesio.spark.readers.databricks.autoloader.AutoLoader.reader", mock_reader) + + schema = StructType( + [ + StructField("string", StringType(), True), + StructField("int", LongType(), True), + StructField("array", ArrayType(LongType()), True), + ] + ) + options = {"multiLine": "true"} + json_file_path_str = f"{data_path}/readers/json_file/dummy.json" + auto_loader = AutoLoader( + format="json", location=json_file_path_str, schema_location="dummy_value", options=options, schema=schema + ) + + auto_loader.execute() + result = auto_loader.output.df + + data_expected = [ + {"string": "string1", "int": 1, "array": [1, 11, 111]}, + {"string": "string2", "int": 2, "array": [2, 22, 222]}, + ] + expected_df = spark.createDataFrame(data_expected, schema) + assert_df_equality(result, expected_df, ignore_column_order=True) + + +def test_read_json_different_explicit_schema_string(spark, mocker, data_path): + mocker.patch("koheesio.spark.readers.databricks.autoloader.AutoLoader.reader", mock_reader) + + schema = "string STRING,array ARRAY" + options = {"multiLine": "true"} + json_file_path_str = f"{data_path}/readers/json_file/dummy.json" + auto_loader = AutoLoader( + format="json", location=json_file_path_str, schema_location="dummy_value", options=options, schema=schema + ) + + auto_loader.execute() + result = auto_loader.output.df + + data_expected = [ + {"string": "string1", "array": [1, 11, 111]}, + {"string": "string2", "array": [2, 22, 222]}, + ] + expected_df = spark.createDataFrame(data_expected, schema) + assert_df_equality(result, expected_df, ignore_column_order=True) From 2d1449e13f1148294e275e1970d9fdaaf2ee39a3 Mon Sep 17 00:00:00 2001 From: Brend Braeckmans <72923643+BrendBraeckmans@users.noreply.github.com> Date: Mon, 17 Jun 2024 08:52:52 +0200 Subject: [PATCH 4/6] Add streaming option to FileLoader. (#51) ## Description Add streaming option to FileLoader. Default behaviour is batch. ## Related Issue [Issue 50 ](https://github.com/Nike-Inc/koheesio/issues/50) ## Motivation and Context Having a `streaming` option for the `FileLoader` would be beneficial during UT's or for people that are not on Databricks and can't make use of the Databricks proprietary `Autoloader`. ## How Has This Been Tested? - UT's - On Databricks ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) ## Checklist: - [x] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [x] I have read the **CONTRIBUTING** document. - [x] I have added tests to cover my changes. - [ ] All new and existing tests passed. --- src/koheesio/spark/readers/file_loader.py | 6 ++++-- tests/spark/readers/test_file_loader.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/koheesio/spark/readers/file_loader.py b/src/koheesio/spark/readers/file_loader.py index a497a0a..9d33806 100644 --- a/src/koheesio/spark/readers/file_loader.py +++ b/src/koheesio/spark/readers/file_loader.py @@ -97,6 +97,7 @@ class FileLoader(Reader, ExtraParamsMixin): schema_: Optional[Union[StructType, str]] = Field( default=None, description="Schema to use when reading the file", validate_default=False, alias="schema" ) + streaming: Optional[bool] = Field(default=False, description="Whether to read the files as a Stream or not") @field_validator("path") def ensure_path_is_str(cls, v): @@ -106,8 +107,9 @@ def ensure_path_is_str(cls, v): return v def execute(self): - """Reads the file using the specified format, schema, while applying any extra parameters.""" - reader = self.spark.read.format(self.format) + """Reads the file, in batch or as a stream, using the specified format and schema, while applying any extra parameters.""" + reader = self.spark.readStream if self.streaming else self.spark.read + reader = reader.format(self.format) if self.schema_: reader.schema(self.schema_) diff --git a/tests/spark/readers/test_file_loader.py b/tests/spark/readers/test_file_loader.py index d6c3d13..9605e56 100644 --- a/tests/spark/readers/test_file_loader.py +++ b/tests/spark/readers/test_file_loader.py @@ -1,5 +1,7 @@ import pytest +import pyspark.sql.types as T + from koheesio.spark import AnalysisException from koheesio.spark.readers.file_loader import ( AvroReader, @@ -106,6 +108,15 @@ def test_json_reader(json_file): assert actual_data == expected_data +def test_json_stream_reader(json_file): + schema = "string STRING, int INT, float FLOAT" + reader = JsonReader(path=json_file, schema=schema, streaming=True) + assert reader.path == json_file + df = reader.read() + assert df.isStreaming + assert df.schema == T._parse_datatype_string(schema) + + def test_parquet_reader(parquet_file): expected_data = [ {"id": 0}, From 4b2e01580d8ffc81e180e3ff8e2879bc491b4382 Mon Sep 17 00:00:00 2001 From: Danny Meijer Date: Fri, 21 Jun 2024 21:15:41 +0200 Subject: [PATCH 5/6] [DOC] documentation updates June 2024 (#48) Documentation updates ## Description - Fixed spelling of and type annotations for Parameters across docstrings - Fixed broken links and unrecognized relative links - Fixed indentation for continuation lines in docstrings - Refactored README for legibility and clarity with a more defined structure and better formatting - General style and formatting improvements - Minor change to the layout of the pages (to better accommodate the reader) - No code changes were made as part of this PR ## Testing To build the docs: - check out the branch - run `make docs` - docsite will be hosted on your local machine ## Related Issue #38 #42 --------- Co-authored-by: Danny Meijer <10511979+dannymeijer@users.noreply.github.com> --- CONTRIBUTING.md | 25 +-- Makefile | 2 +- README.md | 210 +++++++++++++----- docs/assets/documentation-system-overview.png | Bin 0 -> 209013 bytes docs/community/approach-documentation.md | 7 +- docs/community/contribute.md | 11 +- docs/css/custom.css | 26 +-- docs/reference/concepts/concepts.md | 33 ++- docs/reference/concepts/context.md | 4 +- .../concepts/{logging.md => logger.md} | 0 docs/reference/concepts/{steps.md => step.md} | 0 docs/reference/concepts/tasks.md | 8 - docs/reference/{concepts => spark}/readers.md | 2 +- .../{concepts => spark}/transformations.md | 4 +- docs/reference/{concepts => spark}/writers.md | 0 docs/tutorials/getting-started.md | 112 +++++++--- docs/tutorials/how-to.md | 8 - docs/tutorials/learn-koheesio.md | 90 ++++++-- docs/tutorials/onboarding.md | 4 - mkdocs.yml | 43 ++-- pyproject.toml | 3 +- src/koheesio/integrations/spark/sftp.py | 44 ++-- src/koheesio/logger.py | 2 +- src/koheesio/models/__init__.py | 12 +- src/koheesio/models/sql.py | 6 +- src/koheesio/spark/readers/__init__.py | 2 +- src/koheesio/spark/readers/delta.py | 2 +- src/koheesio/spark/readers/hana.py | 2 +- src/koheesio/spark/readers/snowflake.py | 4 +- src/koheesio/spark/readers/teradata.py | 2 +- src/koheesio/spark/snowflake.py | 7 +- .../spark/transformations/__init__.py | 58 +++-- src/koheesio/spark/transformations/arrays.py | 4 +- .../spark/transformations/cast_to_datatype.py | 32 +-- .../transformations/date_time/__init__.py | 12 +- .../transformations/date_time/interval.py | 11 +- .../spark/transformations/strings/__init__.py | 16 +- .../transformations/strings/change_case.py | 8 +- .../spark/transformations/strings/regexp.py | 10 +- .../spark/transformations/strings/trim.py | 6 +- src/koheesio/spark/writers/buffer.py | 21 +- .../dq/test_spark_expectations.py | 6 + 42 files changed, 509 insertions(+), 350 deletions(-) create mode 100644 docs/assets/documentation-system-overview.png rename docs/reference/concepts/{logging.md => logger.md} (100%) rename docs/reference/concepts/{steps.md => step.md} (100%) delete mode 100644 docs/reference/concepts/tasks.md rename docs/reference/{concepts => spark}/readers.md (97%) rename docs/reference/{concepts => spark}/transformations.md (99%) rename docs/reference/{concepts => spark}/writers.md (100%) delete mode 100644 docs/tutorials/how-to.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7cbfedb..0145c92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,26 +2,18 @@ There are a few guidelines that we need contributors to follow so that we are able to process requests as efficiently as possible. - -[//]: # (If you have any questions or concerns please feel free to contact us at [opensource@nike.com](mailto:opensource@nike.com).) +If you have any questions or concerns please feel free to contact us at [opensource@nike.com](mailto:opensource@nike.com). -[//]: # () -[//]: # (## Getting Started) -[//]: # () -[//]: # (* Review our [Code of Conduct](https://github.com/Nike-Inc/nike-inc.github.io/blob/master/CONDUCT.md)) +## Getting Started -[//]: # (* Submit the [Individual Contributor License Agreement](https://www.clahub.com/agreements/Nike-Inc/fastbreak)) -[//]: # (* Make sure you have a [GitHub account](https://github.com/signup/free)) - -[//]: # (* Submit a ticket for your issue, assuming one does not already exist.) - -[//]: # ( * Clearly describe the issue including steps to reproduce when it is a bug.) - -[//]: # ( * Make sure you fill in the earliest version that you know has the issue.) - -[//]: # (* Fork the repository on GitHub) +* Review our [Code of Conduct](https://github.com/Nike-Inc/nike-inc.github.io/blob/master/CONDUCT.md) +* Make sure you have a [GitHub account](https://github.com/signup/free) +* Submit a ticket for your issue, assuming one does not already exist. + * Clearly describe the issue including steps to reproduce when it is a bug. + * Make sure you fill in the earliest version that you know has the issue. +* Fork the repository on GitHub ## Making Changes @@ -98,6 +90,5 @@ At the moment, the release process is manual. We try to make frequent releases. * [GitHub pull request documentation](https://help.github.com/send-pull-requests/) * [Nike's Code of Conduct](https://github.com/Nike-Inc/nike-inc.github.io/blob/master/CONDUCT.md) -[//]: # (* [Nike's Individual Contributor License Agreement](https://www.clahub.com/agreements/Nike-Inc/fastbreak)) [//]: # (* [Nike OSS](https://nike-inc.github.io/)) \ No newline at end of file diff --git a/Makefile b/Makefile index 163a4fd..54da8d0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: help ## Display this message help: - @python koheesio/__about__.py + @python src/koheesio/__about__.py @echo "\nAvailable \033[34m'make'\033[0m commands:" @echo "\n\033[1mSetup:\033[0m" @grep -E '^.PHONY: .*?## setup - .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ".PHONY: |## (setup|hatch) - "}; {printf " \033[36m%-22s\033[0m %s\n", $$2, $$3}' diff --git a/README.md b/README.md index 23454f8..41e7f0a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # Koheesio -
- +

Koheesio logo -

+

| | | |---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -11,10 +10,16 @@ | Package | [![PyPI - Version](https://img.shields.io/pypi/v/koheesio.svg?logo=pypi&label=PyPI&logoColor=gold)](https://pypi.org/project/koheesio/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/koheesio.svg?logo=python&label=Python&logoColor=gold)](https://pypi.org/project/koheesio/) [![PyPI - Downloads](https://img.shields.io/pypi/dm/koheesio?color=blue&label=Installs&logo=pypi&logoColor=gold)](https://pypi.org/project/koheesio/) | | Meta | [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch) [![linting - Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) [![types - Mypy](https://img.shields.io/badge/types-Mypy-blue.svg)](https://github.com/python/mypy) [![docstring - numpydoc](https://img.shields.io/badge/docstring-numpydoc-blue)](https://numpydoc.readthedocs.io/en/latest/format.html) [![code style - black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![License - Apache 2.0](https://img.shields.io/github/license/Nike-Inc/koheesio)](LICENSE.txt) | -Koheesio, named after the Finnish word for cohesion, is a robust Python framework for building efficient data pipelines. -It promotes modularity and collaboration, enabling the creation of complex pipelines from simple, reusable components. +[//]: # (suggested edit: ) +# Koheesio: A Python Framework for Efficient Data Pipelines + +Koheesio - the Finnish word for cohesion - is a robust Python framework designed to build efficient data pipelines. It +encourages modularity and collaboration, allowing the creation of complex pipelines from simple, reusable components. + -The framework is versatile, aiming to support multiple implementations and working seamlessly with various data +## What is Koheesio? + +Koheesio is a versatile framework that supports multiple implementations and works seamlessly with various data processing libraries or frameworks. This ensures that Koheesio can handle any data processing task, regardless of the underlying technology or data scale. @@ -23,50 +28,127 @@ safety and structured configurations within pipeline components. [Pydantic]: docs/includes/glossary.md#pydantic -Koheesio's goal is to ensure predictable pipeline execution through a solid foundation of well-tested code and a rich -set of features, making it an excellent choice for developers and organizations seeking to build robust and adaptable -Data Pipelines. +The goal of Koheesio is to ensure predictable pipeline execution through a solid foundation of well-tested code and a +rich set of features. This makes it an excellent choice for developers and organizations seeking to build robust and +adaptable data pipelines. -## What sets Koheesio apart from other libraries?" -Koheesio encapsulates years of data engineering expertise, fostering a collaborative and innovative community. While -similar libraries exist, Koheesio's focus on data pipelines, integration with PySpark, and specific design for tasks -like data transformation, ETL jobs, data validation, and large-scale data processing sets it apart. - -Koheesio aims to provide a rich set of features including readers, writers, and transformations for any type of Data -processing. Koheesio is not in competition with other libraries. Its aim is to offer wide-ranging support and focus -on utility in a multitude of scenarios. Our preference is for integration, not competition... +### What Koheesio is Not + +Koheesio is **not** a workflow orchestration tool. It does not serve the same purpose as tools like Luigi, +Apache Airflow, or Databricks workflows, which are designed to manage complex computational workflows and generate +DAGs (Directed Acyclic Graphs). + +Instead, Koheesio is focused on providing a robust, modular, and testable framework for data tasks. It's designed to +make it easier to write, maintain, and test data processing code in Python, with a strong emphasis on modularity, +reusability, and error handling. + +If you're looking for a tool to orchestrate complex workflows or manage dependencies between different tasks, you might +want to consider dedicated workflow orchestration tools. + + +### The Strength of Koheesio + +The core strength of Koheesio lies in its **focus on the individual tasks within those workflows**. It's all about +making these tasks as robust, repeatable, and maintainable as possible. Koheesio aims to break down tasks into small, +manageable units of work that can be easily tested, reused, and composed into larger workflows orchestrated with other +tools or frameworks (such as Apache Airflow, Luigi, or Databricks Workflows). + +By using Koheesio, you can ensure that your data tasks are resilient, observable, and repeatable, adhering to good +software engineering practices. This makes your data pipelines more reliable and easier to maintain, ultimately leading +to more efficient and effective data processing. + + +### Promoting Collaboration and Innovation + +Koheesio encapsulates years of software and data engineering expertise. It fosters a collaborative and innovative +community, setting itself apart with its unique design and focus on data pipelines, data transformation, ETL jobs, +data validation, and large-scale data processing. + +The core components of Koheesio are designed to bring strong software engineering principles to data engineering. + +'Steps' break down tasks and workflows into manageable, reusable, and testable units. Each 'Step' comes with built-in +logging, providing transparency and traceability. The 'Context' component allows for flexible customization of task +behavior, making it adaptable to various data processing needs. + +In essence, Koheesio is a comprehensive solution for data engineering challenges, designed with the principles of +modularity, reusability, testability, and transparency at its core. It aims to provide a rich set of features including +utilities, readers, writers, and transformations for any type of data processing. It is not in competition with other +libraries, but rather aims to offer wide-ranging support and focus on utility in a multitude of scenarios. Our +preference is for integration, not competition. We invite contributions from all, promoting collaboration and innovation in the data engineering community. + +### Comparison to other libraries + +#### ML frameworks + +The libraries listed under this section are primarily focused on Machine Learning (ML) workflows. They provide various +functionalities, from orchestrating ML and data processing workflows, simplifying the deployment of ML workflows on +Kubernetes, to managing the end-to-end ML lifecycle. While these libraries have a strong emphasis on ML, Koheesio is a +more general data pipeline framework. It is designed to handle a variety of data processing tasks, not exclusively +focused on ML. This makes Koheesio a versatile choice for data pipeline construction, regardless of whether the +pipeline involves ML tasks or not. + +- [Flyte](https://flyte.org/): A cloud-native platform for orchestrating ML and data processing workflows. Unlike Koheesio, it requires Kubernetes for deployment and has a strong focus on workflow orchestration. +- [Kubeflow](https://kubeflow.org/): A project dedicated to simplifying the deployment of ML workflows on Kubernetes. Unlike Koheesio, it is more specialized for ML workflows. +- [Kedro](https://kedro.readthedocs.io/): A Python framework that applies software engineering best-practice to data and machine-learning pipelines. It is similar to Koheesio but has a stronger emphasis on machine learning pipelines. +- [Metaflow](https://docs.metaflow.org/): A human-centric framework for data science that addresses the entire data science lifecycle. It is more focused on data science projects compared to Koheesio. +- [MLflow](https://mlflow.org/docs/latest/index.html): An open source platform for managing the end-to-end machine learning lifecycle. It is more focused on machine learning projects compared to Koheesio. +- [TFX](https://www.tensorflow.org/tfx/guide): An end-to-end platform for deploying production ML pipelines. It is more focused on TensorFlow-based machine learning pipelines compared to Koheesio. +- [Seldon Core](https://docs.seldon.io/projects/seldon-core/en/latest/): An open source platform for deploying machine learning models on Kubernetes. Unlike Koheesio, it is more focused on model deployment. + + +#### Orchestration tools + +The libraries listed under this section are primarily focused on workflow orchestration. They provide various +functionalities, from authoring, scheduling, and monitoring workflows, to building complex pipelines of batch jobs, and +creating and executing Directed Acyclic Graphs (DAGs). Some of these libraries are designed for modern infrastructure +and powered by open-source workflow engines, while others use a Python-style language for defining workflows. While +these libraries have a strong emphasis on workflow orchestration, Koheesio is a more general data pipeline framework. It +is designed to handle a variety of data processing tasks, not limited to workflow orchestration.Ccode written with +Koheesio is often compatible with these orchestration engines. This makes Koheesio a versatile choice for data pipeline +construction, regardless of how the pipeline orchestration is set up. + +- [Apache Airflow](https://airflow.apache.org/docs/): A platform to programmatically author, schedule and monitor workflows. Unlike Koheesio, it focuses on managing complex computational workflows. +- [Luigi](https://luigi.readthedocs.io/): A Python module that helps you build complex pipelines of batch jobs. It is more focused on workflow orchestration compared to Koheesio. +- [Databricks Workflows](https://www.databricks.com/product/workflows): A set of tools for building, debugging, deploying, and running Apache Spark workflows on Databricks. +- [Prefect](https://docs.prefect.io/): A new workflow management system, designed for modern infrastructure and powered by the open-source Prefect Core workflow engine. It is more focused on workflow orchestration and management compared to Koheesio. +- [Snakemake](https://snakemake.readthedocs.io/en/stable/): A workflow management system that uses a Python-style language for defining workflows. While it's powerful for creating complex workflows, Koheesio's focus on modularity and reusability might make it easier to build, test, and maintain your data pipelines. +- [Dagster](https://docs.dagster.io/): A data orchestrator for machine learning, analytics, and ETL. It's more focused on orchestrating and visualizing data workflows compared to Koheesio. +- [Ploomber](https://ploomber.readthedocs.io/): A Python library for building robust data pipelines. In some ways it is similar to Koheesio, but has a very different API design more focused on workflow orchestration. +- [Pachyderm](https://docs.pachyderm.com/): A data versioning, data lineage, and workflow system running on Kubernetes. It is more focused on data versioning and lineage compared to Koheesio. +- [Argo](https://argoproj.github.io/): An open source container-native workflow engine for orchestrating parallel jobs on Kubernetes. Unlike Koheesio, it requires Kubernetes for deployment. + + +#### Others + The libraries listed under this section offer a variety of unique functionalities, from parallel and distributed + computing, to SQL-first transformation workflows, to data versioning and lineage, to data relation definition and + manipulation, and data warehouse management. Some of these libraries are designed for specific tasks such as + transforming data in warehouses using SQL, building concurrent, multi-stage data ingestion and processing pipelines, + or orchestrating parallel jobs on Kubernetes. + +- [Dask](https://dask.org/): A flexible parallel computing library for analytics. Unlike Koheesio, it is more focused on parallel computing and distributed computing. While not currently support, Dask could be a future implementation pattern for Koheesio, just like Pandas and PySpark at the moment. +- [dbt](https://www.getdbt.com/): A SQL-first transformation workflow that also supports Python. It excels in transforming data in warehouses using SQL. In contrast, Koheesio is a more general data pipeline framework with strong typing, capable of handling a variety of data processing tasks beyond transformations. +- [Broadway](https://elixir-broadway.org/): An Elixir library for building concurrent, multi-stage data ingestion and processing pipelines. If your team is more comfortable with Python or if you're looking for a framework that emphasizes modularity and collaboration, Koheesio could be a better fit. +- [Ray](https://docs.ray.io/en/latest/): A general-purpose distributed computing framework. Unlike Koheesio, it is more focused on distributed computing. +- [DataJoint](https://docs.datajoint.io/): A language for defining data relations and manipulating data. Unlike Koheesio, it is more focused on data relation definition and manipulation. + + ## Koheesio Core Components -Here are the key components included in Koheesio: +Here are the 3 core components included in Koheesio: - __Step__: This is the fundamental unit of work in Koheesio. It represents a single operation in a data pipeline, taking in inputs and producing outputs. - - ```text - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Input 1 │───────▢│ β”œβ”€β”€β”€β”€β”€β”€β”€β–Άβ”‚ Output 1 β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€βˆšβ”€β”€β”€β”€β”€β”˜ - β”‚ β”‚ - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Input 2 │───────▢│ Step │───────▢│ Output 2 β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ β”‚ - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Input 3 │───────▢│ β”œβ”€β”€β”€β”€β”€β”€β”€β–Άβ”‚ Output 3 β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ``` - - __Context__: This is a configuration class used to set up the environment for a Task. It can be used to share variables across tasks and adapt the behavior of a Task based on its environment. - __Logger__: This is a class for logging messages at different levels. ## Installation -You can install Koheesio using either pip or poetry. +You can install Koheesio using either pip, hatch, or poetry. ### Using Pip @@ -81,7 +163,7 @@ pip install koheesio If you're using Hatch for package management, you can add Koheesio to your project by simply adding koheesio to your `pyproject.toml`. - ```toml + ```toml title="pyproject.toml" [dependencies] koheesio = "" ``` @@ -94,34 +176,49 @@ If you're using poetry for package management, you can add Koheesio to your proj poetry add koheesio ``` -or add the following line to your `pyproject.toml` (under `[tool.poetry.dependencies]`), making sure to replace `...` with the version you want to have installed: +or add the following line to your `pyproject.toml` (under `[tool.poetry.dependencies]`), making sure to replace +`...` with the version you want to have installed: -```toml +```toml title="pyproject.toml" koheesio = {version = "..."} ``` -### Features +## Extras + +Koheesio also provides some additional features that can be useful in certain scenarios. We call these 'integrations'. +With an integration we mean a module that requires additional dependencies to be installed. -Koheesio also provides some additional features that can be useful in certain scenarios. These include: +Extras can be added by adding `extras=['name_of_the_extra']` (poetry) or `koheesio[name_of_the_extra]` (pip/hatch) to +the `pyproject.toml` entry mentioned above or installing through pip. -- __Spark Expectations__: Available through the `koheesio.steps.integration.spark.dq.spark_expectations` module; - - Installable through the `se` extra. - - SE Provides Data Quality checks for Spark DataFrames. For more information, refer to the [Spark Expectations docs](https://engineering.nike.com/spark-expectations). +### Integrations + +- __Spark Expectations:__ + Available through the `koheesio.steps.integration.spark.dq.spark_expectations` module; installable through the `se` extra. + - SE Provides Data Quality checks for Spark DataFrames. + - For more information, refer to the [Spark Expectations docs](https://engineering.nike.com/spark-expectations). [//]: # (- **Brickflow:** Available through the `koheesio.steps.integration.workflow` module; installable through the `bf` extra.) [//]: # ( - Brickflow is a workflow orchestration tool that allows you to define and execute workflows in a declarative way.) [//]: # ( - For more information, refer to the [Brickflow docs](https://engineering.nike.com/brickflow)) -- __Box__: Available through the `koheesio.steps.integration.box` module - - Installable through the `box` extra. - - Box is a cloud content management and file sharing service for businesses. +- __Box__: + Available through the `koheesio.integration.box` module; installable through the `box` extra. + - [Box](https://www.box.com) is a cloud content management and file sharing service for businesses. + +- __SFTP__: + Available through the `koheesio.integration.spark.sftp` module; installable through the `sftp` extra. + - SFTP is a network protocol used for secure file transfer over a secure shell. + - The SFTP integration of Koheesio relies on [paramiko](https://www.paramiko.org/) -- __SFTP__: Available through the `koheesio.steps.integration.spark.sftp` module; - - Installable through the `sftp` extra. - - SFTP is a network protocol used for secure file transfer over a secure shell. +[//]: # (TODO: add implementations) +[//]: # (## Implementations) +[//]: # (TODO: add async extra) +[//]: # (TODO: add spark extra) +[//]: # (TODO: add pandas extra) > __Note:__ -> Some of the steps require extra dependencies. See the [Features](#features) section for additional info. +> Some of the steps require extra dependencies. See the [Extras](#extras) section for additional info. > Extras can be done by adding `features=['name_of_the_extra']` to the toml entry mentioned above ## Contributing @@ -130,18 +227,21 @@ Koheesio also provides some additional features that can be useful in certain sc We welcome contributions to our project! Here's a brief overview of our development process: -- __Code Standards__: We use `pylint`, `black`, and `mypy` to maintain code standards. Please ensure your code passes these checks by running `make check`. No errors or warnings should be reported by the linter before you submit a pull request. +- __Code Standards__: We use `pylint`, `black`, and `mypy` to maintain code standards. Please ensure your code passes + these checks by running `make check`. No errors or warnings should be reported by the linter before you submit a pull + request. -- __Testing__: We use `pytest` for testing. Run the tests with `make test` and ensure all tests pass before submitting a pull request. +- __Testing__: We use `pytest` for testing. Run the tests with `make test` and ensure all tests pass before submitting + a pull request. - __Release Process__: We aim for frequent releases. Typically when we have a new feature or bugfix, a developer with admin rights will create a new release on GitHub and publish the new version to PyPI. -For more detailed information, please refer to our [contribution guidelines](./docs/contribute.md). We also adhere to -[Nike's Code of Conduct](https://github.com/Nike-Inc/nike-inc.github.io/blob/master/CONDUCT.md) and [Nike's Individual Contributor License Agreement](https://www.clahub.com/agreements/Nike-Inc/fastbreak). +For more detailed information, please refer to our [contribution guidelines](https://github.com/Nike-Inc/koheesio/blob/main/CONTRIBUTING.md). +We also adhere to [Nike's Code of Conduct](https://github.com/Nike-Inc/nike-inc.github.io/blob/master/CONDUCT.md). ### Additional Resources -- [General GitHub documentation](https://help.github.com/) -- [GitHub pull request documentation](https://help.github.com/send-pull-requests/) +- [General GitHub documentation](https://support.github.com/) +- [GitHub pull request documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) - [Nike OSS](https://nike-inc.github.io/) diff --git a/docs/assets/documentation-system-overview.png b/docs/assets/documentation-system-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..88e60165fde2abe5c42bd9cbf2278c79afc136c7 GIT binary patch literal 209013 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 ATL1t6 literal 0 HcmV?d00001 diff --git a/docs/community/approach-documentation.md b/docs/community/approach-documentation.md index 7e75a84..d53456e 100644 --- a/docs/community/approach-documentation.md +++ b/docs/community/approach-documentation.md @@ -1,8 +1,3 @@ ---- -tags: - - doctype/explanation ---- - ## Scope @@ -21,7 +16,7 @@ From [documentation.divio.com](https://documentation.divio.com): > They are: _tutorials, how-to guides, technical reference and explanation_. They represent four different purposes or functions, and require four different approaches to their creation. Understanding the implications of this will help improve most documentation - often immensely. > > **About the system** -> ![Documentation System Overview](assets/../../assets/documentation-system-overview.png) +> ![Documentation System Overview](../assets/documentation-system-overview.png) > The documentation system outlined here is a simple, comprehensive and nearly universally-applicable scheme. It is proven in practice across a wide variety of fields and applications. > > There are some very simple principles that govern documentation that are very rarely if ever spelled out. They seem to be a secret, though they shouldn’t be. diff --git a/docs/community/contribute.md b/docs/community/contribute.md index 03cec5b..c7805b6 100644 --- a/docs/community/contribute.md +++ b/docs/community/contribute.md @@ -17,15 +17,15 @@ There are a few guidelines that we need contributors to follow so that we are ab * Create a feature branch off of `main` before you start your work. * Please avoid working directly on the `main` branch. -* Setup the required package manager [hatch](#-package-manager) -* Setup the dev environment [see below](#-dev-environment-setup) +* Setup the required package manager [hatch](#package-manager) +* Setup the dev environment [see below](#dev-environment-setup) * Make commits of logical units. * You may be asked to squash unnecessary commits down to logical units. * Check for unnecessary whitespace with `git diff --check` before committing. * Write meaningful, descriptive commit messages. * Please follow existing code conventions when working on a file -* Make sure to check the standards on the code, [see below](#-linting-and-standards) -* Make sure to test the code before you push changes [see below](#-testing) +* Make sure to check the standards on the code, [see below](#linting-and-standards) +* Make sure to test the code before you push changes [see below](#testing) ## 🀝 Submitting Changes @@ -66,7 +66,7 @@ make hatch-install This will install hatch using brew if you are on a Mac. -If you are on a different OS, you can follow the instructions [here]( https://hatch.pypa.io/latest/install/) +If you are on a different OS, you can follow the instructions [here](https://hatch.pypa.io/latest/install/) ### πŸ“Œ Dev Environment Setup @@ -119,5 +119,4 @@ Make sure that all tests pass and that you have adequate coverage before submitt * [General GitHub documentation](https://help.github.com/) * [GitHub pull request documentation](https://help.github.com/send-pull-requests/) * [Nike's Code of Conduct](https://github.com/Nike-Inc/nike-inc.github.io/blob/master/CONDUCT.md) -* [Nike's Individual Contributor License Agreement](https://www.clahub.com/agreements/Nike-Inc/fastbreak) * [Nike OSS](https://nike-inc.github.io/) \ No newline at end of file diff --git a/docs/css/custom.css b/docs/css/custom.css index 684d330..b11661a 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -35,31 +35,7 @@ border-left: .05rem solid var(--md-typeset-table-color); } -/* Mark external links as such. */ -.md-content a.autorefs-external::after, -.md-content a[href^="http"]:after { - /* https://primer.style/octicons/arrow-up-right-24 */ - background-image: url('data:image/svg+xml,'); - content: ' '; - - display: inline-block; - position: relative; - top: 0.1em; - margin-left: 0.2em; - margin-right: 0.1em; - - height: 0.6em; - width: 0.6em; - border-radius: 100%; - background-color: var(--md-typeset-a-color); -} - -.md-content a.autorefs-external:hover::after, -.md-content a[href^="http"]:hover::after { - background-color: var(--md-accent-fg-color); - background-image: url('data:image/svg+xml,'); -} - +/* Gradient banner */ .md-header { background: linear-gradient(142deg, rgba(229,119,39,1) 3%, rgba(172,56,56,1) 31%, rgba(133,59,96,1) 51%, rgba(31,67,103,1) 79%, rgba(31,99,120,1) 94%, rgba(32,135,139,1) 100%); } diff --git a/docs/reference/concepts/concepts.md b/docs/reference/concepts/concepts.md index 7b01b3b..044ed2f 100644 --- a/docs/reference/concepts/concepts.md +++ b/docs/reference/concepts/concepts.md @@ -5,7 +5,14 @@ The core components are the following: > *Note:* click on the 'Concept' to take you to the corresponding module. The module documentation will have greater detail on the specifics of the implementation -## [**Step**](steps.md) + +[//]: # (References) +[Context]: context.md +[Logging]: logger.md +[Step]: step.md + + +## [Step] A custom unit of logic that can be executed. A Step is an atomic operation and serves as the building block of data pipelines built with the framework. A step can be seen as an operation on a set of inputs, and returns a set of @@ -53,39 +60,29 @@ Step ---> O3["Output 3"] Step is the core abstraction of the framework. Meaning, that it is the core building block of the framework and is used to define all the operations that can be executed. -Please see the [Step](steps.md) documentation for more details. - -## [**Task**](tasks.md) - -The unit of work of one execution of the framework. +Please see the [Step] documentation for more details. -An execution usually consists of an `Extract - Transform - Load` approach of one data object. -Tasks typically consist of a series of Steps. -Please see the [Task](tasks.md) documentation for more details. - -## [**Context**](context.md) +## [Context] The Context is used to configure the environment where a Task or Step runs. It is often based on configuration files and can be used to adapt behaviour of a Task or Step based on the environment it runs in. -Please see the [Context](context.md) documentation for more details. +Please see the [Context] documentation for more details. -## [**logger**](logging.md) -A logger object to log messages with different levels. +## [Logging] -Please see the [Logging](logging.md) documentation for more details. +A logger object to log messages with different levels. +Please see the [Logging] documentation for more details. The interactions between the base concepts of the model is visible in the below diagram: ```mermaid ---- -title: Koheesio Class Diagram ---- + classDiagram Step .. Task Step .. Transformation diff --git a/docs/reference/concepts/context.md b/docs/reference/concepts/context.md index ec3ca68..fd7a7c7 100644 --- a/docs/reference/concepts/context.md +++ b/docs/reference/concepts/context.md @@ -12,14 +12,14 @@ complex configurations. It also provides serialization and deserialization capab and load configurations in JSON, YAML, or TOML formats. Whether you're setting up the environment for a Task or Step, or managing variables shared across multiple tasks, -`Context` provides a robust and efficient solution. +`Context` provides a robust and efficient solution. This document will guide you through its key features and show you how to leverage its capabilities in your Koheesio applications. ## API Reference -See [API Reference](../../koheesio/context.html) for a detailed description of the `Context` class and its methods. +See [API Reference](../../api_reference/context.md) for a detailed description of the `Context` class and its methods. ## Key Features diff --git a/docs/reference/concepts/logging.md b/docs/reference/concepts/logger.md similarity index 100% rename from docs/reference/concepts/logging.md rename to docs/reference/concepts/logger.md diff --git a/docs/reference/concepts/steps.md b/docs/reference/concepts/step.md similarity index 100% rename from docs/reference/concepts/steps.md rename to docs/reference/concepts/step.md diff --git a/docs/reference/concepts/tasks.md b/docs/reference/concepts/tasks.md deleted file mode 100644 index 74a57fd..0000000 --- a/docs/reference/concepts/tasks.md +++ /dev/null @@ -1,8 +0,0 @@ -A Task is the unit of work of one execution of the framework. An execution usually consists of an Extract -> Transform --> Load approach of one data object. - -Tasks generally are made up of Steps chained one after another. - -## API Reference - -See [API Reference](../../koheesio/tasks) for a detailed description of the `Task` class and its methods. \ No newline at end of file diff --git a/docs/reference/concepts/readers.md b/docs/reference/spark/readers.md similarity index 97% rename from docs/reference/concepts/readers.md rename to docs/reference/spark/readers.md index 0700dc7..7c87920 100644 --- a/docs/reference/concepts/readers.md +++ b/docs/reference/spark/readers.md @@ -12,7 +12,7 @@ the `df` property of the `Reader`. ## API Reference -See [API Reference](../../koheesio/steps/readers) for a detailed description of the `Reader` class and its methods. +See [API Reference](../../api_reference/spark/readers/index.md) for a detailed description of the `Reader` class and its methods. ## Key Features of a Reader diff --git a/docs/reference/concepts/transformations.md b/docs/reference/spark/transformations.md similarity index 99% rename from docs/reference/concepts/transformations.md rename to docs/reference/spark/transformations.md index 933d0a9..21363a3 100644 --- a/docs/reference/concepts/transformations.md +++ b/docs/reference/spark/transformations.md @@ -15,8 +15,8 @@ pipeline. This can help avoid errors and make your code easier to understand and ## API Reference -See [API Reference](../../koheesio/steps/transformations) for a detailed description of the `Transformation` classes and -their methods. +See [API Reference](../../api_reference/spark/transformations/index.md) for a detailed description of the +`Transformation` classes and their methods. ## Types of Transformations diff --git a/docs/reference/concepts/writers.md b/docs/reference/spark/writers.md similarity index 100% rename from docs/reference/concepts/writers.md rename to docs/reference/spark/writers.md diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index 22bcdf1..8fd80ff 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -6,36 +6,53 @@ ## Installation -### Poetry - -If you're using Poetry, add the following entry to the `pyproject.toml` file: - -```toml title="pyproject.toml" -[[tool.poetry.source]] -name = "nike" -url = "https://artifactory.nike.com/artifactory/api/pypi/python-virtual/simple" -secondary = true -``` - -```bash -poetry add koheesio -``` - -### pip - -If you're using pip, run the following command to install Koheesio: - -Requires [pip](https://pip.pypa.io/en/stable/). - -```bash -pip install koheesio --extra-index-url https://artifactory.nike.com/artifactory/api/pypi/python-virtual/simple -``` +

+ hatch / hatchling + + If you're using hatch (or hatchling), simply add `koheesio` to the `dependencies` or section in your + `pyproject.toml` file: + + ```toml title="pyproject.toml" + dependencies = [ + "koheesio", + ] + ``` +
+ +
+ poetry + + If you're using Poetry, add the following entry to the `pyproject.toml` file: + + ```toml title="pyproject.toml" + [[tool.poetry.source]] + name = "nike" + url = "https://artifactory.nike.com/artifactory/api/pypi/python-virtual/simple" + secondary = true + ``` + + ```bash + poetry add koheesio + ``` +
+ +
+ pip + + If you're using pip, run the following command to install Koheesio: + + Requires [pip](https://pip.pypa.io/en/stable/). + + ```bash + pip install koheesio + ``` +
## Basic Usage Once you've installed Koheesio, you can start using it in your Python scripts. Here's a basic example: -```python +```python title="my_first_step.py" from koheesio import Step # Define a step @@ -50,17 +67,52 @@ step = MyStep() step.execute() ``` -### Advanced Usage -For more advanced usage, you can check out the examples in the `__notebooks__` directory of this repository. These examples show how to use Koheesio's features in more detail. +## Advanced Usage + +```python title="my_first_etl.py" +from pyspark.sql.functions import lit +from pyspark.sql import DataFrame, SparkSession + +# Step 1: import Koheesio dependencies +from koheesio.context import Context +from koheesio.spark.readers.dummy import DummyReader +from koheesio.spark.transformations.camel_to_snake import CamelToSnakeTransformation +from koheesio.spark.writers.dummy import DummyWriter +from koheesio.spark.etl_task import EtlTask + +# Step 2: Set up a SparkSession +spark = SparkSession.builder.getOrCreate() + +# Step 3: Configure your Context +context = Context({ + "source": DummyReader(), + "transformations": [CamelToSnakeTransformation()], + "target": DummyWriter(), + "my_favorite_movie": "inception", +}) + +# Step 4: Create a Task +class MyFavoriteMovieTask(EtlTask): + my_favorite_movie: str + + def transform(self, df: DataFrame = None) -> DataFrame: + df = df.withColumn("MyFavoriteMovie", lit(self.my_favorite_movie)) + return super().transform(df) + +# Step 5: Run your Task +task = MyFavoriteMovieTask(**context) +task.run() +``` ### Contributing -If you want to contribute to Koheesio, check out the `CONTRIBUTING.md` file in this repository. It contains guidelines for contributing, including how to submit issues and pull requests. +If you want to contribute to Koheesio, check out the `CONTRIBUTING.md` file in this repository. It contains guidelines +for contributing, including how to submit issues and pull requests. ### Testing To run the tests for Koheesio, use the following command: ```bash -make test +make dev-test ``` -This will run all the tests in the `test` directory. +This will run all the tests in the `tests` directory. diff --git a/docs/tutorials/how-to.md b/docs/tutorials/how-to.md deleted file mode 100644 index e49986e..0000000 --- a/docs/tutorials/how-to.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -tags: - - doctype/how-to ---- - - - - diff --git a/docs/tutorials/learn-koheesio.md b/docs/tutorials/learn-koheesio.md index 5d71d08..7c237b8 100644 --- a/docs/tutorials/learn-koheesio.md +++ b/docs/tutorials/learn-koheesio.md @@ -1,40 +1,74 @@ # Learn Koheesio -Koheesio is designed to simplify the development of data engineering pipelines. It provides a structured way to define and execute data processing tasks, making it easier to build, test, and maintain complex data workflows. +Koheesio is designed to simplify the development of data engineering pipelines. It provides a structured way to define +and execute data processing tasks, making it easier to build, test, and maintain complex data workflows. ## Core Concepts Koheesio is built around several core concepts: -- **Step**: The fundamental unit of work in Koheesio. It represents a single operation in a data pipeline, taking in inputs and producing outputs. -- **Task**: A larger unit of work, typically encompassing an entire Extract - Transform - Load process for a data object. -- **Context**: A configuration class used to set up the environment for a Task. It can be used to share variables across tasks and adapt the behavior of a Task based on its environment. -- **Logger**: A class for logging messages at different levels. -- **Reader**: A type of Step that reads data from a source and stores the result (to make it available for subsequent steps). -- **Writer**: This controls how data is written to the output in both batch and streaming contexts. -- **Transformation**: A type of Step that takes a DataFrame as input and returns a DataFrame as output. +- **Step**: The fundamental unit of work in Koheesio. It represents a single operation in a data pipeline, taking in + inputs and producing outputs. + > See the [Step](../reference/concepts/step.md) documentation for more information. +- **Context**: A configuration class used to set up the environment for a Task. It can be used to share variables across + tasks and adapt the behavior of a Task based on its environment. + > See the [Context](../reference/concepts/context.md) documentation for more information. +- **Logger**: A class for logging messages at different levels. + > See the [Logger](../reference/concepts/logger.md) documentation for more information. -In any given pipeline, you can expect to use Readers, Writers, and Transformations to express the ETL logic. Readers are responsible for extracting data from various sources, such as databases, files, or APIs. Transformations then process this data, performing operations like filtering, aggregation, or conversion. Finally, Writers handle the loading of the transformed data to the desired destination, which could be a database, a file, or a data stream. The Logger and Context classes provide support for these operations, enabling detailed logging of the pipeline's execution and customization of the pipeline's behavior based on the environment, respectively. The Task class ties these components together, orchestrating the execution of the Steps in a pipeline. +The Logger and Context classes provide support, enabling detailed logging of the pipeline's execution and customization +of the pipeline's behavior based on the environment, respectively. -## Basic Usage -Here's a simple example of how to define and execute a Step: +## Implementations -```python -from koheesio import Step +In the context of Koheesio, an implementation refers to a specific way of executing Steps, the fundamental units of work +in Koheesio. Each implementation uses a different technology or approach to process data along with its own set of +Steps, designed to work with the specific technology or approach used by the implementation. -class MyStep(Step): - def execute(self): - # Your step logic here +For example, the Spark implementation includes Steps for reading data from a Spark DataFrame, transforming the data +using Spark operations, and writing the data to a Spark-supported destination. -step = MyStep() -step.execute() -``` +Currently, Koheesio supports two implementations: Spark, and AsyncIO. -## Advanced Usage +### Spark +_Requires:_ Apache Spark (pyspark) +_Installation:_ `pip install koheesio[spark]` +_Module:_ `koheesio.spark` + +This implementation uses Apache Spark, a powerful open-source unified analytics engine for large-scale data processing. + +Steps that use this implementation can leverage Spark's capabilities for distributed data processing, making it suitable +for handling large volumes of data. The Spark implementation includes the following types of Steps: + +- **Reader**: + `from koheesio.spark.readers import Reader` + A type of Step that reads data from a source and stores the result (to make it available for subsequent steps). + For more information, see the [Reader](../reference/spark/readers.md) documentation. + +- **Writer**: + `from koheesio.spark.writers import Writer` + This controls how data is written to the output in both batch and streaming contexts. + For more information, see the [Writer](../reference/spark/writers.md) documentation. + +- **Transformation**: + `from koheesio.spark.transformations import Transformation` + A type of Step that takes a DataFrame as input and returns a DataFrame as output. + For more information, see the [Transformation](../reference/spark/transformations.md) documentation. + +In any given pipeline, you can expect to use Readers, Writers, and Transformations to express the ETL logic. Readers are +responsible for extracting data from various sources, such as databases, files, or APIs. Transformations then process this +data, performing operations like filtering, aggregation, or conversion. Finally, Writers handle the loading of the +transformed data to the desired destination, which could be a database, a file, or a data stream. + +### Async +_Module:_ `koheesio.asyncio` + +This implementation uses Python's asyncio library for writing single-threaded concurrent code using coroutines, +multiplexing I/O access over sockets and other resources, running network clients and servers, and other related +primitives. Steps that use this implementation can perform data processing tasks asynchronously, which can be beneficial +for IO-bound tasks. -For more advanced usage, check out the examples in the [`__notebooks__`]("__notebooks__") directory of the Koheesio repository. -These examples show how to use Koheesio's features in more detail. ## Best Practices @@ -70,4 +104,14 @@ Here are some best practices for using Koheesio: and loading. This not only simplifies your code but also makes it more robust and efficient. Remember, these are general best practices and might need to be adapted based on your specific use case and -requirements. \ No newline at end of file +requirements. + + +## Pydantic + +Koheesio Steps are Pydantic models, which means they can be validated and serialized. This makes it easy to define +the inputs and outputs of a Step, and to validate them before running the Step. Pydantic models also provide a +consistent way to define the schema of the data that a Step expects and produces, making it easier to understand and +maintain the code. + +Learn more about Pydantic [here](https://docs.pydantic.dev/latest/). diff --git a/docs/tutorials/onboarding.md b/docs/tutorials/onboarding.md index 343c293..55276c1 100644 --- a/docs/tutorials/onboarding.md +++ b/docs/tutorials/onboarding.md @@ -1,7 +1,3 @@ - -tags: - - doctype/how-to - # Onboarding to Koheesio Koheesio is a Python library that simplifies the development of data engineering pipelines. It provides a structured diff --git a/mkdocs.yml b/mkdocs.yml index 0e9b7a9..2dc0774 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,6 +1,5 @@ site_name: Koheesio -#FIXME: Change the site_url to the correct one -site_url: https:///koheesio +site_url: https://engineering.nike.com/koheesio/ site_description: Koheesio is an open source python library that simplifies the development of data engineering pipelines. @@ -43,18 +42,19 @@ nav: - Reference: # reference folder - Concepts: - reference/concepts/concepts.md - - Steps: - - reference/concepts/steps.md - - Readers: reference/concepts/readers.md - - Writers: reference/concepts/writers.md - - Transformations: reference/concepts/transformations.md - - Tasks: reference/concepts/tasks.md + - Steps: reference/concepts/step.md - Context: reference/concepts/context.md - - Logging: reference/concepts/logging.md + - Logger: reference/concepts/logger.md + - Spark: + - Readers: reference/spark/readers.md + - Writers: reference/spark/writers.md + - Transformations: reference/spark/transformations.md + - Glossary: + - includes/glossary.md - API Reference: api_reference/ - Community: # community folder - Contribute: community/contribute.md - - Approach to Documentation: explanation/approach-documentation.md + - Approach to Documentation: community/approach-documentation.md theme: name: material @@ -63,27 +63,20 @@ theme: code: Roboto Mono favicon: assets/logo_koheesio.svg palette: - # Palette toggle for automatic mode - - media: "(prefers-color-scheme)" + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: indigo + accent: indigo toggle: - icon: material/brightness-auto + icon: material/weather-night name: Switch to light mode - # Palette toggle for light mode - media: "(prefers-color-scheme: light)" scheme: default - primary: custom - accent: custom + primary: indigo + accent: indigo toggle: - icon: material/brightness-7 + icon: material/weather-sunny name: Switch to dark mode - # Palette toggle for dark mode - - media: "(prefers-color-scheme: dark)" - scheme: slate - primary: custom - accent: custom - toggle: - icon: material/brightness-4 - name: Switch to light mode features: # - announce.dismiss - content.code.annotate diff --git a/pyproject.toml b/pyproject.toml index 63f988f..a99d431 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,7 @@ async_http = [ "nest-asyncio>=1.6.0", ] box = ["boxsdk[jwt]==3.8.1"] -pandas = ["pandas>=1.3", "setuptools"] +pandas = ["pandas>=1.3", "setuptools", "numpy<2.0.0"] pyspark = ["pyspark>=3.2.0", "pyarrow>13"] se = ["spark-expectations>=2.1.0"] # SFTP dependencies in to_csv line_iterator @@ -95,6 +95,7 @@ docs = [ "mkdocstrings-python>=1.7.5", "pygments>=2.17.2", "pymdown-extensions>=10.7.0", + "black", ] diff --git a/src/koheesio/integrations/spark/sftp.py b/src/koheesio/integrations/spark/sftp.py index 07249ee..672fdfd 100644 --- a/src/koheesio/integrations/spark/sftp.py +++ b/src/koheesio/integrations/spark/sftp.py @@ -121,7 +121,7 @@ class SFTPWriter(Writer): file through SFTP. Details on how the DataFrame is written to the buffer should be implemented in the implementation of the BufferWriter class. Any BufferWriter can be used here, as long as it implements the BufferWriter interface. - mode: SFTPWriteMode, optional, default=SFTPWriteMode.OVERWRITE + mode : SFTPWriteMode, optional, default=SFTPWriteMode.OVERWRITE Write mode: overwrite, append, ignore, exclusive, backup, or update. See the docstring of SFTPWriteMode for more details. """ @@ -341,7 +341,6 @@ class SendCsvToSftp(PandasCsvBufferWriter, SFTPWriter): Parameters ---------- - ### SFTP Parameters (Inherited from SFTPWriter) path : Union[str, Path] Path to the folder to write to. file_name : Optional[str] @@ -354,27 +353,27 @@ class SendCsvToSftp(PandasCsvBufferWriter, SFTPWriter): SFTP Server Username. password : SecretStr SFTP Server Password. - mode: SFTPWriteMode + mode : SFTPWriteMode Write mode: overwrite, append, ignore, exclusive, backup, or update. - - ### CSV Parameters (Inherited from PandasCsvBufferWriter) - header: bool + header : bool Whether to write column names as the first line. Default is True. - sep: str + sep : str Field delimiter for the output file. Default is ','. - quote: str + quote : str Character used to quote fields. Default is '"'. - quoteAll: bool + quoteAll : bool Whether all values should be enclosed in quotes. Default is False. - escape: str + escape : str Character used to escape sep and quote when needed. Default is '\\'. - timestampFormat: str + timestampFormat : str Date format for datetime objects. Default is '%Y-%m-%dT%H:%M:%S.%f'. - lineSep: str + lineSep : str Character used as line separator. Default is os.linesep. - compression: Optional[Literal["infer", "gzip", "bz2", "zip", "xz", "zstd", "tar"]] + compression : Optional[Literal["infer", "gzip", "bz2", "zip", "xz", "zstd", "tar"]] Compression to use for the output data. Default is None. + See Also + -------- For more details on the CSV parameters, refer to the PandasCsvBufferWriter class documentation. """ @@ -383,7 +382,7 @@ class SendCsvToSftp(PandasCsvBufferWriter, SFTPWriter): @model_validator(mode="after") def set_up_buffer_writer(self) -> "SendCsvToSftp": """Set up the buffer writer, passing all CSV related options to it.""" - self.buffer_writer = PandasCsvBufferWriter(**self.get_options(options_type="kohesio_pandas_buffer_writer")) + self.buffer_writer = PandasCsvBufferWriter(**self.get_options(options_type="koheesio_pandas_buffer_writer")) return self def execute(self): @@ -428,7 +427,6 @@ class SendJsonToSftp(PandasJsonBufferWriter, SFTPWriter): Parameters ---------- - ### SFTP Parameters (Inherited from SFTPWriter) path : Union[str, Path] Path to the folder on the SFTP server. file_name : Optional[str] @@ -441,21 +439,19 @@ class SendJsonToSftp(PandasJsonBufferWriter, SFTPWriter): SFTP Server Username. password : SecretStr SFTP Server Password. - mode: SFTPWriteMode + mode : SFTPWriteMode Write mode: overwrite, append, ignore, exclusive, backup, or update. - - ### JSON Parameters (Inherited from PandasJsonBufferWriter) - orient: Literal["split", "records", "index", "columns", "values", "table"] + orient : Literal["split", "records", "index", "columns", "values", "table"] Format of the JSON string. Default is 'records'. - lines: bool + lines : bool If True, output is one JSON object per line. Only used when orient='records'. Default is True. - date_format: Literal["iso", "epoch"] + date_format : Literal["iso", "epoch"] Type of date conversion. Default is 'iso'. - double_precision: int + double_precision : int Decimal places for encoding floating point values. Default is 10. - force_ascii: bool + force_ascii : bool If True, encoded string is ASCII. Default is True. - compression: Optional[Literal["gzip"]] + compression : Optional[Literal["gzip"]] Compression to use for output data. Default is None. See Also diff --git a/src/koheesio/logger.py b/src/koheesio/logger.py index 0ddfe03..9f00d36 100644 --- a/src/koheesio/logger.py +++ b/src/koheesio/logger.py @@ -1,7 +1,7 @@ """Loggers are used to log messages from your application. For a comprehensive guide on the usage, examples, and additional features of the logging classes, please refer to the -[reference/concepts/logging](../reference/concepts/logging.md) section of the Koheesio documentation. +[reference/concepts/logger](../reference/concepts/logger.md) section of the Koheesio documentation. Classes ------- diff --git a/src/koheesio/models/__init__.py b/src/koheesio/models/__init__.py index 77a4597..5ab80f1 100644 --- a/src/koheesio/models/__init__.py +++ b/src/koheesio/models/__init__.py @@ -46,8 +46,8 @@ class BaseModel(PydanticBaseModel, ABC): Additional methods and properties: --------------------------------- ### Fields - Every Koheesio BaseModel has two fields: `name` and `description`. These fields are used to provide a name and a - description to the model. + Every Koheesio BaseModel has two predefined fields: `name` and `description`. These fields are used to provide a + name and a description to the model. - `name`: This is the name of the Model. If not provided, it defaults to the class name. @@ -246,7 +246,7 @@ def log(self) -> Logger: return LoggingFactory.get_logger(name=self.__class__.__name__, inherit_from_koheesio=True) @classmethod - def from_basemodel(cls, basemodel: BaseModel, **kwargs): + def from_basemodel(cls, basemodel: BaseModel, **kwargs) -> InstanceOf[BaseModel]: """Returns a new BaseModel instance based on the data of another BaseModel""" kwargs = {**basemodel.model_dump(), **kwargs} return cls(**kwargs) @@ -669,4 +669,8 @@ def _list_of_columns_validation(columns_value): return list(dict.fromkeys(columns)) # dict.fromkeys is used to dedup while maintaining order -ListOfColumns = Annotated[List[str], BeforeValidator(_list_of_columns_validation)] +ListOfColumns = Annotated[Union[str, List[str]], BeforeValidator(_list_of_columns_validation)] +""" Annotated type for a list of column names. +Will ensure that there are no duplicate columns, empty strings, etc. +In case an individual column is passed, the value will be coerced to a list. +""" diff --git a/src/koheesio/models/sql.py b/src/koheesio/models/sql.py index 8906c2e..baa3bc2 100644 --- a/src/koheesio/models/sql.py +++ b/src/koheesio/models/sql.py @@ -15,11 +15,11 @@ class SqlBaseStep(Step, ExtraParamsMixin, ABC): Parameters ---------- - sql_path: Optional[Union[Path, str]], optional, default=None + sql_path : Optional[Union[Path, str]], optional, default=None Path to a SQL file - sql: Optional[str], optional, default=None + sql : Optional[str], optional, default=None SQL script to apply - params: Dict[str, Any], optional, default_factory=dict + params : Dict[str, Any], optional, default_factory=dict Placeholders (parameters) for templating. These are identified with `${placeholder}` in the SQL script.\n __Note__: any arbitrary kwargs passed to the class will be added to params. """ diff --git a/src/koheesio/spark/readers/__init__.py b/src/koheesio/spark/readers/__init__.py index ab81a7d..fd9867c 100644 --- a/src/koheesio/spark/readers/__init__.py +++ b/src/koheesio/spark/readers/__init__.py @@ -3,7 +3,7 @@ self.output.df. For a comprehensive guide on the usage, examples, and additional features of Reader classes, please refer to the -[reference/concepts/steps/readers](../../../reference/concepts/readers.md) section of the Koheesio documentation. +[reference/spark/steps/readers](../../../reference/spark/readers.md) section of the Koheesio documentation. """ from abc import ABC, abstractmethod diff --git a/src/koheesio/spark/readers/delta.py b/src/koheesio/spark/readers/delta.py index 99c08dd..54ee795 100644 --- a/src/koheesio/spark/readers/delta.py +++ b/src/koheesio/spark/readers/delta.py @@ -50,7 +50,7 @@ class DeltaTableReader(Reader): filter_cond : Optional[Union[Column, str]] Filter condition to apply to the dataframe. Filters can be provided by using Column or string expressions. For example: `f.col('state') == 'Ohio'`, `state = 'Ohio'` or `(col('col1') > 3) & (col('col2') < 9)` - columns: Optional[ListOfColumns] + columns : Optional[ListOfColumns] Columns to select from the table. One or many columns can be provided as strings. For example: `['col1', 'col2']`, `['col1']` or `'col1'` streaming : Optional[bool] diff --git a/src/koheesio/spark/readers/hana.py b/src/koheesio/spark/readers/hana.py index 4d773ce..92cfbbd 100644 --- a/src/koheesio/spark/readers/hana.py +++ b/src/koheesio/spark/readers/hana.py @@ -14,7 +14,7 @@ class HanaReader(JdbcReader): Notes ----- - * Refer to [JdbcReader](jdbc.html#koheesio.spark.readers.jdbc.JdbcReader) for the list of all available parameters. + * Refer to [JdbcReader](jdbc.md#koheesio.spark.readers.jdbc.JdbcReader) for the list of all available parameters. * Refer to SAP HANA Client Interface Programming Reference docs for the list of all available connection string parameters: https://help.sap.com/docs/SAP_HANA_CLIENT/f1b440ded6144a54ada97ff95dac7adf/109397c2206a4ab2a5386d494f4cf75e.html diff --git a/src/koheesio/spark/readers/snowflake.py b/src/koheesio/spark/readers/snowflake.py index bca1bb1..bef8946 100644 --- a/src/koheesio/spark/readers/snowflake.py +++ b/src/koheesio/spark/readers/snowflake.py @@ -20,9 +20,9 @@ See Also -------- -- [koheesio.spark.readers.Reader](../readers#koheesio.spark.readers.Reader) +- [koheesio.spark.readers.Reader](index.md#koheesio.spark.readers.Reader) Base class for all Readers. -- [koheesio.steps.integrations.snowflake](../integrations/snowflake.html) +- [koheesio.spark.snowflake](../snowflake.md) Module containing Snowflake classes. More detailed class descriptions can be found in the class docstrings. diff --git a/src/koheesio/spark/readers/teradata.py b/src/koheesio/spark/readers/teradata.py index aa028fb..b4c8167 100644 --- a/src/koheesio/spark/readers/teradata.py +++ b/src/koheesio/spark/readers/teradata.py @@ -20,7 +20,7 @@ class TeradataReader(JdbcReader): See Also -------- - * Refer to [JdbcReader](../readers/jdbc.html#koheesio.spark.readers.jdbc.JdbcReader) for the list of all available + * Refer to [JdbcReader](jdbc.md#koheesio.spark.readers.jdbc.JdbcReader) for the list of all available parameters. * Refer to Teradata docs for the list of all available connection string parameters: https://teradata-docs.s3.amazonaws.com/doc/connectivity/jdbc/reference/current/jdbcug_chapter_2.html#BABJIHBJ diff --git a/src/koheesio/spark/snowflake.py b/src/koheesio/spark/snowflake.py index fa3ec32..466f912 100644 --- a/src/koheesio/spark/snowflake.py +++ b/src/koheesio/spark/snowflake.py @@ -5,7 +5,7 @@ Notes ----- -Every Step in this module is based on [SnowflakeBaseModel](#koheesio.steps.integrations.snowflake.SnowflakeBaseModel). +Every Step in this module is based on [SnowflakeBaseModel](./snowflake.md#koheesio.spark.snowflake.SnowflakeBaseModel). The following parameters are available for every Step. Parameters @@ -907,8 +907,9 @@ class SnowflakeWriter(SnowflakeBaseModel, Writer): See Also -------- - - [koheesio.steps.writers.Writer](../writers#koheesio.steps.writers.Writer) - - [koheesio.steps.writers.BatchOutputMode](../writers#koheesio.steps.writers.BatchOutputMode) + - [koheesio.steps.writers.Writer](writers/index.md#koheesio.spark.writers.Writer) + - [koheesio.steps.writers.BatchOutputMode](writers/index.md#koheesio.spark.writers.BatchOutputMode) + - [koheesio.steps.writers.StreamingOutputMode](writers/index.md#koheesio.spark.writers.StreamingOutputMode) """ table: str = Field(default=..., description="Target table name") diff --git a/src/koheesio/spark/transformations/__init__.py b/src/koheesio/spark/transformations/__init__.py index 938032c..251d66f 100644 --- a/src/koheesio/spark/transformations/__init__.py +++ b/src/koheesio/spark/transformations/__init__.py @@ -6,7 +6,7 @@ References ---------- For a comprehensive guide on the usage, examples, and additional features of Transformation classes, please refer to the -[reference/concepts/steps/transformations](../../../reference/concepts/transformations.md) section of the Koheesio +[reference/concepts/spark/transformations](../../../reference/spark/transformations.md) section of the Koheesio documentation. Classes @@ -45,7 +45,7 @@ class Transformation(SparkStep, ABC): Parameters ---------- - df: Optional[DataFrame] + df : Optional[DataFrame] The DataFrame to apply the transformation to. If not provided, the DataFrame has to be passed to the transform-method. @@ -158,21 +158,26 @@ class ColumnsTransformation(Transformation, ABC): Concept ------- - A ColumnsTransformation is a Transformation with a standardized input for column or columns. The `columns` are - stored as a list. Either a single string, or a list of strings can be passed to enter the `columns`. - `column` and `columns` are aliases to one another - internally the name `columns` should be used though. + A ColumnsTransformation is a Transformation with a standardized input for column or columns. - `columns` are stored as a list - either a single string, or a list of strings can be passed to enter the `columns` - `column` and `columns` are aliases to one another - internally the name `columns` should be used though. If more than one column is passed, the behavior of the Class changes this way: + - the transformation will be run in a loop against all the given columns Configuring the ColumnsTransformation ------------------------------------- - The ColumnsTransformation class has a `ColumnConfig` class that can be used to configure the behavior of the class. + [ColumnConfig]: ./index.md#koheesio.spark.transformations.ColumnsTransformation.ColumnConfig + [SparkDatatype]: ../utils.md#koheesio.spark.utils.SparkDatatype + + The ColumnsTransformation class has a [ColumnConfig] class that can be used to configure the behavior of the class. + Users should not have to interact with the [ColumnConfig] class directly. + This class has the following fields: + - `run_for_all_data_type` allows to run the transformation for all columns of a given type. @@ -182,20 +187,19 @@ class ColumnsTransformation(Transformation, ABC): - `data_type_strict_mode` Toggles strict mode for data type validation. Will only work if `limit_data_type` is set. - Note that Data types need to be specified as a SparkDatatype enum. + Data types need to be specified as a [SparkDatatype] enum. - See the docstrings of the `ColumnConfig` class for more information. - See the SparkDatatype enum for a list of available data types. + --- - Users should not have to interact with the `ColumnConfig` class directly. - - Parameters - ---------- - columns: - The column (or list of columns) to apply the transformation to. Alias: column + + - See the docstrings of the [ColumnConfig] class for more information.
+ - See the [SparkDatatype] enum for a list of available data types.
+
Example ------- + Implementing a transformation using the `ColumnsTransformation` class: + ```python from pyspark.sql import functions as f from koheesio.steps.transformations import ColumnsTransformation @@ -206,6 +210,14 @@ def execute(self): for column in self.get_columns(): self.output.df = self.df.withColumn(column, f.col(column) + 1) ``` + + In the above example, the `execute` method is implemented to add 1 to the values of a given column. + + Parameters + ---------- + columns : ListOfColumns + The column (or list of columns) to apply the transformation to. Alias: column + """ columns: ListOfColumns = Field( @@ -220,19 +232,19 @@ class ColumnConfig: Parameters ---------- - run_for_all_data_type: Optional[List[SparkDatatype]] + run_for_all_data_type : Optional[List[SparkDatatype]] allows to run the transformation for all columns of a given type. A user can trigger this behavior by either omitting the `columns` parameter or by passing a single `*` as a column name. In both cases, the `run_for_all_data_type` will be used to determine the data type. Value should be be passed as a SparkDatatype enum. (default: [None]) - limit_data_type: Optional[List[SparkDatatype]] + limit_data_type : Optional[List[SparkDatatype]] allows to limit the transformation to a specific data type. Value should be passed as a SparkDatatype enum. (default: [None]) - data_type_strict_mode: bool + data_type_strict_mode : bool Toggles strict mode for data type validation. Will only work if `limit_data_type` is set. - when True, a ValueError will be raised if any column does not adhere to the `limit_data_type` - when False, a warning will be thrown and the column will be skipped instead @@ -307,14 +319,14 @@ def column_type_of_col( Parameters ---------- - col: Union[str, Column] + col : Union[str, Column] The column to check the type of - df: Optional[DataFrame] + df : Optional[DataFrame] The DataFrame belonging to the column. If not provided, the DataFrame passed to the constructor will be used. - simple_return_mode: bool + simple_return_mode : bool If True, the return value will be a simple string. If False, the return value will be a SparkDatatype enum. Returns @@ -352,7 +364,7 @@ def get_all_columns_of_specific_type(self, data_type: Union[str, SparkDatatype]) Parameters ---------- - data_type: Union[str, SparkDatatype] + data_type : Union[str, SparkDatatype] The data type to get the columns for Returns @@ -499,7 +511,7 @@ def func(self, column: Column) -> Column: Parameters ---------- - column: Column + column : Column The column to apply the transformation to Returns diff --git a/src/koheesio/spark/transformations/arrays.py b/src/koheesio/spark/transformations/arrays.py index eaf9a91..d58a133 100644 --- a/src/koheesio/spark/transformations/arrays.py +++ b/src/koheesio/spark/transformations/arrays.py @@ -17,9 +17,9 @@ See Also -------- -* [koheesio.spark.transformations](../transformations) +* [koheesio.spark.transformations](index.md) Module containing all transformation classes. -* [koheesio.spark.transformations.ColumnsTransformationWithTarget](../transformations/index.html#koheesio.spark.transformations.ColumnsTransformationWithTarget) +* [koheesio.spark.transformations.ColumnsTransformationWithTarget](index.md#koheesio.spark.transformations.ColumnsTransformationWithTarget) Base class for all transformations that operate on columns and have a target column. """ diff --git a/src/koheesio/spark/transformations/cast_to_datatype.py b/src/koheesio/spark/transformations/cast_to_datatype.py index 42730a5..004c0ef 100644 --- a/src/koheesio/spark/transformations/cast_to_datatype.py +++ b/src/koheesio/spark/transformations/cast_to_datatype.py @@ -20,35 +20,35 @@ ---- Dates, Arrays and Maps are not supported by this module. -- for dates, use the [koheesio.spark.transformations.date_time](date_time) module -- for arrays, use the [koheesio.spark.transformations.arrays](arrays.html) module +- for dates, use the [koheesio.spark.transformations.date_time](date_time/index.md) module +- for arrays, use the [koheesio.spark.transformations.arrays](arrays.md) module Classes ------- -CastToDatatype: - Cast a column or set of columns to a given datatype +CastToDatatype + Cast a column or set of columns to a given datatype CastToByte - Cast to Byte (a.k.a. tinyint) + Cast to Byte (a.k.a. tinyint) CastToShort - Cast to Short (a.k.a. smallint) + Cast to Short (a.k.a. smallint) CastToInteger - Cast to Integer (a.k.a. int) + Cast to Integer (a.k.a. int) CastToLong - Cast to Long (a.k.a. bigint) + Cast to Long (a.k.a. bigint) CastToFloat - Cast to Float (a.k.a. real) + Cast to Float (a.k.a. real) CastToDouble - Cast to Double + Cast to Double CastToDecimal - Cast to Decimal (a.k.a. decimal, numeric, dec, BigDecimal) + Cast to Decimal (a.k.a. decimal, numeric, dec, BigDecimal) CastToString - Cast to String + Cast to String CastToBinary - Cast to Binary (a.k.a. byte array) + Cast to Binary (a.k.a. byte array) CastToBoolean - Cast to Boolean + Cast to Boolean CastToTimestamp - Cast to Timestamp + Cast to Timestamp Note ---- @@ -820,7 +820,7 @@ class CastToTimestamp(CastToDatatype): See Also -------- - * [koheesio.spark.transformations.date_time](date_time) + * [koheesio.spark.transformations.date_time](date_time/index.md) * https://spark.apache.org/docs/latest/sql-ref-datetime-pattern.html#timestamp-pattern Unsupported datatypes: diff --git a/src/koheesio/spark/transformations/date_time/__init__.py b/src/koheesio/spark/transformations/date_time/__init__.py index c316232..9270110 100644 --- a/src/koheesio/spark/transformations/date_time/__init__.py +++ b/src/koheesio/spark/transformations/date_time/__init__.py @@ -194,12 +194,18 @@ class ToTimestamp(ColumnsTransformationWithTarget): -------- Related Koheesio classes: - * [koheesio.spark.transformations.ColumnsTransformation](transformations/index.html#koheesio.steps.transformation.ColumnsTransformation) : + [ColumnsTransformation]: ../index.md#koheesio.spark.transformations.ColumnsTransformation + [ColumnsTransformationWithTarget]: ../index.md#koheesio.spark.transformations.ColumnsTransformationWithTarget + [pyspark.sql.functions]: https://spark.apache.org/docs/3.5.1/api/python/reference/pyspark.sql/functions.html + + From the `koheesio.spark.transformations` module: + + * [ColumnsTransformation] : Base class for ColumnsTransformation. Defines column / columns field + recursive logic - * [koheesio.spark.transformations.ColumnsTransformationWithTarget](transformations/index.html#koheesio.steps.transformation.ColumnsTransformationWithTarget) : + * [ColumnsTransformationWithTarget] : Defines target_column / target_suffix field - pyspark.sql.functions: + [pyspark.sql.functions]: * datetime pattern : https://spark.apache.org/docs/latest/sql-ref-datetime-pattern.html diff --git a/src/koheesio/spark/transformations/date_time/interval.py b/src/koheesio/spark/transformations/date_time/interval.py index 576b757..9b574a7 100644 --- a/src/koheesio/spark/transformations/date_time/interval.py +++ b/src/koheesio/spark/transformations/date_time/interval.py @@ -35,10 +35,13 @@ --------- Related Koheesio classes: -* [koheesio.spark.transformations.ColumnsTransformation](transformations/index.html#koheesio.steps.transformation.ColumnsTransformation) : - Base class for ColumnsTransformation. Defines column / columns field + recursive logic -* [koheesio.spark.transformations.ColumnsTransformationWithTarget](transformations/index.html#koheesio.steps.transformation.ColumnsTransformationWithTarget) : - Defines target_column / target_suffix field +[ColumnsTransformation]: ../index.md#koheesio.spark.transformations.ColumnsTransformation +[ColumnsTransformationWithTarget]: ../index.md#koheesio.spark.transformations.ColumnsTransformationWithTarget + +From the koheesio.spark.transformations module: + +* [ColumnsTransformation] : Base class for ColumnsTransformation. Defines column / columns field + recursive logic +* [ColumnsTransformationWithTarget] : Defines target_column / target_suffix field pyspark.sql.functions: diff --git a/src/koheesio/spark/transformations/strings/__init__.py b/src/koheesio/spark/transformations/strings/__init__.py index 47c883e..1f97276 100644 --- a/src/koheesio/spark/transformations/strings/__init__.py +++ b/src/koheesio/spark/transformations/strings/__init__.py @@ -7,7 +7,7 @@ The following Transformations are included: -[change_case](change_case.html): +[change_case](change_case.md): - `Lower` Converts a string column to lower case. @@ -16,12 +16,12 @@ - `TitleCase` or `InitCap` Converts a string column to title case, where each word starts with a capital letter. -[concat](concat.html): +[concat](concat.md): - `Concat` Concatenates multiple input columns together into a single column, optionally using the given separator. -[pad](pad.html): +[pad](pad.md): - `Pad` Pads the values of `source_column` with the `character` up until it reaches `length` of characters @@ -30,31 +30,31 @@ - `RPad` Pad with a character on the right side of the string. -[regexp](regexp.html): +[regexp](regexp.md): - `RegexpExtract` Extract a specific group matched by a Java regexp from the specified string column. - `RegexpReplace` Searches for the given regexp and replaces all instances with what is in 'replacement'. -[replace](replace.html): +[replace](replace.md): - `Replace` Replace all instances of a string in a column with another string. -[split](split.html): +[split](split.md): - `SplitAll` Splits the contents of a column on basis of a split_pattern. - `SplitAtFirstMatch` Like SplitAll, but only splits the string once. You can specify whether you want the first or second part. -[substring](substring.html): +[substring](substring.md): - `Substring` Extracts a substring from a string column starting at the given position. -[trim](trim.html): +[trim](trim.md): - `Trim` Trim whitespace from the beginning and/or end of a string. diff --git a/src/koheesio/spark/transformations/strings/change_case.py b/src/koheesio/spark/transformations/strings/change_case.py index 0957ca8..42d6301 100644 --- a/src/koheesio/spark/transformations/strings/change_case.py +++ b/src/koheesio/spark/transformations/strings/change_case.py @@ -36,7 +36,7 @@ class LowerCase(ColumnsTransformationWithTarget): The name of the column or columns to convert to lower case. Alias: column. Lower case will be applied to all columns in the list. Column is required to be of string type. - target_column: str + target_column : str, optional The name of the column to store the result in. If None, the result will be stored in the same column as the input. @@ -94,7 +94,7 @@ class UpperCase(LowerCase): The name of the column or columns to convert to upper case. Alias: column. Upper case will be applied to all columns in the list. Column is required to be of string type. - target_column: str + target_column : str, optional The name of the column to store the result in. If None, the result will be stored in the same column as the input. @@ -143,11 +143,11 @@ class TitleCase(LowerCase): Parameters ---------- - columns: Union[str, List[str]] + columns : ListOfColumns The name of the column or columns to convert to title case. Alias: column. Title case will be applied to all columns in the list. Column is required to be of string type. - target_column: str + target_column : str, optional The name of the column to store the result in. If None, the result will be stored in the same column as the input. diff --git a/src/koheesio/spark/transformations/strings/regexp.py b/src/koheesio/spark/transformations/strings/regexp.py index 63b4de0..63f3171 100644 --- a/src/koheesio/spark/transformations/strings/regexp.py +++ b/src/koheesio/spark/transformations/strings/regexp.py @@ -31,7 +31,7 @@ class RegexpExtract(ColumnsTransformationWithTarget): Parameters ---------- - columns : Union[str, List[str]] + columns : ListOfColumns The column (or list of columns) to extract from. Alias: column target_column : Optional[str], optional, default=None The column to store the result in. If not provided, the result will be stored in the source column. @@ -113,14 +113,14 @@ class RegexpReplace(ColumnsTransformationWithTarget): Parameters ---------- - columns: + columns : ListOfColumns The column (or list of columns) to replace in. Alias: column - target_column: + target_column : Optional[str], optional, default=None The column to store the result in. If not provided, the result will be stored in the source column. Alias: target_suffix - if multiple columns are given as source, this will be used as a suffix. - regexp: + regexp : str The regular expression to replace - replacement: + replacement : str String to replace matched pattern with. Examples diff --git a/src/koheesio/spark/transformations/strings/trim.py b/src/koheesio/spark/transformations/strings/trim.py index 655df98..36a9105 100644 --- a/src/koheesio/spark/transformations/strings/trim.py +++ b/src/koheesio/spark/transformations/strings/trim.py @@ -37,13 +37,13 @@ class Trim(ColumnsTransformationWithTarget): Parameters ---------- - columns: + columns : ListOfColumns The column (or list of columns) to trim. Alias: column If no columns are provided, all string columns will be trimmed. - target_column: + target_column : ListOfColumns, optional The column to store the result in. If not provided, the result will be stored in the source column. Alias: target_suffix - if multiple columns are given as source, this will be used as a suffix. - direction: + direction : trim_type, optional, default "left-right" On which side to remove the spaces. Either "left", "right" or "left-right". Defaults to "left-right" Examples diff --git a/src/koheesio/spark/writers/buffer.py b/src/koheesio/spark/writers/buffer.py index 08d5896..64f57db 100644 --- a/src/koheesio/spark/writers/buffer.py +++ b/src/koheesio/spark/writers/buffer.py @@ -289,7 +289,7 @@ def get_options(self, options_type: str = "csv"): if options_type == "spark": csv_options["lineterminator"] = csv_options.pop(line_sep_option_naming) - elif options_type == "kohesio_pandas_buffer_writer": + elif options_type == "koheesio_pandas_buffer_writer": csv_options["line_terminator"] = csv_options.pop(line_sep_option_naming) return csv_options @@ -320,26 +320,29 @@ class PandasJsonBufferWriter(BufferWriter, ExtraParamsMixin): Parameters ----------- - orient: Literal["split", "records", "index", "columns", "values", "table"] + orient : Literal["split", "records", "index", "columns", "values", "table"] Format of the resulting JSON string. Default is 'records'. - lines: bool + lines : bool Format output as one JSON object per line. Only used when orient='records'. Default is True. - If true, the output will be formatted as one JSON object per line. - If false, the output will be written as a single JSON object. Note: this value is only used when orient='records' and will be ignored otherwise. - date_format: Literal["iso", "epoch"] + date_format : Literal["iso", "epoch"] Type of date conversion. Default is 'iso'. See `Date and Timestamp Formats` for a detailed description and more information. - double_precision: int + double_precision : int Number of decimal places for encoding floating point values. Default is 10. - force_ascii: bool + force_ascii : bool Force encoded string to be ASCII. Default is True. - compression: Optional[Literal["gzip"]] + compression : Optional[Literal["gzip"]] A string representing the compression to use for on-the-fly compression of the output data. Koheesio sets this default to 'None' leaving the data uncompressed. Can be set to gzip' optionally. Other compression options are currently not supported by Koheesio for JSON output. - ## Date and Timestamp Formats in JSON + Other Possible Parameters + ------------------------- + + ### Date and Timestamp Formats in JSON The `date_format` and `date_unit` parameters in pandas `to_json()` method are used to control the representation of dates and timestamps in the resulting JSON. @@ -354,7 +357,7 @@ class PandasJsonBufferWriter(BufferWriter, ExtraParamsMixin): options: 's' for seconds, 'ms' for milliseconds, 'us' for microseconds, and 'ns' for nanoseconds. The default is 'ms'. Note that this parameter is ignored when `date_format='iso'`. - ## Orient Parameter + ### Orient Parameter The `orient` parameter is used to specify the format of the resulting JSON string. Each option is useful in different scenarios depending on whether you need to preserve the index, data types, and/or column names of the original DataFrame. The set of possible orients is: diff --git a/tests/spark/integrations/dq/test_spark_expectations.py b/tests/spark/integrations/dq/test_spark_expectations.py index 259af00..6aa05e6 100644 --- a/tests/spark/integrations/dq/test_spark_expectations.py +++ b/tests/spark/integrations/dq/test_spark_expectations.py @@ -73,6 +73,8 @@ def test_rows_are_dropped(self, spark: SparkSession, prepare_tables): err_table_df = spark.read.table("default.output_table_error") assert err_table_df.count() == 2 + spark.sql("drop table default.output_table_error") + def test_meta_columns_are_not_dropped(self, spark, prepare_tables): from koheesio.integrations.spark.dq.spark_expectations import ( SparkExpectationsTransformation, @@ -98,6 +100,8 @@ def test_meta_columns_are_not_dropped(self, spark, prepare_tables): # Spark Expectations should add either meta_dq_run_date (<=1.1.0) or meta_dq_run_datetime (>= v1.1.1) assert "meta_dq_run_date" in output_columns or "meta_dq_run_datetime" in output_columns + spark.sql("drop table default.output_table_error") + def test_meta_columns_are_dropped(self, spark, prepare_tables): from koheesio.integrations.spark.dq.spark_expectations import ( SparkExpectationsTransformation, @@ -122,6 +126,8 @@ def test_meta_columns_are_dropped(self, spark, prepare_tables): assert "meta_dq_run_id" not in output_columns assert "meta_dq_run_datetime" not in output_columns and "meta_dq_run_datetime" not in output_columns + spark.sql("drop table default.output_table_error") + @staticmethod def apply_spark_sql(spark: SparkSession, source_sql_files: Union[List[str], str]) -> None: if isinstance(source_sql_files, str): From 75c6e543ee1fd8f8f9e437918c83fb56a4206f2c Mon Sep 17 00:00:00 2001 From: Mikita Sakalouski <38785549+mikita-sakalouski@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:31:41 +0200 Subject: [PATCH 6/6] Remove cerberus (#58) ## Description Removed Cerberus module ## Related Issue #57 ## Motivation and Context Cerberus is not in open source anymore, that is why it should be removed. ## How Has This Been Tested? Run all tests ## Screenshots (if appropriate): ## Types of changes - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) ## Checklist: - [x] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [x] I have read the **CONTRIBUTING** document. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. --- src/koheesio/secrets/cerberus.py | 89 -------------------------------- 1 file changed, 89 deletions(-) delete mode 100644 src/koheesio/secrets/cerberus.py diff --git a/src/koheesio/secrets/cerberus.py b/src/koheesio/secrets/cerberus.py deleted file mode 100644 index 6996201..0000000 --- a/src/koheesio/secrets/cerberus.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Module for retrieving secrets from Cerberus. - -Secrets are stored as SecretContext and can be accessed accordingly. - -See CerberusSecret for more information. -""" - -import os -import re -from typing import Optional - -from boto3 import Session -from cerberus.client import CerberusClient - -from koheesio.models import Field, SecretStr, model_validator -from koheesio.steps.integrations.secrets import Secret - - -class CerberusSecret(Secret): - """ - Retrieve secrets from Cerberus and wrap them into Context class for easy access. - All secrets are stored under the "secret" root and "parent". "Parent" either derived from the - secure data path by replacing "/" and "-", or manually provided by the user. - Secrets are wrapped into the pydantic.SecretStr. - - Example: - ```python - context = { - "secrets": { - "parent": { - "webhook": SecretStr("**********"), - "description": SecretStr("**********"), - } - } - } - ``` - - Values can be decoded like this: - ```python - context.secrets.parent.webhook.get_secret_value() - ``` - or if working with dictionary is preferable: - ```python - for key, value in context.get_all().items(): - value.get_secret_value() - ``` - """ - - url: str = Field(default=..., description="Cerberus URL, eg. https://cerberus.domain.com") - path: str = Field(default=..., description="Secure data path, eg. 'app/my-sdb/my-secrets'") - aws_session: Optional[Session] = Field( - default=None, description="AWS Session to pass to Cerberus client, can be used for local execution." - ) - token: Optional[SecretStr] = Field( - default=os.environ.get("CERBERUS_TOKEN", None), - description="Cerberus token, can be used for local development without AWS auth mechanism." - "Note: Token has priority over AWS session.", - ) - verbose: bool = Field(default=False, description="Enable verbose for Cerberus client") - - @model_validator(mode="before") - def _set_parent_to_path(cls, values): - """ - Set default value for `parent` parameter on model initialization when it was not - explicitly set by the user. In this scenario secure data path will be used: - - 'app/my-sdb/my-secrets' -> app_my_sdb_my_secrets - """ - regex = re.compile(r"[/-]") - path = values.get("path") - if not values.get("parent"): - values["parent"] = regex.sub("_", path) - return values - - @property - def _client(self): - """ - Instantiated Cerberus client. - """ - self.token: Optional[SecretStr] - token = self.token.get_secret_value() if self.token else None - - return CerberusClient(cerberus_url=self.url, token=token, aws_session=self.aws_session, verbose=self.verbose) - - def _get_secrets(self): - """ - Dictionary of secrets. - """ - return self._client.get_secrets_data(self.path)