summaryrefslogtreecommitdiff
path: root/Cython/Utility/Dataclasses.py
diff options
context:
space:
mode:
Diffstat (limited to 'Cython/Utility/Dataclasses.py')
-rw-r--r--Cython/Utility/Dataclasses.py112
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)