diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/tools/python3/src/Lib/dataclasses.py | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Lib/dataclasses.py')
-rw-r--r-- | contrib/tools/python3/src/Lib/dataclasses.py | 178 |
1 files changed, 89 insertions, 89 deletions
diff --git a/contrib/tools/python3/src/Lib/dataclasses.py b/contrib/tools/python3/src/Lib/dataclasses.py index 09982bcc3e..5ff67ad2ea 100644 --- a/contrib/tools/python3/src/Lib/dataclasses.py +++ b/contrib/tools/python3/src/Lib/dataclasses.py @@ -7,7 +7,7 @@ import keyword import builtins import functools import _thread -from types import GenericAlias +from types import GenericAlias __all__ = ['dataclass', @@ -200,24 +200,24 @@ _POST_INIT_NAME = '__post_init__' # https://bugs.python.org/issue33453 for details. _MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)') -class InitVar: - __slots__ = ('type', ) - - def __init__(self, type): - self.type = type - - def __repr__(self): - if isinstance(self.type, type) and not isinstance(self.type, GenericAlias): - type_name = self.type.__name__ - else: - # typing objects, e.g. List[int] - type_name = repr(self.type) - return f'dataclasses.InitVar[{type_name}]' - - def __class_getitem__(cls, type): - return InitVar(type) - - +class InitVar: + __slots__ = ('type', ) + + def __init__(self, type): + self.type = type + + def __repr__(self): + if isinstance(self.type, type) and not isinstance(self.type, GenericAlias): + type_name = self.type.__name__ + else: + # typing objects, e.g. List[int] + type_name = repr(self.type) + return f'dataclasses.InitVar[{type_name}]' + + def __class_getitem__(cls, type): + return InitVar(type) + + # Instances of Field are only ever created from within this module, # and only from the field() function, although Field instances are # exposed externally as (conceptually) read-only objects. @@ -285,9 +285,9 @@ class Field: # it. func(self.default, owner, name) - __class_getitem__ = classmethod(GenericAlias) + __class_getitem__ = classmethod(GenericAlias) + - class _DataclassParams: __slots__ = ('init', 'repr', @@ -381,26 +381,26 @@ def _create_fn(name, args, body, *, globals=None, locals=None, # worries about external callers. if locals is None: locals = {} - if 'BUILTINS' not in locals: - locals['BUILTINS'] = builtins + if 'BUILTINS' not in locals: + locals['BUILTINS'] = builtins return_annotation = '' if return_type is not MISSING: locals['_return_type'] = return_type return_annotation = '->_return_type' args = ','.join(args) - body = '\n'.join(f' {b}' for b in body) + body = '\n'.join(f' {b}' for b in body) # Compute the text of the entire function. - txt = f' def {name}({args}){return_annotation}:\n{body}' + txt = f' def {name}({args}){return_annotation}:\n{body}' + + local_vars = ', '.join(locals.keys()) + txt = f"def __create_fn__({local_vars}):\n{txt}\n return {name}" - local_vars = ', '.join(locals.keys()) - txt = f"def __create_fn__({local_vars}):\n{txt}\n return {name}" + ns = {} + exec(txt, globals, ns) + return ns['__create_fn__'](**locals) - ns = {} - exec(txt, globals, ns) - return ns['__create_fn__'](**locals) - def _field_assign(frozen, name, value, self_name): # If we're a frozen class, then assign to our fields in __init__ # via object.__setattr__. Otherwise, just use a simple @@ -409,7 +409,7 @@ def _field_assign(frozen, name, value, self_name): # self_name is what "self" is called in this function: don't # hard-code "self", since that might be a field name. if frozen: - return f'BUILTINS.object.__setattr__({self_name},{name!r},{value})' + return f'BUILTINS.object.__setattr__({self_name},{name!r},{value})' return f'{self_name}.{name}={value}' @@ -486,7 +486,7 @@ def _init_param(f): return f'{f.name}:_type_{f.name}{default}' -def _init_fn(fields, frozen, has_post_init, self_name, globals): +def _init_fn(fields, frozen, has_post_init, self_name, globals): # fields contains both real fields and InitVar pseudo-fields. # Make sure we don't have fields without defaults following fields @@ -504,15 +504,15 @@ def _init_fn(fields, frozen, has_post_init, self_name, globals): raise TypeError(f'non-default argument {f.name!r} ' 'follows default argument') - locals = {f'_type_{f.name}': f.type for f in fields} - locals.update({ - 'MISSING': MISSING, - '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, - }) + locals = {f'_type_{f.name}': f.type for f in fields} + locals.update({ + 'MISSING': MISSING, + '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, + }) body_lines = [] for f in fields: - line = _field_init(f, frozen, locals, self_name) + line = _field_init(f, frozen, locals, self_name) # line is None means that this field doesn't require # initialization (it's a pseudo-field). Just skip it. if line: @@ -536,19 +536,19 @@ def _init_fn(fields, frozen, has_post_init, self_name, globals): return_type=None) -def _repr_fn(fields, globals): +def _repr_fn(fields, globals): fn = _create_fn('__repr__', ('self',), ['return self.__class__.__qualname__ + f"(' + ', '.join([f"{f.name}={{self.{f.name}!r}}" for f in fields]) + - ')"'], - globals=globals) + ')"'], + globals=globals) return _recursive_repr(fn) -def _frozen_get_del_attr(cls, fields, globals): - locals = {'cls': cls, +def _frozen_get_del_attr(cls, fields, globals): + locals = {'cls': cls, 'FrozenInstanceError': FrozenInstanceError} if fields: fields_str = '(' + ','.join(repr(f.name) for f in fields) + ',)' @@ -560,19 +560,19 @@ def _frozen_get_del_attr(cls, fields, globals): (f'if type(self) is cls or name in {fields_str}:', ' raise FrozenInstanceError(f"cannot assign to field {name!r}")', f'super(cls, self).__setattr__(name, value)'), - locals=locals, + locals=locals, globals=globals), _create_fn('__delattr__', ('self', 'name'), (f'if type(self) is cls or name in {fields_str}:', ' raise FrozenInstanceError(f"cannot delete field {name!r}")', f'super(cls, self).__delattr__(name)'), - locals=locals, + locals=locals, globals=globals), ) -def _cmp_fn(name, op, self_tuple, other_tuple, globals): +def _cmp_fn(name, op, self_tuple, other_tuple, globals): # Create a comparison function. If the fields in the object are # named 'x' and 'y', then self_tuple is the string # '(self.x,self.y)' and other_tuple is the string @@ -582,16 +582,16 @@ def _cmp_fn(name, op, self_tuple, other_tuple, globals): ('self', 'other'), [ 'if other.__class__ is self.__class__:', f' return {self_tuple}{op}{other_tuple}', - 'return NotImplemented'], - globals=globals) + 'return NotImplemented'], + globals=globals) -def _hash_fn(fields, globals): +def _hash_fn(fields, globals): self_tuple = _tuple_str('self', fields) return _create_fn('__hash__', ('self',), - [f'return hash({self_tuple})'], - globals=globals) + [f'return hash({self_tuple})'], + globals=globals) def _is_classvar(a_type, typing): @@ -605,8 +605,8 @@ def _is_classvar(a_type, typing): def _is_initvar(a_type, dataclasses): # The module we're checking against is the module we're # currently in (dataclasses.py). - return (a_type is dataclasses.InitVar - or type(a_type) is dataclasses.InitVar) + return (a_type is dataclasses.InitVar + or type(a_type) is dataclasses.InitVar) def _is_type(annotation, cls, a_module, a_type, is_type_predicate): @@ -696,7 +696,7 @@ def _get_field(cls, a_name, a_type): # In addition to checking for actual types here, also check for # string annotations. get_type_hints() won't always work for us # (see https://github.com/python/typing/issues/508 for example), - # plus it's expensive and would require an eval for every string + # plus it's expensive and would require an eval for every string # annotation. So, make a best effort to see if this is a ClassVar # or InitVar using regex's and checking that the thing referenced # is actually of the correct type. @@ -764,14 +764,14 @@ def _set_new_attribute(cls, name, value): # take. The common case is to do nothing, so instead of providing a # function that is a no-op, use None to signify that. -def _hash_set_none(cls, fields, globals): +def _hash_set_none(cls, fields, globals): return None -def _hash_add(cls, fields, globals): +def _hash_add(cls, fields, globals): flds = [f for f in fields if (f.compare if f.hash is None else f.hash)] - return _hash_fn(flds, globals) + return _hash_fn(flds, globals) -def _hash_exception(cls, fields, globals): +def _hash_exception(cls, fields, globals): # Raise an exception. raise TypeError(f'Cannot overwrite attribute __hash__ ' f'in class {cls.__name__}') @@ -813,16 +813,16 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): # is defined by the base class, which is found first. fields = {} - if cls.__module__ in sys.modules: - globals = sys.modules[cls.__module__].__dict__ - else: - # Theoretically this can happen if someone writes - # a custom string to cls.__module__. In which case - # such dataclass won't be fully introspectable - # (w.r.t. typing.get_type_hints) but will still function - # correctly. - globals = {} - + if cls.__module__ in sys.modules: + globals = sys.modules[cls.__module__].__dict__ + else: + # Theoretically this can happen if someone writes + # a custom string to cls.__module__. In which case + # such dataclass won't be fully introspectable + # (w.r.t. typing.get_type_hints) but will still function + # correctly. + globals = {} + setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order, unsafe_hash, frozen)) @@ -836,7 +836,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): # Only process classes that have been processed by our # decorator. That is, they have a _FIELDS attribute. base_fields = getattr(b, _FIELDS, None) - if base_fields is not None: + if base_fields is not None: has_dataclass_bases = True for f in base_fields.values(): fields[f.name] = f @@ -932,7 +932,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): # if possible. '__dataclass_self__' if 'self' in fields else 'self', - globals, + globals, )) # Get the fields as a list, and include only real fields. This is @@ -941,18 +941,18 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): if repr: flds = [f for f in field_list if f.repr] - _set_new_attribute(cls, '__repr__', _repr_fn(flds, globals)) + _set_new_attribute(cls, '__repr__', _repr_fn(flds, globals)) if eq: - # Create __eq__ method. There's no need for a __ne__ method, + # Create __eq__ method. There's no need for a __ne__ method, # since python will call __eq__ and negate it. flds = [f for f in field_list if f.compare] self_tuple = _tuple_str('self', flds) other_tuple = _tuple_str('other', flds) _set_new_attribute(cls, '__eq__', _cmp_fn('__eq__', '==', - self_tuple, other_tuple, - globals=globals)) + self_tuple, other_tuple, + globals=globals)) if order: # Create and set the ordering methods. @@ -965,14 +965,14 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): ('__ge__', '>='), ]: if _set_new_attribute(cls, name, - _cmp_fn(name, op, self_tuple, other_tuple, - globals=globals)): + _cmp_fn(name, op, self_tuple, other_tuple, + globals=globals)): raise TypeError(f'Cannot overwrite attribute {name} ' f'in class {cls.__name__}. Consider using ' 'functools.total_ordering') if frozen: - for fn in _frozen_get_del_attr(cls, field_list, globals): + for fn in _frozen_get_del_attr(cls, field_list, globals): if _set_new_attribute(cls, fn.__name__, fn): raise TypeError(f'Cannot overwrite attribute {fn.__name__} ' f'in class {cls.__name__}') @@ -985,7 +985,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): if hash_action: # No need to call _set_new_attribute here, since by the time # we're here the overwriting is unconditional. - cls.__hash__ = hash_action(cls, field_list, globals) + cls.__hash__ = hash_action(cls, field_list, globals) if not getattr(cls, '__doc__'): # Create a class doc-string. @@ -995,7 +995,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): return cls -def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, +def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False): """Returns the same class as was passed in, with dunder methods added based on the fields defined in the class. @@ -1013,12 +1013,12 @@ def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen) # See if we're being called as @dataclass or @dataclass(). - if cls is None: + if cls is None: # We're called with parens. return wrap # We're called as @dataclass without parens. - return wrap(cls) + return wrap(cls) def fields(class_or_instance): @@ -1041,14 +1041,14 @@ def fields(class_or_instance): def _is_dataclass_instance(obj): """Returns True if obj is an instance of a dataclass.""" - return hasattr(type(obj), _FIELDS) + return hasattr(type(obj), _FIELDS) def is_dataclass(obj): """Returns True if obj is a dataclass or an instance of a dataclass.""" - cls = obj if isinstance(obj, type) and not isinstance(obj, GenericAlias) else type(obj) - return hasattr(cls, _FIELDS) + cls = obj if isinstance(obj, type) and not isinstance(obj, GenericAlias) else type(obj) + return hasattr(cls, _FIELDS) def asdict(obj, *, dict_factory=dict): @@ -1094,7 +1094,7 @@ def _asdict_inner(obj, dict_factory): # method, because: # - it does not recurse in to the namedtuple fields and # convert them to dicts (using dict_factory). - # - I don't actually want to return a dict here. The main + # - I don't actually want to return a dict here. The main # use case here is json.dumps, and it handles converting # namedtuples to lists. Admittedly we're losing some # information here when we produce a json list instead of a @@ -1216,7 +1216,7 @@ def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, raise TypeError(f'Invalid field: {item!r}') if not isinstance(name, str) or not name.isidentifier(): - raise TypeError(f'Field names must be valid identifiers: {name!r}') + raise TypeError(f'Field names must be valid identifiers: {name!r}') if keyword.iskeyword(name): raise TypeError(f'Field names must not be keywords: {name!r}') if name in seen: @@ -1233,7 +1233,7 @@ def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, unsafe_hash=unsafe_hash, frozen=frozen) -def replace(obj, /, **changes): +def replace(obj, /, **changes): """Return a new object replacing specified fields with new values. This is especially useful for frozen classes. Example usage: @@ -1271,7 +1271,7 @@ def replace(obj, /, **changes): continue if f.name not in changes: - if f._field_type is _FIELD_INITVAR and f.default is MISSING: + if f._field_type is _FIELD_INITVAR and f.default is MISSING: raise ValueError(f"InitVar {f.name!r} " 'must be specified with replace()') changes[f.name] = getattr(obj, f.name) |