Passed
Pull Request — main (#226)
by Jan
06:27
created

openscap_report.dataclasses.dataclasses.asdict()   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 copy
0 ignored issues
show
coding-style introduced by
Too many lines in module (1270/1000)
Loading history...
2
import inspect
3
import keyword
4
import re
5
import sys
6
import types
7
8
__all__ = [
9
    "dataclass",
10
    "field",
11
    "Field",
12
    "FrozenInstanceError",
13
    "InitVar",
14
    "MISSING",
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):
152
    pass
153
154
155
# A sentinel object for default values to signal that a default
156
# factory will be used.  This is given a nice repr() which will appear
157
# in the function signature of dataclasses' constructors.
158
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...
159
    def __repr__(self):
160
        return "<factory>"
161
162
163
_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS()
164
165
166
# A sentinel object to detect if a parameter is supplied or not.  Use
167
# a class to give it a better repr.
168
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...
169
    pass
170
171
172
MISSING = _MISSING_TYPE()
173
174
# Since most per-field metadata will be unused, create an empty
175
# read-only proxy that can be shared among all fields.
176
_EMPTY_METADATA = types.MappingProxyType({})
177
178
179
# Markers for the various kinds of fields and pseudo-fields.
180
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...
181
    def __init__(self, name):
182
        self.name = name
183
184
    def __repr__(self):
185
        return self.name
186
187
188
_FIELD = _FIELD_BASE("_FIELD")
189
_FIELD_CLASSVAR = _FIELD_BASE("_FIELD_CLASSVAR")
190
_FIELD_INITVAR = _FIELD_BASE("_FIELD_INITVAR")
191
192
# The name of an attribute on the class where we store the Field
193
# objects.  Also used to check if a class is a Data Class.
194
_FIELDS = "__dataclass_fields__"
195
196
# The name of an attribute on the class that stores the parameters to
197
# @dataclass.
198
_PARAMS = "__dataclass_params__"
199
200
# The name of the function, that if it exists, is called at the end of
201
# __init__.
202
_POST_INIT_NAME = "__post_init__"
203
204
# String regex that string annotations for ClassVar or InitVar must match.
205
# Allows "identifier.identifier[" or "identifier[".
206
# https://bugs.python.org/issue33453 for details.
207
_MODULE_IDENTIFIER_RE = re.compile(r"^(?:\s*(\w+)\s*\.)?\s*(\w+)")
208
209
210
class _InitVarMeta(type):
211
    def __getitem__(cls, params):
212
        return cls
213
214
215
class InitVar(metaclass=_InitVarMeta):
216
    pass
217
218
219
# Instances of Field are only ever created from within this module,
220
# and only from the field() function, although Field instances are
221
# exposed externally as (conceptually) read-only objects.
222
#
223
# name and type are filled in after the fact, not in __init__.
224
# They're not known at the time this class is instantiated, but it's
225
# convenient if they're available later.
226
#
227
# When cls._FIELDS is filled in with a list of Field objects, the name
228
# and type fields will have been populated.
229
class Field:
0 ignored issues
show
best-practice introduced by
Too many instance attributes (10/7)
Loading history...
230
    __slots__ = (
231
        "name",
232
        "type",
233
        "default",
234
        "default_factory",
235
        "repr",
236
        "hash",
237
        "init",
238
        "compare",
239
        "metadata",
240
        "_field_type",  # Private: not to be used by user code.
241
    )
242
243
    def __init__(self, default, default_factory, init, repr, hash, compare, metadata):
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...
244
        self.name = None
245
        self.type = None
246
        self.default = default
247
        self.default_factory = default_factory
248
        self.init = init
249
        self.repr = repr
250
        self.hash = hash
251
        self.compare = compare
252
        self.metadata = (
253
            _EMPTY_METADATA
254
            if metadata is None or len(metadata) == 0
255
            else types.MappingProxyType(metadata)
256
        )
257
        self._field_type = None
258
259
    def __repr__(self):
260
        return (
261
            "Field("
262
            f"name={self.name!r},"
263
            f"type={self.type!r},"
264
            f"default={self.default!r},"
265
            f"default_factory={self.default_factory!r},"
266
            f"init={self.init!r},"
267
            f"repr={self.repr!r},"
268
            f"hash={self.hash!r},"
269
            f"compare={self.compare!r},"
270
            f"metadata={self.metadata!r},"
271
            f"_field_type={self._field_type}"
272
            ")"
273
        )
274
275
    # This is used to support the PEP 487 __set_name__ protocol in the
276
    # case where we're using a field that contains a descriptor as a
277
    # default value.  For details on __set_name__, see
278
    # https://www.python.org/dev/peps/pep-0487/#implementation-details.
279
    #
280
    # Note that in _process_class, this Field object is overwritten
281
    # with the default value, so the end result is a descriptor that
282
    # had __set_name__ called on it at the right time.
283
    def __set_name__(self, owner, name):
284
        func = getattr(type(self.default), "__set_name__", None)
285
        if func:
286
            # There is a __set_name__ method on the descriptor, call
287
            # it.
288
            func(self.default, owner, name)
289
290
291
class _DataclassParams:
292
    __slots__ = (
293
        "init",
294
        "repr",
295
        "eq",
296
        "order",
297
        "unsafe_hash",
298
        "frozen",
299
    )
300
301
    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...
302
        self.init = init
303
        self.repr = repr
304
        self.eq = eq
305
        self.order = order
306
        self.unsafe_hash = unsafe_hash
307
        self.frozen = frozen
308
309
    def __repr__(self):
310
        return (
311
            "_DataclassParams("
312
            f"init={self.init!r},"
313
            f"repr={self.repr!r},"
314
            f"eq={self.eq!r},"
315
            f"order={self.order!r},"
316
            f"unsafe_hash={self.unsafe_hash!r},"
317
            f"frozen={self.frozen!r}"
318
            ")"
319
        )
320
321
322
# This function is used instead of exposing Field creation directly,
323
# so that a type checker can be told (via overloads) that this is a
324
# function whose type depends on its parameters.
325
def field(
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
326
    *,
327
    default=MISSING,
328
    default_factory=MISSING,
329
    init=True,
330
    repr=True,
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...
331
    hash=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...
332
    compare=True,
333
    metadata=None,
334
):
335
    """Return an object to identify dataclass fields.
336
337
    default is the default value of the field.  default_factory is a
338
    0-argument function called to initialize a field's value.  If init
339
    is True, the field will be a parameter to the class's __init__()
340
    function.  If repr is True, the field will be included in the
341
    object's repr().  If hash is True, the field will be included in
342
    the object's hash().  If compare is True, the field will be used
343
    in comparison functions.  metadata, if specified, must be a
344
    mapping which is stored but not otherwise examined by dataclass.
345
346
    It is an error to specify both default and default_factory.
347
    """
348
349
    if default is not MISSING and default_factory is not MISSING:
350
        raise ValueError("cannot specify both default and default_factory")
351
    return Field(default, default_factory, init, repr, hash, compare, metadata)
352
353
354
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 1020).

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...
355
    # Return a string representing each field of obj_name as a tuple
356
    # member.  So, if fields is ['x', 'y'] and obj_name is "self",
357
    # return "(self.x,self.y)".
358
359
    # Special case for the 0-tuple.
360
    if not fields:
361
        return "()"
362
    # Note the trailing comma, needed if this turns out to be a 1-tuple.
363
    return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)'
364
365
366
def _create_fn(name, args, body, *, globals=None, locals=None, return_type=MISSING):
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...
367
    # Note that we mutate locals when exec() is called.  Caller
368
    # beware!  The only callers are internal to this module, so no
369
    # worries about external callers.
370
    if locals is None:
371
        locals = {}
372
    return_annotation = ""
373
    if return_type is not MISSING:
374
        locals["_return_type"] = return_type
375
        return_annotation = "->_return_type"
376
    args = ",".join(args)
377
    body = "\n".join(f" {b}" for b in body)
378
379
    # Compute the text of the entire function.
380
    txt = f"def {name}({args}){return_annotation}:\n{body}"
381
382
    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...
383
    return locals[name]
384
385
386
def _field_assign(frozen, name, value, self_name):
387
    # If we're a frozen class, then assign to our fields in __init__
388
    # via object.__setattr__.  Otherwise, just use a simple
389
    # assignment.
390
    #
391
    # self_name is what "self" is called in this function: don't
392
    # hard-code "self", since that might be a field name.
393
    if frozen:
394
        return f"object.__setattr__({self_name},{name!r},{value})"
395
    return f"{self_name}.{name}={value}"
396
397
398
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...
399
    # Return the text of the line in the body of __init__ that will
400
    # initialize this field.
401
402
    default_name = f"_dflt_{f.name}"
403
    if f.default_factory is not MISSING:
404
        if f.init:
405
            # This field has a default factory.  If a parameter is
406
            # given, use it.  If not, call the factory.
407
            globals[default_name] = f.default_factory
408
            value = (
409
                f"{default_name}() "
410
                f"if {f.name} is _HAS_DEFAULT_FACTORY "
411
                f"else {f.name}"
412
            )
413
        else:
414
            # This is a field that's not in the __init__ params, but
415
            # has a default factory function.  It needs to be
416
            # initialized here by calling the factory function,
417
            # because there's no other way to initialize it.
418
419
            # For a field initialized with a default=defaultvalue, the
420
            # class dict just has the default value
421
            # (cls.fieldname=defaultvalue).  But that won't work for a
422
            # default factory, the factory must be called in __init__
423
            # and we must assign that to self.fieldname.  We can't
424
            # fall back to the class dict's value, both because it's
425
            # not set, and because it might be different per-class
426
            # (which, after all, is why we have a factory function!).
427
428
            globals[default_name] = f.default_factory
429
            value = f"{default_name}()"
430
    else:
431
        # No default factory.
432
        if f.init:
433
            if f.default is MISSING:
434
                # There's no default, just do an assignment.
435
                value = f.name
436
            elif f.default is not MISSING:
437
                globals[default_name] = f.default
438
                value = f.name
439
        else:
440
            # This field does not need initialization.  Signify that
441
            # to the caller by returning None.
442
            return None
443
444
    # Only test this now, so that we can create variables for the
445
    # default.  However, return None to signify that we're not going
446
    # to actually do the assignment statement for InitVars.
447
    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...
448
        return None
449
450
    # Now, actually generate the field assignment.
451
    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...
452
453
454
def _init_param(f):
455
    # Return the __init__ parameter string for this field.  For
456
    # example, the equivalent of 'x:int=3' (except instead of 'int',
457
    # reference a variable set to int, and instead of '3', reference a
458
    # variable set to 3).
459
    default = None
460
    if f.default is MISSING and f.default_factory is MISSING:
461
        # There's no default, and no default_factory, just output the
462
        # variable name and type.
463
        default = ""
464
    elif f.default is not MISSING:
465
        # There's a default, this will be the name that's used to look
466
        # it up.
467
        default = f"=_dflt_{f.name}"
468
    elif f.default_factory is not MISSING:
469
        # There's a factory function.  Set a marker.
470
        default = "=_HAS_DEFAULT_FACTORY"
471
    return f"{f.name}:_type_{f.name}{default}"
472
473
474
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 1020).

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...
475
    # fields contains both real fields and InitVar pseudo-fields.
476
477
    # Make sure we don't have fields without defaults following fields
478
    # with defaults.  This actually would be caught when exec-ing the
479
    # function source code, but catching it here gives a better error
480
    # message, and future-proofs us in case we build up the function
481
    # using ast.
482
    seen_default = False
483
    for f in fields:
484
        # Only consider fields in the __init__ call.
485
        if f.init:
486
            if not (f.default is MISSING and f.default_factory is MISSING):
487
                seen_default = True
488
            elif seen_default:
489
                raise TypeError(
490
                    f"non-default argument {f.name!r} " "follows default argument"
491
                )
492
493
    globals = {"MISSING": MISSING, "_HAS_DEFAULT_FACTORY": _HAS_DEFAULT_FACTORY}
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...
494
495
    body_lines = []
496
    for f in fields:
497
        line = _field_init(f, frozen, globals, self_name)
498
        # line is None means that this field doesn't require
499
        # initialization (it's a pseudo-field).  Just skip it.
500
        if line:
501
            body_lines.append(line)
502
503
    # Does this class have a post-init function?
504
    if has_post_init:
505
        params_str = ",".join(f.name for f in fields 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...
506
        body_lines.append(f"{self_name}.{_POST_INIT_NAME}({params_str})")
507
508
    # If no body lines, use 'pass'.
509
    if not body_lines:
510
        body_lines = ["pass"]
511
512
    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...
513
    return _create_fn(
514
        "__init__",
515
        [self_name] + [_init_param(f) for f in fields if f.init],
516
        body_lines,
517
        locals=locals,
518
        globals=globals,
519
        return_type=None,
520
    )
521
522
523
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 1020).

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...
524
    return _create_fn(
525
        "__repr__",
526
        ("self",),
527
        [
528
            'return self.__class__.__qualname__ + f"('
529
            + ", ".join([f"{f.name}={{self.{f.name}!r}}" for f in fields])  # noqa: W503
530
            + ')"'  # noqa: W503
531
        ],
532
    )
533
534
535
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 1020).

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...
536
    # 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...
537
    # the modified version is used in the second call.  Is this okay?
538
    globals = {"cls": cls, "FrozenInstanceError": FrozenInstanceError}
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...
539
    if fields:
540
        fields_str = "(" + ",".join(repr(f.name) for f in fields) + ",)"
541
    else:
542
        # Special case for the zero-length tuple.
543
        fields_str = "()"
544
    return (
545
        _create_fn(
546
            "__setattr__",
547
            ("self", "name", "value"),
548
            (
549
                f"if type(self) is cls or name in {fields_str}:",
550
                ' raise FrozenInstanceError(f"cannot assign to field {name!r}")',
551
                "super(cls, self).__setattr__(name, value)",
552
            ),
553
            globals=globals,
554
        ),
555
        _create_fn(
556
            "__delattr__",
557
            ("self", "name"),
558
            (
559
                f"if type(self) is cls or name in {fields_str}:",
560
                ' raise FrozenInstanceError(f"cannot delete field {name!r}")',
561
                "super(cls, self).__delattr__(name)",
562
            ),
563
            globals=globals,
564
        ),
565
    )
566
567
568
def _cmp_fn(name, op, self_tuple, other_tuple):
569
    # Create a comparison function.  If the fields in the object are
570
    # named 'x' and 'y', then self_tuple is the string
571
    # '(self.x,self.y)' and other_tuple is the string
572
    # '(other.x,other.y)'.
573
574
    return _create_fn(
575
        name,
576
        ("self", "other"),
577
        [
578
            "if other.__class__ is self.__class__:",
579
            f" return {self_tuple}{op}{other_tuple}",
580
            "return NotImplemented",
581
        ],
582
    )
583
584
585
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 1020).

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...
586
    self_tuple = _tuple_str("self", fields)
587
    return _create_fn("__hash__", ("self",), [f"return hash({self_tuple})"])
588
589
590
def _is_classvar(a_type, typing):
591
    # This test uses a typing internal class, but it's the best way to
592
    # test if this is a ClassVar.
593
    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...
594
595
596
def _is_initvar(a_type, dataclasses):
597
    # The module we're checking against is the module we're
598
    # currently in (dataclasses.py).
599
    return a_type is dataclasses.InitVar
600
601
602
def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
603
    # Given a type annotation string, does it refer to a_type in
604
    # a_module?  For example, when checking that annotation denotes a
605
    # ClassVar, then a_module is typing, and a_type is
606
    # typing.ClassVar.
607
608
    # It's possible to look up a_module given a_type, but it involves
609
    # looking in sys.modules (again!), and seems like a waste since
610
    # the caller already knows a_module.
611
612
    # - annotation is a string type annotation
613
    # - cls is the class that this annotation was found in
614
    # - a_module is the module we want to match
615
    # - a_type is the type in that module we want to match
616
    # - is_type_predicate is a function called with (obj, a_module)
617
    #   that determines if obj is of the desired type.
618
619
    # Since this test does not do a local namespace lookup (and
620
    # instead only a module (global) lookup), there are some things it
621
    # gets wrong.
622
623
    # With string annotations, cv0 will be detected as a ClassVar:
624
    #   CV = ClassVar
625
    #   @dataclass
626
    #   class C0:
627
    #     cv0: CV
628
629
    # But in this example cv1 will not be detected as a ClassVar:
630
    #   @dataclass
631
    #   class C1:
632
    #     CV = ClassVar
633
    #     cv1: CV
634
635
    # In C1, the code in this function (_is_type) will look up "CV" in
636
    # the module and not find it, so it will not consider cv1 as a
637
    # ClassVar.  This is a fairly obscure corner case, and the best
638
    # way to fix it would be to eval() the string "CV" with the
639
    # correct global and local namespaces.  However that would involve
640
    # a eval() penalty for every single field of every dataclass
641
    # that's defined.  It was judged not worth it.
642
643
    match = _MODULE_IDENTIFIER_RE.match(annotation)
644
    if match:
645
        ns = None
646
        module_name = match.group(1)
647
        if not module_name:
648
            # No module name, assume the class's module did
649
            # "from .dataclasses import InitVar".
650
            ns = sys.modules.get(cls.__module__).__dict__
651
        else:
652
            # Look up module_name in the class's module.
653
            module = sys.modules.get(cls.__module__)
654
            if module and module.__dict__.get(module_name) is a_module:
655
                ns = sys.modules.get(a_type.__module__).__dict__
656
        if ns and is_type_predicate(ns.get(match.group(2)), a_module):
657
            return True
658
    return False
659
660
661
def _get_field(cls, a_name, a_type):
662
    # Return a Field object for this field name and type.  ClassVars
663
    # and InitVars are also returned, but marked as such (see
664
    # f._field_type).
665
666
    # If the default value isn't derived from Field, then it's only a
667
    # normal default value.  Convert it to a Field().
668
    default = getattr(cls, a_name, MISSING)
669
    if isinstance(default, Field):
670
        f = default
671
    else:
672
        if isinstance(default, types.MemberDescriptorType):
673
            # This is a field in __slots__, so it has no default value.
674
            default = MISSING
675
        f = field(default=default)
676
677
    # Only at this point do we know the name and the type.  Set them.
678
    f.name = a_name
679
    f.type = a_type
680
681
    # Assume it's a normal field until proven otherwise.  We're next
682
    # going to decide if it's a ClassVar or InitVar, everything else
683
    # is just a normal field.
684
    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...
685
686
    # In addition to checking for actual types here, also check for
687
    # string annotations.  get_type_hints() won't always work for us
688
    # (see https://github.com/python/typing/issues/508 for example),
689
    # plus it's expensive and would require an eval for every string
690
    # annotation.  So, make a best effort to see if this is a ClassVar
691
    # or InitVar using regex's and checking that the thing referenced
692
    # is actually of the correct type.
693
694
    # For the complete discussion, see https://bugs.python.org/issue33453
695
696
    # If typing has not been imported, then it's impossible for any
697
    # annotation to be a ClassVar.  So, only look for ClassVar if
698
    # typing has been imported by any module (not necessarily cls's
699
    # module).
700
    typing = sys.modules.get("typing")
701
    if typing:
702
        if _is_classvar(a_type, typing) or (
703
            isinstance(f.type, str)
704
            and _is_type(f.type, cls, typing, typing.ClassVar, _is_classvar)  # noqa: W503
705
        ):
706
            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...
707
708
    # If the type is InitVar, or if it's a matching string annotation,
709
    # then it's an InitVar.
710
    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...
711
        # The module we're checking against is the module we're
712
        # currently in (dataclasses.py).
713
        dataclasses = sys.modules[__name__]
714
        if _is_initvar(a_type, dataclasses) or (
715
            isinstance(f.type, str)
716
            and _is_type(f.type, cls, dataclasses, dataclasses.InitVar, _is_initvar)  # noqa: W503
717
        ):
718
            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...
719
720
    # Validations for individual fields.  This is delayed until now,
721
    # instead of in the Field() constructor, since only here do we
722
    # know the field name, which allows for better error reporting.
723
724
    # Special restrictions for ClassVar and InitVar.
725
    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...
726
        if f.default_factory is not MISSING:
727
            raise TypeError(f"field {f.name} cannot have a " "default factory")
728
        # Should I check for other field settings? default_factory
729
        # seems the most serious to check for.  Maybe add others.  For
730
        # example, how about init=False (or really,
731
        # init=<not-the-default-init-value>)?  It makes no sense for
732
        # ClassVar and InitVar to specify init=<anything>.
733
734
    # For real fields, disallow mutable defaults for known types.
735
    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...
736
        raise ValueError(
737
            f"mutable default {type(f.default)} for field "
738
            f"{f.name} is not allowed: use default_factory"
739
        )
740
741
    return f
742
743
744
def _set_new_attribute(cls, name, value):
745
    # Never overwrites an existing attribute.  Returns True if the
746
    # attribute already exists.
747
    if name in cls.__dict__:
748
        return True
749
    setattr(cls, name, value)
750
    return False
751
752
753
# Decide if/how we're going to create a hash function.  Key is
754
# (unsafe_hash, eq, frozen, does-hash-exist).  Value is the action to
755
# take.  The common case is to do nothing, so instead of providing a
756
# function that is a no-op, use None to signify that.
757
758
759
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 1020).

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...
760
    return None
761
762
763
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 1020).

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...
764
    flds = [f for f in fields if (f.compare if f.hash is None else f.hash)]
765
    return _hash_fn(flds)
766
767
768
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 1020).

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...
769
    # Raise an exception.
770
    raise TypeError(f"Cannot overwrite attribute __hash__ " f"in class {cls.__name__}")
771
772
773
#
774
#                +-------------------------------------- unsafe_hash?
775
#                |      +------------------------------- eq?
776
#                |      |      +------------------------ frozen?
777
#                |      |      |      +----------------  has-explicit-hash?
778
#                |      |      |      |
779
#                |      |      |      |        +-------  action
780
#                |      |      |      |        |
781
#                v      v      v      v        v
782
_hash_action = {
783
    (False, False, False, False): None,
784
    (False, False, False, True): None,
785
    (False, False, True, False): None,
786
    (False, False, True, True): None,
787
    (False, True, False, False): _hash_set_none,
788
    (False, True, False, True): None,
789
    (False, True, True, False): _hash_add,
790
    (False, True, True, True): None,
791
    (True, False, False, False): _hash_add,
792
    (True, False, False, True): _hash_exception,
793
    (True, False, True, False): _hash_add,
794
    (True, False, True, True): _hash_exception,
795
    (True, True, False, False): _hash_add,
796
    (True, True, False, True): _hash_exception,
797
    (True, True, True, False): _hash_add,
798
    (True, True, True, True): _hash_exception,
799
}
800
# See https://bugs.python.org/issue32929#msg312829 for an if-statement
801
# version of this table.
802
803
804
def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):  # noqa: C901
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...
805
    # Now that dicts retain insertion order, there's no reason to use
806
    # an ordered dict.  I am leveraging that ordering here, because
807
    # derived class fields overwrite base class fields, but the order
808
    # is defined by the base class, which is found first.
809
    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 1020).

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...
810
811
    setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order, unsafe_hash, frozen))
812
813
    # Find our base classes in reverse MRO order, and exclude
814
    # ourselves.  In reversed order so that more derived classes
815
    # override earlier field definitions in base classes.  As long as
816
    # we're iterating over them, see if any are frozen.
817
    any_frozen_base = False
818
    has_dataclass_bases = False
819
    for b in cls.__mro__[-1:0:-1]:
820
        # Only process classes that have been processed by our
821
        # decorator.  That is, they have a _FIELDS attribute.
822
        base_fields = getattr(b, _FIELDS, None)
823
        if base_fields:
824
            has_dataclass_bases = True
825
            for f in base_fields.values():
826
                fields[f.name] = f
827
            if getattr(b, _PARAMS).frozen:
828
                any_frozen_base = True
829
830
    # Annotations that are defined in this class (not in base
831
    # classes).  If __annotations__ isn't present, then this class
832
    # adds no new annotations.  We use this to compute fields that are
833
    # added by this class.
834
    #
835
    # Fields are found from cls_annotations, which is guaranteed to be
836
    # ordered.  Default values are from class attributes, if a field
837
    # has a default.  If the default value is a Field(), then it
838
    # contains additional info beyond (and possibly including) the
839
    # actual default value.  Pseudo-fields ClassVars and InitVars are
840
    # included, despite the fact that they're not real fields.  That's
841
    # dealt with later.
842
    cls_annotations = cls.__dict__.get("__annotations__", {})
843
844
    # Now find fields in our class.  While doing so, validate some
845
    # things, and set the default values (as class attributes) where
846
    # we can.
847
    cls_fields = [_get_field(cls, name, type) for name, type in cls_annotations.items()]
848
    for f in cls_fields:
849
        fields[f.name] = f
850
851
        # If the class attribute (which is the default value for this
852
        # field) exists and is of type 'Field', replace it with the
853
        # real default.  This is so that normal class introspection
854
        # sees a real default value, not a Field.
855
        if isinstance(getattr(cls, f.name, None), Field):
856
            if f.default is MISSING:
857
                # If there's no default, delete the class attribute.
858
                # This happens if we specify field(repr=False), for
859
                # example (that is, we specified a field object, but
860
                # no default value).  Also if we're using a default
861
                # factory.  The class attribute should not be set at
862
                # all in the post-processed class.
863
                delattr(cls, f.name)
864
            else:
865
                setattr(cls, f.name, f.default)
866
867
    # Do we have any Field members that don't also have annotations?
868
    for name, value in cls.__dict__.items():
869
        if isinstance(value, Field) and name not in cls_annotations:
870
            raise TypeError(f"{name!r} is a field but has no type annotation")
871
872
    # Check rules that apply if we are derived from any dataclasses.
873
    if has_dataclass_bases:
874
        # Raise an exception if any of our bases are frozen, but we're not.
875
        if any_frozen_base and not frozen:
876
            raise TypeError("cannot inherit non-frozen dataclass from a " "frozen one")
0 ignored issues
show
introduced by
Implicit string concatenation found in call
Loading history...
877
878
        # Raise an exception if we're frozen, but none of our bases are.
879
        if not any_frozen_base and frozen:
880
            raise TypeError("cannot inherit frozen dataclass from a " "non-frozen one")
0 ignored issues
show
introduced by
Implicit string concatenation found in call
Loading history...
881
882
    # Remember all of the fields on our class (including bases).  This
883
    # also marks this class as being a dataclass.
884
    setattr(cls, _FIELDS, fields)
885
886
    # Was this class defined with an explicit __hash__?  Note that if
887
    # __eq__ is defined in this class, then python will automatically
888
    # set __hash__ to None.  This is a heuristic, as it's possible
889
    # that such a __hash__ == None was not auto-generated, but it
890
    # close enough.
891
    class_hash = cls.__dict__.get("__hash__", MISSING)
892
    has_explicit_hash = not (
893
        class_hash is MISSING or (class_hash is None and "__eq__" in cls.__dict__)
894
    )
895
896
    # If we're generating ordering methods, we must be generating the
897
    # eq methods.
898
    if order and not eq:
899
        raise ValueError("eq must be true if order is true")
900
901
    if init:
902
        # Does this class have a post-init function?
903
        has_post_init = hasattr(cls, _POST_INIT_NAME)
904
905
        # Include InitVars and regular fields (so, not ClassVars).
906
        flds = [f for f in fields.values() 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...
907
        _set_new_attribute(
908
            cls,
909
            "__init__",
910
            _init_fn(
911
                flds,
912
                frozen,
913
                has_post_init,
914
                # The name to use for the "self"
915
                # param in __init__.  Use "self"
916
                # if possible.
917
                "__dataclass_self__" if "self" in fields else "self",
918
            ),
919
        )
920
921
    # Get the fields as a list, and include only real fields.  This is
922
    # used in all of the following methods.
923
    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...
924
925
    if repr:
926
        flds = [f for f in field_list if f.repr]
927
        _set_new_attribute(cls, "__repr__", _repr_fn(flds))
928
929
    if eq:
930
        # Create _eq__ method.  There's no need for a __ne__ method,
931
        # since python will call __eq__ and negate it.
932
        flds = [f for f in field_list if f.compare]
933
        self_tuple = _tuple_str("self", flds)
934
        other_tuple = _tuple_str("other", flds)
935
        _set_new_attribute(
936
            cls, "__eq__", _cmp_fn("__eq__", "==", self_tuple, other_tuple)
937
        )
938
939
    if order:
940
        # Create and set the ordering methods.
941
        flds = [f for f in field_list if f.compare]
942
        self_tuple = _tuple_str("self", flds)
943
        other_tuple = _tuple_str("other", flds)
944
        for name, op in [
945
            ("__lt__", "<"),
946
            ("__le__", "<="),
947
            ("__gt__", ">"),
948
            ("__ge__", ">="),
949
        ]:
950
            if _set_new_attribute(
951
                cls, name, _cmp_fn(name, op, self_tuple, other_tuple)
952
            ):
953
                raise TypeError(
954
                    f"Cannot overwrite attribute {name} "
955
                    f"in class {cls.__name__}. Consider using "
956
                    "functools.total_ordering"
957
                )
958
959
    if frozen:
960
        for fn in _frozen_get_del_attr(cls, field_list):
961
            if _set_new_attribute(cls, fn.__name__, fn):
962
                raise TypeError(
963
                    f"Cannot overwrite attribute {fn.__name__} "
964
                    f"in class {cls.__name__}"
965
                )
966
967
    # Decide if/how we're going to create a hash function.
968
    hash_action = _hash_action[
969
        bool(unsafe_hash), bool(eq), bool(frozen), has_explicit_hash
970
    ]
971
    if hash_action:
972
        # No need to call _set_new_attribute here, since by the time
973
        # we're here the overwriting is unconditional.
974
        cls.__hash__ = hash_action(cls, field_list)
975
976
    if not getattr(cls, "__doc__"):
977
        # Create a class doc-string.
978
        cls.__doc__ = cls.__name__ + str(inspect.signature(cls)).replace(" -> None", "")
979
980
    return cls
981
982
983
# _cls should never be specified by keyword, so start it with an
984
# underscore.  The presence of _cls is used to detect if this
985
# decorator is being called with parameters or not.
986
def dataclass(
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
987
    _cls=None,
988
    *,
989
    init=True,
990
    repr=True,
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...
991
    eq=True,
992
    order=False,
993
    unsafe_hash=False,
994
    frozen=False,
995
):
996
    """Returns the same class as was passed in, with dunder methods
997
    added based on the fields defined in the class.
998
999
    Examines PEP 526 __annotations__ to determine fields.
1000
1001
    If init is true, an __init__() method is added to the class. If
1002
    repr is true, a __repr__() method is added. If order is true, rich
1003
    comparison dunder methods are added. If unsafe_hash is true, a
1004
    __hash__() method function is added. If frozen is true, fields may
1005
    not be assigned to after instance creation.
1006
    """
1007
1008
    def wrap(cls):
1009
        return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
1010
1011
    # See if we're being called as @dataclass or @dataclass().
1012
    if _cls is None:
1013
        # We're called with parens.
1014
        return wrap
1015
1016
    # We're called as @dataclass without parens.
1017
    return wrap(_cls)
1018
1019
1020
def fields(class_or_instance):
1021
    """Return a tuple describing the fields of this dataclass.
1022
1023
    Accepts a dataclass or an instance of one. Tuple elements are of
1024
    type Field.
1025
    """
1026
1027
    # Might it be worth caching this, per class?
1028
    try:
1029
        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 1020).

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...
1030
    except AttributeError:
1031
        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...
1032
1033
    # Exclude pseudo-fields.  Note that fields is sorted by insertion
1034
    # order, so the order of the tuple is as the fields were defined.
1035
    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...
1036
1037
1038
def _is_dataclass_instance(obj):
1039
    """Returns True if obj is an instance of a dataclass."""
1040
    return not isinstance(obj, type) and hasattr(obj, _FIELDS)
1041
1042
1043
def is_dataclass(obj):
1044
    """Returns True if obj is a dataclass or an instance of a
1045
    dataclass."""
1046
    return hasattr(obj, _FIELDS)
1047
1048
1049
def asdict(obj, *, dict_factory=dict):
1050
    """Return the fields of a dataclass instance as a new dictionary mapping
1051
    field names to field values.
1052
1053
    Example usage:
1054
1055
      @dataclass
1056
      class C:
1057
          x: int
1058
          y: int
1059
1060
      c = C(1, 2)
1061
      assert asdict(c) == {'x': 1, 'y': 2}
1062
1063
    If given, 'dict_factory' will be used instead of built-in dict.
1064
    The function applies recursively to field values that are
1065
    dataclass instances. This will also look into built-in containers:
1066
    tuples, lists, and dicts.
1067
    """
1068
    if not _is_dataclass_instance(obj):
1069
        raise TypeError("asdict() should be called on dataclass instances")
1070
    return _asdict_inner(obj, dict_factory)
1071
1072
1073 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...
1074
    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...
1075
        result = []
1076
        for f in fields(obj):
1077
            value = _asdict_inner(getattr(obj, f.name), dict_factory)
1078
            result.append((f.name, value))
1079
        return dict_factory(result)
1080
    elif isinstance(obj, (list, tuple)):
1081
        return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
1082
    elif isinstance(obj, dict):
1083
        return type(obj)(
1084
            (_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory))
1085
            for k, v in obj.items()
1086
        )
1087
    else:
1088
        return copy.deepcopy(obj)
1089
1090
1091
def astuple(obj, *, tuple_factory=tuple):
1092
    """Return the fields of a dataclass instance as a new tuple of field values.
1093
1094
    Example usage::
1095
1096
      @dataclass
1097
      class C:
1098
          x: int
1099
          y: int
1100
1101
    c = C(1, 2)
1102
    assert astuple(c) == (1, 2)
1103
1104
    If given, 'tuple_factory' will be used instead of built-in tuple.
1105
    The function applies recursively to field values that are
1106
    dataclass instances. This will also look into built-in containers:
1107
    tuples, lists, and dicts.
1108
    """
1109
1110
    if not _is_dataclass_instance(obj):
1111
        raise TypeError("astuple() should be called on dataclass instances")
1112
    return _astuple_inner(obj, tuple_factory)
1113
1114
1115 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...
1116
    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...
1117
        result = []
1118
        for f in fields(obj):
1119
            value = _astuple_inner(getattr(obj, f.name), tuple_factory)
1120
            result.append(value)
1121
        return tuple_factory(result)
1122
    elif isinstance(obj, (list, tuple)):
1123
        return type(obj)(_astuple_inner(v, tuple_factory) for v in obj)
1124
    elif isinstance(obj, dict):
1125
        return type(obj)(
1126
            (_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory))
1127
            for k, v in obj.items()
1128
        )
1129
    else:
1130
        return copy.deepcopy(obj)
1131
1132
1133
def make_dataclass(
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...
1134
    cls_name,
1135
    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 1020).

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...
1136
    *,
1137
    bases=(),
1138
    namespace=None,
1139
    init=True,
1140
    repr=True,
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...
1141
    eq=True,
1142
    order=False,
1143
    unsafe_hash=False,
1144
    frozen=False,
1145
):
1146
    """Return a new dynamically created dataclass.
1147
1148
    The dataclass name will be 'cls_name'.  'fields' is an iterable
1149
    of either (name), (name, type) or (name, type, Field) objects. If type is
1150
    omitted, use the string 'typing.Any'.  Field objects are created by
1151
    the equivalent of calling 'field(name, type [, Field-info])'.
1152
1153
      C = make_dataclass('C', ['x', ('y', int), ('z', int, field(init=False))], bases=(Base,))
1154
1155
    is equivalent to:
1156
1157
      @dataclass
1158
      class C(Base):
1159
          x: 'typing.Any'
1160
          y: int
1161
          z: int = field(init=False)
1162
1163
    For the bases and namespace parameters, see the builtin type() function.
1164
1165
    The parameters init, repr, eq, order, unsafe_hash, and frozen are passed to
1166
    dataclass().
1167
    """
1168
1169
    if namespace is None:
1170
        namespace = {}
1171
    else:
1172
        # Copy namespace since we're going to mutate it.
1173
        namespace = namespace.copy()
1174
1175
    # While we're looking through the field names, validate that they
1176
    # are identifiers, are not keywords, and not duplicates.
1177
    seen = set()
1178
    anns = {}
1179
    for item in fields:
1180
        if isinstance(item, str):
1181
            name = item
1182
            tp = "typing.Any"
1183
        elif len(item) == 2:
1184
            (
1185
                name,
1186
                tp,
1187
            ) = item
1188
        elif len(item) == 3:
1189
            name, tp, spec = item
1190
            namespace[name] = spec
1191
        else:
1192
            raise TypeError(f"Invalid field: {item!r}")
1193
1194
        if not isinstance(name, str) or not name.isidentifier():
1195
            raise TypeError(f"Field names must be valid identifiers: {name!r}")
1196
        if keyword.iskeyword(name):
1197
            raise TypeError(f"Field names must not be keywords: {name!r}")
1198
        if name in seen:
1199
            raise TypeError(f"Field name duplicated: {name!r}")
1200
1201
        seen.add(name)
1202
        anns[name] = tp
1203
1204
    namespace["__annotations__"] = anns
1205
    # We use `types.new_class()` instead of simply `type()` to allow dynamic creation
1206
    # of generic dataclassses.
1207
    cls = types.new_class(cls_name, bases, {}, lambda ns: ns.update(namespace))
1208
    return dataclass(
1209
        cls,
1210
        init=init,
1211
        repr=repr,
1212
        eq=eq,
1213
        order=order,
1214
        unsafe_hash=unsafe_hash,
1215
        frozen=frozen,
1216
    )
1217
1218
1219
def replace(obj, **changes):
1220
    """Return a new object replacing specified fields with new values.
1221
1222
    This is especially useful for frozen classes.  Example usage:
1223
1224
      @dataclass(frozen=True)
1225
      class C:
1226
          x: int
1227
          y: int
1228
1229
      c = C(1, 2)
1230
      c1 = replace(c, x=3)
1231
      assert c1.x == 3 and c1.y == 2
1232
    """
1233
1234
    # We're going to mutate 'changes', but that's okay because it's a
1235
    # new dict, even if called with 'replace(obj, **my_changes)'.
1236
1237
    if not _is_dataclass_instance(obj):
1238
        raise TypeError("replace() should be called on dataclass instances")
1239
1240
    # It's an error to have init=False fields in 'changes'.
1241
    # If a field is not in 'changes', read its value from the provided obj.
1242
1243
    for f in getattr(obj, _FIELDS).values():
1244
        # Only consider normal fields or InitVars.
1245
        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...
1246
            continue
1247
1248
        if not f.init:
1249
            # Error if this field is specified in changes.
1250
            if f.name in changes:
1251
                raise ValueError(
1252
                    f"field {f.name} is declared with "
1253
                    "init=False, it cannot be specified with "
1254
                    "replace()"
1255
                )
1256
            continue
1257
1258
        if f.name not in changes:
1259
            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...
1260
                raise ValueError(
1261
                    f"InitVar {f.name!r} " "must be specified with replace()"
1262
                )
1263
            changes[f.name] = getattr(obj, f.name)
1264
1265
    # Create the new object, which calls __init__() and
1266
    # __post_init__() (if defined), using all of the init fields we've
1267
    # added and/or left in 'changes'.  If there are values supplied in
1268
    # changes that aren't fields, this will correctly raise a
1269
    # TypeError.
1270
    return obj.__class__(**changes)
1271