diff options
Diffstat (limited to 'Cython/Utility/Dataclasses.py')
-rw-r--r-- | Cython/Utility/Dataclasses.py | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/Cython/Utility/Dataclasses.py b/Cython/Utility/Dataclasses.py new file mode 100644 index 000000000..2aa2d25a3 --- /dev/null +++ b/Cython/Utility/Dataclasses.py @@ -0,0 +1,112 @@ +################### Dataclasses_fallback ############################### + +# This is the fallback dataclass code if the stdlib module isn't available. +# It defines enough of the support types to be used with cdef classes +# and to fail if used on regular types. + +# (Intended to be included as py code - not compiled) + +from collections import namedtuple +try: + from types import MappingProxyType +except ImportError: + # mutable fallback if unavailable + MappingProxyType = lambda x: x + +class _MISSING_TYPE(object): + pass +MISSING = _MISSING_TYPE() + +_DataclassParams = namedtuple('_DataclassParams', + ["init", "repr", "eq", "order", "unsafe_hash", "frozen", + "match_args", "kw_only", "slots", "weakref_slot"]) +class Field(object): + __slots__ = ('name', + 'type', + 'default', + 'default_factory', + 'repr', + 'hash', + 'init', + 'compare', + 'metadata', + 'kw_only', + '_field_type', # Private: not to be used by user code. + ) + + def __init__(self, default, default_factory, init, repr, hash, compare, + metadata, kw_only): + self.name = None + self.type = None + self.default = default + self.default_factory = default_factory + self.init = init + self.repr = repr + self.hash = hash + self.compare = compare + # Be aware that if MappingProxyType is unavailable (i.e. py2?) then we + # don't enforce non-mutability that the real module does + self.metadata = (MappingProxyType({}) + if metadata is None else + MappingProxyType(metadata)) + self.kw_only = kw_only + self._field_type = None + + def __repr__(self): + return ('Field(' + 'name={0!r},' + 'type={1!r},' + 'default={2!r},' + 'default_factory={3!r},' + 'init={4!r},' + 'repr={5!r},' + 'hash={6!r},' + 'compare={7!r},' + 'metadata={8!r},' + 'kwonly={9!r},' + ')'.format(self.name, self.type, self.default, + self.default_factory, self.init, + self.repr, self.hash, self.compare, + self.metadata, self.kw_only)) + +# A sentinel object for default values to signal that a default +# factory will be used. This is given a nice repr() which will appear +# in the function signature of dataclasses' constructors. +class _HAS_DEFAULT_FACTORY_CLASS: + def __repr__(self): + return '<factory>' +_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS() + +def dataclass(*args, **kwds): + raise NotImplementedError("Standard library 'dataclasses' module" + "is unavailable, likely due to the version of Python you're using.") + +# Markers for the various kinds of fields and pseudo-fields. +class _FIELD_BASE: + def __init__(self, name): + self.name = name + def __repr__(self): + return self.name +_FIELD = _FIELD_BASE('_FIELD') +_FIELD_CLASSVAR = _FIELD_BASE('_FIELD_CLASSVAR') +_FIELD_INITVAR = _FIELD_BASE('_FIELD_INITVAR') + +def field(*ignore, **kwds): + default = kwds.pop("default", MISSING) + default_factory = kwds.pop("default_factory", MISSING) + init = kwds.pop("init", True) + repr = kwds.pop("repr", True) + hash = kwds.pop("hash", None) + compare = kwds.pop("compare", True) + metadata = kwds.pop("metadata", None) + kw_only = kwds.pop("kw_only", None) + + if kwds: + raise ValueError("field received unexpected keyword arguments: %s" + % list(kwds.keys())) + if default is not MISSING and default_factory is not MISSING: + raise ValueError('cannot specify both default and default_factory') + if ignore: + raise ValueError("'field' does not take any positional arguments") + return Field(default, default_factory, init, + repr, hash, compare, metadata, kw_only) |