Repository: ManimCommunity/manim

Issue:
BUG : kwargs in ApplyMethod Breaks Scene Caching
```python
class IssueKwargsCache(Scene):
    def construct(self):
        m = Dot()
        self.play(ApplyMethod(m.scale, 2, {"about_point": RIGHT}))
```

When trying to run this scene, it breaks with this backtrace:

```Traceback (most recent call last):
  File ".../manim/manim/__main__.py", line 170, in main
    scene = SceneClass()
  File ".../manim/manim/scene/scene.py", line 86, in __init__
    self.construct()
  File "intro.py", line 247, in construct
    self.play(ApplyMethod(v.scale, 0.5, {"about_point": v.get_start()}))
  File ".../manim/manim/scene/scene.py", line 818, in wrapper
    hash_play = get_hash_from_play_call(
  File ".../manim/manim/utils/hashing.py", line 240, in get_hash_from_play_call
    animations_list_json = [get_json(x) for x in sorted(animations_list, key=str)]
  File ".../manim/manim/utils/hashing.py", line 240, in <listcomp>
    animations_list_json = [get_json(x) for x in sorted(animations_list, key=str)]
  File ".../manim/manim/utils/hashing.py", line 185, in get_json
    return json.dumps(obj, cls=CustomEncoder)
  File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
    return cls(
  File ".../manim/manim/utils/hashing.py", line 169, in encode
    return super().encode(obj)
  File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File ".../manim/manim/utils/hashing.py", line 67, in default
    return self._check_iterable(temp)
  File ".../manim/manim/utils/hashing.py", line 148, in _check_iterable
    return _iter_check_dict(iterable)
  File ".../manim/manim/utils/hashing.py", line 142, in _iter_check_dict
    dct_copy[k_new] = _iter_check_list(v)
  File ".../manim/manim/utils/hashing.py", line 122, in _iter_check_list
    lst_copy[i] = _iter_check_dict(el)
TypeError: 'tuple' object does not support item assignment
```

And yes, huguesdevimeux, the problem disappears when `--disable_caching` is used.


Discussion:
Thanks for the report. I see where the issue comes from, it was my biggest fear but it happened. 

Will fix this asap :D 

Resolving patch:
diff --git a/manim/utils/hashing.py b/manim/utils/hashing.py
--- a/manim/utils/hashing.py
+++ b/manim/utils/hashing.py
@@ -111,6 +111,11 @@ def _iter_check_list(lst):
             # We have to make a copy, as we don't want to touch to the original list
             # A deepcopy isn't necessary as it is already recursive.
             lst_copy = copy.copy(lst)
+            if isinstance(lst, tuple):
+                # NOTE: Sometimes a tuple can pass through this function. As a tuple
+                # is immutable, we convert it to a list to be able to modify it.
+                # It's ok as it is a copy.
+                lst_copy = list(lst_copy)
             for i, el in enumerate(lst):
                 if not isinstance(lst, tuple):
                     lst_copy[i] = self._handle_already_processed(


Test patch:
diff --git a/tests/test_hashing.py b/tests/test_hashing.py
--- a/tests/test_hashing.py
+++ b/tests/test_hashing.py
@@ -108,3 +108,9 @@ def test_JSON_with_big_np_array():
     a = np.zeros((1000, 1000))
     o_ser = hashing.get_json(a)
     assert "TRUNCATED ARRAY" in o_ser
+
+
+def test_JSON_with_tuple():
+    o = [(1, [1])]
+    o_ser = hashing.get_json(o)
+    assert o_ser == "[[1, [1]]]"