Passed
Pull Request — main (#226)
by Jan
10:43
created

openscap_report.dataclasses.astuple()   A

Complexity

Conditions 2

Size

Total Lines 22
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nop 3
dl 0
loc 22
ccs 0
cts 4
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
import re
0 ignored issues
show
coding-style introduced by
Too many lines in module (1184/1000)
Loading history...
2
import sys
3
import copy
4
import types
5
import inspect
6
import keyword
7
8
__all__ = ['dataclass',
9
           'field',
10
           'Field',
11
           'FrozenInstanceError',
12
           'InitVar',
13
           'MISSING',
14
15
           # Helper functions.
16
           'fields',
17
           'asdict',
18
           'astuple',
19
           'make_dataclass',
20
           'replace',
21
           'is_dataclass',
22
           ]
23
24
# Conditions for adding methods.  The boxes indicate what action the
25
# dataclass decorator takes.  For all of these tables, when I talk
26
# about init=, repr=, eq=, order=, unsafe_hash=, or frozen=, I'm
27
# referring to the arguments to the @dataclass decorator.  When
28
# checking if a dunder method already exists, I mean check for an
29
# entry in the class's __dict__.  I never check to see if an attribute
30
# is defined in a base class.
31
32
# Key:
33
# +=========+=========================================+
34
# + Value   | Meaning                                 |
35
# +=========+=========================================+
36
# | <blank> | No action: no method is added.          |
37
# +---------+-----------------------------------------+
38
# | add     | Generated method is added.              |
39
# +---------+-----------------------------------------+
40
# | raise   | TypeError is raised.                    |
41
# +---------+-----------------------------------------+
42
# | None    | Attribute is set to None.               |
43
# +=========+=========================================+
44
45
# __init__
46
#
47
#   +--- init= parameter
48
#   |
49
#   v     |       |       |
50
#         |  no   |  yes  |  <--- class has __init__ in __dict__?
51
# +=======+=======+=======+
52
# | False |       |       |
53
# +-------+-------+-------+
54
# | True  | add   |       |  <- the default
55
# +=======+=======+=======+
56
57
# __repr__
58
#
59
#    +--- repr= parameter
60
#    |
61
#    v    |       |       |
62
#         |  no   |  yes  |  <--- class has __repr__ in __dict__?
63
# +=======+=======+=======+
64
# | False |       |       |
65
# +-------+-------+-------+
66
# | True  | add   |       |  <- the default
67
# +=======+=======+=======+
68
69
70
# __setattr__
71
# __delattr__
72
#
73
#    +--- frozen= parameter
74
#    |
75
#    v    |       |       |
76
#         |  no   |  yes  |  <--- class has __setattr__ or __delattr__ in __dict__?
77
# +=======+=======+=======+
78
# | False |       |       |  <- the default
79
# +-------+-------+-------+
80
# | True  | add   | raise |
81
# +=======+=======+=======+
82
# Raise because not adding these methods would break the "frozen-ness"
83
# of the class.
84
85
# __eq__
86
#
87
#    +--- eq= parameter
88
#    |
89
#    v    |       |       |
90
#         |  no   |  yes  |  <--- class has __eq__ in __dict__?
91
# +=======+=======+=======+
92
# | False |       |       |
93
# +-------+-------+-------+
94
# | True  | add   |       |  <- the default
95
# +=======+=======+=======+
96
97
# __lt__
98
# __le__
99
# __gt__
100
# __ge__
101
#
102
#    +--- order= parameter
103
#    |
104
#    v    |       |       |
105
#         |  no   |  yes  |  <--- class has any comparison method in __dict__?
106
# +=======+=======+=======+
107
# | False |       |       |  <- the default
108
# +-------+-------+-------+
109
# | True  | add   | raise |
110
# +=======+=======+=======+
111
# Raise because to allow this case would interfere with using
112
# functools.total_ordering.
113
114
# __hash__
115
116
#    +------------------- unsafe_hash= parameter
117
#    |       +----------- eq= parameter
118
#    |       |       +--- frozen= parameter
119
#    |       |       |
120
#    v       v       v    |        |        |
121
#                         |   no   |  yes   |  <--- class has explicitly defined __hash__
122
# +=======+=======+=======+========+========+
123
# | False | False | False |        |        | No __eq__, use the base class __hash__
124
# +-------+-------+-------+--------+--------+
125
# | False | False | True  |        |        | No __eq__, use the base class __hash__
126
# +-------+-------+-------+--------+--------+
127
# | False | True  | False | None   |        | <-- the default, not hashable
128
# +-------+-------+-------+--------+--------+
129
# | False | True  | True  | add    |        | Frozen, so hashable, allows override
130
# +-------+-------+-------+--------+--------+
131
# | True  | False | False | add    | raise  | Has no __eq__, but hashable
132
# +-------+-------+-------+--------+--------+
133
# | True  | False | True  | add    | raise  | Has no __eq__, but hashable
134
# +-------+-------+-------+--------+--------+
135
# | True  | True  | False | add    | raise  | Not frozen, but hashable
136
# +-------+-------+-------+--------+--------+
137
# | True  | True  | True  | add    | raise  | Frozen, so hashable
138
# +=======+=======+=======+========+========+
139
# For boxes that are blank, __hash__ is untouched and therefore
140
# inherited from the base class.  If the base is object, then
141
# id-based hashing is used.
142
#
143
# Note that a class may already have __hash__=None if it specified an
144
# __eq__ method in the class body (not one that was created by
145
# @dataclass).
146
#
147
# See _hash_action (below) for a coded version of this table.
148
149
150
# Raised when an attempt is made to modify a frozen class.
151
class FrozenInstanceError(AttributeError): pass
0 ignored issues
show
Coding Style introduced by
More than one statement on a single line
Loading history...
152
153
# A sentinel object for default values to signal that a default
154
# factory will be used.  This is given a nice repr() which will appear
155
# in the function signature of dataclasses' constructors.
156
class _HAS_DEFAULT_FACTORY_CLASS:
0 ignored issues
show
Coding Style Naming introduced by
Class name "_HAS_DEFAULT_FACTORY_CLASS" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]*$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
157
    def __repr__(self):
158
        return '<factory>'
159
_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS()
160
161
# A sentinel object to detect if a parameter is supplied or not.  Use
162
# a class to give it a better repr.
163
class _MISSING_TYPE:
0 ignored issues
show
Coding Style Naming introduced by
Class name "_MISSING_TYPE" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]*$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
164
    pass
165
MISSING = _MISSING_TYPE()
166
167
# Since most per-field metadata will be unused, create an empty
168
# read-only proxy that can be shared among all fields.
169
_EMPTY_METADATA = types.MappingProxyType({})
170
171
# Markers for the various kinds of fields and pseudo-fields.
172
class _FIELD_BASE:
0 ignored issues
show
Coding Style Naming introduced by
Class name "_FIELD_BASE" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]*$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
173
    def __init__(self, name):
174
        self.name = name
175
    def __repr__(self):
176
        return self.name
177
_FIELD = _FIELD_BASE('_FIELD')
178
_FIELD_CLASSVAR = _FIELD_BASE('_FIELD_CLASSVAR')
179
_FIELD_INITVAR = _FIELD_BASE('_FIELD_INITVAR')
180
181
# The name of an attribute on the class where we store the Field
182
# objects.  Also used to check if a class is a Data Class.
183
_FIELDS = '__dataclass_fields__'
184
185
# The name of an attribute on the class that stores the parameters to
186
# @dataclass.
187
_PARAMS = '__dataclass_params__'
188
189
# The name of the function, that if it exists, is called at the end of
190
# __init__.
191
_POST_INIT_NAME = '__post_init__'
192
193
# String regex that string annotations for ClassVar or InitVar must match.
194
# Allows "identifier.identifier[" or "identifier[".
195
# https://bugs.python.org/issue33453 for details.
196
_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')
197
198
class _InitVarMeta(type):
199
    def __getitem__(self, params):
0 ignored issues
show
Coding Style Best Practice introduced by
The first argument of the metaclass method __getitem__ should be named cls.
Loading history...
200
        return self
201
202
class InitVar(metaclass=_InitVarMeta):
203
    pass
204
205
206
# Instances of Field are only ever created from within this module,
207
# and only from the field() function, although Field instances are
208
# exposed externally as (conceptually) read-only objects.
209
#
210
# name and type are filled in after the fact, not in __init__.
211
# They're not known at the time this class is instantiated, but it's
212
# convenient if they're available later.
213
#
214
# When cls._FIELDS is filled in with a list of Field objects, the name
215
# and type fields will have been populated.
216
class Field:
0 ignored issues
show
best-practice introduced by
Too many instance attributes (10/7)
Loading history...
217
    __slots__ = ('name',
218
                 'type',
219
                 'default',
220
                 'default_factory',
221
                 'repr',
222
                 'hash',
223
                 'init',
224
                 'compare',
225
                 'metadata',
226
                 '_field_type',  # Private: not to be used by user code.
227
                 )
228
229
    def __init__(self, default, default_factory, init, repr, hash, compare,
0 ignored issues
show
best-practice introduced by
Too many arguments (8/5)
Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in repr.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in hash.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
230
                 metadata):
231
        self.name = None
232
        self.type = None
233
        self.default = default
234
        self.default_factory = default_factory
235
        self.init = init
236
        self.repr = repr
237
        self.hash = hash
238
        self.compare = compare
239
        self.metadata = (_EMPTY_METADATA
240
                         if metadata is None or len(metadata) == 0 else
241
                         types.MappingProxyType(metadata))
242
        self._field_type = None
243
244
    def __repr__(self):
245
        return ('Field('
246
                f'name={self.name!r},'
247
                f'type={self.type!r},'
248
                f'default={self.default!r},'
249
                f'default_factory={self.default_factory!r},'
250
                f'init={self.init!r},'
251
                f'repr={self.repr!r},'
252
                f'hash={self.hash!r},'
253
                f'compare={self.compare!r},'
254
                f'metadata={self.metadata!r},'
255
                f'_field_type={self._field_type}'
256
                ')')
257
258
    # This is used to support the PEP 487 __set_name__ protocol in the
259
    # case where we're using a field that contains a descriptor as a
260
    # default value.  For details on __set_name__, see
261
    # https://www.python.org/dev/peps/pep-0487/#implementation-details.
262
    #
263
    # Note that in _process_class, this Field object is overwritten
264
    # with the default value, so the end result is a descriptor that
265
    # had __set_name__ called on it at the right time.
266
    def __set_name__(self, owner, name):
267
        func = getattr(type(self.default), '__set_name__', None)
268
        if func:
269
            # There is a __set_name__ method on the descriptor, call
270
            # it.
271
            func(self.default, owner, name)
272
273
274
class _DataclassParams:
275
    __slots__ = ('init',
276
                 'repr',
277
                 'eq',
278
                 'order',
279
                 'unsafe_hash',
280
                 'frozen',
281
                 )
282
283
    def __init__(self, init, repr, eq, order, unsafe_hash, frozen):
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in repr.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
284
        self.init = init
285
        self.repr = repr
286
        self.eq = eq
287
        self.order = order
288
        self.unsafe_hash = unsafe_hash
289
        self.frozen = frozen
290
291
    def __repr__(self):
292
        return ('_DataclassParams('
293
                f'init={self.init!r},'
294
                f'repr={self.repr!r},'
295
                f'eq={self.eq!r},'
296
                f'order={self.order!r},'
297
                f'unsafe_hash={self.unsafe_hash!r},'
298
                f'frozen={self.frozen!r}'
299
                ')')
300
301
302
# This function is used instead of exposing Field creation directly,
303
# so that a type checker can be told (via overloads) that this is a
304
# function whose type depends on its parameters.
305
def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in repr.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
306
          hash=None, compare=True, metadata=None):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in hash.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
307
    """Return an object to identify dataclass fields.
308
309
    default is the default value of the field.  default_factory is a
310
    0-argument function called to initialize a field's value.  If init
311
    is True, the field will be a parameter to the class's __init__()
312
    function.  If repr is True, the field will be included in the
313
    object's repr().  If hash is True, the field will be included in
314
    the object's hash().  If compare is True, the field will be used
315
    in comparison functions.  metadata, if specified, must be a
316
    mapping which is stored but not otherwise examined by dataclass.
317
318
    It is an error to specify both default and default_factory.
319
    """
320
321
    if default is not MISSING and default_factory is not MISSING:
322
        raise ValueError('cannot specify both default and default_factory')
323
    return Field(default, default_factory, init, repr, hash, compare,
324
                 metadata)
325
326
327
def _tuple_str(obj_name, fields):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
328
    # Return a string representing each field of obj_name as a tuple
329
    # member.  So, if fields is ['x', 'y'] and obj_name is "self",
330
    # return "(self.x,self.y)".
331
332
    # Special case for the 0-tuple.
333
    if not fields:
334
        return '()'
335
    # Note the trailing comma, needed if this turns out to be a 1-tuple.
336
    return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)'
337
338
339
def _create_fn(name, args, body, *, globals=None, locals=None,
0 ignored issues
show
best-practice introduced by
Too many arguments (6/5)
Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in globals.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in locals.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
340
               return_type=MISSING):
341
    # Note that we mutate locals when exec() is called.  Caller
342
    # beware!  The only callers are internal to this module, so no
343
    # worries about external callers.
344
    if locals is None:
345
        locals = {}
346
    return_annotation = ''
347
    if return_type is not MISSING:
348
        locals['_return_type'] = return_type
349
        return_annotation = '->_return_type'
350
    args = ','.join(args)
351
    body = '\n'.join(f' {b}' for b in body)
352
353
    # Compute the text of the entire function.
354
    txt = f'def {name}({args}){return_annotation}:\n{body}'
355
356
    exec(txt, globals, locals)
0 ignored issues
show
Coding Style Security introduced by
The use of exec is discouraged.

Execution of dynamic code might introduce security vulnerabilities. It is generally recommended to use this feature with care and only when necessary.

Loading history...
357
    return locals[name]
358
359
360
def _field_assign(frozen, name, value, self_name):
361
    # If we're a frozen class, then assign to our fields in __init__
362
    # via object.__setattr__.  Otherwise, just use a simple
363
    # assignment.
364
    #
365
    # self_name is what "self" is called in this function: don't
366
    # hard-code "self", since that might be a field name.
367
    if frozen:
368
        return f'object.__setattr__({self_name},{name!r},{value})'
369
    return f'{self_name}.{name}={value}'
370
371
372
def _field_init(f, frozen, globals, self_name):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in globals.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
373
    # Return the text of the line in the body of __init__ that will
374
    # initialize this field.
375
376
    default_name = f'_dflt_{f.name}'
377
    if f.default_factory is not MISSING:
378
        if f.init:
379
            # This field has a default factory.  If a parameter is
380
            # given, use it.  If not, call the factory.
381
            globals[default_name] = f.default_factory
382
            value = (f'{default_name}() '
383
                     f'if {f.name} is _HAS_DEFAULT_FACTORY '
384
                     f'else {f.name}')
385
        else:
386
            # This is a field that's not in the __init__ params, but
387
            # has a default factory function.  It needs to be
388
            # initialized here by calling the factory function,
389
            # because there's no other way to initialize it.
390
391
            # For a field initialized with a default=defaultvalue, the
392
            # class dict just has the default value
393
            # (cls.fieldname=defaultvalue).  But that won't work for a
394
            # default factory, the factory must be called in __init__
395
            # and we must assign that to self.fieldname.  We can't
396
            # fall back to the class dict's value, both because it's
397
            # not set, and because it might be different per-class
398
            # (which, after all, is why we have a factory function!).
399
400
            globals[default_name] = f.default_factory
401
            value = f'{default_name}()'
402
    else:
403
        # No default factory.
404
        if f.init:
405
            if f.default is MISSING:
406
                # There's no default, just do an assignment.
407
                value = f.name
408
            elif f.default is not MISSING:
409
                globals[default_name] = f.default
410
                value = f.name
411
        else:
412
            # This field does not need initialization.  Signify that
413
            # to the caller by returning None.
414
            return None
415
416
    # Only test this now, so that we can create variables for the
417
    # default.  However, return None to signify that we're not going
418
    # to actually do the assignment statement for InitVars.
419
    if f._field_type is _FIELD_INITVAR:
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
420
        return None
421
422
    # Now, actually generate the field assignment.
423
    return _field_assign(frozen, f.name, value, self_name)
0 ignored issues
show
introduced by
The variable value does not seem to be defined for all execution paths.
Loading history...
424
425
426
def _init_param(f):
427
    # Return the __init__ parameter string for this field.  For
428
    # example, the equivalent of 'x:int=3' (except instead of 'int',
429
    # reference a variable set to int, and instead of '3', reference a
430
    # variable set to 3).
431
    if f.default is MISSING and f.default_factory is MISSING:
432
        # There's no default, and no default_factory, just output the
433
        # variable name and type.
434
        default = ''
435
    elif f.default is not MISSING:
436
        # There's a default, this will be the name that's used to look
437
        # it up.
438
        default = f'=_dflt_{f.name}'
439
    elif f.default_factory is not MISSING:
440
        # There's a factory function.  Set a marker.
441
        default = '=_HAS_DEFAULT_FACTORY'
442
    return f'{f.name}:_type_{f.name}{default}'
443
444
445
def _init_fn(fields, frozen, has_post_init, self_name):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
446
    # fields contains both real fields and InitVar pseudo-fields.
447
448
    # Make sure we don't have fields without defaults following fields
449
    # with defaults.  This actually would be caught when exec-ing the
450
    # function source code, but catching it here gives a better error
451
    # message, and future-proofs us in case we build up the function
452
    # using ast.
453
    seen_default = False
454
    for f in fields:
455
        # Only consider fields in the __init__ call.
456
        if f.init:
457
            if not (f.default is MISSING and f.default_factory is MISSING):
458
                seen_default = True
459
            elif seen_default:
460
                raise TypeError(f'non-default argument {f.name!r} '
461
                                'follows default argument')
462
463
    globals = {'MISSING': MISSING,
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in globals.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
464
               '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY}
465
466
    body_lines = []
467
    for f in fields:
468
        line = _field_init(f, frozen, globals, self_name)
469
        # line is None means that this field doesn't require
470
        # initialization (it's a pseudo-field).  Just skip it.
471
        if line:
472
            body_lines.append(line)
473
474
    # Does this class have a post-init function?
475
    if has_post_init:
476
        params_str = ','.join(f.name for f in fields
477
                              if f._field_type is _FIELD_INITVAR)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
478
        body_lines.append(f'{self_name}.{_POST_INIT_NAME}({params_str})')
479
480
    # If no body lines, use 'pass'.
481
    if not body_lines:
482
        body_lines = ['pass']
483
484
    locals = {f'_type_{f.name}': f.type for f in fields}
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in locals.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
485
    return _create_fn('__init__',
486
                      [self_name] + [_init_param(f) for f in fields if f.init],
487
                      body_lines,
488
                      locals=locals,
489
                      globals=globals,
490
                      return_type=None)
491
492
493
def _repr_fn(fields):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
494
    return _create_fn('__repr__',
495
                      ('self',),
496
                      ['return self.__class__.__qualname__ + f"(' +
497
                       ', '.join([f"{f.name}={{self.{f.name}!r}}"
498
                                  for f in fields]) +
499
                       ')"'])
500
501
502
def _frozen_get_del_attr(cls, fields):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
503
    # XXX: globals is modified on the first call to _create_fn, then
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
504
    # the modified version is used in the second call.  Is this okay?
505
    globals = {'cls': cls,
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in globals.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
506
              'FrozenInstanceError': FrozenInstanceError}
507
    if fields:
508
        fields_str = '(' + ','.join(repr(f.name) for f in fields) + ',)'
509
    else:
510
        # Special case for the zero-length tuple.
511
        fields_str = '()'
512
    return (_create_fn('__setattr__',
513
                      ('self', 'name', 'value'),
514
                      (f'if type(self) is cls or name in {fields_str}:',
515
                        ' raise FrozenInstanceError(f"cannot assign to field {name!r}")',
516
                       f'super(cls, self).__setattr__(name, value)'),
0 ignored issues
show
introduced by
Using an f-string that does not have any interpolated variables
Loading history...
517
                       globals=globals),
518
            _create_fn('__delattr__',
519
                      ('self', 'name'),
520
                      (f'if type(self) is cls or name in {fields_str}:',
521
                        ' raise FrozenInstanceError(f"cannot delete field {name!r}")',
522
                       f'super(cls, self).__delattr__(name)'),
0 ignored issues
show
introduced by
Using an f-string that does not have any interpolated variables
Loading history...
523
                       globals=globals),
524
            )
525
526
527
def _cmp_fn(name, op, self_tuple, other_tuple):
528
    # Create a comparison function.  If the fields in the object are
529
    # named 'x' and 'y', then self_tuple is the string
530
    # '(self.x,self.y)' and other_tuple is the string
531
    # '(other.x,other.y)'.
532
533
    return _create_fn(name,
534
                      ('self', 'other'),
535
                      [ 'if other.__class__ is self.__class__:',
536
                       f' return {self_tuple}{op}{other_tuple}',
537
                        'return NotImplemented'])
538
539
540
def _hash_fn(fields):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
541
    self_tuple = _tuple_str('self', fields)
542
    return _create_fn('__hash__',
543
                      ('self',),
544
                      [f'return hash({self_tuple})'])
545
546
547
def _is_classvar(a_type, typing):
548
    # This test uses a typing internal class, but it's the best way to
549
    # test if this is a ClassVar.
550
    return type(a_type) is typing._ClassVar
0 ignored issues
show
introduced by
Use isinstance() rather than type() for a typecheck.
Loading history...
Coding Style Best Practice introduced by
It seems like _ClassVar was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
551
552
553
def _is_initvar(a_type, dataclasses):
554
    # The module we're checking against is the module we're
555
    # currently in (dataclasses.py).
556
    return a_type is dataclasses.InitVar
557
558
559
def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
560
    # Given a type annotation string, does it refer to a_type in
561
    # a_module?  For example, when checking that annotation denotes a
562
    # ClassVar, then a_module is typing, and a_type is
563
    # typing.ClassVar.
564
565
    # It's possible to look up a_module given a_type, but it involves
566
    # looking in sys.modules (again!), and seems like a waste since
567
    # the caller already knows a_module.
568
569
    # - annotation is a string type annotation
570
    # - cls is the class that this annotation was found in
571
    # - a_module is the module we want to match
572
    # - a_type is the type in that module we want to match
573
    # - is_type_predicate is a function called with (obj, a_module)
574
    #   that determines if obj is of the desired type.
575
576
    # Since this test does not do a local namespace lookup (and
577
    # instead only a module (global) lookup), there are some things it
578
    # gets wrong.
579
580
    # With string annotations, cv0 will be detected as a ClassVar:
581
    #   CV = ClassVar
582
    #   @dataclass
583
    #   class C0:
584
    #     cv0: CV
585
586
    # But in this example cv1 will not be detected as a ClassVar:
587
    #   @dataclass
588
    #   class C1:
589
    #     CV = ClassVar
590
    #     cv1: CV
591
592
    # In C1, the code in this function (_is_type) will look up "CV" in
593
    # the module and not find it, so it will not consider cv1 as a
594
    # ClassVar.  This is a fairly obscure corner case, and the best
595
    # way to fix it would be to eval() the string "CV" with the
596
    # correct global and local namespaces.  However that would involve
597
    # a eval() penalty for every single field of every dataclass
598
    # that's defined.  It was judged not worth it.
599
600
    match = _MODULE_IDENTIFIER_RE.match(annotation)
601
    if match:
602
        ns = None
603
        module_name = match.group(1)
604
        if not module_name:
605
            # No module name, assume the class's module did
606
            # "from .dataclasses import InitVar".
607
            ns = sys.modules.get(cls.__module__).__dict__
608
        else:
609
            # Look up module_name in the class's module.
610
            module = sys.modules.get(cls.__module__)
611
            if module and module.__dict__.get(module_name) is a_module:
612
                ns = sys.modules.get(a_type.__module__).__dict__
613
        if ns and is_type_predicate(ns.get(match.group(2)), a_module):
614
            return True
615
    return False
616
617
618
def _get_field(cls, a_name, a_type):
619
    # Return a Field object for this field name and type.  ClassVars
620
    # and InitVars are also returned, but marked as such (see
621
    # f._field_type).
622
623
    # If the default value isn't derived from Field, then it's only a
624
    # normal default value.  Convert it to a Field().
625
    default = getattr(cls, a_name, MISSING)
626
    if isinstance(default, Field):
627
        f = default
628
    else:
629
        if isinstance(default, types.MemberDescriptorType):
630
            # This is a field in __slots__, so it has no default value.
631
            default = MISSING
632
        f = field(default=default)
633
634
    # Only at this point do we know the name and the type.  Set them.
635
    f.name = a_name
636
    f.type = a_type
637
638
    # Assume it's a normal field until proven otherwise.  We're next
639
    # going to decide if it's a ClassVar or InitVar, everything else
640
    # is just a normal field.
641
    f._field_type = _FIELD
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
642
643
    # In addition to checking for actual types here, also check for
644
    # string annotations.  get_type_hints() won't always work for us
645
    # (see https://github.com/python/typing/issues/508 for example),
646
    # plus it's expensive and would require an eval for every string
647
    # annotation.  So, make a best effort to see if this is a ClassVar
648
    # or InitVar using regex's and checking that the thing referenced
649
    # is actually of the correct type.
650
651
    # For the complete discussion, see https://bugs.python.org/issue33453
652
653
    # If typing has not been imported, then it's impossible for any
654
    # annotation to be a ClassVar.  So, only look for ClassVar if
655
    # typing has been imported by any module (not necessarily cls's
656
    # module).
657
    typing = sys.modules.get('typing')
658
    if typing:
659
        if (_is_classvar(a_type, typing)
660
            or (isinstance(f.type, str)
661
                and _is_type(f.type, cls, typing, typing.ClassVar,
662
                             _is_classvar))):
663
            f._field_type = _FIELD_CLASSVAR
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
664
665
    # If the type is InitVar, or if it's a matching string annotation,
666
    # then it's an InitVar.
667
    if f._field_type is _FIELD:
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
668
        # The module we're checking against is the module we're
669
        # currently in (dataclasses.py).
670
        dataclasses = sys.modules[__name__]
671
        if (_is_initvar(a_type, dataclasses)
672
            or (isinstance(f.type, str)
673
                and _is_type(f.type, cls, dataclasses, dataclasses.InitVar,
674
                             _is_initvar))):
675
            f._field_type = _FIELD_INITVAR
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
676
677
    # Validations for individual fields.  This is delayed until now,
678
    # instead of in the Field() constructor, since only here do we
679
    # know the field name, which allows for better error reporting.
680
681
    # Special restrictions for ClassVar and InitVar.
682
    if f._field_type in (_FIELD_CLASSVAR, _FIELD_INITVAR):
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
683
        if f.default_factory is not MISSING:
684
            raise TypeError(f'field {f.name} cannot have a '
685
                            'default factory')
686
        # Should I check for other field settings? default_factory
687
        # seems the most serious to check for.  Maybe add others.  For
688
        # example, how about init=False (or really,
689
        # init=<not-the-default-init-value>)?  It makes no sense for
690
        # ClassVar and InitVar to specify init=<anything>.
691
692
    # For real fields, disallow mutable defaults for known types.
693
    if f._field_type is _FIELD and isinstance(f.default, (list, dict, set)):
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
694
        raise ValueError(f'mutable default {type(f.default)} for field '
695
                         f'{f.name} is not allowed: use default_factory')
696
697
    return f
698
699
700
def _set_new_attribute(cls, name, value):
701
    # Never overwrites an existing attribute.  Returns True if the
702
    # attribute already exists.
703
    if name in cls.__dict__:
704
        return True
705
    setattr(cls, name, value)
706
    return False
707
708
709
# Decide if/how we're going to create a hash function.  Key is
710
# (unsafe_hash, eq, frozen, does-hash-exist).  Value is the action to
711
# take.  The common case is to do nothing, so instead of providing a
712
# function that is a no-op, use None to signify that.
713
714
def _hash_set_none(cls, fields):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
Unused Code introduced by
The argument cls seems to be unused.
Loading history...
Unused Code introduced by
The argument fields seems to be unused.
Loading history...
715
    return None
716
717
def _hash_add(cls, fields):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
Unused Code introduced by
The argument cls seems to be unused.
Loading history...
718
    flds = [f for f in fields if (f.compare if f.hash is None else f.hash)]
719
    return _hash_fn(flds)
720
721
def _hash_exception(cls, fields):
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
722
    # Raise an exception.
723
    raise TypeError(f'Cannot overwrite attribute __hash__ '
724
                    f'in class {cls.__name__}')
725
726
#
727
#                +-------------------------------------- unsafe_hash?
728
#                |      +------------------------------- eq?
729
#                |      |      +------------------------ frozen?
730
#                |      |      |      +----------------  has-explicit-hash?
731
#                |      |      |      |
732
#                |      |      |      |        +-------  action
733
#                |      |      |      |        |
734
#                v      v      v      v        v
735
_hash_action = {(False, False, False, False): None,
736
                (False, False, False, True ): None,
737
                (False, False, True,  False): None,
738
                (False, False, True,  True ): None,
739
                (False, True,  False, False): _hash_set_none,
740
                (False, True,  False, True ): None,
741
                (False, True,  True,  False): _hash_add,
742
                (False, True,  True,  True ): None,
743
                (True,  False, False, False): _hash_add,
744
                (True,  False, False, True ): _hash_exception,
745
                (True,  False, True,  False): _hash_add,
746
                (True,  False, True,  True ): _hash_exception,
747
                (True,  True,  False, False): _hash_add,
748
                (True,  True,  False, True ): _hash_exception,
749
                (True,  True,  True,  False): _hash_add,
750
                (True,  True,  True,  True ): _hash_exception,
751
                }
752
# See https://bugs.python.org/issue32929#msg312829 for an if-statement
753
# version of this table.
754
755
756
def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (27/15).
Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in repr.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
757
    # Now that dicts retain insertion order, there's no reason to use
758
    # an ordered dict.  I am leveraging that ordering here, because
759
    # derived class fields overwrite base class fields, but the order
760
    # is defined by the base class, which is found first.
761
    fields = {}
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
762
763
    setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order,
764
                                           unsafe_hash, frozen))
765
766
    # Find our base classes in reverse MRO order, and exclude
767
    # ourselves.  In reversed order so that more derived classes
768
    # override earlier field definitions in base classes.  As long as
769
    # we're iterating over them, see if any are frozen.
770
    any_frozen_base = False
771
    has_dataclass_bases = False
772
    for b in cls.__mro__[-1:0:-1]:
773
        # Only process classes that have been processed by our
774
        # decorator.  That is, they have a _FIELDS attribute.
775
        base_fields = getattr(b, _FIELDS, None)
776
        if base_fields:
777
            has_dataclass_bases = True
778
            for f in base_fields.values():
779
                fields[f.name] = f
780
            if getattr(b, _PARAMS).frozen:
781
                any_frozen_base = True
782
783
    # Annotations that are defined in this class (not in base
784
    # classes).  If __annotations__ isn't present, then this class
785
    # adds no new annotations.  We use this to compute fields that are
786
    # added by this class.
787
    #
788
    # Fields are found from cls_annotations, which is guaranteed to be
789
    # ordered.  Default values are from class attributes, if a field
790
    # has a default.  If the default value is a Field(), then it
791
    # contains additional info beyond (and possibly including) the
792
    # actual default value.  Pseudo-fields ClassVars and InitVars are
793
    # included, despite the fact that they're not real fields.  That's
794
    # dealt with later.
795
    cls_annotations = cls.__dict__.get('__annotations__', {})
796
797
    # Now find fields in our class.  While doing so, validate some
798
    # things, and set the default values (as class attributes) where
799
    # we can.
800
    cls_fields = [_get_field(cls, name, type)
801
                  for name, type in cls_annotations.items()]
802
    for f in cls_fields:
803
        fields[f.name] = f
804
805
        # If the class attribute (which is the default value for this
806
        # field) exists and is of type 'Field', replace it with the
807
        # real default.  This is so that normal class introspection
808
        # sees a real default value, not a Field.
809
        if isinstance(getattr(cls, f.name, None), Field):
810
            if f.default is MISSING:
811
                # If there's no default, delete the class attribute.
812
                # This happens if we specify field(repr=False), for
813
                # example (that is, we specified a field object, but
814
                # no default value).  Also if we're using a default
815
                # factory.  The class attribute should not be set at
816
                # all in the post-processed class.
817
                delattr(cls, f.name)
818
            else:
819
                setattr(cls, f.name, f.default)
820
821
    # Do we have any Field members that don't also have annotations?
822
    for name, value in cls.__dict__.items():
823
        if isinstance(value, Field) and not name in cls_annotations:
824
            raise TypeError(f'{name!r} is a field but has no type annotation')
825
826
    # Check rules that apply if we are derived from any dataclasses.
827
    if has_dataclass_bases:
828
        # Raise an exception if any of our bases are frozen, but we're not.
829
        if any_frozen_base and not frozen:
830
            raise TypeError('cannot inherit non-frozen dataclass from a '
831
                            'frozen one')
832
833
        # Raise an exception if we're frozen, but none of our bases are.
834
        if not any_frozen_base and frozen:
835
            raise TypeError('cannot inherit frozen dataclass from a '
836
                            'non-frozen one')
837
838
    # Remember all of the fields on our class (including bases).  This
839
    # also marks this class as being a dataclass.
840
    setattr(cls, _FIELDS, fields)
841
842
    # Was this class defined with an explicit __hash__?  Note that if
843
    # __eq__ is defined in this class, then python will automatically
844
    # set __hash__ to None.  This is a heuristic, as it's possible
845
    # that such a __hash__ == None was not auto-generated, but it
846
    # close enough.
847
    class_hash = cls.__dict__.get('__hash__', MISSING)
848
    has_explicit_hash = not (class_hash is MISSING or
849
                             (class_hash is None and '__eq__' in cls.__dict__))
850
851
    # If we're generating ordering methods, we must be generating the
852
    # eq methods.
853
    if order and not eq:
854
        raise ValueError('eq must be true if order is true')
855
856
    if init:
857
        # Does this class have a post-init function?
858
        has_post_init = hasattr(cls, _POST_INIT_NAME)
859
860
        # Include InitVars and regular fields (so, not ClassVars).
861
        flds = [f for f in fields.values()
862
                if f._field_type in (_FIELD, _FIELD_INITVAR)]
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
863
        _set_new_attribute(cls, '__init__',
864
                           _init_fn(flds,
865
                                    frozen,
866
                                    has_post_init,
867
                                    # The name to use for the "self"
868
                                    # param in __init__.  Use "self"
869
                                    # if possible.
870
                                    '__dataclass_self__' if 'self' in fields
871
                                            else 'self',
872
                          ))
873
874
    # Get the fields as a list, and include only real fields.  This is
875
    # used in all of the following methods.
876
    field_list = [f for f in fields.values() if f._field_type is _FIELD]
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
877
878
    if repr:
879
        flds = [f for f in field_list if f.repr]
880
        _set_new_attribute(cls, '__repr__', _repr_fn(flds))
881
882
    if eq:
883
        # Create _eq__ method.  There's no need for a __ne__ method,
884
        # since python will call __eq__ and negate it.
885
        flds = [f for f in field_list if f.compare]
886
        self_tuple = _tuple_str('self', flds)
887
        other_tuple = _tuple_str('other', flds)
888
        _set_new_attribute(cls, '__eq__',
889
                           _cmp_fn('__eq__', '==',
890
                                   self_tuple, other_tuple))
891
892
    if order:
893
        # Create and set the ordering methods.
894
        flds = [f for f in field_list if f.compare]
895
        self_tuple = _tuple_str('self', flds)
896
        other_tuple = _tuple_str('other', flds)
897
        for name, op in [('__lt__', '<'),
898
                         ('__le__', '<='),
899
                         ('__gt__', '>'),
900
                         ('__ge__', '>='),
901
                         ]:
902
            if _set_new_attribute(cls, name,
903
                                  _cmp_fn(name, op, self_tuple, other_tuple)):
904
                raise TypeError(f'Cannot overwrite attribute {name} '
905
                                f'in class {cls.__name__}. Consider using '
906
                                'functools.total_ordering')
907
908
    if frozen:
909
        for fn in _frozen_get_del_attr(cls, field_list):
910
            if _set_new_attribute(cls, fn.__name__, fn):
911
                raise TypeError(f'Cannot overwrite attribute {fn.__name__} '
912
                                f'in class {cls.__name__}')
913
914
    # Decide if/how we're going to create a hash function.
915
    hash_action = _hash_action[bool(unsafe_hash),
916
                               bool(eq),
917
                               bool(frozen),
918
                               has_explicit_hash]
919
    if hash_action:
920
        # No need to call _set_new_attribute here, since by the time
921
        # we're here the overwriting is unconditional.
922
        cls.__hash__ = hash_action(cls, field_list)
923
924
    if not getattr(cls, '__doc__'):
925
        # Create a class doc-string.
926
        cls.__doc__ = (cls.__name__ +
927
                       str(inspect.signature(cls)).replace(' -> None', ''))
928
929
    return cls
930
931
932
# _cls should never be specified by keyword, so start it with an
933
# underscore.  The presence of _cls is used to detect if this
934
# decorator is being called with parameters or not.
935
def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False,
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
Bug Best Practice introduced by
This seems to re-define the built-in repr.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
936
              unsafe_hash=False, frozen=False):
937
    """Returns the same class as was passed in, with dunder methods
938
    added based on the fields defined in the class.
939
940
    Examines PEP 526 __annotations__ to determine fields.
941
942
    If init is true, an __init__() method is added to the class. If
943
    repr is true, a __repr__() method is added. If order is true, rich
944
    comparison dunder methods are added. If unsafe_hash is true, a
945
    __hash__() method function is added. If frozen is true, fields may
946
    not be assigned to after instance creation.
947
    """
948
949
    def wrap(cls):
950
        return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
951
952
    # See if we're being called as @dataclass or @dataclass().
953
    if _cls is None:
954
        # We're called with parens.
955
        return wrap
956
957
    # We're called as @dataclass without parens.
958
    return wrap(_cls)
959
960
961
def fields(class_or_instance):
962
    """Return a tuple describing the fields of this dataclass.
963
964
    Accepts a dataclass or an instance of one. Tuple elements are of
965
    type Field.
966
    """
967
968
    # Might it be worth caching this, per class?
969
    try:
970
        fields = getattr(class_or_instance, _FIELDS)
0 ignored issues
show
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
971
    except AttributeError:
972
        raise TypeError('must be called with a dataclass type or instance')
0 ignored issues
show
introduced by
Consider explicitly re-raising using 'except AttributeError as exc' and 'raise TypeError('must be called with a dataclass type or instance') from exc'
Loading history...
973
974
    # Exclude pseudo-fields.  Note that fields is sorted by insertion
975
    # order, so the order of the tuple is as the fields were defined.
976
    return tuple(f for f in fields.values() if f._field_type is _FIELD)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
977
978
979
def _is_dataclass_instance(obj):
980
    """Returns True if obj is an instance of a dataclass."""
981
    return not isinstance(obj, type) and hasattr(obj, _FIELDS)
982
983
984
def is_dataclass(obj):
985
    """Returns True if obj is a dataclass or an instance of a
986
    dataclass."""
987
    return hasattr(obj, _FIELDS)
988
989
990
def asdict(obj, *, dict_factory=dict):
991
    """Return the fields of a dataclass instance as a new dictionary mapping
992
    field names to field values.
993
994
    Example usage:
995
996
      @dataclass
997
      class C:
998
          x: int
999
          y: int
1000
1001
      c = C(1, 2)
1002
      assert asdict(c) == {'x': 1, 'y': 2}
1003
1004
    If given, 'dict_factory' will be used instead of built-in dict.
1005
    The function applies recursively to field values that are
1006
    dataclass instances. This will also look into built-in containers:
1007
    tuples, lists, and dicts.
1008
    """
1009
    if not _is_dataclass_instance(obj):
1010
        raise TypeError("asdict() should be called on dataclass instances")
1011
    return _asdict_inner(obj, dict_factory)
1012
1013
1014 View Code Duplication
def _asdict_inner(obj, dict_factory):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1015
    if _is_dataclass_instance(obj):
0 ignored issues
show
unused-code introduced by
Unnecessary "elif" after "return", remove the leading "el" from "elif"
Loading history...
1016
        result = []
1017
        for f in fields(obj):
1018
            value = _asdict_inner(getattr(obj, f.name), dict_factory)
1019
            result.append((f.name, value))
1020
        return dict_factory(result)
1021
    elif isinstance(obj, (list, tuple)):
1022
        return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
1023
    elif isinstance(obj, dict):
1024
        return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory))
1025
                          for k, v in obj.items())
1026
    else:
1027
        return copy.deepcopy(obj)
1028
1029
1030
def astuple(obj, *, tuple_factory=tuple):
1031
    """Return the fields of a dataclass instance as a new tuple of field values.
1032
1033
    Example usage::
1034
1035
      @dataclass
1036
      class C:
1037
          x: int
1038
          y: int
1039
1040
    c = C(1, 2)
1041
    assert astuple(c) == (1, 2)
1042
1043
    If given, 'tuple_factory' will be used instead of built-in tuple.
1044
    The function applies recursively to field values that are
1045
    dataclass instances. This will also look into built-in containers:
1046
    tuples, lists, and dicts.
1047
    """
1048
1049
    if not _is_dataclass_instance(obj):
1050
        raise TypeError("astuple() should be called on dataclass instances")
1051
    return _astuple_inner(obj, tuple_factory)
1052
1053
1054 View Code Duplication
def _astuple_inner(obj, tuple_factory):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1055
    if _is_dataclass_instance(obj):
0 ignored issues
show
unused-code introduced by
Unnecessary "elif" after "return", remove the leading "el" from "elif"
Loading history...
1056
        result = []
1057
        for f in fields(obj):
1058
            value = _astuple_inner(getattr(obj, f.name), tuple_factory)
1059
            result.append(value)
1060
        return tuple_factory(result)
1061
    elif isinstance(obj, (list, tuple)):
1062
        return type(obj)(_astuple_inner(v, tuple_factory) for v in obj)
1063
    elif isinstance(obj, dict):
1064
        return type(obj)((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory))
1065
                          for k, v in obj.items())
1066
    else:
1067
        return copy.deepcopy(obj)
1068
1069
1070
def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True,
0 ignored issues
show
best-practice introduced by
Too many arguments (10/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (17/15).
Loading history...
Comprehensibility Bug introduced by
fields is re-defining a name which is already available in the outer-scope (previously defined on line 961).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
1071
                   repr=True, eq=True, order=False, unsafe_hash=False,
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in repr.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
1072
                   frozen=False):
1073
    """Return a new dynamically created dataclass.
1074
1075
    The dataclass name will be 'cls_name'.  'fields' is an iterable
1076
    of either (name), (name, type) or (name, type, Field) objects. If type is
1077
    omitted, use the string 'typing.Any'.  Field objects are created by
1078
    the equivalent of calling 'field(name, type [, Field-info])'.
1079
1080
      C = make_dataclass('C', ['x', ('y', int), ('z', int, field(init=False))], bases=(Base,))
1081
1082
    is equivalent to:
1083
1084
      @dataclass
1085
      class C(Base):
1086
          x: 'typing.Any'
1087
          y: int
1088
          z: int = field(init=False)
1089
1090
    For the bases and namespace parameters, see the builtin type() function.
1091
1092
    The parameters init, repr, eq, order, unsafe_hash, and frozen are passed to
1093
    dataclass().
1094
    """
1095
1096
    if namespace is None:
1097
        namespace = {}
1098
    else:
1099
        # Copy namespace since we're going to mutate it.
1100
        namespace = namespace.copy()
1101
1102
    # While we're looking through the field names, validate that they
1103
    # are identifiers, are not keywords, and not duplicates.
1104
    seen = set()
1105
    anns = {}
1106
    for item in fields:
1107
        if isinstance(item, str):
1108
            name = item
1109
            tp = 'typing.Any'
1110
        elif len(item) == 2:
1111
            name, tp, = item
1112
        elif len(item) == 3:
1113
            name, tp, spec = item
1114
            namespace[name] = spec
1115
        else:
1116
            raise TypeError(f'Invalid field: {item!r}')
1117
1118
        if not isinstance(name, str) or not name.isidentifier():
1119
            raise TypeError(f'Field names must be valid identifiers: {name!r}')
1120
        if keyword.iskeyword(name):
1121
            raise TypeError(f'Field names must not be keywords: {name!r}')
1122
        if name in seen:
1123
            raise TypeError(f'Field name duplicated: {name!r}')
1124
1125
        seen.add(name)
1126
        anns[name] = tp
1127
1128
    namespace['__annotations__'] = anns
1129
    # We use `types.new_class()` instead of simply `type()` to allow dynamic creation
1130
    # of generic dataclassses.
1131
    cls = types.new_class(cls_name, bases, {}, lambda ns: ns.update(namespace))
1132
    return dataclass(cls, init=init, repr=repr, eq=eq, order=order,
1133
                     unsafe_hash=unsafe_hash, frozen=frozen)
1134
1135
1136
def replace(obj, **changes):
1137
    """Return a new object replacing specified fields with new values.
1138
1139
    This is especially useful for frozen classes.  Example usage:
1140
1141
      @dataclass(frozen=True)
1142
      class C:
1143
          x: int
1144
          y: int
1145
1146
      c = C(1, 2)
1147
      c1 = replace(c, x=3)
1148
      assert c1.x == 3 and c1.y == 2
1149
      """
1150
1151
    # We're going to mutate 'changes', but that's okay because it's a
1152
    # new dict, even if called with 'replace(obj, **my_changes)'.
1153
1154
    if not _is_dataclass_instance(obj):
1155
        raise TypeError("replace() should be called on dataclass instances")
1156
1157
    # It's an error to have init=False fields in 'changes'.
1158
    # If a field is not in 'changes', read its value from the provided obj.
1159
1160
    for f in getattr(obj, _FIELDS).values():
1161
        # Only consider normal fields or InitVars.
1162
        if f._field_type is _FIELD_CLASSVAR:
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
1163
            continue
1164
1165
        if not f.init:
1166
            # Error if this field is specified in changes.
1167
            if f.name in changes:
1168
                raise ValueError(f'field {f.name} is declared with '
1169
                                 'init=False, it cannot be specified with '
1170
                                 'replace()')
1171
            continue
1172
1173
        if f.name not in changes:
1174
            if f._field_type is _FIELD_INITVAR:
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _field_type was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
1175
                raise ValueError(f"InitVar {f.name!r} "
1176
                                 'must be specified with replace()')
1177
            changes[f.name] = getattr(obj, f.name)
1178
1179
    # Create the new object, which calls __init__() and
1180
    # __post_init__() (if defined), using all of the init fields we've
1181
    # added and/or left in 'changes'.  If there are values supplied in
1182
    # changes that aren't fields, this will correctly raise a
1183
    # TypeError.
1184
    return obj.__class__(**changes)
1185