diff --git a/.github/workflows/all-checks.yml b/.github/workflows/all-checks.yml index afd9caced0..c108d1ad42 100644 --- a/.github/workflows/all-checks.yml +++ b/.github/workflows/all-checks.yml @@ -26,7 +26,7 @@ jobs: strategy: matrix: os: [ windows-latest, ubuntu-latest ] - python-version: [ "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] uses: ./.github/workflows/unit-tests.yml with: os: ${{ matrix.os }} @@ -36,7 +36,7 @@ jobs: strategy: matrix: os: [ windows-latest, ubuntu-latest ] - python-version: [ "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] uses: ./.github/workflows/e2e-tests.yml with: os: ${{ matrix.os }} @@ -59,7 +59,7 @@ jobs: strategy: matrix: os: [ windows-latest, ubuntu-latest ] - python-version: [ "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] uses: ./.github/workflows/pip-compile.yml with: os: ${{ matrix.os }} diff --git a/.github/workflows/check-release.yml b/.github/workflows/check-release.yml index 329278919e..51ab45c362 100644 --- a/.github/workflows/check-release.yml +++ b/.github/workflows/check-release.yml @@ -16,7 +16,7 @@ jobs: python-version: '3.11' - name: Install uv run: | - python -m pip install "uv==0.1.32" + python -m pip install "uv==0.4.29" - name: Install dependencies run: | uv pip install --system requests @@ -52,7 +52,7 @@ jobs: python-version: '3.11' - name: Install uv run: | - python -m pip install "uv==0.1.32" + python -m pip install "uv==0.4.29" - name: Install dependencies run: | uv pip install --system build diff --git a/.github/workflows/docs-only-checks.yml b/.github/workflows/docs-only-checks.yml index edd95de234..8f1098baa2 100644 --- a/.github/workflows/docs-only-checks.yml +++ b/.github/workflows/docs-only-checks.yml @@ -21,7 +21,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest ] - python-version: [ "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] uses: ./.github/workflows/lint.yml with: os: ${{ matrix.os }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c9a5c5397c..aea1855741 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ default_stages: [pre-commit, manual] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.1 + rev: v0.7.1 hooks: - id: ruff name: "ruff on kedro/, tests/ and docs/" diff --git a/Makefile b/Makefile index e3f1e7b5c8..8095b52cc2 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ package: clean install python -m pip install build && python -m build install-test-requirements: - python -m pip install "uv==0.1.32" + python -m pip install "uv==0.4.29" uv pip install --system "kedro[test] @ ." install-pre-commit: diff --git a/RELEASE.md b/RELEASE.md index ac3c4d95d9..7e5214ab18 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -2,6 +2,7 @@ ## Major features and improvements * Implemented dict-like interface for `KedroDataCatalog`. +* Added Python 3.13 support. **Note:** ``KedroDataCatalog`` is an experimental feature and is under active development. Therefore, it is possible we'll introduce breaking changes to this class, so be mindful of that if you decide to use it already. Let us know if you have any feedback about the ``KedroDataCatalog`` or ideas for new features. diff --git a/kedro/__init__.py b/kedro/__init__.py index 00ebebc5a7..afb4928658 100644 --- a/kedro/__init__.py +++ b/kedro/__init__.py @@ -21,7 +21,7 @@ class KedroPythonVersionWarning(UserWarning): warnings.simplefilter("default", KedroDeprecationWarning) warnings.simplefilter("error", KedroPythonVersionWarning) -if sys.version_info >= (3, 13): +if sys.version_info >= (3, 14): warnings.warn( """Kedro is not yet fully compatible with this Python version. To proceed at your own risk and ignore this warning, diff --git a/kedro/framework/cli/micropkg.py b/kedro/framework/cli/micropkg.py index a80efd172a..ef6f91426f 100644 --- a/kedro/framework/cli/micropkg.py +++ b/kedro/framework/cli/micropkg.py @@ -211,67 +211,71 @@ def _pull_package( # noqa: PLR0913 destination: str | None = None, fs_args: str | None = None, ) -> None: - with tempfile.TemporaryDirectory() as temp_dir: - temp_dir_path = Path(temp_dir).resolve() - _unpack_sdist(package_path, temp_dir_path, fs_args) - - # temp_dir_path is the parent directory of the project root dir - contents = [member for member in temp_dir_path.iterdir() if member.is_dir()] - if len(contents) != 1: - raise KedroCliError( - "Invalid sdist was extracted: exactly one directory was expected, " - f"got {contents}" - ) - project_root_dir = contents[0] - - # This is much slower than parsing the requirements - # directly from the metadata files - # because it installs the package in an isolated environment, - # but it's the only reliable way of doing it - # without making assumptions on the project metadata. - library_meta = project_wheel_metadata(project_root_dir) - - # Project name will be `my-pipeline` even if `pyproject.toml` says `my_pipeline` - # because standards mandate normalization of names for comparison, - # see https://packaging.python.org/en/latest/specifications/core-metadata/#name - # The proper way to get it would be - # project_name = library_meta.get("Name") - # However, the rest of the code expects the non-normalized package name, - # so we have to find it. - packages = [ - project_item.name - for project_item in project_root_dir.iterdir() - if project_item.is_dir() - and project_item.name != "tests" - and (project_item / "__init__.py").exists() - ] - if len(packages) != 1: - # Should not happen if user is calling `micropkg pull` - # with the result of a `micropkg package`, - # and in general if the distribution only contains one package (most likely), - # but helps give a sensible error message otherwise - raise KedroCliError( - "Invalid package contents: exactly one package was expected, " - f"got {packages}" - ) - package_name = packages[0] + import tempfile + + temp_dir = tempfile.TemporaryDirectory() + temp_dir_path = Path(temp_dir).resolve() + _unpack_sdist(package_path, temp_dir_path, fs_args) + + # temp_dir_path is the parent directory of the project root dir + contents = [member for member in temp_dir_path.iterdir() if member.is_dir()] + if len(contents) != 1: + raise KedroCliError( + "Invalid sdist was extracted: exactly one directory was expected, " + f"got {contents}" + ) + project_root_dir = contents[0] + + # This is much slower than parsing the requirements + # directly from the metadata files + # because it installs the package in an isolated environment, + # but it's the only reliable way of doing it + # without making assumptions on the project metadata. + library_meta = project_wheel_metadata(project_root_dir) + + # Project name will be `my-pipeline` even if `pyproject.toml` says `my_pipeline` + # because standards mandate normalization of names for comparison, + # see https://packaging.python.org/en/latest/specifications/core-metadata/#name + # The proper way to get it would be + # project_name = library_meta.get("Name") + # However, the rest of the code expects the non-normalized package name, + # so we have to find it. + packages = [ + project_item.name + for project_item in project_root_dir.iterdir() + if project_item.is_dir() + and project_item.name != "tests" + and (project_item / "__init__.py").exists() + ] + if len(packages) != 1: + # Should not happen if user is calling `micropkg pull` + # with the result of a `micropkg package`, + # and in general if the distribution only contains one package (most likely), + # but helps give a sensible error message otherwise + raise KedroCliError( + "Invalid package contents: exactly one package was expected, " + f"got {packages}" + ) + package_name = packages[0] - # Type ignored because of https://github.com/pypa/build/pull/693 - package_reqs = _get_all_library_reqs(library_meta) # type: ignore[arg-type] + # Type ignored because of https://github.com/pypa/build/pull/693 + package_reqs = _get_all_library_reqs(library_meta) # type: ignore[arg-type] - if package_reqs: - requirements_txt = metadata.project_path / "requirements.txt" - _append_package_reqs(requirements_txt, package_reqs, package_name) + if package_reqs: + requirements_txt = metadata.project_path / "requirements.txt" + _append_package_reqs(requirements_txt, package_reqs, package_name) - _clean_pycache(temp_dir_path) - _install_files( - metadata, - package_name, - project_root_dir, - env, - alias, - destination, - ) + _clean_pycache(temp_dir_path) + _install_files( + metadata, + package_name, + project_root_dir, + env, + alias, + destination, + ) + temp_dir.cleanup() + click.secho("dummy") def _pull_packages_from_manifest(metadata: ProjectMetadata) -> None: diff --git a/tests/test_import.py b/tests/test_import.py index 6dc9da4df4..511b6d19b4 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -4,8 +4,8 @@ def test_import_kedro_with_no_official_support_raise_error(mocker): - """Test importing kedro with python>=3.13 should fail""" - mocker.patch("kedro.sys.version_info", (3, 13)) + """Test importing kedro with python>=3.14 should fail""" + mocker.patch("kedro.sys.version_info", (3, 14)) # We use the parent class to avoid issues with `exec_module` with pytest.raises(UserWarning) as excinfo: @@ -15,8 +15,8 @@ def test_import_kedro_with_no_official_support_raise_error(mocker): def test_import_kedro_with_no_official_support_emits_warning(mocker): - """Test importing kedro python>=3.13 and controlled warnings should work""" - mocker.patch("kedro.sys.version_info", (3, 13)) + """Test importing kedro python>=3.14 and controlled warnings should work""" + mocker.patch("kedro.sys.version_info", (3, 14)) mocker.patch("kedro.sys.warnoptions", ["default:Kedro is not yet fully compatible"]) # We use the parent class to avoid issues with `exec_module`