ai-content-maker/.venv/Lib/site-packages/confection/util.py

144 lines
4.2 KiB
Python

import functools
import sys
from copy import deepcopy
from typing import Any, Callable, Iterator, TypeVar
if sys.version_info < (3, 8):
# Ignoring type for mypy to avoid "Incompatible import" error (https://github.com/python/mypy/issues/4427).
from typing_extensions import Protocol # type: ignore
else:
from typing import Protocol
_DIn = TypeVar("_DIn")
class Decorator(Protocol):
"""Protocol to mark a function as returning its child with identical signature."""
def __call__(self, name: str) -> Callable[[_DIn], _DIn]:
...
# This is how functools.partials seems to do it, too, to retain the return type
PartialT = TypeVar("PartialT")
def partial(
func: Callable[..., PartialT], *args: Any, **kwargs: Any
) -> Callable[..., PartialT]:
"""Wrapper around functools.partial that retains docstrings and can include
other workarounds if needed.
"""
partial_func = functools.partial(func, *args, **kwargs)
partial_func.__doc__ = func.__doc__
return partial_func
class Generator(Iterator):
"""Custom generator type. Used to annotate function arguments that accept
generators so they can be validated by pydantic (which doesn't support
iterators/iterables otherwise).
"""
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if not hasattr(v, "__iter__") and not hasattr(v, "__next__"):
raise TypeError("not a valid iterator")
return v
DEFAULT_FROZEN_DICT_ERROR = (
"Can't write to frozen dictionary. This is likely an internal "
"error. Are you writing to a default function argument?"
)
DEFAULT_FROZEN_LIST_ERROR = (
"Can't write to frozen list. Maybe you're trying to modify a computed "
"property or default function argument?"
)
class SimpleFrozenDict(dict):
"""Simplified implementation of a frozen dict, mainly used as default
function or method argument (for arguments that should default to empty
dictionary). Will raise an error if the user attempts to add to dict.
"""
def __init__(
self,
*args,
error: str = DEFAULT_FROZEN_DICT_ERROR,
**kwargs,
) -> None:
"""Initialize the frozen dict. Can be initialized with pre-defined
values.
error (str): The error message when user tries to assign to dict.
"""
super().__init__(*args, **kwargs)
self.error = error
def __setitem__(self, key, value):
raise NotImplementedError(self.error)
def pop(self, key, default=None):
raise NotImplementedError(self.error)
def update(self, other):
raise NotImplementedError(self.error)
def __deepcopy__(self, memo):
return self.__class__(deepcopy({k: v for k, v in self.items()}))
class SimpleFrozenList(list):
"""Wrapper class around a list that lets us raise custom errors if certain
attributes/methods are accessed. Mostly used for properties that return an
immutable list (and that we don't want to convert to a tuple to not break
too much backwards compatibility). If a user accidentally calls
frozen_list.append(), we can raise a more helpful error.
"""
def __init__(
self,
*args,
error: str = DEFAULT_FROZEN_LIST_ERROR,
) -> None:
"""Initialize the frozen list.
error (str): The error message when user tries to mutate the list.
"""
self.error = error
super().__init__(*args)
def append(self, *args, **kwargs):
raise NotImplementedError(self.error)
def clear(self, *args, **kwargs):
raise NotImplementedError(self.error)
def extend(self, *args, **kwargs):
raise NotImplementedError(self.error)
def insert(self, *args, **kwargs):
raise NotImplementedError(self.error)
def pop(self, *args, **kwargs):
raise NotImplementedError(self.error)
def remove(self, *args, **kwargs):
raise NotImplementedError(self.error)
def reverse(self, *args, **kwargs):
raise NotImplementedError(self.error)
def sort(self, *args, **kwargs):
raise NotImplementedError(self.error)
def __deepcopy__(self, memo):
return self.__class__(deepcopy(v) for v in self)