summaryrefslogtreecommitdiff
path: root/astroid/brain/brain_dataclasses.py
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2019-09-26 09:19:40 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2019-09-26 09:19:40 +0200
commit3e4eac76e9abfa0400fa07b58c61973ac5495bd2 (patch)
tree79eec3d7ae47e882c2793ad1073c0467ba14c0ac /astroid/brain/brain_dataclasses.py
parentda1a1d70b8a3668a59de863d32132db6eaffadb6 (diff)
downloadastroid-git-3e4eac76e9abfa0400fa07b58c61973ac5495bd2.tar.gz
A transform for the builtin `dataclasses` module was added.
This should address various `dataclasses` issues that were surfaced even more after the release of pylint 2.4.0. In the previous versions of `astroid`, annotated assign nodes were allowed to be retrieved via `getattr()` but that no longer happens with the latest `astroid` release, as those attribute are not actual attributes, but rather virtual ones, thus an operation such as `getattr()` does not make sense for them.
Diffstat (limited to 'astroid/brain/brain_dataclasses.py')
-rw-r--r--astroid/brain/brain_dataclasses.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/astroid/brain/brain_dataclasses.py b/astroid/brain/brain_dataclasses.py
new file mode 100644
index 00000000..7a25e0c6
--- /dev/null
+++ b/astroid/brain/brain_dataclasses.py
@@ -0,0 +1,50 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
+"""
+Astroid hook for the dataclasses library
+"""
+
+import astroid
+from astroid import MANAGER
+
+
+DATACLASSES_DECORATORS = frozenset(("dataclasses.dataclass", "dataclass"))
+
+
+def is_decorated_with_dataclass(node, decorator_names=DATACLASSES_DECORATORS):
+ """Return True if a decorated node has a `dataclass` decorator applied."""
+ if not node.decorators:
+ return False
+ for decorator_attribute in node.decorators.nodes:
+ if isinstance(decorator_attribute, astroid.Call): # decorator with arguments
+ decorator_attribute = decorator_attribute.func
+ if decorator_attribute.as_string() in decorator_names:
+ return True
+ return False
+
+
+def dataclass_transform(node):
+ """Rewrite a dataclass to be easily understood by pylint"""
+
+ for assign_node in node.body:
+ if not isinstance(assign_node, (astroid.AnnAssign, astroid.Assign)):
+ continue
+
+ targets = (
+ assign_node.targets
+ if hasattr(assign_node, "targets")
+ else [assign_node.target]
+ )
+ for target in targets:
+ rhs_node = astroid.Unknown(
+ lineno=assign_node.lineno,
+ col_offset=assign_node.col_offset,
+ parent=assign_node,
+ )
+ node.instance_attrs[target.name] = [rhs_node]
+ node.locals[target.name] = [rhs_node]
+
+
+MANAGER.register_transform(
+ astroid.ClassDef, dataclass_transform, is_decorated_with_dataclass
+)