Repository: probabl-ai/skore

Issue:
error thrown in put when precising the parameters' names
### Describe the bug

I have an error when using the put function if I precise what parameter is which in the function. 

### Steps/Code to Reproduce

Supposing that we already have a project created:  

```python
from skore import load
project = load("project.skore")
test = 3
project.put(key="test", value=test)
``` 
On main branch on Oct18th.  

### Expected Behavior

I'd expect the same thing as `project.put("test", test)` to happen.

### Actual Behavior

an error is thrown. 

### Environment

```shell
System:
    python: 3.12.7 | packaged by Anaconda, Inc. | (main, Oct  4 2024, 13:27:36) [GCC 11.2.0]
executable: /home/marie/anaconda3/envs/skore_test/bin/python
   machine: Linux-6.8.0-45-generic-x86_64-with-glibc2.35

Python dependencies:
        skore: 0.0.0+unknown
          pip: 24.2
   setuptools: 75.1.0
 altair<6,>=5: None
    diskcache: 5.6.3
      fastapi: 0.115.0
         rich: 13.9.2
        skops: 0.10.0
      uvicorn: 0.31.0
```


Discussion:

Patch:
diff --git a/skore/src/skore/project.py b/skore/src/skore/project.py
index 011a788..0616c96 100644
--- a/skore/src/skore/project.py
+++ b/skore/src/skore/project.py
@@ -1,9 +1,8 @@
 """Define a Project."""
 
 import logging
-from functools import singledispatchmethod
 from pathlib import Path
-from typing import Any, Literal, Union
+from typing import Any, Literal, Optional, Union
 
 from skore.item import (
     CrossValidationItem,
@@ -39,9 +38,49 @@ class Project:
         self.item_repository = item_repository
         self.view_repository = view_repository
 
-    @singledispatchmethod
-    def put(self, key: str, value: Any, on_error: Literal["warn", "raise"] = "warn"):
-        """Add a value to the Project.
+    def put(
+        self,
+        key: Union[str, dict[str, Any]],
+        value: Optional[Any] = None,
+        on_error: Literal["warn", "raise"] = "warn",
+    ):
+        """Add one or more key-value pairs to the Project.
+
+        If `key` is a string, then `put` adds the single `key`-`value` pair mapping to
+        the Project.
+        If `key` is a dict, it is interpreted as multiple key-value pairs to add to
+        the Project.
+
+        If `on_error` is "raise", any error stops the execution. If `on_error`
+        is "warn" (or anything other than "raise"), a warning is shown instead.
+
+        Parameters
+        ----------
+        key : str | dict[str, Any]
+            The key to associate with `value` in the Project,
+            or dict of key-value pairs to add to the Project.
+        value : Any | None
+            The value to associate with `key` in the Project.
+            If `key` is a dict, this argument is ignored.
+        on_error : "warn" or "raise", optional
+            Upon error (e.g. if the key is not a string), whether to raise an error or
+            to print a warning. Default is "warn".
+
+        Raises
+        ------
+        ProjectPutError
+            If the key-value pair(s) cannot be saved properly,
+            and `on_error` is "raise".
+        """
+        if isinstance(key, dict):
+            self.put_several(key, on_error=on_error)
+        else:
+            self.put_one(key, value, on_error=on_error)
+
+    def put_one(
+        self, key: str, value: Any, on_error: Literal["warn", "raise"] = "warn"
+    ):
+        """Add a key-value pair to the Project.
 
         If `on_error` is "raise", any error stops the execution. If `on_error`
         is "warn" (or anything other than "raise"), a warning is shown instead.
@@ -75,7 +114,6 @@ class Project:
                 f"due to the following error: {e}"
             )
 
-    @put.register
     def put_several(
         self, key_to_value: dict, on_error: Literal["warn", "raise"] = "warn"
     ):
@@ -101,7 +139,7 @@ class Project:
             and `on_error` is "raise".
         """
         for key, value in key_to_value.items():
-            self.put(key, value, on_error=on_error)
+            self.put_one(key, value, on_error=on_error)
 
     def put_item(self, key: str, item: Item):
         """Add an Item to the Project."""


Test patch:
diff --git a/skore/tests/unit/test_project.py b/skore/tests/unit/test_project.py
index 9bfe395..dc5c795 100644
--- a/skore/tests/unit/test_project.py
+++ b/skore/tests/unit/test_project.py
@@ -133,6 +133,17 @@ def test_put(in_memory_project):
     assert in_memory_project.list_item_keys() == ["key1", "key2", "key3", "key4"]
 
 
+def test_put_kwargs(in_memory_project):
+    in_memory_project.put(key="key1", value=1)
+    assert in_memory_project.list_item_keys() == ["key1"]
+
+
+def test_put_wrong_key_type(in_memory_project):
+    with pytest.raises(ProjectPutError):
+        in_memory_project.put(key=2, value=1, on_error="raise")
+    assert in_memory_project.list_item_keys() == []
+
+
 def test_put_twice(in_memory_project):
     in_memory_project.put("key2", 2)
     in_memory_project.put("key2", 5)