Skip to content

Commit

Permalink
Make kedro commands work from inside subdirectories in project (#3683)
Browse files Browse the repository at this point in the history
* Move _find_kedro_project to utils

Signed-off-by: Ankita Katiyar <[email protected]>

* Refactor fn

Signed-off-by: Ankita Katiyar <[email protected]>

* Fix _find_kedro_project

Signed-off-by: Ankita Katiyar <[email protected]>

* Make kedro commands available inside subdirectories

Signed-off-by: Ankita Katiyar <[email protected]>

* Add e2e test and update release notes

Signed-off-by: Ankita Katiyar <[email protected]>

* Fix e2e test

Signed-off-by: Ankita Katiyar <[email protected]>

* Resolve paths for session and update release notes

Signed-off-by: Ankita Katiyar <[email protected]>

---------

Signed-off-by: Ankita Katiyar <[email protected]>
Signed-off-by: Ankita Katiyar <[email protected]>
  • Loading branch information
ankatiyar authored Mar 7, 2024
1 parent da709d4 commit a22bc32
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 27 deletions.
2 changes: 2 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Upcoming Release 0.19.4

## Major features and improvements
* Kedro commands now work from any subdirectory within a Kedro project.
* Kedro CLI now provides a better error message when project commands are run outside of a project i.e. `kedro run`

## Bug fixes and other changes
* Updated `kedro pipeline create` and `kedro pipeline delete` to read the base environment from the project settings.

## Breaking changes to the API
* Methods `_is_project` and `_find_kedro_project` have been moved to `kedro.utils`. We recommend not using private methods in your code, but if you do, please update your code to use the new location.

## Documentation changes

Expand Down
8 changes: 8 additions & 0 deletions features/run.feature
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,11 @@ Feature: Run Project
When I execute the kedro command "run --params extra1=1,extra2=value2"
Then I should get a successful exit code
And the logs should show that 4 nodes were run

Scenario: Run kedro run from within a sub-directory
Given I have prepared a config file
And I have run a non-interactive kedro new with starter "default"
And I have changed the current working directory to "data"
When I execute the kedro command "run"
Then I should get a successful exit code
And the logs should show that 4 nodes were run
6 changes: 6 additions & 0 deletions features/steps/cli_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,9 @@ def add_micropkg_to_pyproject_toml(context: behave.runner.Context):
)
with pyproject_toml_path.open(mode="a") as file:
file.write(project_toml_str)


@given('I have changed the current working directory to "{dir}"')
def change_dir(context, dir):
"""Execute Kedro target."""
util.chdir(dir)
7 changes: 5 additions & 2 deletions kedro/framework/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
load_entry_points,
)
from kedro.framework.project import LOGGING # noqa: F401
from kedro.framework.startup import _is_project, bootstrap_project
from kedro.framework.startup import bootstrap_project
from kedro.utils import _find_kedro_project, _is_project

LOGO = rf"""
_ _
Expand Down Expand Up @@ -226,5 +227,7 @@ def main() -> None: # pragma: no cover
commands to `kedro`'s before invoking the CLI.
"""
_init_plugins()
cli_collection = KedroCLI(project_path=Path.cwd())
cli_collection = KedroCLI(
project_path=_find_kedro_project(Path.cwd()) or Path.cwd()
)
cli_collection()
5 changes: 4 additions & 1 deletion kedro/framework/session/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from kedro.framework.session.store import BaseSessionStore
from kedro.io.core import generate_timestamp
from kedro.runner import AbstractRunner, SequentialRunner
from kedro.utils import _find_kedro_project


def _describe_git(project_path: Path) -> dict[str, dict[str, Any]]:
Expand Down Expand Up @@ -104,7 +105,9 @@ def __init__( # noqa: PLR0913
save_on_close: bool = False,
conf_source: str | None = None,
):
self._project_path = Path(project_path or Path.cwd()).resolve()
self._project_path = Path(
project_path or _find_kedro_project(Path.cwd()) or Path.cwd()
).resolve()
self.session_id = session_id
self.save_on_close = save_on_close
self._package_name = package_name
Expand Down
11 changes: 0 additions & 11 deletions kedro/framework/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,6 @@ def _version_mismatch_error(kedro_init_version: str) -> str:
)


def _is_project(project_path: Union[str, Path]) -> bool:
metadata_file = Path(project_path).expanduser().resolve() / _PYPROJECT
if not metadata_file.is_file():
return False

try:
return "[tool.kedro]" in metadata_file.read_text(encoding="utf-8")
except Exception: # noqa: broad-except
return False


def _get_project_metadata(project_path: Union[str, Path]) -> ProjectMetadata:
"""Read project metadata from `<project_root>/pyproject.toml` config file,
under the `[tool.kedro]` section.
Expand Down
13 changes: 2 additions & 11 deletions kedro/ipython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
pipelines,
)
from kedro.framework.session import KedroSession
from kedro.framework.startup import _is_project, bootstrap_project
from kedro.framework.startup import bootstrap_project
from kedro.pipeline.node import Node
from kedro.utils import _is_databricks
from kedro.utils import _find_kedro_project, _is_databricks

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -186,15 +186,6 @@ def _remove_cached_modules(package_name: str) -> None: # pragma: no cover
del sys.modules[module]


def _find_kedro_project(current_dir: Path) -> Any: # pragma: no cover
while current_dir != current_dir.parent:
if _is_project(current_dir):
return current_dir
current_dir = current_dir.parent

return None


def _guess_run_environment() -> str: # pragma: no cover
"""Best effort to guess the IPython/Jupyter environment"""
# https://github.com/microsoft/vscode-jupyter/issues/7380
Expand Down
24 changes: 23 additions & 1 deletion kedro/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
"""
import importlib
import os
from typing import Any
from pathlib import Path
from typing import Any, Union

_PYPROJECT = "pyproject.toml"


def load_obj(obj_path: str, default_obj_path: str = "") -> Any:
Expand All @@ -29,3 +32,22 @@ def load_obj(obj_path: str, default_obj_path: str = "") -> Any:

def _is_databricks() -> bool:
return "DATABRICKS_RUNTIME_VERSION" in os.environ


def _is_project(project_path: Union[str, Path]) -> bool:
metadata_file = Path(project_path).expanduser().resolve() / _PYPROJECT
if not metadata_file.is_file():
return False

try:
return "[tool.kedro]" in metadata_file.read_text(encoding="utf-8")
except Exception: # noqa: broad-except
return False


def _find_kedro_project(current_dir: Path) -> Any: # pragma: no cover
paths_to_check = [current_dir] + list(current_dir.parents)
for parent_dir in paths_to_check:
if _is_project(parent_dir):
return parent_dir
return None
2 changes: 1 addition & 1 deletion tests/framework/test_startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
from kedro.framework.startup import (
ProjectMetadata,
_get_project_metadata,
_is_project,
_validate_source_path,
bootstrap_project,
)
from kedro.utils import _is_project


class TestIsProject:
Expand Down

0 comments on commit a22bc32

Please sign in to comment.