From fd8162d5bf384ef666c01ef2c529d01fd9fa8354 Mon Sep 17 00:00:00 2001 From: Julius Hetzel Date: Fri, 23 Jun 2023 16:53:05 +0200 Subject: [PATCH 01/13] =?UTF-8?q?Check=20for=20the=20whole=20protocol=20in?= =?UTF-8?q?cluding=20delimited=20(://)=20when=20j=E2=80=A6=20(#271?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Check for the whole protocol including delimited (://) when joining path for partitions in partitioned data set Signed-off-by: Julius Hetzel * Add bugfix description to release nodes Signed-off-by: Julius Hetzel --------- Signed-off-by: Julius Hetzel --- RELEASE.md | 1 + kedro/io/partitioned_dataset.py | 7 ++++--- tests/io/test_partitioned_dataset.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index c8ffa1188a..260ebe289c 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -3,6 +3,7 @@ ## Major features and improvements ## Bug fixes and other changes +* Compare for protocol and delimiter in `PartitionedDataSet` to be able to pass the protocol to partitions which paths starts with the same characters as the protocol (e.g. `s3://s3-my-bucket`). ## Breaking changes to the API diff --git a/kedro/io/partitioned_dataset.py b/kedro/io/partitioned_dataset.py index 07b34ca65c..683abac283 100644 --- a/kedro/io/partitioned_dataset.py +++ b/kedro/io/partitioned_dataset.py @@ -263,10 +263,11 @@ def _list_partitions(self) -> list[str]: ] def _join_protocol(self, path: str) -> str: - if self._path.startswith(self._protocol) and not path.startswith( - self._protocol + protocol_prefix = f"{self._protocol}://" + if self._path.startswith(protocol_prefix) and not path.startswith( + protocol_prefix ): - return f"{self._protocol}://{path}" + return f"{protocol_prefix}{path}" return path def _partition_to_path(self, path: str): diff --git a/tests/io/test_partitioned_dataset.py b/tests/io/test_partitioned_dataset.py index 05993593ae..2d0af84a61 100644 --- a/tests/io/test_partitioned_dataset.py +++ b/tests/io/test_partitioned_dataset.py @@ -401,7 +401,7 @@ def test_dataset_creds(self, pds_config, expected_ds_creds, global_creds): assert pds._credentials == global_creds -BUCKET_NAME = "fake_bucket_name" +BUCKET_NAME = "s3_fake_bucket_name" S3_DATASET_DEFINITION = [ "pandas.CSVDataSet", "kedro.extras.datasets.pandas.CSVDataSet", From 2ec03adcad266e150a560f455fdcebd766737781 Mon Sep 17 00:00:00 2001 From: Nok Lam Chan Date: Mon, 26 Jun 2023 17:38:13 +0100 Subject: [PATCH 02/13] Fix PartitionedDataset tests (#2727) Signed-off-by: Nok Chan --- tests/io/test_partitioned_dataset.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/io/test_partitioned_dataset.py b/tests/io/test_partitioned_dataset.py index 2d0af84a61..97735a7380 100644 --- a/tests/io/test_partitioned_dataset.py +++ b/tests/io/test_partitioned_dataset.py @@ -401,7 +401,7 @@ def test_dataset_creds(self, pds_config, expected_ds_creds, global_creds): assert pds._credentials == global_creds -BUCKET_NAME = "s3_fake_bucket_name" +BUCKET_NAME = "fake_bucket_name" S3_DATASET_DEFINITION = [ "pandas.CSVDataSet", "kedro.extras.datasets.pandas.CSVDataSet", @@ -471,6 +471,19 @@ def test_load_s3a(self, mocked_csvs_in_s3, partitioned_data_pandas, mocker): ] mocked_ds.assert_has_calls(expected, any_order=True) + @pytest.mark.parametrize( + "partition_path", ["s3_bucket/dummy.csv", "fake_bucket/dummy.csv"] + ) + def test_join_protocol_with_bucket_name_startswith_protocol( + self, mocked_csvs_in_s3, partition_path + ): + """Make sure protocol is joined correctly for the edge case when + bucket name starts with the protocol name, i.e. `s3://s3_bucket/dummy_.txt` + """ + + pds = PartitionedDataset(mocked_csvs_in_s3, "pandas.CSVDataSet") + assert pds._join_protocol(partition_path) == f"s3://{partition_path}" + @pytest.mark.parametrize("dataset", S3_DATASET_DEFINITION) def test_save(self, dataset, mocked_csvs_in_s3): pds = PartitionedDataset(mocked_csvs_in_s3, dataset) From 4536caf70121f3eb483200b070a2438faaccd279 Mon Sep 17 00:00:00 2001 From: Nok Lam Chan Date: Tue, 27 Jun 2023 12:11:17 +0100 Subject: [PATCH 03/13] Update puppeteer-config.json for mermaid-cli headless warning (#2731) * Update puppeteer-config.json for mermaid-cli headless warning * Update conf.py --- docs/source/conf.py | 1 + docs/source/puppeteer-config.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4140dc4381..5624e36ed7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -551,6 +551,7 @@ def setup(app): # https://github.com/kedro-org/kedro/issues/1772 mermaid_output_format = "png" # https://github.com/mermaidjs/mermaid.cli#linux-sandbox-issue +# https://github.com/mermaid-js/mermaid-cli/issues/544 mermaid_params = ["-p", here / "puppeteer-config.json", "-s", "2"] # https://github.com/kedro-org/kedro/issues/2451 mermaid_version = mermaid_init_js = "" diff --git a/docs/source/puppeteer-config.json b/docs/source/puppeteer-config.json index 3201af7b73..5adc866e94 100644 --- a/docs/source/puppeteer-config.json +++ b/docs/source/puppeteer-config.json @@ -1,3 +1,4 @@ { - "args": ["--no-sandbox"] + "args": ["--no-sandbox"], + "headless": "old" } From 513341f3dcf6e3240c5a5419a0565769fe2ffc43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Luis=20Cano=20Rodr=C3=ADguez?= Date: Tue, 27 Jun 2023 16:27:51 +0200 Subject: [PATCH 04/13] Add debugging information for Windows tests (#2730) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add debugging information for Windows tests Signed-off-by: Juan Luis Cano Rodríguez * Add verbosity to unit tests Signed-off-by: Juan Luis Cano Rodríguez * Lift version caps for psutil to use wheels on modern Python Signed-off-by: Juan Luis Cano Rodríguez --------- Signed-off-by: Juan Luis Cano Rodríguez --- .circleci/continue_config.yml | 9 ++++++--- features/windows_reqs.txt | 2 +- test_requirements.txt | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.circleci/continue_config.yml b/.circleci/continue_config.yml index bd3c364e95..cedab70234 100644 --- a/.circleci/continue_config.yml +++ b/.circleci/continue_config.yml @@ -163,9 +163,12 @@ commands: - run: name: Install GDAL, Fiona and pytables command: conda activate kedro_builder; conda install gdal fiona pytables -c conda-forge -y + - run: + name: Show pip information + command: conda activate kedro_builder; pip debug --verbose - run: name: Install all requirements - command: conda activate kedro_builder; pip install -r test_requirements.txt -U + command: conda activate kedro_builder; pip install -v -r test_requirements.txt -U - run: name: Print Python environment command: conda activate kedro_builder; make print-python-env @@ -245,14 +248,14 @@ jobs: steps: - run: name: Run unit tests in parallel - command: make test + command: PYTEST_ADDOPTS="-v" make test - when: condition: equal: [ "3.10", <> ] steps: - run: name: Run unit tests sequentially - command: pytest tests --cov-config pyproject.toml + command: pytest -v tests --cov-config pyproject.toml win_unit_tests: diff --git a/features/windows_reqs.txt b/features/windows_reqs.txt index 191c9e7293..c41bf77a4d 100644 --- a/features/windows_reqs.txt +++ b/features/windows_reqs.txt @@ -3,7 +3,7 @@ # everything, so just this subset will be enough for CI behave==1.2.6 pandas~=1.3 -psutil==5.8.0 +psutil~=5.8 requests~=2.20 toml~=0.10.1 PyYAML>=4.2, <7.0 diff --git a/test_requirements.txt b/test_requirements.txt index 4683509a8b..5c81ebdc89 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -40,7 +40,7 @@ pandas~=1.3 # 1.3 for read_xml/to_xml Pillow~=9.0 plotly>=4.8.0, <6.0 pre-commit>=2.9.2, <3.0 # The hook `mypy` requires pre-commit version 2.9.2. -psutil==5.8.0 +psutil~=5.8 pyarrow>=1.0, <7.0 pylint>=2.17.0, <3.0 pyproj~=3.0 From 6e5e4e1258fe02f5195c7669b4c469b2706ef2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nok=20Lam=20Chan=20=E9=99=B3=E8=AB=BE=E6=9E=97?= Date: Wed, 28 Jun 2023 11:00:52 +0100 Subject: [PATCH 05/13] Make GitPod works (#2688) * update base image Signed-off-by: Nok * update gitpod image and apt-get Signed-off-by: Nok * update docker Signed-off-by: Nok --------- Signed-off-by: Nok --- .gitpod.Dockerfile | 13 +++++++++++++ .gitpod.yml | 30 ++++++++---------------------- 2 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 .gitpod.Dockerfile diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile new file mode 100644 index 0000000000..e03635f196 --- /dev/null +++ b/.gitpod.Dockerfile @@ -0,0 +1,13 @@ +FROM gitpod/workspace-full:2023-05-08-21-16-55 + +# Some datasets work on 3.8 only +RUN pyenv install 3.8.15\ + && pyenv global 3.8.15 + +# VideoDataSet +RUN sudo apt-get update && sudo apt-get install -y --no-install-recommends libgl1 +RUN sudo apt-get install make +RUN npm install -g @mermaid-js/mermaid-cli +# https://stackoverflow.com/questions/69564238/puppeteer-error-failed-to-launch-the-browser-process +# https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#chrome-doesnt-launch-on-linux +RUN sudo apt-get install -y --no-install-recommends libatk-bridge2.0-0 libcups2 ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils diff --git a/.gitpod.yml b/.gitpod.yml index b8fedd3f93..c2ec591de9 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,32 +1,18 @@ -image: gitpod/workspace-full:legacy-dazzle-v1 - +image: + file: .gitpod.Dockerfile tasks: - # We want packages installed during the pre-build init steps to go to /workspace - # rather than ~ so that they are persisted. Gitpod sets PIP_USER=yes to ensure this, - # but pre-commit requires PIP_USER=no. Hence we set PIP_USER=no and use - # pip install --user to install to /workspace. - name: kedro - before: | - echo PIP_USER=no >> ~/.bashrc && export PIP_USER=no + init: | make sign-off - pip install -r test_requirements.txt --user - gp sync-done kedro - command: | - pre-commit install --install-hooks - clear - # Generate a test Kedro project at /workspace/project using the local Kedro version. - - name: test-project - init: | - gp sync-await kedro - export PIP_USER=no + pip install -e /workspace/kedro cd /workspace - pip install -e /workspace/kedro --no-deps - source ~/.bashrc yes project | kedro new -s pandas-iris --checkout main + pip install -r /workspace/kedro/test_requirements.txt + cd /workspace/kedro + pre-commit install --install-hooks + command: | - pip install -e /workspace/kedro --no-deps - cd /workspace/project clear kedro info From c0d246fbef0e9e79df8c0dd889440ac0983455f6 Mon Sep 17 00:00:00 2001 From: Deepyaman Datta Date: Wed, 28 Jun 2023 05:47:20 -0500 Subject: [PATCH 06/13] Remove `DeprecatedClassMeta` in favor of `getattr` (#2724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Complete build requirements Signed-off-by: Juan Luis Cano Rodríguez * Add timeout for e2e process waiting Signed-off-by: Juan Luis Cano Rodríguez * Remove DeprecatedClassMeta in favor of getattr Fix https://github.com/kedro-org/kedro-starters/issues/137 Signed-off-by: Juan Luis Cano Rodríguez * Ignore deprecation warnings in our own code Signed-off-by: Juan Luis Cano Rodríguez --------- Signed-off-by: Juan Luis Cano Rodríguez Co-authored-by: Juan Luis Cano Rodríguez Co-authored-by: Deepyaman Datta --- features/jupyter.feature | 2 +- features/steps/cli_steps.py | 6 +-- kedro/io/__init__.py | 23 ++++++---- kedro/io/cached_dataset.py | 20 ++++++--- kedro/io/lambda_dataset.py | 20 ++++++--- kedro/io/memory_dataset.py | 20 ++++++--- kedro/io/partitioned_dataset.py | 36 +++++++++------ kedro/runner/parallel_runner.py | 20 ++++++--- kedro/utils.py | 65 ---------------------------- pyproject.toml | 1 + tests/runner/test_parallel_runner.py | 7 +++ tests/test_utils.py | 52 +--------------------- 12 files changed, 110 insertions(+), 162 deletions(-) diff --git a/features/jupyter.feature b/features/jupyter.feature index 188d07f2f4..65b5173442 100644 --- a/features/jupyter.feature +++ b/features/jupyter.feature @@ -22,6 +22,6 @@ Feature: Jupyter targets in new project Given I have added a test jupyter notebook When I execute the test jupyter notebook and save changes And I execute the kedro jupyter command "convert --all" - And Wait until the process is finished + And Wait until the process is finished for up to "120" seconds Then I should get a successful exit code And Code cell with node tag should be converted into kedro node diff --git a/features/steps/cli_steps.py b/features/steps/cli_steps.py index 76bb0d2722..0008841de4 100644 --- a/features/steps/cli_steps.py +++ b/features/steps/cli_steps.py @@ -352,10 +352,10 @@ def wait_for_notebook_to_run(context, timeout): raise TimeoutError("Failed to run Jupyter server in time") -@when("Wait until the process is finished") -def wait(context): +@when('Wait until the process is finished for up to "{timeout:d}" seconds') +def wait(context, timeout): """Wait for child process to terminate.""" - context.result.wait() + context.result.wait(timeout) @when("I execute the test jupyter notebook and save changes") diff --git a/kedro/io/__init__.py b/kedro/io/__init__.py index 5899f904c6..2888b9f79c 100644 --- a/kedro/io/__init__.py +++ b/kedro/io/__init__.py @@ -3,7 +3,9 @@ """ from __future__ import annotations -from .cached_dataset import CachedDataSet, CachedDataset +import warnings + +from .cached_dataset import CachedDataset from .core import ( AbstractDataSet, AbstractVersionedDataSet, @@ -13,14 +15,17 @@ Version, ) from .data_catalog import DataCatalog -from .lambda_dataset import LambdaDataSet, LambdaDataset -from .memory_dataset import MemoryDataSet, MemoryDataset -from .partitioned_dataset import ( - IncrementalDataSet, - IncrementalDataset, - PartitionedDataSet, - PartitionedDataset, -) +from .lambda_dataset import LambdaDataset +from .memory_dataset import MemoryDataset +from .partitioned_dataset import IncrementalDataset, PartitionedDataset + +with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + from .cached_dataset import CachedDataSet + from .lambda_dataset import LambdaDataSet + from .memory_dataset import MemoryDataSet + from .partitioned_dataset import IncrementalDataSet, PartitionedDataSet + # https://github.com/pylint-dev/pylint/issues/4300#issuecomment-1043601901 DataSetError: type[Exception] diff --git a/kedro/io/cached_dataset.py b/kedro/io/cached_dataset.py index 21e60ab3ef..ed03983b37 100644 --- a/kedro/io/cached_dataset.py +++ b/kedro/io/cached_dataset.py @@ -5,11 +5,14 @@ from __future__ import annotations import logging +import warnings from typing import Any from kedro.io.core import VERSIONED_FLAG_KEY, AbstractDataSet, Version from kedro.io.memory_dataset import MemoryDataset -from kedro.utils import DeprecatedClassMeta + +# https://github.com/pylint-dev/pylint/issues/4300#issuecomment-1043601901 +CachedDataSet: AbstractDataSet class CachedDataset(AbstractDataSet): @@ -120,7 +123,14 @@ def __getstate__(self): return self.__dict__ -class CachedDataSet(metaclass=DeprecatedClassMeta): - # pylint: disable=missing-class-docstring, too-few-public-methods - - _DeprecatedClassMeta__alias = CachedDataset +def __getattr__(name): + if name == "CachedDataSet": + alias = CachedDataset + warnings.warn( + f"{repr(name)} has been renamed to {repr(alias.__name__)}, " + f"and the alias will be removed in Kedro 0.19.0", + DeprecationWarning, + stacklevel=2, + ) + return alias + raise AttributeError(f"module {repr(__name__)} has no attribute {repr(name)}") diff --git a/kedro/io/lambda_dataset.py b/kedro/io/lambda_dataset.py index 7dc96df75e..70378eac92 100644 --- a/kedro/io/lambda_dataset.py +++ b/kedro/io/lambda_dataset.py @@ -4,10 +4,13 @@ """ from __future__ import annotations +import warnings from typing import Any, Callable from kedro.io.core import AbstractDataSet, DatasetError -from kedro.utils import DeprecatedClassMeta + +# https://github.com/pylint-dev/pylint/issues/4300#issuecomment-1043601901 +LambdaDataSet: AbstractDataSet class LambdaDataset(AbstractDataSet): @@ -121,7 +124,14 @@ def __init__( self.metadata = metadata -class LambdaDataSet(metaclass=DeprecatedClassMeta): - # pylint: disable=missing-class-docstring, too-few-public-methods - - _DeprecatedClassMeta__alias = LambdaDataset +def __getattr__(name): + if name == "LambdaDataSet": + alias = LambdaDataset + warnings.warn( + f"{repr(name)} has been renamed to {repr(alias.__name__)}, " + f"and the alias will be removed in Kedro 0.19.0", + DeprecationWarning, + stacklevel=2, + ) + return alias + raise AttributeError(f"module {repr(__name__)} has no attribute {repr(name)}") diff --git a/kedro/io/memory_dataset.py b/kedro/io/memory_dataset.py index 349523c5d3..808fac8f81 100644 --- a/kedro/io/memory_dataset.py +++ b/kedro/io/memory_dataset.py @@ -3,13 +3,16 @@ from __future__ import annotations import copy +import warnings from typing import Any from kedro.io.core import AbstractDataSet, DatasetError -from kedro.utils import DeprecatedClassMeta _EMPTY = object() +# https://github.com/pylint-dev/pylint/issues/4300#issuecomment-1043601901 +MemoryDataSet: AbstractDataSet + class MemoryDataset(AbstractDataSet): """``MemoryDataset`` loads and saves data from/to an in-memory @@ -139,7 +142,14 @@ def _copy_with_mode(data: Any, copy_mode: str) -> Any: return copied_data -class MemoryDataSet(metaclass=DeprecatedClassMeta): - # pylint: disable=missing-class-docstring, too-few-public-methods - - _DeprecatedClassMeta__alias = MemoryDataset +def __getattr__(name): + if name == "MemoryDataSet": + alias = MemoryDataset + warnings.warn( + f"{repr(name)} has been renamed to {repr(alias.__name__)}, " + f"and the alias will be removed in Kedro 0.19.0", + DeprecationWarning, + stacklevel=2, + ) + return alias + raise AttributeError(f"module {repr(__name__)} has no attribute {repr(name)}") diff --git a/kedro/io/partitioned_dataset.py b/kedro/io/partitioned_dataset.py index 683abac283..67ab51df3d 100644 --- a/kedro/io/partitioned_dataset.py +++ b/kedro/io/partitioned_dataset.py @@ -4,10 +4,10 @@ from __future__ import annotations import operator +import warnings from copy import deepcopy from typing import Any, Callable from urllib.parse import urlparse -from warnings import warn from cachetools import Cache, cachedmethod @@ -19,7 +19,7 @@ parse_dataset_definition, ) from kedro.io.data_catalog import CREDENTIALS_KEY -from kedro.utils import DeprecatedClassMeta, load_obj +from kedro.utils import load_obj DATASET_CREDENTIALS_KEY = "dataset_credentials" CHECKPOINT_CREDENTIALS_KEY = "checkpoint_credentials" @@ -31,6 +31,10 @@ S3_PROTOCOLS = ("s3", "s3a", "s3n") +# https://github.com/pylint-dev/pylint/issues/4300#issuecomment-1043601901 +PartitionedDataSet: AbstractDataSet +IncrementalDataSet: AbstractDataSet + class PartitionedDataset(AbstractDataSet): # pylint: disable=too-many-instance-attributes,protected-access @@ -230,7 +234,7 @@ def __init__( # pylint: disable=too-many-arguments self._filepath_arg = filepath_arg if self._filepath_arg in self._dataset_config: - warn( + warnings.warn( f"'{self._filepath_arg}' key must not be specified in the dataset " f"definition as it will be overwritten by partition path" ) @@ -338,12 +342,6 @@ def _release(self) -> None: self._invalidate_caches() -class PartitionedDataSet(metaclass=DeprecatedClassMeta): - # pylint: disable=missing-class-docstring, too-few-public-methods - - _DeprecatedClassMeta__alias = PartitionedDataset - - class IncrementalDataset(PartitionedDataset): """``IncrementalDataset`` inherits from ``PartitionedDataset``, which loads and saves partitioned file-like data using the underlying dataset @@ -560,8 +558,20 @@ def confirm(self) -> None: self._checkpoint.save(partition_ids[-1]) # checkpoint to last partition -class IncrementalDataSet(metaclass=DeprecatedClassMeta): - # pylint: disable=missing-class-docstring, too-few-public-methods +_DEPRECATED_ERROR_CLASSES = { + "PartitionedDataSet": PartitionedDataset, + "IncrementalDataSet": IncrementalDataset, +} + - # pylint: disable=unused-private-member - __DeprecatedClassMeta__alias = IncrementalDataset +def __getattr__(name): + if name in _DEPRECATED_ERROR_CLASSES: + alias = _DEPRECATED_ERROR_CLASSES[name] + warnings.warn( + f"{repr(name)} has been renamed to {repr(alias.__name__)}, " + f"and the alias will be removed in Kedro 0.19.0", + DeprecationWarning, + stacklevel=2, + ) + return alias + raise AttributeError(f"module {repr(__name__)} has no attribute {repr(name)}") diff --git a/kedro/runner/parallel_runner.py b/kedro/runner/parallel_runner.py index fd0fa7d097..542dc74d63 100644 --- a/kedro/runner/parallel_runner.py +++ b/kedro/runner/parallel_runner.py @@ -7,6 +7,7 @@ import os import pickle import sys +import warnings from collections import Counter from concurrent.futures import FIRST_COMPLETED, ProcessPoolExecutor, wait from itertools import chain @@ -27,11 +28,13 @@ from kedro.pipeline import Pipeline from kedro.pipeline.node import Node from kedro.runner.runner import AbstractRunner, run_node -from kedro.utils import DeprecatedClassMeta # see https://github.com/python/cpython/blob/master/Lib/concurrent/futures/process.py#L114 _MAX_WINDOWS_WORKERS = 61 +# https://github.com/pylint-dev/pylint/issues/4300#issuecomment-1043601901 +_SharedMemoryDataSet: Any + class _SharedMemoryDataset: """``_SharedMemoryDataset`` is a wrapper class for a shared MemoryDataset in SyncManager. @@ -70,10 +73,17 @@ def save(self, data: Any): raise exc -class _SharedMemoryDataSet(metaclass=DeprecatedClassMeta): - # pylint: disable=too-few-public-methods - - _DeprecatedClassMeta__alias = _SharedMemoryDataset +def __getattr__(name): + if name == "_SharedMemoryDataSet": + alias = _SharedMemoryDataset + warnings.warn( + f"{repr(name)} has been renamed to {repr(alias.__name__)}, " + f"and the alias will be removed in Kedro 0.19.0", + DeprecationWarning, + stacklevel=2, + ) + return alias + raise AttributeError(f"module {repr(__name__)} has no attribute {repr(name)}") class ParallelRunnerManager(SyncManager): diff --git a/kedro/utils.py b/kedro/utils.py index 380372853c..6067d96b6c 100644 --- a/kedro/utils.py +++ b/kedro/utils.py @@ -3,7 +3,6 @@ """ import importlib from typing import Any -from warnings import warn def load_obj(obj_path: str, default_obj_path: str = "") -> Any: @@ -27,67 +26,3 @@ def load_obj(obj_path: str, default_obj_path: str = "") -> Any: if not hasattr(module_obj, obj_name): raise AttributeError(f"Object '{obj_name}' cannot be loaded from '{obj_path}'.") return getattr(module_obj, obj_name) - - -class DeprecatedClassMeta(type): - """Metaclass for constructing deprecated aliases of renamed classes. - - Code implementation copied from https://stackoverflow.com/a/52087847 - """ - - def __new__(mcs, name, bases, classdict, *args, **kwargs): - alias = classdict.get("_DeprecatedClassMeta__alias") - - if alias is not None: - - def new(mcs, *args, **kwargs): - alias = getattr(mcs, "_DeprecatedClassMeta__alias") - - if alias is not None: - warn( - f"{repr(mcs.__name__)} has been renamed to " - f"{repr(alias.__name__)}, and the alias will " - f"be removed in Kedro 0.19.0", - DeprecationWarning, - stacklevel=2, - ) - - return alias(*args, **kwargs) - - classdict["__new__"] = new - classdict["_DeprecatedClassMeta__alias"] = alias - - fixed_bases = [] - - for base in bases: - alias = getattr(base, "_DeprecatedClassMeta__alias", None) - - if alias is not None: - warn( - f"{repr(base.__name__)} has been renamed to " - f"{repr(alias.__name__)}, and the alias will be " - f"removed in Kedro 0.19.0", - DeprecationWarning, - stacklevel=2, - ) - - # Avoid duplicate base classes. - base = alias or base - if base not in fixed_bases: - fixed_bases.append(base) - - fixed_bases = tuple(fixed_bases) - - return super().__new__(mcs, name, fixed_bases, classdict, *args, **kwargs) - - def __instancecheck__(cls, instance): - return any( - # pylint: disable=no-value-for-parameter - cls.__subclasscheck__(c) - for c in [type(instance), instance.__class__] - ) - - def __subclasscheck__(cls, subclass): - return subclass is cls or issubclass( - subclass, getattr(cls, "_DeprecatedClassMeta__alias") - ) diff --git a/pyproject.toml b/pyproject.toml index 8cdf924f8e..ec06b75d5f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,6 +2,7 @@ [build-system] # Minimum requirements for the build system to execute. requires = ["setuptools>=65.5.1"] # PEP 518 specifications +build-backend = "setuptools.build_meta" [project] name = "kedro" diff --git a/tests/runner/test_parallel_runner.py b/tests/runner/test_parallel_runner.py index 5b5d37c98a..6870561d8d 100644 --- a/tests/runner/test_parallel_runner.py +++ b/tests/runner/test_parallel_runner.py @@ -1,5 +1,6 @@ from __future__ import annotations +import importlib import sys from concurrent.futures.process import ProcessPoolExecutor from typing import Any @@ -33,6 +34,12 @@ ) +def test_deprecation(): + class_name = "_SharedMemoryDataSet" + with pytest.warns(DeprecationWarning, match=f"{repr(class_name)} has been renamed"): + getattr(importlib.import_module("kedro.runner.parallel_runner"), class_name) + + @pytest.mark.skipif( sys.platform.startswith("win"), reason="Due to bug in parallel runner" ) diff --git a/tests/test_utils.py b/tests/test_utils.py index b6ebe9e95a..4e99f3f726 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,7 +2,7 @@ import pytest -from kedro.utils import DeprecatedClassMeta, load_obj +from kedro.utils import load_obj # pylint: disable=too-few-public-methods @@ -28,53 +28,3 @@ def test_load_obj_invalid_attribute(self): def test_load_obj_invalid_module(self): with pytest.raises(ImportError, match=r"No module named 'missing_path'"): load_obj("InvalidClass", "missing_path") - - -class NewClass: - value = 1 - - -class NewClassSubclass(NewClass): - pass - - -class DeprecatedClass(metaclass=DeprecatedClassMeta): - _DeprecatedClassMeta__alias = NewClass - - -class DeprecatedClassSubclass(DeprecatedClass): - value = 2 - - -class DeprecatedClassSubSubclass(DeprecatedClassSubclass): - value = 3 - - -class TestDeprecatedClassMeta: - def test_is_subclass_of_deprecated_class(self): - assert issubclass(DeprecatedClass, DeprecatedClass) - assert issubclass(DeprecatedClassSubclass, DeprecatedClass) - assert issubclass(DeprecatedClassSubSubclass, DeprecatedClass) - assert issubclass(NewClass, DeprecatedClass) - assert issubclass(NewClassSubclass, DeprecatedClass) - - def test_is_subclass_of_new_class(self): - assert issubclass(DeprecatedClassSubclass, NewClass) - assert issubclass(DeprecatedClassSubSubclass, NewClass) - - def test_is_instance_of_deprecated_class(self): - assert isinstance(DeprecatedClass(), DeprecatedClass) - assert isinstance(DeprecatedClassSubclass(), DeprecatedClass) - assert isinstance(DeprecatedClassSubSubclass(), DeprecatedClass) - assert isinstance(NewClass(), DeprecatedClass) - assert isinstance(NewClassSubclass(), DeprecatedClass) - - def test_is_instance_of_new_class(self): - assert isinstance(DeprecatedClassSubclass(), NewClass) - assert isinstance(DeprecatedClassSubSubclass(), NewClass) - - def test_inheritance(self): - assert NewClass().value == 1 - assert DeprecatedClass().value == 1 # pylint: disable=no-member - assert DeprecatedClassSubclass().value == 2 - assert DeprecatedClassSubSubclass().value == 3 From 931366f59b0b79a5db46cc1ab3b6e43affec94a3 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Date: Wed, 28 Jun 2023 15:47:26 +0100 Subject: [PATCH 07/13] FIX: Typo in cli help (#2737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FIX: Typo in cli help Signed-off-by: debugger24 * Make GitPod works (#2688) * update base image Signed-off-by: Nok * update gitpod image and apt-get Signed-off-by: Nok * update docker Signed-off-by: Nok --------- Signed-off-by: Nok Signed-off-by: debugger24 * Remove `DeprecatedClassMeta` in favor of `getattr` (#2724) * Complete build requirements Signed-off-by: Juan Luis Cano Rodríguez * Add timeout for e2e process waiting Signed-off-by: Juan Luis Cano Rodríguez * Remove DeprecatedClassMeta in favor of getattr Fix https://github.com/kedro-org/kedro-starters/issues/137 Signed-off-by: Juan Luis Cano Rodríguez * Ignore deprecation warnings in our own code Signed-off-by: Juan Luis Cano Rodríguez --------- Signed-off-by: Juan Luis Cano Rodríguez Co-authored-by: Juan Luis Cano Rodríguez Co-authored-by: Deepyaman Datta Signed-off-by: debugger24 --------- Signed-off-by: debugger24 Signed-off-by: Nok Signed-off-by: Juan Luis Cano Rodríguez Co-authored-by: Nok Lam Chan 陳諾林 Co-authored-by: Deepyaman Datta Co-authored-by: Juan Luis Cano Rodríguez --- kedro/framework/cli/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kedro/framework/cli/project.py b/kedro/framework/cli/project.py index 73f4bfc912..034b460023 100644 --- a/kedro/framework/cli/project.py +++ b/kedro/framework/cli/project.py @@ -44,7 +44,7 @@ TO_NODES_HELP = """A list of node names which should be used as an end point.""" NODE_ARG_HELP = """Run only nodes with specified names.""" RUNNER_ARG_HELP = """Specify a runner that you want to run the pipeline with. -Available runners: 'SequentialRunner', 'ParallelRunner' and 'ThreadRun'.""" +Available runners: 'SequentialRunner', 'ParallelRunner' and 'ThreadRunner'.""" ASYNC_ARG_HELP = """Load and save node inputs and outputs asynchronously with threads. If not specified, load and save datasets synchronously.""" TAG_ARG_HELP = """Construct the pipeline using only nodes which have this tag From 2f3811aeab25c25fba8476f1152651753e85ee7e Mon Sep 17 00:00:00 2001 From: Jannic <37243923+jmholzer@users.noreply.github.com> Date: Wed, 28 Jun 2023 17:02:27 +0100 Subject: [PATCH 08/13] Add databricks-iris as an official starter (#2739) Signed-off-by: Jannic Holzer --- RELEASE.md | 1 + kedro/framework/cli/starters.py | 1 + 2 files changed, 2 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index 260ebe289c..b2b3280e29 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -12,6 +12,7 @@ # Upcoming Release 0.18.11 ## Major features and improvements +* Added `databricks-iris` as an official starter. ## Bug fixes and other changes * Reworked micropackaging workflow to use standard Python packaging practices. diff --git a/kedro/framework/cli/starters.py b/kedro/framework/cli/starters.py index d7a7015987..77491d391f 100644 --- a/kedro/framework/cli/starters.py +++ b/kedro/framework/cli/starters.py @@ -69,6 +69,7 @@ class KedroStarterSpec: # pylint: disable=too-few-public-methods KedroStarterSpec("pyspark", _STARTERS_REPO, "pyspark"), KedroStarterSpec("pyspark-iris", _STARTERS_REPO, "pyspark-iris"), KedroStarterSpec("spaceflights", _STARTERS_REPO, "spaceflights"), + KedroStarterSpec("databricks-iris", _STARTERS_REPO, "databricks-iris"), ] # Set the origin for official starters for starter_spec in _OFFICIAL_STARTER_SPECS: From 9c49a65da88bb9cbbbe0ae9b6dbccf11dc2d3021 Mon Sep 17 00:00:00 2001 From: Deepyaman Datta Date: Fri, 30 Jun 2023 09:12:04 -0600 Subject: [PATCH 09/13] Do not unsuppress `DeprecationWarning`s with Kedro (#2747) * Do not unsuppress `DeprecationWarning`s with Kedro Signed-off-by: Deepyaman Datta * Remove unused import Signed-off-by: Deepyaman Datta --------- Signed-off-by: Deepyaman Datta --- kedro/io/__init__.py | 23 +++++++++-------------- kedro/io/core.py | 2 -- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/kedro/io/__init__.py b/kedro/io/__init__.py index 2888b9f79c..351c7f510e 100644 --- a/kedro/io/__init__.py +++ b/kedro/io/__init__.py @@ -3,9 +3,7 @@ """ from __future__ import annotations -import warnings - -from .cached_dataset import CachedDataset +from .cached_dataset import CachedDataset, CachedDataSet from .core import ( AbstractDataSet, AbstractVersionedDataSet, @@ -15,17 +13,14 @@ Version, ) from .data_catalog import DataCatalog -from .lambda_dataset import LambdaDataset -from .memory_dataset import MemoryDataset -from .partitioned_dataset import IncrementalDataset, PartitionedDataset - -with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - from .cached_dataset import CachedDataSet - from .lambda_dataset import LambdaDataSet - from .memory_dataset import MemoryDataSet - from .partitioned_dataset import IncrementalDataSet, PartitionedDataSet - +from .lambda_dataset import LambdaDataset, LambdaDataSet +from .memory_dataset import MemoryDataset, MemoryDataSet +from .partitioned_dataset import ( + IncrementalDataset, + IncrementalDataSet, + PartitionedDataset, + PartitionedDataSet, +) # https://github.com/pylint-dev/pylint/issues/4300#issuecomment-1043601901 DataSetError: type[Exception] diff --git a/kedro/io/core.py b/kedro/io/core.py index fd90d25b8f..c0e6ee48e0 100644 --- a/kedro/io/core.py +++ b/kedro/io/core.py @@ -22,8 +22,6 @@ from kedro.utils import load_obj -warnings.simplefilter("default", DeprecationWarning) - VERSION_FORMAT = "%Y-%m-%dT%H.%M.%S.%fZ" VERSIONED_FLAG_KEY = "versioned" VERSION_KEY = "version" From 574cff11810dfd51885c75aebbfa3dccc265a8b2 Mon Sep 17 00:00:00 2001 From: Juan Manuel Lovera <8958924+jmalovera10@users.noreply.github.com> Date: Mon, 3 Jul 2023 05:27:41 -0500 Subject: [PATCH 10/13] Add Prefect 2.0 guide for simple deployment with agent on localhost (#2748) * Add Prefect 2.0 guide for simple deployment with agent Add a step by step deployment guide for Kedro with Prefect 2.0. The guide includes a basic example of leveraging local resources with an agent that pulls from a work pool Signed-off-by: Juan Lovera <8958924+jmalovera10@users.noreply.github.com> * Include introduction section suggestions Clarify on the conditions in which this guide was executed and better orient the developer to earlier versions for documentation on Prefect 1.0. Fix redaction on second paragraph. Signed-off-by: Juan Lovera <8958924+jmalovera10@users.noreply.github.com> --------- Signed-off-by: Juan Lovera <8958924+jmalovera10@users.noreply.github.com> Co-authored-by: Jo Stichbury --- docs/source/deployment/prefect.md | 366 +++++++++--------- .../meta/images/prefect_2_flow_deployment.png | Bin 0 -> 28010 bytes .../meta/images/prefect_2_flow_details.png | Bin 0 -> 89931 bytes 3 files changed, 193 insertions(+), 173 deletions(-) create mode 100644 docs/source/meta/images/prefect_2_flow_deployment.png create mode 100644 docs/source/meta/images/prefect_2_flow_details.png diff --git a/docs/source/deployment/prefect.md b/docs/source/deployment/prefect.md index 556097faa6..64d1018984 100644 --- a/docs/source/deployment/prefect.md +++ b/docs/source/deployment/prefect.md @@ -1,40 +1,70 @@ # Prefect -This page explains how to run your Kedro pipeline using [Prefect Core](https://www.prefect.io/products/core/), an open-source workflow management system. +This page explains how to run your Kedro pipeline using [Prefect 2.0](https://www.prefect.io/products/core/), an open-source workflow management system. -In scope of this deployment, we are interested in [Prefect Server](https://docs.prefect.io/orchestration/server/overview.html#what-is-prefect-server), an open-source backend that makes it easy to monitor and execute your Prefect flows and automatically extends the Prefect Core. Prefect Server ships out-of-the-box with a fully featured user interface. +The scope of this documentation is the deployment to a self hosted [Prefect Server](https://docs.prefect.io/2.10.17/host/), which is an open-source backend that makes it easy to monitor and execute your Prefect flows and automatically extends Prefect 2.0. We will use an [Agent that dequeues submitted flow runs from a Work Queue](https://docs.prefect.io/2.10.17/tutorial/deployments/#why-workpools-and-workers). ```{note} -This deployment has been tested using kedro 0.17.6, 0.17.7 and 0.18.2 with prefect version 1.1.0. - -The current implementation has not been tested with prefect 2.0.0. +This deployment has been tested using Kedro 0.18.10 with Prefect version 2.10.17. If you want to deploy with Prefect 1.0, we recommend you review [earlier versions of Kedro's Prefect deployment documentation](https://docs.kedro.org/en/0.18.9/deployment/prefect.html). ``` ## Prerequisites -To use Prefect Core and Prefect Server, ensure you have the following prerequisites in place: +To use Prefect 2.0 and Prefect Server, ensure you have the following prerequisites in place: + +- [Prefect 2.0 is installed](https://docs.prefect.io/2.10.17/getting-started/installation/#installing-the-latest-version) on your machine + +## Setup + +Configure your `PREFECT_API_URL` to point to your local Prefect instance: + +```bash +prefect config set PREFECT_API_URL="http://127.0.0.1:4200/api" +``` + +For each new Kedro project you create, you need to decide whether to opt into [usage analytics](https://github.com/kedro-org/kedro-plugins/tree/main/kedro-telemetry). Your decision is recorded in the `.telemetry` file stored in the project root. + +```{important} +When you run a Kedro project locally, you are asked on the first `kedro` command for the project, but in this use case, the project will hang unless you follow these instructions. +``` + +Create a `.telemetry` file manually and put it in the **root of your Kedro project** and add your preference to give or decline consent. To do this, specify either `true` (to give consent) or `false`. The example given below accepts Kedro's usage analytics. + +```text +consent: true +``` -- [Prefect Core is installed](https://docs.prefect.io/core/getting_started/install.html) on your machine -- [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) are installed and Docker Engine is running -- [Prefect Server is up and running](https://docs.prefect.io/orchestration/Server/deploy-local.html) -- `PREFECT__LOGGING__EXTRA_LOGGERS` environment variable is set (this is required to get Kedro logs published): +Run a Prefect Server instance: -```console -export PREFECT__LOGGING__EXTRA_LOGGERS="['kedro']" +```bash +prefect server start ``` -## How to run your Kedro pipeline using Prefect +In a separate terminal, [create a work pool](https://docs.prefect.io/2.10.17/concepts/work-pools/#work-pool-configuration) to organize the work and [create a work queue](https://docs.prefect.io/2.10.17/concepts/work-pools/#work-queues) for your agent to pull from: -### Convert your Kedro pipeline to Prefect flow +```bash +prefect work-pool create --type prefect-agent +prefect work-queue create --pool +``` + +Now run a Prefect Agent that subscribes to a work queue inside the work pool you created: + +```bash +prefect agent start --pool --work-queue +``` -To build a [Prefect flow](https://docs.prefect.io/core/concepts/flows.html) for your Kedro pipeline programmatically and register it with the Prefect API, use the following Python script, which should be stored in your project’s root directory: +## How to run your Kedro pipeline using Prefect 2.0 + +### Convert your Kedro pipeline to Prefect 2.0 flow + +To build a [Prefect flow](https://docs.prefect.io/core/concepts/flows.html) for your Kedro pipeline programmatically and register it with the Prefect API, use the following Python script, which should be stored in your project’s **root directory**: ```python # /register_prefect_flow.py +import click from pathlib import Path -from typing import Any, Dict, List, Tuple, Union +from typing import Dict, List, Union, Callable -import click from kedro.framework.hooks.manager import _create_hook_manager from kedro.framework.project import pipelines from kedro.framework.session import KedroSession @@ -42,204 +72,194 @@ from kedro.framework.startup import bootstrap_project from kedro.io import DataCatalog, MemoryDataSet from kedro.pipeline.node import Node from kedro.runner import run_node -from prefect import Client, Flow, Task -from prefect.exceptions import ClientError + +from prefect import flow, task, get_run_logger +from prefect.deployments import Deployment @click.command() -@click.option("-p", "--pipeline", "pipeline_name", default=None) -@click.option("--env", "-e", type=str, default=None) -@click.option("--package_name", "package_name", default="kedro_prefect") -def prefect_deploy(pipeline_name, env, package_name): +@click.option("-p", "--pipeline", "pipeline_name", default="__default__") +@click.option("--env", "-e", type=str, default="base") +@click.option("--deployment_name", "deployment_name", default="example") +@click.option("--work_pool_name", "work_pool_name", default="default") +@click.option("--work_queue_name", "work_queue_name", default="default") +@click.option("--version", "version", default="1.0") +def prefect_deploy( + pipeline_name, env, deployment_name, work_pool_name, work_queue_name, version +): """Register a Kedro pipeline as a Prefect flow.""" - # Project path and metadata required for session initialization task. + # Pipeline name to execute + pipeline_name = pipeline_name or "__default__" + + # Use standard deployment configuration for local execution. If you require a different + # infrastructure, check the API docs for Deployments at: https://docs.prefect.io/latest/api-ref/prefect/deployments/ + deployment = Deployment.build_from_flow( + flow=my_flow, + name=deployment_name, + path=str(Path.cwd()), + version=version, + parameters={ + "pipeline_name": pipeline_name, + "env": env, + }, + infra_overrides={"env": {"PREFECT_LOGGING_LEVEL": "DEBUG"}}, + work_pool_name=work_pool_name, + work_queue_name=work_queue_name, + ) + + deployment.apply() + + +@flow(name="my_flow") +def my_flow(pipeline_name: str, env: str): + logger = get_run_logger() project_path = Path.cwd() + metadata = bootstrap_project(project_path) + logger.info("Project name: %s", metadata.project_name) - pipeline_name = pipeline_name or "__default__" - pipeline = pipelines.get(pipeline_name) + logger.info("Initializing Kedro...") + execution_config = kedro_init( + pipeline_name=pipeline_name, project_path=project_path, env=env + ) + + logger.info("Building execution layers...") + execution_layers = init_kedro_tasks_by_execution_layer( + pipeline_name, execution_config + ) + + for layer in execution_layers: + logger.info("Running layer...") + for node_task in layer: + logger.info("Running node...") + node_task() - tasks = {} - for node, parent_nodes in pipeline.node_dependencies.items(): - # Use a function for task instantiation which avoids duplication of - # tasks - _, tasks = instantiate_task(node, tasks) - parent_tasks = [] - for parent in parent_nodes: - parent_task, tasks = instantiate_task(parent, tasks) - parent_tasks.append(parent_task) +@task() +def kedro_init( + pipeline_name: str, + project_path: Path, + env: str, +): + """ + Initializes a Kedro session and returns the DataCatalog and + KedroSession + """ + # bootstrap project within task / flow scope - tasks[node._unique_key]["parent_tasks"] = parent_tasks + logger = get_run_logger() + logger.info("Bootstrapping project") + bootstrap_project(project_path) - # Below task is used to instantiate a KedroSession within the scope of a - # Prefect flow - init_task = KedroInitTask( - pipeline_name=pipeline_name, + session = KedroSession.create( project_path=project_path, - package_name=package_name, env=env, ) + # Note that for logging inside a Prefect task logger is used. + logger.info("Session created with ID %s", session.session_id) + pipeline = pipelines.get(pipeline_name) + logger.info("Loading context...") + context = session.load_context() + catalog = context.catalog + logger.info("Registering datasets...") + unregistered_ds = pipeline.data_sets() - set(catalog.list()) # NOQA + for ds_name in unregistered_ds: + catalog.add(ds_name, MemoryDataSet()) + return {"catalog": catalog, "sess_id": session.session_id} + + +def init_kedro_tasks_by_execution_layer( + pipeline_name: str, + execution_config: Union[None, Dict[str, Union[DataCatalog, str]]] = None, +) -> List[List[Callable]]: + """ + Inits the Kedro tasks ordered topologically in groups, which implies that an earlier group + is the dependency of later one. - with Flow(pipeline_name) as flow: - generate_flow(init_task, tasks) - instantiate_client(metadata.project_name) - - # Register the flow with the server - flow.register(project_name=metadata.project_name) - - # Start a local agent that can communicate between the server - # and your flow code - flow.run_agent() - - -class KedroInitTask(Task): - """Task to initialize KedroSession""" - - def __init__( - self, - pipeline_name: str, - package_name: str, - project_path: Union[Path, str] = None, - env: str = None, - extra_params: Dict[str, Any] = None, - *args, - **kwargs, - ): - self.project_path = Path(project_path or Path.cwd()).resolve() - self.extra_params = extra_params - self.pipeline_name = pipeline_name - self.env = env - super().__init__(name=f"{package_name}_init", *args, **kwargs) - - def run(self) -> Dict[str, Union[DataCatalog, str]]: - """ - Initializes a Kedro session and returns the DataCatalog and - KedroSession - """ - # bootstrap project within task / flow scope - bootstrap_project(self.project_path) - - session = KedroSession.create( - project_path=self.project_path, - env=self.env, - extra_params=self.extra_params, # noqa: E501 - ) - # Note that for logging inside a Prefect task self.logger is used. - self.logger.info("Session created with ID %s", session.session_id) - pipeline = pipelines.get(self.pipeline_name) - context = session.load_context() - catalog = context.catalog - unregistered_ds = pipeline.data_sets() - set(catalog.list()) # NOQA - for ds_name in unregistered_ds: - catalog.add(ds_name, MemoryDataSet()) - return {"catalog": catalog, "sess_id": session.session_id} - - -class KedroTask(Task): - """Kedro node as a Prefect task.""" - - def __init__(self, node: Node): - self._node = node - super().__init__(name=node.name, tags=node.tags) - - def run(self, task_dict: Dict[str, Union[DataCatalog, str]]): - run_node( - self._node, - task_dict["catalog"], - _create_hook_manager(), - task_dict["sess_id"], - ) - + Args: + pipeline_name (str): The pipeline name to execute + execution_config (Union[None, Dict[str, Union[DataCatalog, str]]], optional): + The required execution config for each node. Defaults to None. -def instantiate_task( - node: Node, - tasks: Dict[str, Dict[str, Union[KedroTask, List[KedroTask]]]], -) -> Tuple[KedroTask, Dict[str, Dict[str, Union[KedroTask, List[KedroTask]]]]]: + Returns: + List[List[Callable]]: A list of topologically ordered task groups """ - Function pulls node task from dictionary. If node task not - available in the function instantiates the tasks and adds - it to . In this way we avoid duplicate instantiations of - the same node task. - Args: - node: Kedro node for which a Prefect task is being created. - tasks: dictionary mapping node names to a dictionary containing - node tasks and parent node tasks. + pipeline = pipelines.get(pipeline_name) - Returns: Prefect task for the passed node and task dictionary. + execution_layers = [] - """ - if tasks.get(node._unique_key) is not None: - node_task = tasks[node._unique_key]["task"] - else: - node_task = KedroTask(node) - tasks[node._unique_key] = {"task": node_task} + # Return a list of the pipeline nodes in topologically ordered groups, + # i.e. if node A needs to be run before node B, it will appear in an + # earlier group. + for layer in pipeline.grouped_nodes: + execution_layer = [] + for node in layer: + # Use a function for task instantiation which avoids duplication of + # tasks + task = instantiate_task(node, execution_config) + execution_layer.append(task) + execution_layers.append(execution_layer) - # return tasks as it is mutated. We want to make this obvious to the user. - return node_task, tasks # type: ignore[return-value] + return execution_layers -def generate_flow( - init_task: KedroInitTask, - tasks: Dict[str, Dict[str, Union[KedroTask, List[KedroTask]]]], +def kedro_task( + node: Node, task_dict: Union[None, Dict[str, Union[DataCatalog, str]]] = None ): + run_node( + node, + task_dict["catalog"], + _create_hook_manager(), + task_dict["sess_id"], + ) + + +def instantiate_task( + node: Node, + execution_config: Union[None, Dict[str, Union[DataCatalog, str]]] = None, +) -> Callable: """ - Constructs a Prefect flow given a task dictionary. Task dictionary - maps Kedro node names to a dictionary containing a node task and its - parents. + Function that wraps a Node inside a task for future execution Args: - init_task: Prefect initialisation tasks. Used to instantiate a Kedro - session within the scope of a Prefect flow. - tasks: dictionary mapping Kedro node names to a dictionary - containing a corresponding node task and its parents. + node: Kedro node for which a Prefect task is being created. + execution_config: The configurations required for the node to execute + that includes catalogs and session id + + Returns: Prefect task for the passed node - Returns: None """ - child_task_dict = init_task - for task in tasks.values(): - node_task = task["task"] - if len(task["parent_tasks"]) == 0: - # When a task has no parent only the session init task should - # precede it. - parent_tasks = [init_task] - else: - parent_tasks = task["parent_tasks"] - # Set upstream tasks and bind required kwargs. - # Note: Unpacking the return from init tasks will generate two - # sub-tasks in the prefect graph. To avoid this we pass the init - # return on unpacked. - node_task.bind(upstream_tasks=parent_tasks, task_dict=child_task_dict) - - -def instantiate_client(project_name: str): - """Initiates Prefect client""" - client = Client() - try: - client.create_project(project_name=project_name) - except ClientError: - raise + return task(lambda: kedro_task(node, execution_config)).with_options(name=node.name) if __name__ == "__main__": prefect_deploy() ``` -```{note} -The script launches a [local agent](https://docs.prefect.io/orchestration/agents/local.html). Remember to stop the agent with Ctrl-C when you complete. +Then, run the deployment script in other terminal: + +```bash +python register_prefect_flow.py --work_pool_name --work_queue_name ``` +```{note} +Be sure that your Prefect Server is up and running. Verify that the deployment script arguments match the work pool and work queue names. +``` ### Run Prefect flow -Now, having the flow registered, you can use [Prefect UI](https://docs.prefect.io/orchestration/ui/dashboard.html) to orchestrate and monitor it. +Now, having the flow registered, you can use [Prefect Server UI](https://docs.prefect.io/2.10.17/host/) to orchestrate and monitor it. -Navigate to http://localhost:8080/default?flows= to see your registered flow. +Navigate to http://localhost:4200/deployments to see your registered flow. -![](../meta/images/prefect_flows.png) +![prefect_2_flow_deployment](../meta/images/prefect_2_flow_deployment.png) -Click on the flow to open it and then trigger your flow using the "RUN"/"QUICK RUN" button. +Click on the flow to open it and then trigger your flow using the "RUN" > "QUICK RUN" button and leave the parameters by default. If you want to run a specific pipeline you can replace the `__default__` value. + +```{note} +Be sure that both your Prefect Server and Agent are up and running. +``` -![](../meta/images/prefect_flow_details.png) +![prefect_2_flow_details](../meta/images/prefect_2_flow_details.png) diff --git a/docs/source/meta/images/prefect_2_flow_deployment.png b/docs/source/meta/images/prefect_2_flow_deployment.png new file mode 100644 index 0000000000000000000000000000000000000000..b3f725447fec717f0283354e1a9b7e02e7a3ca9f GIT binary patch literal 28010 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 literal 0 HcmV?d00001 diff --git a/docs/source/meta/images/prefect_2_flow_details.png b/docs/source/meta/images/prefect_2_flow_details.png new file mode 100644 index 0000000000000000000000000000000000000000..c935e974a833eb82239c8fbdd7b87727219dc872 GIT binary patch literal 89931 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

R{Om}mL{Eu?19@+~O&u7s2as}@QYiz9 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 Date: Mon, 3 Jul 2023 12:27:49 +0100 Subject: [PATCH 11/13] Update docs to include SparkStreamingDataSet and ManagedTableDataSet (#2679) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update kedro_datasets.rst * test branch * Re-trigger CI * Re-trigger CI pt 2 * Re-trigger CI pt 3 * Re-trigger CI pt N * Update setup.py * Update setup.py * Update setup.py * Update setup.py * Update .readthedocs.yml * Update kedro_datasets.rst I hope htis is right! * Modify setup.py Signed-off-by: Jannic Holzer * Modify setup.py Signed-off-by: Jannic Holzer * Empty commit Signed-off-by: Jannic Holzer * Trigger build Signed-off-by: Jannic Holzer * Remove spurious whitespace Signed-off-by: Jannic Holzer * Change pip list -> pip freeze to ease debugging * Update setup.py --------- Signed-off-by: Jannic Holzer Co-authored-by: Ahdra Merali <90615669+AhdraMeraliQB@users.noreply.github.com> Co-authored-by: Jo Stichbury Co-authored-by: Jannic Holzer Co-authored-by: Juan Luis Cano Rodríguez --- .readthedocs.yml | 1 + docs/source/kedro_datasets.rst | 2 ++ setup.py | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 4b1c5f4824..2df6853225 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -16,6 +16,7 @@ build: post_create_environment: - npm install -g @mermaid-js/mermaid-cli pre_build: + - pip freeze - python -m sphinx -WETan -j auto -D language=en -b linkcheck -d _build/doctrees docs/source _build/linkcheck # Build documentation in the docs/ directory with Sphinx diff --git a/docs/source/kedro_datasets.rst b/docs/source/kedro_datasets.rst index b8e9f5d442..b3d3ab328b 100644 --- a/docs/source/kedro_datasets.rst +++ b/docs/source/kedro_datasets.rst @@ -14,6 +14,7 @@ kedro_datasets kedro_datasets.api.APIDataSet kedro_datasets.biosequence.BioSequenceDataSet kedro_datasets.dask.ParquetDataSet + kedro_datasets.databricks.ManagedTableDataSet kedro_datasets.email.EmailMessageDataSet kedro_datasets.geopandas.GeoJSONDataSet kedro_datasets.holoviews.HoloviewsWriter @@ -45,6 +46,7 @@ kedro_datasets kedro_datasets.spark.SparkDataSet kedro_datasets.spark.SparkHiveDataSet kedro_datasets.spark.SparkJDBCDataSet + kedro_datasets.spark.SparkStreamingDataSet kedro_datasets.svmlight.SVMLightDataSet kedro_datasets.tensorflow.TensorFlowModelDataSet kedro_datasets.text.TextDataSet diff --git a/setup.py b/setup.py index 1d63d779cf..92eca04e5a 100644 --- a/setup.py +++ b/setup.py @@ -104,7 +104,7 @@ def _collect_requirements(requires): "sphinxcontrib-mermaid~=0.7.1", "myst-parser~=1.0.0", "Jinja2<3.1.0", - "kedro-datasets[all]~=1.4.0", + "kedro-datasets[all]~=1.4.2", ], "geopandas": _collect_requirements(geopandas_require), "matplotlib": _collect_requirements(matplotlib_require), From 8065fb0d30cb222bc3ddfa93eab1fbacc448abba Mon Sep 17 00:00:00 2001 From: Ahdra Merali <90615669+AhdraMeraliQB@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:19:53 +0100 Subject: [PATCH 12/13] Release 0.18.11 (#2745) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update release date in CITATION.cff Signed-off-by: Ahdra Merali * Rename old version to 0.18.11 where relevant Signed-off-by: Ahdra Merali * Add Upcoming release section to RELEASE.md Signed-off-by: Ahdra Merali * Fix prepopulated TOC Signed-off-by: Ahdra Merali * Fix prepopulated TOC Signed-off-by: Ahdra Merali * update release notes with documentation details Signed-off-by: Jo Stichbury Signed-off-by: Ahdra Merali * Add note of deprecation warning to RELEASE.md Signed-off-by: Ahdra Merali * Do not unsuppress `DeprecationWarning`s with Kedro (#2747) * Do not unsuppress `DeprecationWarning`s with Kedro Signed-off-by: Deepyaman Datta * Remove unused import Signed-off-by: Deepyaman Datta --------- Signed-off-by: Deepyaman Datta Signed-off-by: Ahdra Merali * Update RELEASE.md with deprecation table Signed-off-by: Ahdra Merali * Update CITATION.cff Signed-off-by: Ahdra Merali * Update CITATION.cff Signed-off-by: Ahdra Merali * Update docs/source/configuration/advanced_configuration.md Co-authored-by: Jo Stichbury * Update tutorial_template.md * Add community contributions Signed-off-by: Juan Luis Cano Rodríguez * Add Prefect 2.0 docs update to changelog Signed-off-by: Juan Luis Cano Rodríguez --------- Signed-off-by: Ahdra Merali Signed-off-by: Jo Stichbury Signed-off-by: Deepyaman Datta Signed-off-by: Juan Luis Cano Rodríguez Co-authored-by: Jo Stichbury Co-authored-by: Deepyaman Datta Co-authored-by: Juan Luis Cano Rodríguez --- CITATION.cff | 4 +- RELEASE.md | 40 +++++++++++++++++-- docs/source/development/commands_reference.md | 2 +- docs/source/extend_kedro/plugins.md | 2 +- kedro/__init__.py | 2 +- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 191a56a8f7..256c577eb8 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -45,6 +45,6 @@ authors: - family-names: Theisen given-names: Merel title: Kedro -version: 0.18.10 -date-released: 2023-06-08 +version: 0.18.11 +date-released: 2023-07-03 url: https://github.com/kedro-org/kedro diff --git a/RELEASE.md b/RELEASE.md index b2b3280e29..4d645c1279 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -9,7 +9,19 @@ ## Migration guide from Kedro 0.18.* to 0.19.* -# Upcoming Release 0.18.11 +# Upcoming Release 0.18.12 + +## Major features and improvements + +## Bug fixes and other changes + +## Documentation changes + +## Breaking changes to the API + +## Upcoming deprecations for Kedro 0.19.0 + +# Release 0.18.11 ## Major features and improvements * Added `databricks-iris` as an official starter. @@ -19,11 +31,31 @@ * Make `kedro micropkg package` accept `--verbose`. ## Documentation changes -* Added documentation for developing a Kedro project using a Databricks workspace. - -## Breaking changes to the API +* Significant improvements to the documentation that covers working with Databricks and Kedro, including a new page for workspace-only development, and a guide to choosing the best workflow for your use case. +* Updated documentation for deploying with Prefect for version 2.0. ## Upcoming deprecations for Kedro 0.19.0 +* Renamed dataset and error classes, in accordance with the [Kedro lexicon](https://github.com/kedro-org/kedro/wiki/Kedro-documentation-style-guide#kedro-lexicon). Dataset classes ending with "DataSet" and error classes starting with "DataSet" are deprecated and will be removed in 0.19.0. Note that all of the below classes are also importable from `kedro.io`; only the module where they are defined is listed as the location. + +| Type | Deprecated Alias | Location | +| --------------------------- | --------------------------- | ------------------------------ | +| `CachedDataset` | `CachedDataSet` | `kedro.io.cached_dataset` | +| `LambdaDataset` | `LambdaDataSet` | `kedro.io.lambda_dataset` | +| `IncrementalDataset` | `IncrementalDataSet` | `kedro.io.partitioned_dataset` | +| `MemoryDataset` | `MemoryDataSet` | `kedro.io.memory_dataset` | +| `PartitionedDataset` | `PartitionedDataSet` | `kedro.io.partitioned_dataset` | +| `DatasetError` | `DataSetError` | `kedro.io.core` | +| `DatasetAlreadyExistsError` | `DataSetAlreadyExistsError` | `kedro.io.core` | +| `DatasetNotFoundError` | `DataSetNotFoundError` | `kedro.io.core` | + +## Community contributions +Many thanks to the following Kedroids for contributing PRs to this release: + +* [jmalovera10](https://github.com/jmalovera10) +* [debugger24](https://github.com/debugger24) +* [juliushetzel](https://github.com/juliushetzel) +* [jacobweiss2305](https://github.com/jacobweiss2305) +* [eduardoconto](https://github.com/eduardoconto) # Release 0.18.10 diff --git a/docs/source/development/commands_reference.md b/docs/source/development/commands_reference.md index 1745aee8b9..ae2933e256 100644 --- a/docs/source/development/commands_reference.md +++ b/docs/source/development/commands_reference.md @@ -114,7 +114,7 @@ Returns output similar to the following, depending on the version of Kedro used | |/ / _ \/ _` | '__/ _ \ | < __/ (_| | | | (_) | |_|\_\___|\__,_|_| \___/ -v0.18.10 +v0.18.11 Kedro is a Python framework for creating reproducible, maintainable diff --git a/docs/source/extend_kedro/plugins.md b/docs/source/extend_kedro/plugins.md index 37dbd5abe9..51cb3b1946 100644 --- a/docs/source/extend_kedro/plugins.md +++ b/docs/source/extend_kedro/plugins.md @@ -84,7 +84,7 @@ setup( After that you can use this starter with `kedro new --starter=test_plugin_starter`. ```{note} -If your starter lives on a git repository, by default Kedro attempts to use a tag or branch labelled with your version of Kedro, e.g. `0.18.10`. This means that you can host different versions of your starter template on the same repository, and the correct one will automatically be used. If you do not wish to follow this structure, you should override it with the `checkout` flag, e.g. `kedro new --starter=test_plugin_starter --checkout=main`. +If your starter lives on a git repository, by default Kedro attempts to use a tag or branch labelled with your version of Kedro, e.g. `0.18.11`. This means that you can host different versions of your starter template on the same repository, and the correct one will automatically be used. If you do not wish to follow this structure, you should override it with the `checkout` flag, e.g. `kedro new --starter=test_plugin_starter --checkout=main`. ``` ## Working with `click` diff --git a/kedro/__init__.py b/kedro/__init__.py index ac4b0c5332..be9febd329 100644 --- a/kedro/__init__.py +++ b/kedro/__init__.py @@ -3,4 +3,4 @@ configuration and pipeline assembly. """ -__version__ = "0.18.10" +__version__ = "0.18.11" From dc5ba300932947a1fa405ce1a182fb363db88537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Luis=20Cano=20Rodr=C3=ADguez?= Date: Tue, 4 Jul 2023 11:35:09 +0100 Subject: [PATCH 13/13] Add @merelcht as global CODEOWNER (#2763) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juan Luis Cano Rodríguez --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 08a8744c60..a4c421df40 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,2 @@ -* @idanov +* @merelcht docs/ @yetudada @astrojuanlu @stichbury

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