MCPcopy
hub / github.com/python/mypy / find_dataclass_transform_spec

Function find_dataclass_transform_spec

mypy/semanal_shared.py:380–450  ·  view source on GitHub ↗

Find the dataclass transform spec for the given node, if any exists. Per PEP 681 (https://peps.python.org/pep-0681/#the-dataclass-transform-decorator), dataclass transforms can be specified in multiple ways, including decorator functions and metaclasses/base classes. This function

(node: Node | None)

Source from the content-addressed store, hash-verified

378
379
380def find_dataclass_transform_spec(node: Node | None) -> DataclassTransformSpec | None:
381 """
382 Find the dataclass transform spec for the given node, if any exists.
383
384 Per PEP 681 (https://peps.python.org/pep-0681/#the-dataclass-transform-decorator), dataclass
385 transforms can be specified in multiple ways, including decorator functions and
386 metaclasses/base classes. This function resolves the spec from any of these variants.
387 """
388
389 # The spec only lives on the function/class definition itself, so we need to unwrap down to that
390 # point
391 if isinstance(node, CallExpr):
392 # Like dataclasses.dataclass, transform-based decorators can be applied either with or
393 # without parameters; ie, both of these forms are accepted:
394 #
395 # @typing.dataclass_transform
396 # class Foo: ...
397 # @typing.dataclass_transform(eq=True, order=True, ...)
398 # class Bar: ...
399 #
400 # We need to unwrap the call for the second variant.
401 node = node.callee
402
403 if isinstance(node, RefExpr):
404 node = node.node
405
406 if isinstance(node, Decorator):
407 # typing.dataclass_transform usage must always result in a Decorator; it always uses the
408 # `@dataclass_transform(...)` syntax and never `@dataclass_transform`
409 node = node.func
410
411 if isinstance(node, OverloadedFuncDef):
412 # The dataclass_transform decorator may be attached to any single overload, so we must
413 # search them all.
414 # Note that using more than one decorator is undefined behavior, so we can just take the
415 # first that we find.
416 for candidate in node.items:
417 spec = find_dataclass_transform_spec(candidate)
418 if spec is not None:
419 return spec
420 return find_dataclass_transform_spec(node.impl)
421
422 # For functions, we can directly consult the AST field for the spec
423 if isinstance(node, FuncDef):
424 return node.dataclass_transform_spec
425
426 if isinstance(node, ClassDef):
427 node = node.info
428 if isinstance(node, TypeInfo):
429 # Search all parent classes to see if any are decorated with `typing.dataclass_transform`
430 for base in node.mro[1:]:
431 if base.dataclass_transform_spec is not None:
432 return base.dataclass_transform_spec
433
434 # Check if there is a metaclass that is decorated with `typing.dataclass_transform`
435 #
436 # Note that PEP 681 only discusses using a metaclass that is directly decorated with
437 # `typing.dataclass_transform`; subclasses thereof should be treated with dataclass

Callers 6

visit_class_defMethod · 0.90
apply_hooks_to_classFunction · 0.90
snapshot_definitionFunction · 0.90
_get_transform_specFunction · 0.90

Calls 1

isinstanceFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…