Repository: Galileo-Galilei/kedro-mlflow (python)

Issue:
MlflowArtifactDataset - loading from a specific run_id after the run_id was enforced for all MlflowArtifactDatasets
## Description
Hey, some time ago, the possibility to load mlflow artifacts from different run that then active run was added (#95). However, after resolving #613, manually specified run_id is overwritten by the run_id of a run started at the beginning of the pipeline for all artifact datasets. So the run_id parameter seems to have no effect on the MlflowArtifactDataset. After this change, how to correctly load an artifact from a different run than the one currently active? 

## Context

Can't load artifact from different run than the one currently active (#95 not solved anymore). run_id parameter of MlflowArtifactDataset does not work as described in [docs](https://kedro-mlflow.readthedocs.io/en/stable/source/10_experiment_tracking/03_version_datasets.html#can-i-reload-an-artifact-from-an-existing-run-to-use-it-in-another-run). 

## Steps to Reproduce

1. Run kedro pipeline storing some artifact in MLflow as MlflowArtifactDataset. 
2. Run the pipeline once again but specifying run_id parameter of MlflowArtifactDataset as the run_id from point 1. 


## Expected Result

The artifact from previous run should be loaded

## Actual Result

run_id provided as MlflowArtifactDataset is overwritten in `add_run_id_to_artifact_datasets(catalog, mlflow.active_run().info.run_id)` to the current run. 



## Your Environment

<!-- Include as many relevant details about the environment in which you experienced the bug: -->

* `kedro` and `kedro-mlflow` version used (`pip show kedro` and `pip show kedro-mlflow`):
Name: kedro
Version: 0.19.11
Name: kedro-mlflow
Version: 0.14.0
* Python version used (`python -V`):
3.11
* Operating system and version:
MAC Sonoma 14.4

## Does the bug also happen with the last version on master?
yes


Pull request:
Load from a specific run_id for MlflowArtifactDataset
## Description

Close #622 

## Development notes

Add a check to specify update run id beteen thread only if it is not set by user. 

## Checklist

- [X] Read the [contributing](https://github.com/Galileo-Galilei/kedro-mlflow/blob/master/CONTRIBUTING.md) guidelines
- [X] Open this PR as a 'Draft Pull Request' if it is work-in-progress
- [] Update the documentation to reflect the code changes
- [X] Add a description of this change and add your name to the list of supporting contributions in the [`CHANGELOG.md`](https://github.com/Galileo-Galilei/kedro-mlflow/blob/master/CHANGELOG.md) file. Please respect [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) guidelines.
- [X] Add tests to cover your changes

## Notice

- [X] I acknowledge and agree that, by checking this box and clicking "Submit Pull Request":

- I submit this contribution under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.txt) and represent that I am entitled to do so on behalf of myself, my employer, or relevant third parties, as applicable.
- I certify that (a) this contribution is my original creation and / or (b) to the extent it is not my original creation, I am authorised to submit this contribution on behalf of the original creator(s) or their licensees.
- I certify that the use of this contribution as authorised by the Apache 2.0 license does not violate the intellectual property rights of anyone else.


Patch:
diff --git a/.gitignore b/.gitignore
index 282c2f0..5564ffd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -141,4 +141,8 @@ debug/
 *.xlsx
 *.pptx
 
-docs/source/05_framework_ml/05_example_project_step_by_step.md
+# uv
+
+uv.lock
+
+# End of .gitignore
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d731a7..4115dd5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@
 
 -   :memo: Change documentation theme to [the pydata sphinx theme](https://pydata-sphinx-theme.readthedocs.io/en/stable/#), and refactor sections to make them clearer  ([#621](https://github.com/Galileo-Galilei/kedro-mlflow/pull/621))
 
+### Fixed
+
+-   :bug: Fix a regression introduced by ``0.13.4`` and enable again to load an artifact from a different ``run_id`` ([#622](https://github.com/Galileo-Galilei/kedro-mlflow/issues/622)).  
+
 ## [0.14.0] - 2025-01-28
 
 ### Added
diff --git a/README.md b/README.md
index 6ca4f10..daf6579 100644
--- a/README.md
+++ b/README.md
@@ -68,7 +68,7 @@ This package is still in active development. We use [SemVer](https://semver.org/
 
 The user must be aware that we will not reach `1.0.0` milestone before Kedro does (mlflow has already reached `1.0.0`). **That said, the API is considered as stable from 0.8.0 version and user can reliably consider that no consequent breaking change will happen unless necessary for Kedro compatibility (e.g. for minor or major Kedro version).**
 
-If you want to migrate from an older version of `kedro-mlflow` to most recent ones, see the [migration guide](https://kedro-mlflow.readthedocs.io/en/latest/source/02_getting_started/01_installation/03_migration_guide.html).
+If you want to migrate from an older version of `kedro-mlflow` to most recent ones, see the [migration guide](https://kedro-mlflow.readthedocs.io/en/latest/source/06_migration_guide/index.html).
 
 
 # Can I contribute?
diff --git a/kedro_mlflow/io/catalog/add_run_id_to_artifact_datasets.py b/kedro_mlflow/io/catalog/add_run_id_to_artifact_datasets.py
index 05f2735..a51b5bd 100644
--- a/kedro_mlflow/io/catalog/add_run_id_to_artifact_datasets.py
+++ b/kedro_mlflow/io/catalog/add_run_id_to_artifact_datasets.py
@@ -5,5 +5,5 @@ from kedro_mlflow.io.artifacts.mlflow_artifact_dataset import (
 
 def add_run_id_to_artifact_datasets(catalog, run_id: str):
     for name, dataset in catalog._datasets.items():
-        if _is_instance_mlflow_artifact_dataset(dataset):
+        if (_is_instance_mlflow_artifact_dataset(dataset)) and (dataset.run_id is None):
             catalog._datasets[name].run_id = run_id


Test patch:
diff --git a/tests/framework/hooks/test_hook_log_artifact.py b/tests/framework/hooks/test_hook_log_artifact.py
index 9cd3205..a366506 100644
--- a/tests/framework/hooks/test_hook_log_artifact.py
+++ b/tests/framework/hooks/test_hook_log_artifact.py
@@ -100,11 +100,51 @@ def test_mlflow_hook_automatically_update_artifact_run_id(
         )
 
         run_id = mlflow.active_run().info.run_id
-        # Check if metrics datasets have prefix with its names.
-        # for metric
+        # Check if artifact datasets have the run_id
         assert dummy_catalog._datasets["model"].run_id == run_id
 
 
+def test_mlflow_hook_automatically_update_artifact_run_id_except_if_it_already_has_run_id(
+    kedro_project, dummy_run_params, dummy_pipeline, dummy_catalog
+):
+    # since mlflow>=2.18, the fluent API create a new run for each thread
+    # hence for thread runner we need to prefix the catalog with the run id
+
+    bootstrap_project(kedro_project)
+    with KedroSession.create(project_path=kedro_project) as session:
+        context = session.load_context()  # triggers conf setup
+
+        # we modify the run id to simulate an existing run id.
+        # We need to do it after load_context() to ensure the tracking uri is properly set up.
+        with mlflow.start_run():
+            existing_run_id = mlflow.active_run().info.run_id
+            dummy_catalog_with_run_id = dummy_catalog.shallow_copy()
+            dummy_catalog_with_run_id._datasets["model"].run_id = existing_run_id
+
+        mlflow_hook = MlflowHook()
+        mlflow_hook.after_context_created(context)  # setup mlflow config
+
+        mlflow_hook.after_catalog_created(
+            catalog=dummy_catalog,
+            # `after_catalog_created` is not using any of below arguments,
+            # so we are setting them to empty values.
+            conf_catalog={},
+            conf_creds={},
+            feed_dict={},
+            save_version="",
+            load_versions="",
+        )
+
+        mlflow_hook.before_pipeline_run(
+            run_params=dummy_run_params, pipeline=dummy_pipeline, catalog=dummy_catalog
+        )
+
+        run_id = mlflow.active_run().info.run_id
+        # Check if artifact datasets have the run_id
+        assert run_id != existing_run_id
+        assert dummy_catalog._datasets["model"].run_id == existing_run_id
+
+
 def test_mlflow_hook_log_artifacts_within_same_run_with_thread_runner(
     kedro_project, dummy_run_params, dummy_pipeline, dummy_catalog
 ):