Repository: ManimCommunity/manim
File: manim/utils/hashing.py (Python)

Code before:
            processed_dict = {}
            for k, v in dct.items():
                v = _Memoizer.check_already_processed(v)
                if k in KEYS_TO_FILTER_OUT:
                    continue
                # We check if the k is of the right format (supporter by Json)
                if not isinstance(k, (str, int, float, bool)) and k is not None:
                    k_new = _key_to_hash(k)
                else:
                    k_new = k
                if isinstance(v, dict):
                    new_value = _iter_check_dict(v)
                elif isinstance(v, (list, tuple)):
                    new_value = _iter_check_list(v)
                else:
                    new_value = v
                processed_dict[k_new] = new_value
            return processed_dict

        if isinstance(iterable, (list, tuple)):
            return _iter_check_list(iterable)
        elif isinstance(iterable, dict):
            return _iter_check_dict(iterable)
        else:
            # mypy requires this line, even though it should not be reached.
            return iterable

    def encode(self, obj: Any) -> str:
        """Overriding of :meth:`JSONEncoder.encode`, to make our own process.

        Parameters
        ----------
        obj
            The object to encode in JSON.

        Returns
        -------
        :class:`str`
           The object encoder with the standard json process.
        """
        _Memoizer.mark_as_processed(obj)
        if isinstance(obj, (dict, list, tuple)):
            return super().encode(self._cleaned_iterable(obj))
        return super().encode(obj)


def get_json(obj: Any) -> str:
    """Recursively serialize `object` to JSON using the :class:`CustomEncoder` class.

    Parameters
    ----------

Review comment (bug):
MyPy requires this line, because, in the hypothetical case that `_cleaned_iterable()` receives a different object that's neither an iterable or a dictionary, the function would implicitly return `None`.

Now, as you mention, this shouldn't be reached, because the object should always be an iterable or a dictionary. In this case, I suggest raising an exception instead of silently returning the same iterable. In this way, if `_cleaned_iterable()` is being passed something different, we can catch the bug instead of silently omitting it:
```suggestion
            raise TypeError("'iterable' is neither an iterable nor a dictionary.")
```

Code after:
                else:
                    new_value = el
                processed_list[i] = new_value
            return processed_list

        def _iter_check_dict(dct: dict[Any, Any]) -> dict[Any, Any]:
            processed_dict = {}
            for k, v in dct.items():
                v = _Memoizer.check_already_processed(v)
                if k in KEYS_TO_FILTER_OUT:
                    continue
                # We check if the k is of the right format (supported by JSON)
                if not isinstance(k, (str, int, float, bool)) and k is not None:
                    k_new = _key_to_hash(k)
                else:
                    k_new = k
                if isinstance(v, dict):
                    new_value = _iter_check_dict(v)
                elif isinstance(v, (list, tuple)):
                    new_value = _iter_check_list(v)
                else:
                    new_value = v
                processed_dict[k_new] = new_value
            return processed_dict

        if isinstance(iterable, (list, tuple)):
            return _iter_check_list(iterable)
        elif isinstance(iterable, dict):
            return _iter_check_dict(iterable)
        else:
            raise TypeError("'iterable' is neither an iterable nor a dictionary.")

    def encode(self, obj: Any) -> str:
        """Overriding of :meth:`JSONEncoder.encode`, to make our own process.

        Parameters
        ----------
        obj
            The object to encode in JSON.

        Returns
        -------
        :class:`str`
           The object encoder with the standard json process.
        """
        _Memoizer.mark_as_processed(obj)
        if isinstance(obj, (dict, list, tuple)):
            return super().encode(self._cleaned_iterable(obj))
        return super().encode(obj)