diff --git a/RELEASE.md b/RELEASE.md index 0772ea022..68e3f753f 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -6,6 +6,15 @@ Please follow the established format: - Include the ID number for the related PR (or PRs) in parentheses --> +# Release 10.2.0 + + +## Major features and improvements + +## Bug fixes and other changes + +- Fix kedro viz `--load-file` to run from any directory without requiring a Kedro project. (#2206) + # Release 10.1.0 ## Major features and improvements @@ -17,6 +26,7 @@ Please follow the established format: ## Bug fixes and other changes + - Fix tag being undefined when pipeline are ordered differently (#2162, #2146) - Fix unserializable parameters value. (#2122) - Update kedro-viz lite banner icon and message. (#2196) diff --git a/docs/source/cli-docs.md b/docs/source/cli-docs.md index 72ea1b8af..a4c3b95b7 100644 --- a/docs/source/cli-docs.md +++ b/docs/source/cli-docs.md @@ -44,10 +44,10 @@ kedro viz run [OPTIONS] - Whether to open the Kedro Viz interface in the default browser. The browser will open if the host is `localhost`. Defaults to `True`. - `--load-file ` - - Path to load Kedro Viz data from a directory. If provided, Kedro Viz will load the visualisation data from this path instead of generating it from the pipeline. + - Path to load Kedro Viz data from a [directory](#kedro-viz-directory-structure-when-you-save-it-as-a-file). If provided, Kedro Viz will load the visualisation data from this path instead of generating it from the pipeline - `--save-file ` - - Path to save Kedro Viz data to a directory. If provided, the visualisation data will be saved to this path for later use. + - Path to save Kedro Viz data to a [directory](#kedro-viz-directory-structure-when-you-save-it-as-a-file). If provided, the visualisation data will be saved to this path for later use. - `--pipeline, -p ` - Name of the registered pipeline to visualise. If not set, the default pipeline is visualised. @@ -162,4 +162,23 @@ kedro viz build --include-previews ``` +### Kedro-viz directory structure when you save it as a file + +When you use the `--save-file` option, Kedro Viz generates a directory structure to save the visualization data. This directory can later be used with the `--load-file` to reload the visualization. + +The generated directory structure looks like this: + +```bash +api/ +├── main # Main file containing pipeline structure +├── nodes/ +│ ├── node1 # JSON files for individual nodes +│ ├── node2 +│ └── ... +├── pipelines/ +│ ├── pipeline1 # JSON files for individual pipelines +│ ├── pipeline2 +│ └── ... +``` + diff --git a/docs/source/conf.py b/docs/source/conf.py index 20fa9b182..b8ae078b7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -54,7 +54,7 @@ exclude_patterns = [] source_suffix = {".rst": "restructuredtext", ".md": "markdown"} -myst_heading_anchors = 2 +myst_heading_anchors = 7 intersphinx_mapping = { "kedro": ("https://docs.kedro.org/en/stable/", None), diff --git a/docs/source/kedro-viz_visualisation.md b/docs/source/kedro-viz_visualisation.md index de4509e5b..66c9cf651 100644 --- a/docs/source/kedro-viz_visualisation.md +++ b/docs/source/kedro-viz_visualisation.md @@ -279,8 +279,8 @@ The `%run_viz` command supports various optional arguments found in `kedro viz r * `--host=`: Specify the server host. * `--port=`: Set the server port. -* `--load-file=`: Load a specific pipeline visualisation file. -* `--save-file=`: Save the current pipeline visualisation to a file. +* `--load-file=`: Load a specific pipeline visualisation from a [directory](./cli-docs.md#kedro-viz-directory-structure-when-you-save-it-as-a-file). +* `--save-file=`: Save the current pipeline visualisation to a [directory](./cli-docs.md#kedro-viz-directory-structure-when-you-save-it-as-a-file). * `--pipeline=`: Visualise a specific pipeline. * `--env=`: Set the environment for the visualisation. * `--autoreload`: Enable automatic reloading of the visualisation when source code changes. diff --git a/package/kedro_viz/launchers/cli/run.py b/package/kedro_viz/launchers/cli/run.py index e4093b940..466d7f7aa 100644 --- a/package/kedro_viz/launchers/cli/run.py +++ b/package/kedro_viz/launchers/cli/run.py @@ -123,16 +123,21 @@ def run( ) from kedro_viz.server import run_server - kedro_project_path = _find_kedro_project(Path.cwd()) - - if kedro_project_path is None: - display_cli_message( - "ERROR: Failed to start Kedro-Viz : " - "Could not find the project configuration " - f"file '{_PYPROJECT}' at '{Path.cwd()}'. ", - "red", - ) - return + kedro_project_path = None + + if load_file: + if not Path(load_file).exists(): + raise ValueError(f"The provided filepath '{load_file}' does not exist.") + else: + kedro_project_path = _find_kedro_project(Path.cwd()) + if kedro_project_path is None: + display_cli_message( + "ERROR: Failed to start Kedro-Viz : " + "Could not find the project configuration " + f"file '{_PYPROJECT}' at '{Path.cwd()}'. ", + "red", + ) + return installed_version = parse(__version__) latest_version = get_latest_version() diff --git a/package/kedro_viz/server.py b/package/kedro_viz/server.py index db95289b6..8643bec73 100644 --- a/package/kedro_viz/server.py +++ b/package/kedro_viz/server.py @@ -132,9 +132,6 @@ def run_server( app = apps.create_api_app_from_project(path, autoreload) else: - if not Path(load_file).exists(): - raise ValueError(f"The provided filepath '{load_file}' does not exist.") - app = apps.create_api_app_from_file(f"{path}/{load_file}/api") uvicorn.run(app, host=host, port=port, log_config=None) diff --git a/package/tests/test_launchers/test_cli/test_run.py b/package/tests/test_launchers/test_cli/test_run.py index 95a809d2e..ccf579b0f 100644 --- a/package/tests/test_launchers/test_cli/test_run.py +++ b/package/tests/test_launchers/test_cli/test_run.py @@ -1,3 +1,4 @@ +from pathlib import Path from unittest.mock import call import pytest @@ -411,3 +412,23 @@ def test_find_available_port_with_occupied_ports(self, mocker): assert ( available_port == 4143 ), "Expected port 4143 to be returned as the available port" + + +def test_invalid_load_file_directory(mocker): + """ + Test that Kedro-Viz raises a ValueError when an invalid filepath + is provided to the `--load-file` argument. + """ + runner = CliRunner() + + # Mock the existence of the file path to always return False (invalid path) + mocker.patch.object(Path, "exists", return_value=False) + + # Invoke the CLI with an invalid `--load-file` path + result = runner.invoke( + main.viz_cli, ["viz", "run", "--load-file", "nonexistent_path.json"] + ) + + assert "The provided filepath 'nonexistent_path.json' does not exist." == str( + result.exception + ) diff --git a/package/tests/test_server.py b/package/tests/test_server.py index 2169e9d4d..ca8d19a2c 100644 --- a/package/tests/test_server.py +++ b/package/tests/test_server.py @@ -121,32 +121,15 @@ def test_specific_pipeline( {"data_science": example_pipelines["data_science"]} ) - @pytest.mark.parametrize( - "file_path, expected_exception", - [ - ("test.json", ValueError), # File does not exist, expect ValueError - ("test.json", None), # File exists, expect no ValueError - ], - ) - def test_load_file( - self, file_path, expected_exception, patched_create_api_app_from_file, tmp_path - ): - if expected_exception is not None: - with pytest.raises(expected_exception) as exc_info: - run_server(load_file=file_path) - - # Check if the error message contains the expected message - assert "The provided filepath" in str(exc_info.value) - assert "does not exist." in str(exc_info.value) - else: - json_file_path = tmp_path / file_path - - # File exists, no exception expected - with json_file_path.open("w") as file: - json.dump({"name": "John", "age": 30}, file) - - run_server(load_file=json_file_path) - patched_create_api_app_from_file.assert_called_once() + def test_load_file(self, patched_create_api_app_from_file, tmp_path): + file_path = "test.json" + json_file_path = tmp_path / file_path + + with json_file_path.open("w") as file: + json.dump({"name": "John", "age": 30}, file) + + run_server(load_file=json_file_path) + patched_create_api_app_from_file.assert_called_once() def test_save_file(self, tmp_path, mocker): mock_filesystem = mocker.patch("fsspec.filesystem")