Repository: ipython/traitlets

Issue:
Changed behaviour since v5.12.0 of `traitlets.Set.set` if value is a string
Before v5.12.0, if the passed value is of type str, the new value hold by the traitlet was a set (or maybe a list?) with a single element of type string. Since 5.12.0, the value of the traitlet is the set of all characters contained in the original string. Hence, #883  introduced a breaking change.

A easy fix would be to change the respective method to:
```python
def set(self, obj: t.Any, value: t.Any) -> None:
    if isinstance(value, str):
        return super().set(
            obj,
            set(
                [value],
            ),
        )
    else:
        return super().set(obj, value)
```

Discussion:
@minrk: closed by #903, auto-close didn't parse the link

Solution patch:
diff --git a/traitlets/traitlets.py b/traitlets/traitlets.py
index 1d1675a..ecd0d7c 100644
--- a/traitlets/traitlets.py
+++ b/traitlets/traitlets.py
@@ -3698,12 +3698,7 @@ class Set(Container[t.Set[t.Any]]):
 
     def set(self, obj: t.Any, value: t.Any) -> None:
         if isinstance(value, str):
-            return super().set(
-                obj,
-                set(
-                    value,
-                ),
-            )
+            return super().set(obj, {value})
         else:
             return super().set(obj, value)
 


Test patch:
diff --git a/tests/test_traitlets.py b/tests/test_traitlets.py
index dfcf3f0..f9f623b 100644
--- a/tests/test_traitlets.py
+++ b/tests/test_traitlets.py
@@ -1658,6 +1658,24 @@ class TestList(TraitTestBase):
         return value
 
 
+class SetTrait(HasTraits):
+    value = Set(Unicode())
+
+
+class TestSet(TraitTestBase):
+    obj = SetTrait()
+
+    _default_value: t.Set[str] = set()
+    _good_values = [{"a", "b"}, "ab"]
+    _bad_values = [1]
+
+    def coerce(self, value):
+        if isinstance(value, str):
+            # compatibility handling: convert string to set containing string
+            value = {value}
+        return value
+
+
 class Foo:
     pass