Reflow dataclasses comments (GH-6893)
To be more consistent with other code (and so people stop hassling me!), reflow the dataclasses comments to not use a single space indentation when continuing a paragraph of text.
This commit is contained in:
parent
98d50cb8f5
commit
f8e7549490
@ -25,8 +25,8 @@ __all__ = ['dataclass',
|
|||||||
# about init=, repr=, eq=, order=, unsafe_hash=, or frozen=, I'm
|
# about init=, repr=, eq=, order=, unsafe_hash=, or frozen=, I'm
|
||||||
# referring to the arguments to the @dataclass decorator. When
|
# referring to the arguments to the @dataclass decorator. When
|
||||||
# checking if a dunder method already exists, I mean check for an
|
# checking if a dunder method already exists, I mean check for an
|
||||||
# entry in the class's __dict__. I never check to see if an
|
# entry in the class's __dict__. I never check to see if an attribute
|
||||||
# attribute is defined in a base class.
|
# is defined in a base class.
|
||||||
|
|
||||||
# Key:
|
# Key:
|
||||||
# +=========+=========================================+
|
# +=========+=========================================+
|
||||||
@ -138,19 +138,20 @@ __all__ = ['dataclass',
|
|||||||
# For boxes that are blank, __hash__ is untouched and therefore
|
# For boxes that are blank, __hash__ is untouched and therefore
|
||||||
# inherited from the base class. If the base is object, then
|
# inherited from the base class. If the base is object, then
|
||||||
# id-based hashing is used.
|
# id-based hashing is used.
|
||||||
|
#
|
||||||
# Note that a class may already have __hash__=None if it specified an
|
# Note that a class may already have __hash__=None if it specified an
|
||||||
# __eq__ method in the class body (not one that was created by
|
# __eq__ method in the class body (not one that was created by
|
||||||
# @dataclass).
|
# @dataclass).
|
||||||
|
#
|
||||||
# See _hash_action (below) for a coded version of this table.
|
# See _hash_action (below) for a coded version of this table.
|
||||||
|
|
||||||
|
|
||||||
# Raised when an attempt is made to modify a frozen class.
|
# Raised when an attempt is made to modify a frozen class.
|
||||||
class FrozenInstanceError(AttributeError): pass
|
class FrozenInstanceError(AttributeError): pass
|
||||||
|
|
||||||
# A sentinel object for default values to signal that a
|
# A sentinel object for default values to signal that a default
|
||||||
# default factory will be used.
|
# factory will be used. This is given a nice repr() which will appear
|
||||||
# This is given a nice repr() which will appear in the function
|
# in the function signature of dataclasses' constructors.
|
||||||
# signature of dataclasses' constructors.
|
|
||||||
class _HAS_DEFAULT_FACTORY_CLASS:
|
class _HAS_DEFAULT_FACTORY_CLASS:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<factory>'
|
return '<factory>'
|
||||||
@ -204,9 +205,11 @@ class InitVar(metaclass=_InitVarMeta):
|
|||||||
# Instances of Field are only ever created from within this module,
|
# Instances of Field are only ever created from within this module,
|
||||||
# and only from the field() function, although Field instances are
|
# and only from the field() function, although Field instances are
|
||||||
# exposed externally as (conceptually) read-only objects.
|
# exposed externally as (conceptually) read-only objects.
|
||||||
# name and type are filled in after the fact, not in __init__. They're
|
#
|
||||||
# not known at the time this class is instantiated, but it's
|
# name and type are filled in after the fact, not in __init__.
|
||||||
|
# They're not known at the time this class is instantiated, but it's
|
||||||
# convenient if they're available later.
|
# convenient if they're available later.
|
||||||
|
#
|
||||||
# When cls._FIELDS is filled in with a list of Field objects, the name
|
# When cls._FIELDS is filled in with a list of Field objects, the name
|
||||||
# and type fields will have been populated.
|
# and type fields will have been populated.
|
||||||
class Field:
|
class Field:
|
||||||
@ -255,14 +258,15 @@ class Field:
|
|||||||
# case where we're using a field that contains a descriptor as a
|
# case where we're using a field that contains a descriptor as a
|
||||||
# defaul value. For details on __set_name__, see
|
# defaul value. For details on __set_name__, see
|
||||||
# https://www.python.org/dev/peps/pep-0487/#implementation-details.
|
# https://www.python.org/dev/peps/pep-0487/#implementation-details.
|
||||||
# Note that in _process_class, this Field object is overwritten with
|
#
|
||||||
# the default value, so the end result is a descriptor that had
|
# Note that in _process_class, this Field object is overwritten
|
||||||
# __set_name__ called on it at the right time.
|
# with the default value, so the end result is a descriptor that
|
||||||
|
# had __set_name__ called on it at the right time.
|
||||||
def __set_name__(self, owner, name):
|
def __set_name__(self, owner, name):
|
||||||
func = getattr(type(self.default), '__set_name__', None)
|
func = getattr(type(self.default), '__set_name__', None)
|
||||||
if func:
|
if func:
|
||||||
# There is a __set_name__ method on the descriptor,
|
# There is a __set_name__ method on the descriptor, call
|
||||||
# call it.
|
# it.
|
||||||
func(self.default, owner, name)
|
func(self.default, owner, name)
|
||||||
|
|
||||||
|
|
||||||
@ -306,9 +310,9 @@ def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,
|
|||||||
is True, the field will be a parameter to the class's __init__()
|
is True, the field will be a parameter to the class's __init__()
|
||||||
function. If repr is True, the field will be included in the
|
function. If repr is True, the field will be included in the
|
||||||
object's repr(). If hash is True, the field will be included in
|
object's repr(). If hash is True, the field will be included in
|
||||||
the object's hash(). If compare is True, the field will be used in
|
the object's hash(). If compare is True, the field will be used
|
||||||
comparison functions. metadata, if specified, must be a mapping
|
in comparison functions. metadata, if specified, must be a
|
||||||
which is stored but not otherwise examined by dataclass.
|
mapping which is stored but not otherwise examined by dataclass.
|
||||||
|
|
||||||
It is an error to specify both default and default_factory.
|
It is an error to specify both default and default_factory.
|
||||||
"""
|
"""
|
||||||
@ -333,9 +337,9 @@ def _tuple_str(obj_name, fields):
|
|||||||
|
|
||||||
def _create_fn(name, args, body, *, globals=None, locals=None,
|
def _create_fn(name, args, body, *, globals=None, locals=None,
|
||||||
return_type=MISSING):
|
return_type=MISSING):
|
||||||
# Note that we mutate locals when exec() is called. Caller beware!
|
# Note that we mutate locals when exec() is called. Caller
|
||||||
# The only callers are internal to this module, so no worries
|
# beware! The only callers are internal to this module, so no
|
||||||
# about external callers.
|
# worries about external callers.
|
||||||
if locals is None:
|
if locals is None:
|
||||||
locals = {}
|
locals = {}
|
||||||
return_annotation = ''
|
return_annotation = ''
|
||||||
@ -356,6 +360,7 @@ def _field_assign(frozen, name, value, self_name):
|
|||||||
# If we're a frozen class, then assign to our fields in __init__
|
# If we're a frozen class, then assign to our fields in __init__
|
||||||
# via object.__setattr__. Otherwise, just use a simple
|
# via object.__setattr__. Otherwise, just use a simple
|
||||||
# assignment.
|
# assignment.
|
||||||
|
#
|
||||||
# self_name is what "self" is called in this function: don't
|
# self_name is what "self" is called in this function: don't
|
||||||
# hard-code "self", since that might be a field name.
|
# hard-code "self", since that might be a field name.
|
||||||
if frozen:
|
if frozen:
|
||||||
@ -403,8 +408,8 @@ def _field_init(f, frozen, globals, self_name):
|
|||||||
globals[default_name] = f.default
|
globals[default_name] = f.default
|
||||||
value = f.name
|
value = f.name
|
||||||
else:
|
else:
|
||||||
# This field does not need initialization. Signify that to
|
# This field does not need initialization. Signify that
|
||||||
# the caller by returning None.
|
# to the caller by returning None.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Only test this now, so that we can create variables for the
|
# Only test this now, so that we can create variables for the
|
||||||
@ -418,16 +423,17 @@ def _field_init(f, frozen, globals, self_name):
|
|||||||
|
|
||||||
|
|
||||||
def _init_param(f):
|
def _init_param(f):
|
||||||
# Return the __init__ parameter string for this field.
|
# Return the __init__ parameter string for this field. For
|
||||||
# For example, the equivalent of 'x:int=3' (except instead of 'int',
|
# example, the equivalent of 'x:int=3' (except instead of 'int',
|
||||||
# reference a variable set to int, and instead of '3', reference a
|
# reference a variable set to int, and instead of '3', reference a
|
||||||
# variable set to 3).
|
# variable set to 3).
|
||||||
if f.default is MISSING and f.default_factory is MISSING:
|
if f.default is MISSING and f.default_factory is MISSING:
|
||||||
# There's no default, and no default_factory, just
|
# There's no default, and no default_factory, just output the
|
||||||
# output the variable name and type.
|
# variable name and type.
|
||||||
default = ''
|
default = ''
|
||||||
elif f.default is not MISSING:
|
elif f.default is not MISSING:
|
||||||
# There's a default, this will be the name that's used to look it up.
|
# There's a default, this will be the name that's used to look
|
||||||
|
# it up.
|
||||||
default = f'=_dflt_{f.name}'
|
default = f'=_dflt_{f.name}'
|
||||||
elif f.default_factory is not MISSING:
|
elif f.default_factory is not MISSING:
|
||||||
# There's a factory function. Set a marker.
|
# There's a factory function. Set a marker.
|
||||||
@ -493,8 +499,8 @@ def _repr_fn(fields):
|
|||||||
|
|
||||||
|
|
||||||
def _frozen_get_del_attr(cls, fields):
|
def _frozen_get_del_attr(cls, fields):
|
||||||
# XXX: globals is modified on the first call to _create_fn, then the
|
# XXX: globals is modified on the first call to _create_fn, then
|
||||||
# modified version is used in the second call. Is this okay?
|
# the modified version is used in the second call. Is this okay?
|
||||||
globals = {'cls': cls,
|
globals = {'cls': cls,
|
||||||
'FrozenInstanceError': FrozenInstanceError}
|
'FrozenInstanceError': FrozenInstanceError}
|
||||||
if fields:
|
if fields:
|
||||||
@ -573,25 +579,25 @@ def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
|
|||||||
# instead only a module (global) lookup), there are some things it
|
# instead only a module (global) lookup), there are some things it
|
||||||
# gets wrong.
|
# gets wrong.
|
||||||
|
|
||||||
# With string annotations, this will work:
|
# With string annotations, cv0 will be detected as a ClassVar:
|
||||||
# CV = ClassVar
|
# CV = ClassVar
|
||||||
# @dataclass
|
# @dataclass
|
||||||
# class C0:
|
# class C0:
|
||||||
# cv0: CV
|
# cv0: CV
|
||||||
|
|
||||||
# But this will not:
|
# But in this example cv1 will not be detected as a ClassVar:
|
||||||
# @dataclass
|
# @dataclass
|
||||||
# class C1:
|
# class C1:
|
||||||
# CV = ClassVar
|
# CV = ClassVar
|
||||||
# cv1: CV
|
# cv1: CV
|
||||||
|
|
||||||
# In C1, the code in this function will look up "CV" in the module
|
# In C1, the code in this function (_is_type) will look up "CV" in
|
||||||
# and not find it, so it will not consider cv1 as a ClassVar.
|
# the module and not find it, so it will not consider cv1 as a
|
||||||
# This is a fairly obscure corner case, and the best way to fix it
|
# ClassVar. This is a fairly obscure corner case, and the best
|
||||||
# would be to eval() the string "CV" with the correct global and
|
# way to fix it would be to eval() the string "CV" with the
|
||||||
# local namespaces. However that would involve a eval() penalty
|
# correct global and local namespaces. However that would involve
|
||||||
# for every single field of every dataclass that's defined. It
|
# a eval() penalty for every single field of every dataclass
|
||||||
# was judged not worth it.
|
# that's defined. It was judged not worth it.
|
||||||
|
|
||||||
match = _MODULE_IDENTIFIER_RE.match(annotation)
|
match = _MODULE_IDENTIFIER_RE.match(annotation)
|
||||||
if match:
|
if match:
|
||||||
@ -616,8 +622,8 @@ def _get_field(cls, a_name, a_type):
|
|||||||
# and InitVars are also returned, but marked as such (see
|
# and InitVars are also returned, but marked as such (see
|
||||||
# f._field_type).
|
# f._field_type).
|
||||||
|
|
||||||
# If the default value isn't derived from Field, then it's
|
# If the default value isn't derived from Field, then it's only a
|
||||||
# only a normal default value. Convert it to a Field().
|
# normal default value. Convert it to a Field().
|
||||||
default = getattr(cls, a_name, MISSING)
|
default = getattr(cls, a_name, MISSING)
|
||||||
if isinstance(default, Field):
|
if isinstance(default, Field):
|
||||||
f = default
|
f = default
|
||||||
@ -640,9 +646,9 @@ def _get_field(cls, a_name, a_type):
|
|||||||
# string annotations. get_type_hints() won't always work for us
|
# string annotations. get_type_hints() won't always work for us
|
||||||
# (see https://github.com/python/typing/issues/508 for example),
|
# (see https://github.com/python/typing/issues/508 for example),
|
||||||
# plus it's expensive and would require an eval for every stirng
|
# plus it's expensive and would require an eval for every stirng
|
||||||
# annotation. So, make a best effort to see if this is a
|
# annotation. So, make a best effort to see if this is a ClassVar
|
||||||
# ClassVar or InitVar using regex's and checking that the thing
|
# or InitVar using regex's and checking that the thing referenced
|
||||||
# referenced is actually of the correct type.
|
# is actually of the correct type.
|
||||||
|
|
||||||
# For the complete discussion, see https://bugs.python.org/issue33453
|
# For the complete discussion, see https://bugs.python.org/issue33453
|
||||||
|
|
||||||
@ -652,8 +658,6 @@ def _get_field(cls, a_name, a_type):
|
|||||||
# module).
|
# module).
|
||||||
typing = sys.modules.get('typing')
|
typing = sys.modules.get('typing')
|
||||||
if typing:
|
if typing:
|
||||||
# This test uses a typing internal class, but it's the best
|
|
||||||
# way to test if this is a ClassVar.
|
|
||||||
if (_is_classvar(a_type, typing)
|
if (_is_classvar(a_type, typing)
|
||||||
or (isinstance(f.type, str)
|
or (isinstance(f.type, str)
|
||||||
and _is_type(f.type, cls, typing, typing.ClassVar,
|
and _is_type(f.type, cls, typing, typing.ClassVar,
|
||||||
@ -682,8 +686,8 @@ def _get_field(cls, a_name, a_type):
|
|||||||
raise TypeError(f'field {f.name} cannot have a '
|
raise TypeError(f'field {f.name} cannot have a '
|
||||||
'default factory')
|
'default factory')
|
||||||
# Should I check for other field settings? default_factory
|
# Should I check for other field settings? default_factory
|
||||||
# seems the most serious to check for. Maybe add others.
|
# seems the most serious to check for. Maybe add others. For
|
||||||
# For example, how about init=False (or really,
|
# example, how about init=False (or really,
|
||||||
# init=<not-the-default-init-value>)? It makes no sense for
|
# init=<not-the-default-init-value>)? It makes no sense for
|
||||||
# ClassVar and InitVar to specify init=<anything>.
|
# ClassVar and InitVar to specify init=<anything>.
|
||||||
|
|
||||||
@ -763,8 +767,8 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
|
|||||||
|
|
||||||
# Find our base classes in reverse MRO order, and exclude
|
# Find our base classes in reverse MRO order, and exclude
|
||||||
# ourselves. In reversed order so that more derived classes
|
# ourselves. In reversed order so that more derived classes
|
||||||
# override earlier field definitions in base classes.
|
# override earlier field definitions in base classes. As long as
|
||||||
# As long as we're iterating over them, see if any are frozen.
|
# we're iterating over them, see if any are frozen.
|
||||||
any_frozen_base = False
|
any_frozen_base = False
|
||||||
has_dataclass_bases = False
|
has_dataclass_bases = False
|
||||||
for b in cls.__mro__[-1:0:-1]:
|
for b in cls.__mro__[-1:0:-1]:
|
||||||
@ -780,29 +784,30 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
|
|||||||
|
|
||||||
# Annotations that are defined in this class (not in base
|
# Annotations that are defined in this class (not in base
|
||||||
# classes). If __annotations__ isn't present, then this class
|
# classes). If __annotations__ isn't present, then this class
|
||||||
# adds no new annotations. We use this to compute fields that
|
# adds no new annotations. We use this to compute fields that are
|
||||||
# are added by this class.
|
# added by this class.
|
||||||
|
#
|
||||||
# Fields are found from cls_annotations, which is guaranteed to be
|
# Fields are found from cls_annotations, which is guaranteed to be
|
||||||
# ordered. Default values are from class attributes, if a field
|
# ordered. Default values are from class attributes, if a field
|
||||||
# has a default. If the default value is a Field(), then it
|
# has a default. If the default value is a Field(), then it
|
||||||
# contains additional info beyond (and possibly including) the
|
# contains additional info beyond (and possibly including) the
|
||||||
# actual default value. Pseudo-fields ClassVars and InitVars are
|
# actual default value. Pseudo-fields ClassVars and InitVars are
|
||||||
# included, despite the fact that they're not real fields.
|
# included, despite the fact that they're not real fields. That's
|
||||||
# That's dealt with later.
|
# dealt with later.
|
||||||
cls_annotations = cls.__dict__.get('__annotations__', {})
|
cls_annotations = cls.__dict__.get('__annotations__', {})
|
||||||
|
|
||||||
# Now find fields in our class. While doing so, validate some
|
# Now find fields in our class. While doing so, validate some
|
||||||
# things, and set the default values (as class attributes)
|
# things, and set the default values (as class attributes) where
|
||||||
# where we can.
|
# we can.
|
||||||
cls_fields = [_get_field(cls, name, type)
|
cls_fields = [_get_field(cls, name, type)
|
||||||
for name, type in cls_annotations.items()]
|
for name, type in cls_annotations.items()]
|
||||||
for f in cls_fields:
|
for f in cls_fields:
|
||||||
fields[f.name] = f
|
fields[f.name] = f
|
||||||
|
|
||||||
# If the class attribute (which is the default value for
|
# If the class attribute (which is the default value for this
|
||||||
# this field) exists and is of type 'Field', replace it
|
# field) exists and is of type 'Field', replace it with the
|
||||||
# with the real default. This is so that normal class
|
# real default. This is so that normal class introspection
|
||||||
# introspection sees a real default value, not a Field.
|
# sees a real default value, not a Field.
|
||||||
if isinstance(getattr(cls, f.name, None), Field):
|
if isinstance(getattr(cls, f.name, None), Field):
|
||||||
if f.default is MISSING:
|
if f.default is MISSING:
|
||||||
# If there's no default, delete the class attribute.
|
# If there's no default, delete the class attribute.
|
||||||
@ -832,8 +837,8 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
|
|||||||
raise TypeError('cannot inherit frozen dataclass from a '
|
raise TypeError('cannot inherit frozen dataclass from a '
|
||||||
'non-frozen one')
|
'non-frozen one')
|
||||||
|
|
||||||
# Remember all of the fields on our class (including bases). This also
|
# Remember all of the fields on our class (including bases). This
|
||||||
# marks this class as being a dataclass.
|
# also marks this class as being a dataclass.
|
||||||
setattr(cls, _FIELDS, fields)
|
setattr(cls, _FIELDS, fields)
|
||||||
|
|
||||||
# Was this class defined with an explicit __hash__? Note that if
|
# Was this class defined with an explicit __hash__? Note that if
|
||||||
@ -845,8 +850,8 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
|
|||||||
has_explicit_hash = not (class_hash is MISSING or
|
has_explicit_hash = not (class_hash is MISSING or
|
||||||
(class_hash is None and '__eq__' in cls.__dict__))
|
(class_hash is None and '__eq__' in cls.__dict__))
|
||||||
|
|
||||||
# If we're generating ordering methods, we must be generating
|
# If we're generating ordering methods, we must be generating the
|
||||||
# the eq methods.
|
# eq methods.
|
||||||
if order and not eq:
|
if order and not eq:
|
||||||
raise ValueError('eq must be true if order is true')
|
raise ValueError('eq must be true if order is true')
|
||||||
|
|
||||||
@ -861,8 +866,9 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
|
|||||||
_init_fn(flds,
|
_init_fn(flds,
|
||||||
frozen,
|
frozen,
|
||||||
has_post_init,
|
has_post_init,
|
||||||
# The name to use for the "self" param
|
# The name to use for the "self"
|
||||||
# in __init__. Use "self" if possible.
|
# param in __init__. Use "self"
|
||||||
|
# if possible.
|
||||||
'__dataclass_self__' if 'self' in fields
|
'__dataclass_self__' if 'self' in fields
|
||||||
else 'self',
|
else 'self',
|
||||||
))
|
))
|
||||||
@ -1130,8 +1136,8 @@ def replace(obj, **changes):
|
|||||||
assert c1.x == 3 and c1.y == 2
|
assert c1.x == 3 and c1.y == 2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# We're going to mutate 'changes', but that's okay because it's a new
|
# We're going to mutate 'changes', but that's okay because it's a
|
||||||
# dict, even if called with 'replace(obj, **my_changes)'.
|
# new dict, even if called with 'replace(obj, **my_changes)'.
|
||||||
|
|
||||||
if not _is_dataclass_instance(obj):
|
if not _is_dataclass_instance(obj):
|
||||||
raise TypeError("replace() should be called on dataclass instances")
|
raise TypeError("replace() should be called on dataclass instances")
|
||||||
@ -1152,8 +1158,8 @@ def replace(obj, **changes):
|
|||||||
changes[f.name] = getattr(obj, f.name)
|
changes[f.name] = getattr(obj, f.name)
|
||||||
|
|
||||||
# Create the new object, which calls __init__() and
|
# Create the new object, which calls __init__() and
|
||||||
# __post_init__() (if defined), using all of the init fields
|
# __post_init__() (if defined), using all of the init fields we've
|
||||||
# we've added and/or left in 'changes'. If there are values
|
# added and/or left in 'changes'. If there are values supplied in
|
||||||
# supplied in changes that aren't fields, this will correctly
|
# changes that aren't fields, this will correctly raise a
|
||||||
# raise a TypeError.
|
# TypeError.
|
||||||
return obj.__class__(**changes)
|
return obj.__class__(**changes)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user