summaryrefslogtreecommitdiff
path: root/venv/Lib/site-packages/pylint/pyreverse
diff options
context:
space:
mode:
Diffstat (limited to 'venv/Lib/site-packages/pylint/pyreverse')
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__init__.py8
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pycbin0 -> 241 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pycbin0 -> 7621 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pycbin0 -> 8716 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pycbin0 -> 10187 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pycbin0 -> 4522 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pycbin0 -> 5787 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pycbin0 -> 4697 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pycbin0 -> 7286 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/diadefslib.py238
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/diagrams.py268
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/inspector.py357
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/main.py214
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/utils.py220
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/vcgutils.py229
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/writer.py213
16 files changed, 1747 insertions, 0 deletions
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__init__.py b/venv/Lib/site-packages/pylint/pyreverse/__init__.py
new file mode 100644
index 0000000..9ca1da5
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__init__.py
@@ -0,0 +1,8 @@
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""
+pyreverse.extensions
+"""
+
+__revision__ = "$Id $"
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..6054dd9
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pyc
new file mode 100644
index 0000000..64bdd6b
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pyc
new file mode 100644
index 0000000..cd5a663
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pyc
new file mode 100644
index 0000000..0bcfb4d
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pyc
new file mode 100644
index 0000000..c8f9398
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pyc
new file mode 100644
index 0000000..1711f15
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pyc
new file mode 100644
index 0000000..f1a93f5
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pyc
new file mode 100644
index 0000000..a0ac15c
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pyc
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/diadefslib.py b/venv/Lib/site-packages/pylint/pyreverse/diadefslib.py
new file mode 100644
index 0000000..de4e9fd
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/diadefslib.py
@@ -0,0 +1,238 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2006, 2008-2010, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
+# Copyright (c) 2014 Brett Cannon <brett@python.org>
+# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
+# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
+# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
+# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
+# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
+# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
+# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
+# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""handle diagram generation options for class diagram or default diagrams
+"""
+
+import astroid
+
+from pylint.pyreverse.diagrams import ClassDiagram, PackageDiagram
+from pylint.pyreverse.utils import LocalsVisitor
+
+BUILTINS_NAME = "builtins"
+
+# diagram generators ##########################################################
+
+
+class DiaDefGenerator:
+ """handle diagram generation options"""
+
+ def __init__(self, linker, handler):
+ """common Diagram Handler initialization"""
+ self.config = handler.config
+ self._set_default_options()
+ self.linker = linker
+ self.classdiagram = None # defined by subclasses
+
+ def get_title(self, node):
+ """get title for objects"""
+ title = node.name
+ if self.module_names:
+ title = "%s.%s" % (node.root().name, title)
+ return title
+
+ def _set_option(self, option):
+ """activate some options if not explicitly deactivated"""
+ # if we have a class diagram, we want more information by default;
+ # so if the option is None, we return True
+ if option is None:
+ return bool(self.config.classes)
+ return option
+
+ def _set_default_options(self):
+ """set different default options with _default dictionary"""
+ self.module_names = self._set_option(self.config.module_names)
+ all_ancestors = self._set_option(self.config.all_ancestors)
+ all_associated = self._set_option(self.config.all_associated)
+ anc_level, association_level = (0, 0)
+ if all_ancestors:
+ anc_level = -1
+ if all_associated:
+ association_level = -1
+ if self.config.show_ancestors is not None:
+ anc_level = self.config.show_ancestors
+ if self.config.show_associated is not None:
+ association_level = self.config.show_associated
+ self.anc_level, self.association_level = anc_level, association_level
+
+ def _get_levels(self):
+ """help function for search levels"""
+ return self.anc_level, self.association_level
+
+ def show_node(self, node):
+ """true if builtins and not show_builtins"""
+ if self.config.show_builtin:
+ return True
+ return node.root().name != BUILTINS_NAME
+
+ def add_class(self, node):
+ """visit one class and add it to diagram"""
+ self.linker.visit(node)
+ self.classdiagram.add_object(self.get_title(node), node)
+
+ def get_ancestors(self, node, level):
+ """return ancestor nodes of a class node"""
+ if level == 0:
+ return
+ for ancestor in node.ancestors(recurs=False):
+ if not self.show_node(ancestor):
+ continue
+ yield ancestor
+
+ def get_associated(self, klass_node, level):
+ """return associated nodes of a class node"""
+ if level == 0:
+ return
+ for association_nodes in list(klass_node.instance_attrs_type.values()) + list(
+ klass_node.locals_type.values()
+ ):
+ for node in association_nodes:
+ if isinstance(node, astroid.Instance):
+ node = node._proxied
+ if not (isinstance(node, astroid.ClassDef) and self.show_node(node)):
+ continue
+ yield node
+
+ def extract_classes(self, klass_node, anc_level, association_level):
+ """extract recursively classes related to klass_node"""
+ if self.classdiagram.has_node(klass_node) or not self.show_node(klass_node):
+ return
+ self.add_class(klass_node)
+
+ for ancestor in self.get_ancestors(klass_node, anc_level):
+ self.extract_classes(ancestor, anc_level - 1, association_level)
+
+ for node in self.get_associated(klass_node, association_level):
+ self.extract_classes(node, anc_level, association_level - 1)
+
+
+class DefaultDiadefGenerator(LocalsVisitor, DiaDefGenerator):
+ """generate minimum diagram definition for the project :
+
+ * a package diagram including project's modules
+ * a class diagram including project's classes
+ """
+
+ def __init__(self, linker, handler):
+ DiaDefGenerator.__init__(self, linker, handler)
+ LocalsVisitor.__init__(self)
+
+ def visit_project(self, node):
+ """visit a pyreverse.utils.Project node
+
+ create a diagram definition for packages
+ """
+ mode = self.config.mode
+ if len(node.modules) > 1:
+ self.pkgdiagram = PackageDiagram("packages %s" % node.name, mode)
+ else:
+ self.pkgdiagram = None
+ self.classdiagram = ClassDiagram("classes %s" % node.name, mode)
+
+ def leave_project(self, node): # pylint: disable=unused-argument
+ """leave the pyreverse.utils.Project node
+
+ return the generated diagram definition
+ """
+ if self.pkgdiagram:
+ return self.pkgdiagram, self.classdiagram
+ return (self.classdiagram,)
+
+ def visit_module(self, node):
+ """visit an astroid.Module node
+
+ add this class to the package diagram definition
+ """
+ if self.pkgdiagram:
+ self.linker.visit(node)
+ self.pkgdiagram.add_object(node.name, node)
+
+ def visit_classdef(self, node):
+ """visit an astroid.Class node
+
+ add this class to the class diagram definition
+ """
+ anc_level, association_level = self._get_levels()
+ self.extract_classes(node, anc_level, association_level)
+
+ def visit_importfrom(self, node):
+ """visit astroid.ImportFrom and catch modules for package diagram
+ """
+ if self.pkgdiagram:
+ self.pkgdiagram.add_from_depend(node, node.modname)
+
+
+class ClassDiadefGenerator(DiaDefGenerator):
+ """generate a class diagram definition including all classes related to a
+ given class
+ """
+
+ def __init__(self, linker, handler):
+ DiaDefGenerator.__init__(self, linker, handler)
+
+ def class_diagram(self, project, klass):
+ """return a class diagram definition for the given klass and its
+ related klasses
+ """
+
+ self.classdiagram = ClassDiagram(klass, self.config.mode)
+ if len(project.modules) > 1:
+ module, klass = klass.rsplit(".", 1)
+ module = project.get_module(module)
+ else:
+ module = project.modules[0]
+ klass = klass.split(".")[-1]
+ klass = next(module.ilookup(klass))
+
+ anc_level, association_level = self._get_levels()
+ self.extract_classes(klass, anc_level, association_level)
+ return self.classdiagram
+
+
+# diagram handler #############################################################
+
+
+class DiadefsHandler:
+ """handle diagram definitions :
+
+ get it from user (i.e. xml files) or generate them
+ """
+
+ def __init__(self, config):
+ self.config = config
+
+ def get_diadefs(self, project, linker):
+ """Get the diagrams configuration data
+
+ :param project:The pyreverse project
+ :type project: pyreverse.utils.Project
+ :param linker: The linker
+ :type linker: pyreverse.inspector.Linker(IdGeneratorMixIn, LocalsVisitor)
+
+ :returns: The list of diagram definitions
+ :rtype: list(:class:`pylint.pyreverse.diagrams.ClassDiagram`)
+ """
+
+ # read and interpret diagram definitions (Diadefs)
+ diagrams = []
+ generator = ClassDiadefGenerator(linker, self)
+ for klass in self.config.classes:
+ diagrams.append(generator.class_diagram(project, klass))
+ if not diagrams:
+ diagrams = DefaultDiadefGenerator(linker, self).visit(project)
+ for diagram in diagrams:
+ diagram.extract_relationships()
+ return diagrams
diff --git a/venv/Lib/site-packages/pylint/pyreverse/diagrams.py b/venv/Lib/site-packages/pylint/pyreverse/diagrams.py
new file mode 100644
index 0000000..b53b845
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/diagrams.py
@@ -0,0 +1,268 @@
+# Copyright (c) 2006, 2008-2010, 2012-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
+# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2014 Brett Cannon <brett@python.org>
+# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
+# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
+# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""diagram objects
+"""
+
+import astroid
+
+from pylint.checkers.utils import decorated_with_property
+from pylint.pyreverse.utils import FilterMixIn, is_interface
+
+
+class Figure:
+ """base class for counter handling"""
+
+
+class Relationship(Figure):
+ """a relation ship from an object in the diagram to another
+ """
+
+ def __init__(self, from_object, to_object, relation_type, name=None):
+ Figure.__init__(self)
+ self.from_object = from_object
+ self.to_object = to_object
+ self.type = relation_type
+ self.name = name
+
+
+class DiagramEntity(Figure):
+ """a diagram object, i.e. a label associated to an astroid node
+ """
+
+ def __init__(self, title="No name", node=None):
+ Figure.__init__(self)
+ self.title = title
+ self.node = node
+
+
+class ClassDiagram(Figure, FilterMixIn):
+ """main class diagram handling
+ """
+
+ TYPE = "class"
+
+ def __init__(self, title, mode):
+ FilterMixIn.__init__(self, mode)
+ Figure.__init__(self)
+ self.title = title
+ self.objects = []
+ self.relationships = {}
+ self._nodes = {}
+ self.depends = []
+
+ def get_relationships(self, role):
+ # sorted to get predictable (hence testable) results
+ return sorted(
+ self.relationships.get(role, ()),
+ key=lambda x: (x.from_object.fig_id, x.to_object.fig_id),
+ )
+
+ def add_relationship(self, from_object, to_object, relation_type, name=None):
+ """create a relation ship
+ """
+ rel = Relationship(from_object, to_object, relation_type, name)
+ self.relationships.setdefault(relation_type, []).append(rel)
+
+ def get_relationship(self, from_object, relation_type):
+ """return a relation ship or None
+ """
+ for rel in self.relationships.get(relation_type, ()):
+ if rel.from_object is from_object:
+ return rel
+ raise KeyError(relation_type)
+
+ def get_attrs(self, node):
+ """return visible attributes, possibly with class name"""
+ attrs = []
+ properties = [
+ (n, m)
+ for n, m in node.items()
+ if isinstance(m, astroid.FunctionDef) and decorated_with_property(m)
+ ]
+ for node_name, associated_nodes in (
+ list(node.instance_attrs_type.items())
+ + list(node.locals_type.items())
+ + properties
+ ):
+ if not self.show_attr(node_name):
+ continue
+ names = self.class_names(associated_nodes)
+ if names:
+ node_name = "%s : %s" % (node_name, ", ".join(names))
+ attrs.append(node_name)
+ return sorted(attrs)
+
+ def get_methods(self, node):
+ """return visible methods"""
+ methods = [
+ m
+ for m in node.values()
+ if isinstance(m, astroid.FunctionDef)
+ and not decorated_with_property(m)
+ and self.show_attr(m.name)
+ ]
+ return sorted(methods, key=lambda n: n.name)
+
+ def add_object(self, title, node):
+ """create a diagram object
+ """
+ assert node not in self._nodes
+ ent = DiagramEntity(title, node)
+ self._nodes[node] = ent
+ self.objects.append(ent)
+
+ def class_names(self, nodes):
+ """return class names if needed in diagram"""
+ names = []
+ for node in nodes:
+ if isinstance(node, astroid.Instance):
+ node = node._proxied
+ if (
+ isinstance(node, astroid.ClassDef)
+ and hasattr(node, "name")
+ and not self.has_node(node)
+ ):
+ if node.name not in names:
+ node_name = node.name
+ names.append(node_name)
+ return names
+
+ def nodes(self):
+ """return the list of underlying nodes
+ """
+ return self._nodes.keys()
+
+ def has_node(self, node):
+ """return true if the given node is included in the diagram
+ """
+ return node in self._nodes
+
+ def object_from_node(self, node):
+ """return the diagram object mapped to node
+ """
+ return self._nodes[node]
+
+ def classes(self):
+ """return all class nodes in the diagram"""
+ return [o for o in self.objects if isinstance(o.node, astroid.ClassDef)]
+
+ def classe(self, name):
+ """return a class by its name, raise KeyError if not found
+ """
+ for klass in self.classes():
+ if klass.node.name == name:
+ return klass
+ raise KeyError(name)
+
+ def extract_relationships(self):
+ """extract relation ships between nodes in the diagram
+ """
+ for obj in self.classes():
+ node = obj.node
+ obj.attrs = self.get_attrs(node)
+ obj.methods = self.get_methods(node)
+ # shape
+ if is_interface(node):
+ obj.shape = "interface"
+ else:
+ obj.shape = "class"
+ # inheritance link
+ for par_node in node.ancestors(recurs=False):
+ try:
+ par_obj = self.object_from_node(par_node)
+ self.add_relationship(obj, par_obj, "specialization")
+ except KeyError:
+ continue
+ # implements link
+ for impl_node in node.implements:
+ try:
+ impl_obj = self.object_from_node(impl_node)
+ self.add_relationship(obj, impl_obj, "implements")
+ except KeyError:
+ continue
+ # associations link
+ for name, values in list(node.instance_attrs_type.items()) + list(
+ node.locals_type.items()
+ ):
+ for value in values:
+ if value is astroid.Uninferable:
+ continue
+ if isinstance(value, astroid.Instance):
+ value = value._proxied
+ try:
+ associated_obj = self.object_from_node(value)
+ self.add_relationship(associated_obj, obj, "association", name)
+ except KeyError:
+ continue
+
+
+class PackageDiagram(ClassDiagram):
+ """package diagram handling
+ """
+
+ TYPE = "package"
+
+ def modules(self):
+ """return all module nodes in the diagram"""
+ return [o for o in self.objects if isinstance(o.node, astroid.Module)]
+
+ def module(self, name):
+ """return a module by its name, raise KeyError if not found
+ """
+ for mod in self.modules():
+ if mod.node.name == name:
+ return mod
+ raise KeyError(name)
+
+ def get_module(self, name, node):
+ """return a module by its name, looking also for relative imports;
+ raise KeyError if not found
+ """
+ for mod in self.modules():
+ mod_name = mod.node.name
+ if mod_name == name:
+ return mod
+ # search for fullname of relative import modules
+ package = node.root().name
+ if mod_name == "%s.%s" % (package, name):
+ return mod
+ if mod_name == "%s.%s" % (package.rsplit(".", 1)[0], name):
+ return mod
+ raise KeyError(name)
+
+ def add_from_depend(self, node, from_module):
+ """add dependencies created by from-imports
+ """
+ mod_name = node.root().name
+ obj = self.module(mod_name)
+ if from_module not in obj.node.depends:
+ obj.node.depends.append(from_module)
+
+ def extract_relationships(self):
+ """extract relation ships between nodes in the diagram
+ """
+ ClassDiagram.extract_relationships(self)
+ for obj in self.classes():
+ # ownership
+ try:
+ mod = self.object_from_node(obj.node.root())
+ self.add_relationship(obj, mod, "ownership")
+ except KeyError:
+ continue
+ for obj in self.modules():
+ obj.shape = "package"
+ # dependencies
+ for dep_name in obj.node.depends:
+ try:
+ dep = self.get_module(dep_name, obj.node)
+ except KeyError:
+ continue
+ self.add_relationship(obj, dep, "depends")
diff --git a/venv/Lib/site-packages/pylint/pyreverse/inspector.py b/venv/Lib/site-packages/pylint/pyreverse/inspector.py
new file mode 100644
index 0000000..702b108
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/inspector.py
@@ -0,0 +1,357 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
+# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
+# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""
+Visitor doing some postprocessing on the astroid tree.
+Try to resolve definitions (namespace) dictionary, relationship...
+"""
+import collections
+import os
+import traceback
+
+import astroid
+from astroid import bases, exceptions, manager, modutils, node_classes
+
+from pylint.pyreverse import utils
+
+
+def _iface_hdlr(_):
+ """Handler used by interfaces to handle suspicious interface nodes."""
+ return True
+
+
+def _astroid_wrapper(func, modname):
+ print("parsing %s..." % modname)
+ try:
+ return func(modname)
+ except exceptions.AstroidBuildingException as exc:
+ print(exc)
+ except Exception as exc: # pylint: disable=broad-except
+ traceback.print_exc()
+
+
+def interfaces(node, herited=True, handler_func=_iface_hdlr):
+ """Return an iterator on interfaces implemented by the given class node."""
+ try:
+ implements = bases.Instance(node).getattr("__implements__")[0]
+ except exceptions.NotFoundError:
+ return
+ if not herited and implements.frame() is not node:
+ return
+ found = set()
+ missing = False
+ for iface in node_classes.unpack_infer(implements):
+ if iface is astroid.Uninferable:
+ missing = True
+ continue
+ if iface not in found and handler_func(iface):
+ found.add(iface)
+ yield iface
+ if missing:
+ raise exceptions.InferenceError()
+
+
+class IdGeneratorMixIn:
+ """Mixin adding the ability to generate integer uid."""
+
+ def __init__(self, start_value=0):
+ self.id_count = start_value
+
+ def init_counter(self, start_value=0):
+ """init the id counter
+ """
+ self.id_count = start_value
+
+ def generate_id(self):
+ """generate a new identifier
+ """
+ self.id_count += 1
+ return self.id_count
+
+
+class Linker(IdGeneratorMixIn, utils.LocalsVisitor):
+ """Walk on the project tree and resolve relationships.
+
+ According to options the following attributes may be
+ added to visited nodes:
+
+ * uid,
+ a unique identifier for the node (on astroid.Project, astroid.Module,
+ astroid.Class and astroid.locals_type). Only if the linker
+ has been instantiated with tag=True parameter (False by default).
+
+ * Function
+ a mapping from locals names to their bounded value, which may be a
+ constant like a string or an integer, or an astroid node
+ (on astroid.Module, astroid.Class and astroid.Function).
+
+ * instance_attrs_type
+ as locals_type but for klass member attributes (only on astroid.Class)
+
+ * implements,
+ list of implemented interface _objects_ (only on astroid.Class nodes)
+ """
+
+ def __init__(self, project, inherited_interfaces=0, tag=False):
+ IdGeneratorMixIn.__init__(self)
+ utils.LocalsVisitor.__init__(self)
+ # take inherited interface in consideration or not
+ self.inherited_interfaces = inherited_interfaces
+ # tag nodes or not
+ self.tag = tag
+ # visited project
+ self.project = project
+
+ def visit_project(self, node):
+ """visit a pyreverse.utils.Project node
+
+ * optionally tag the node with a unique id
+ """
+ if self.tag:
+ node.uid = self.generate_id()
+ for module in node.modules:
+ self.visit(module)
+
+ def visit_package(self, node):
+ """visit an astroid.Package node
+
+ * optionally tag the node with a unique id
+ """
+ if self.tag:
+ node.uid = self.generate_id()
+ for subelmt in node.values():
+ self.visit(subelmt)
+
+ def visit_module(self, node):
+ """visit an astroid.Module node
+
+ * set the locals_type mapping
+ * set the depends mapping
+ * optionally tag the node with a unique id
+ """
+ if hasattr(node, "locals_type"):
+ return
+ node.locals_type = collections.defaultdict(list)
+ node.depends = []
+ if self.tag:
+ node.uid = self.generate_id()
+
+ def visit_classdef(self, node):
+ """visit an astroid.Class node
+
+ * set the locals_type and instance_attrs_type mappings
+ * set the implements list and build it
+ * optionally tag the node with a unique id
+ """
+ if hasattr(node, "locals_type"):
+ return
+ node.locals_type = collections.defaultdict(list)
+ if self.tag:
+ node.uid = self.generate_id()
+ # resolve ancestors
+ for baseobj in node.ancestors(recurs=False):
+ specializations = getattr(baseobj, "specializations", [])
+ specializations.append(node)
+ baseobj.specializations = specializations
+ # resolve instance attributes
+ node.instance_attrs_type = collections.defaultdict(list)
+ for assignattrs in node.instance_attrs.values():
+ for assignattr in assignattrs:
+ self.handle_assignattr_type(assignattr, node)
+ # resolve implemented interface
+ try:
+ node.implements = list(interfaces(node, self.inherited_interfaces))
+ except astroid.InferenceError:
+ node.implements = ()
+
+ def visit_functiondef(self, node):
+ """visit an astroid.Function node
+
+ * set the locals_type mapping
+ * optionally tag the node with a unique id
+ """
+ if hasattr(node, "locals_type"):
+ return
+ node.locals_type = collections.defaultdict(list)
+ if self.tag:
+ node.uid = self.generate_id()
+
+ link_project = visit_project
+ link_module = visit_module
+ link_class = visit_classdef
+ link_function = visit_functiondef
+
+ def visit_assignname(self, node):
+ """visit an astroid.AssignName node
+
+ handle locals_type
+ """
+ # avoid double parsing done by different Linkers.visit
+ # running over the same project:
+ if hasattr(node, "_handled"):
+ return
+ node._handled = True
+ if node.name in node.frame():
+ frame = node.frame()
+ else:
+ # the name has been defined as 'global' in the frame and belongs
+ # there.
+ frame = node.root()
+ try:
+ if not hasattr(frame, "locals_type"):
+ # If the frame doesn't have a locals_type yet,
+ # it means it wasn't yet visited. Visit it now
+ # to add what's missing from it.
+ if isinstance(frame, astroid.ClassDef):
+ self.visit_classdef(frame)
+ elif isinstance(frame, astroid.FunctionDef):
+ self.visit_functiondef(frame)
+ else:
+ self.visit_module(frame)
+
+ current = frame.locals_type[node.name]
+ values = set(node.infer())
+ frame.locals_type[node.name] = list(set(current) | values)
+ except astroid.InferenceError:
+ pass
+
+ @staticmethod
+ def handle_assignattr_type(node, parent):
+ """handle an astroid.assignattr node
+
+ handle instance_attrs_type
+ """
+ try:
+ values = set(node.infer())
+ current = set(parent.instance_attrs_type[node.attrname])
+ parent.instance_attrs_type[node.attrname] = list(current | values)
+ except astroid.InferenceError:
+ pass
+
+ def visit_import(self, node):
+ """visit an astroid.Import node
+
+ resolve module dependencies
+ """
+ context_file = node.root().file
+ for name in node.names:
+ relative = modutils.is_relative(name[0], context_file)
+ self._imported_module(node, name[0], relative)
+
+ def visit_importfrom(self, node):
+ """visit an astroid.ImportFrom node
+
+ resolve module dependencies
+ """
+ basename = node.modname
+ context_file = node.root().file
+ if context_file is not None:
+ relative = modutils.is_relative(basename, context_file)
+ else:
+ relative = False
+ for name in node.names:
+ if name[0] == "*":
+ continue
+ # analyze dependencies
+ fullname = "%s.%s" % (basename, name[0])
+ if fullname.find(".") > -1:
+ try:
+ fullname = modutils.get_module_part(fullname, context_file)
+ except ImportError:
+ continue
+ if fullname != basename:
+ self._imported_module(node, fullname, relative)
+
+ def compute_module(self, context_name, mod_path):
+ """return true if the module should be added to dependencies"""
+ package_dir = os.path.dirname(self.project.path)
+ if context_name == mod_path:
+ return 0
+ if modutils.is_standard_module(mod_path, (package_dir,)):
+ return 1
+ return 0
+
+ def _imported_module(self, node, mod_path, relative):
+ """Notify an imported module, used to analyze dependencies"""
+ module = node.root()
+ context_name = module.name
+ if relative:
+ mod_path = "%s.%s" % (".".join(context_name.split(".")[:-1]), mod_path)
+ if self.compute_module(context_name, mod_path):
+ # handle dependencies
+ if not hasattr(module, "depends"):
+ module.depends = []
+ mod_paths = module.depends
+ if mod_path not in mod_paths:
+ mod_paths.append(mod_path)
+
+
+class Project:
+ """a project handle a set of modules / packages"""
+
+ def __init__(self, name=""):
+ self.name = name
+ self.path = None
+ self.modules = []
+ self.locals = {}
+ self.__getitem__ = self.locals.__getitem__
+ self.__iter__ = self.locals.__iter__
+ self.values = self.locals.values
+ self.keys = self.locals.keys
+ self.items = self.locals.items
+
+ def add_module(self, node):
+ self.locals[node.name] = node
+ self.modules.append(node)
+
+ def get_module(self, name):
+ return self.locals[name]
+
+ def get_children(self):
+ return self.modules
+
+ def __repr__(self):
+ return "<Project %r at %s (%s modules)>" % (
+ self.name,
+ id(self),
+ len(self.modules),
+ )
+
+
+def project_from_files(
+ files, func_wrapper=_astroid_wrapper, project_name="no name", black_list=("CVS",)
+):
+ """return a Project from a list of files or modules"""
+ # build the project representation
+ astroid_manager = manager.AstroidManager()
+ project = Project(project_name)
+ for something in files:
+ if not os.path.exists(something):
+ fpath = modutils.file_from_modpath(something.split("."))
+ elif os.path.isdir(something):
+ fpath = os.path.join(something, "__init__.py")
+ else:
+ fpath = something
+ ast = func_wrapper(astroid_manager.ast_from_file, fpath)
+ if ast is None:
+ continue
+ project.path = project.path or ast.file
+ project.add_module(ast)
+ base_name = ast.name
+ # recurse in package except if __init__ was explicitly given
+ if ast.package and something.find("__init__") == -1:
+ # recurse on others packages / modules if this is a package
+ for fpath in modutils.get_module_files(
+ os.path.dirname(ast.file), black_list
+ ):
+ ast = func_wrapper(astroid_manager.ast_from_file, fpath)
+ if ast is None or ast.name == base_name:
+ continue
+ project.add_module(ast)
+ return project
diff --git a/venv/Lib/site-packages/pylint/pyreverse/main.py b/venv/Lib/site-packages/pylint/pyreverse/main.py
new file mode 100644
index 0000000..652b954
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/main.py
@@ -0,0 +1,214 @@
+# Copyright (c) 2008-2010, 2012-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
+# Copyright (c) 2014 Brett Cannon <brett@python.org>
+# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
+# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
+# Copyright (c) 2016 Alexander Pervakov <frost.nzcr4@jagmort.com>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""
+ %prog [options] <packages>
+
+ create UML diagrams for classes and modules in <packages>
+"""
+import os
+import subprocess
+import sys
+
+from pylint.config import ConfigurationMixIn
+from pylint.pyreverse import writer
+from pylint.pyreverse.diadefslib import DiadefsHandler
+from pylint.pyreverse.inspector import Linker, project_from_files
+from pylint.pyreverse.utils import insert_default_options
+
+OPTIONS = (
+ (
+ "filter-mode",
+ dict(
+ short="f",
+ default="PUB_ONLY",
+ dest="mode",
+ type="string",
+ action="store",
+ metavar="<mode>",
+ help="""filter attributes and functions according to
+ <mode>. Correct modes are :
+ 'PUB_ONLY' filter all non public attributes
+ [DEFAULT], equivalent to PRIVATE+SPECIAL_A
+ 'ALL' no filter
+ 'SPECIAL' filter Python special functions
+ except constructor
+ 'OTHER' filter protected and private
+ attributes""",
+ ),
+ ),
+ (
+ "class",
+ dict(
+ short="c",
+ action="append",
+ metavar="<class>",
+ dest="classes",
+ default=[],
+ help="create a class diagram with all classes related to <class>;\
+ this uses by default the options -ASmy",
+ ),
+ ),
+ (
+ "show-ancestors",
+ dict(
+ short="a",
+ action="store",
+ metavar="<ancestor>",
+ type="int",
+ help="show <ancestor> generations of ancestor classes not in <projects>",
+ ),
+ ),
+ (
+ "all-ancestors",
+ dict(
+ short="A",
+ default=None,
+ help="show all ancestors off all classes in <projects>",
+ ),
+ ),
+ (
+ "show-associated",
+ dict(
+ short="s",
+ action="store",
+ metavar="<association_level>",
+ type="int",
+ help="show <association_level> levels of associated classes not in <projects>",
+ ),
+ ),
+ (
+ "all-associated",
+ dict(
+ short="S",
+ default=None,
+ help="show recursively all associated off all associated classes",
+ ),
+ ),
+ (
+ "show-builtin",
+ dict(
+ short="b",
+ action="store_true",
+ default=False,
+ help="include builtin objects in representation of classes",
+ ),
+ ),
+ (
+ "module-names",
+ dict(
+ short="m",
+ default=None,
+ type="yn",
+ metavar="[yn]",
+ help="include module name in representation of classes",
+ ),
+ ),
+ (
+ "only-classnames",
+ dict(
+ short="k",
+ action="store_true",
+ default=False,
+ help="don't show attributes and methods in the class boxes; \
+this disables -f values",
+ ),
+ ),
+ (
+ "output",
+ dict(
+ short="o",
+ dest="output_format",
+ action="store",
+ default="dot",
+ metavar="<format>",
+ help="create a *.<format> output file if format available.",
+ ),
+ ),
+ (
+ "ignore",
+ {
+ "type": "csv",
+ "metavar": "<file[,file...]>",
+ "dest": "black_list",
+ "default": ("CVS",),
+ "help": "Add files or directories to the blacklist. They "
+ "should be base names, not paths.",
+ },
+ ),
+ (
+ "project",
+ {
+ "default": "",
+ "type": "string",
+ "short": "p",
+ "metavar": "<project name>",
+ "help": "set the project name.",
+ },
+ ),
+)
+
+
+def _check_graphviz_available(output_format):
+ """check if we need graphviz for different output format"""
+ try:
+ subprocess.call(["dot", "-V"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ except OSError:
+ print(
+ "The output format '%s' is currently not available.\n"
+ "Please install 'Graphviz' to have other output formats "
+ "than 'dot' or 'vcg'." % output_format
+ )
+ sys.exit(32)
+
+
+class Run(ConfigurationMixIn):
+ """base class providing common behaviour for pyreverse commands"""
+
+ options = OPTIONS # type: ignore
+
+ def __init__(self, args):
+ ConfigurationMixIn.__init__(self, usage=__doc__)
+ insert_default_options()
+ args = self.load_command_line_configuration()
+ if self.config.output_format not in ("dot", "vcg"):
+ _check_graphviz_available(self.config.output_format)
+
+ sys.exit(self.run(args))
+
+ def run(self, args):
+ """checking arguments and run project"""
+ if not args:
+ print(self.help())
+ return 1
+ # insert current working directory to the python path to recognize
+ # dependencies to local modules even if cwd is not in the PYTHONPATH
+ sys.path.insert(0, os.getcwd())
+ try:
+ project = project_from_files(
+ args,
+ project_name=self.config.project,
+ black_list=self.config.black_list,
+ )
+ linker = Linker(project, tag=True)
+ handler = DiadefsHandler(self.config)
+ diadefs = handler.get_diadefs(project, linker)
+ finally:
+ sys.path.pop(0)
+
+ if self.config.output_format == "vcg":
+ writer.VCGWriter(self.config).write(diadefs)
+ else:
+ writer.DotWriter(self.config).write(diadefs)
+ return 0
+
+
+if __name__ == "__main__":
+ Run(sys.argv[1:])
diff --git a/venv/Lib/site-packages/pylint/pyreverse/utils.py b/venv/Lib/site-packages/pylint/pyreverse/utils.py
new file mode 100644
index 0000000..5a1e7e2
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/utils.py
@@ -0,0 +1,220 @@
+# Copyright (c) 2006, 2008, 2010, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
+# Copyright (c) 2014 Brett Cannon <brett@python.org>
+# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
+# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
+# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
+# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""
+generic classes/functions for pyreverse core/extensions
+"""
+import os
+import re
+import sys
+
+########### pyreverse option utils ##############################
+
+
+RCFILE = ".pyreverserc"
+
+
+def get_default_options():
+ """
+ Read config file and return list of options
+ """
+ options = []
+ home = os.environ.get("HOME", "")
+ if home:
+ rcfile = os.path.join(home, RCFILE)
+ try:
+ options = open(rcfile).read().split()
+ except IOError:
+ pass # ignore if no config file found
+ return options
+
+
+def insert_default_options():
+ """insert default options to sys.argv
+ """
+ options = get_default_options()
+ options.reverse()
+ for arg in options:
+ sys.argv.insert(1, arg)
+
+
+# astroid utilities ###########################################################
+
+SPECIAL = re.compile("^__[A-Za-z0-9]+[A-Za-z0-9_]*__$")
+PRIVATE = re.compile("^__[_A-Za-z0-9]*[A-Za-z0-9]+_?$")
+PROTECTED = re.compile("^_[_A-Za-z0-9]*$")
+
+
+def get_visibility(name):
+ """return the visibility from a name: public, protected, private or special
+ """
+ if SPECIAL.match(name):
+ visibility = "special"
+ elif PRIVATE.match(name):
+ visibility = "private"
+ elif PROTECTED.match(name):
+ visibility = "protected"
+
+ else:
+ visibility = "public"
+ return visibility
+
+
+ABSTRACT = re.compile("^.*Abstract.*")
+FINAL = re.compile("^[A-Z_]*$")
+
+
+def is_abstract(node):
+ """return true if the given class node correspond to an abstract class
+ definition
+ """
+ return ABSTRACT.match(node.name)
+
+
+def is_final(node):
+ """return true if the given class/function node correspond to final
+ definition
+ """
+ return FINAL.match(node.name)
+
+
+def is_interface(node):
+ # bw compat
+ return node.type == "interface"
+
+
+def is_exception(node):
+ # bw compat
+ return node.type == "exception"
+
+
+# Helpers #####################################################################
+
+_CONSTRUCTOR = 1
+_SPECIAL = 2
+_PROTECTED = 4
+_PRIVATE = 8
+MODES = {
+ "ALL": 0,
+ "PUB_ONLY": _SPECIAL + _PROTECTED + _PRIVATE,
+ "SPECIAL": _SPECIAL,
+ "OTHER": _PROTECTED + _PRIVATE,
+}
+VIS_MOD = {
+ "special": _SPECIAL,
+ "protected": _PROTECTED,
+ "private": _PRIVATE,
+ "public": 0,
+}
+
+
+class FilterMixIn:
+ """filter nodes according to a mode and nodes' visibility
+ """
+
+ def __init__(self, mode):
+ "init filter modes"
+ __mode = 0
+ for nummod in mode.split("+"):
+ try:
+ __mode += MODES[nummod]
+ except KeyError as ex:
+ print("Unknown filter mode %s" % ex, file=sys.stderr)
+ self.__mode = __mode
+
+ def show_attr(self, node):
+ """return true if the node should be treated
+ """
+ visibility = get_visibility(getattr(node, "name", node))
+ return not self.__mode & VIS_MOD[visibility]
+
+
+class ASTWalker:
+ """a walker visiting a tree in preorder, calling on the handler:
+
+ * visit_<class name> on entering a node, where class name is the class of
+ the node in lower case
+
+ * leave_<class name> on leaving a node, where class name is the class of
+ the node in lower case
+ """
+
+ def __init__(self, handler):
+ self.handler = handler
+ self._cache = {}
+
+ def walk(self, node, _done=None):
+ """walk on the tree from <node>, getting callbacks from handler"""
+ if _done is None:
+ _done = set()
+ if node in _done:
+ raise AssertionError((id(node), node, node.parent))
+ _done.add(node)
+ self.visit(node)
+ for child_node in node.get_children():
+ assert child_node is not node
+ self.walk(child_node, _done)
+ self.leave(node)
+ assert node.parent is not node
+
+ def get_callbacks(self, node):
+ """get callbacks from handler for the visited node"""
+ klass = node.__class__
+ methods = self._cache.get(klass)
+ if methods is None:
+ handler = self.handler
+ kid = klass.__name__.lower()
+ e_method = getattr(
+ handler, "visit_%s" % kid, getattr(handler, "visit_default", None)
+ )
+ l_method = getattr(
+ handler, "leave_%s" % kid, getattr(handler, "leave_default", None)
+ )
+ self._cache[klass] = (e_method, l_method)
+ else:
+ e_method, l_method = methods
+ return e_method, l_method
+
+ def visit(self, node):
+ """walk on the tree from <node>, getting callbacks from handler"""
+ method = self.get_callbacks(node)[0]
+ if method is not None:
+ method(node)
+
+ def leave(self, node):
+ """walk on the tree from <node>, getting callbacks from handler"""
+ method = self.get_callbacks(node)[1]
+ if method is not None:
+ method(node)
+
+
+class LocalsVisitor(ASTWalker):
+ """visit a project by traversing the locals dictionary"""
+
+ def __init__(self):
+ ASTWalker.__init__(self, self)
+ self._visited = set()
+
+ def visit(self, node):
+ """launch the visit starting from the given node"""
+ if node in self._visited:
+ return None
+
+ self._visited.add(node)
+ methods = self.get_callbacks(node)
+ if methods[0] is not None:
+ methods[0](node)
+ if hasattr(node, "locals"): # skip Instance and other proxy
+ for local_node in node.values():
+ self.visit(local_node)
+ if methods[1] is not None:
+ return methods[1](node)
+ return None
diff --git a/venv/Lib/site-packages/pylint/pyreverse/vcgutils.py b/venv/Lib/site-packages/pylint/pyreverse/vcgutils.py
new file mode 100644
index 0000000..89c6911
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/vcgutils.py
@@ -0,0 +1,229 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
+# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""Functions to generate files readable with Georg Sander's vcg
+(Visualization of Compiler Graphs).
+
+You can download vcg at http://rw4.cs.uni-sb.de/~sander/html/gshome.html
+Note that vcg exists as a debian package.
+
+See vcg's documentation for explanation about the different values that
+maybe used for the functions parameters.
+"""
+
+ATTRS_VAL = {
+ "algos": (
+ "dfs",
+ "tree",
+ "minbackward",
+ "left_to_right",
+ "right_to_left",
+ "top_to_bottom",
+ "bottom_to_top",
+ "maxdepth",
+ "maxdepthslow",
+ "mindepth",
+ "mindepthslow",
+ "mindegree",
+ "minindegree",
+ "minoutdegree",
+ "maxdegree",
+ "maxindegree",
+ "maxoutdegree",
+ ),
+ "booleans": ("yes", "no"),
+ "colors": (
+ "black",
+ "white",
+ "blue",
+ "red",
+ "green",
+ "yellow",
+ "magenta",
+ "lightgrey",
+ "cyan",
+ "darkgrey",
+ "darkblue",
+ "darkred",
+ "darkgreen",
+ "darkyellow",
+ "darkmagenta",
+ "darkcyan",
+ "gold",
+ "lightblue",
+ "lightred",
+ "lightgreen",
+ "lightyellow",
+ "lightmagenta",
+ "lightcyan",
+ "lilac",
+ "turquoise",
+ "aquamarine",
+ "khaki",
+ "purple",
+ "yellowgreen",
+ "pink",
+ "orange",
+ "orchid",
+ ),
+ "shapes": ("box", "ellipse", "rhomb", "triangle"),
+ "textmodes": ("center", "left_justify", "right_justify"),
+ "arrowstyles": ("solid", "line", "none"),
+ "linestyles": ("continuous", "dashed", "dotted", "invisible"),
+}
+
+# meaning of possible values:
+# O -> string
+# 1 -> int
+# list -> value in list
+GRAPH_ATTRS = {
+ "title": 0,
+ "label": 0,
+ "color": ATTRS_VAL["colors"],
+ "textcolor": ATTRS_VAL["colors"],
+ "bordercolor": ATTRS_VAL["colors"],
+ "width": 1,
+ "height": 1,
+ "borderwidth": 1,
+ "textmode": ATTRS_VAL["textmodes"],
+ "shape": ATTRS_VAL["shapes"],
+ "shrink": 1,
+ "stretch": 1,
+ "orientation": ATTRS_VAL["algos"],
+ "vertical_order": 1,
+ "horizontal_order": 1,
+ "xspace": 1,
+ "yspace": 1,
+ "layoutalgorithm": ATTRS_VAL["algos"],
+ "late_edge_labels": ATTRS_VAL["booleans"],
+ "display_edge_labels": ATTRS_VAL["booleans"],
+ "dirty_edge_labels": ATTRS_VAL["booleans"],
+ "finetuning": ATTRS_VAL["booleans"],
+ "manhattan_edges": ATTRS_VAL["booleans"],
+ "smanhattan_edges": ATTRS_VAL["booleans"],
+ "port_sharing": ATTRS_VAL["booleans"],
+ "edges": ATTRS_VAL["booleans"],
+ "nodes": ATTRS_VAL["booleans"],
+ "splines": ATTRS_VAL["booleans"],
+}
+NODE_ATTRS = {
+ "title": 0,
+ "label": 0,
+ "color": ATTRS_VAL["colors"],
+ "textcolor": ATTRS_VAL["colors"],
+ "bordercolor": ATTRS_VAL["colors"],
+ "width": 1,
+ "height": 1,
+ "borderwidth": 1,
+ "textmode": ATTRS_VAL["textmodes"],
+ "shape": ATTRS_VAL["shapes"],
+ "shrink": 1,
+ "stretch": 1,
+ "vertical_order": 1,
+ "horizontal_order": 1,
+}
+EDGE_ATTRS = {
+ "sourcename": 0,
+ "targetname": 0,
+ "label": 0,
+ "linestyle": ATTRS_VAL["linestyles"],
+ "class": 1,
+ "thickness": 0,
+ "color": ATTRS_VAL["colors"],
+ "textcolor": ATTRS_VAL["colors"],
+ "arrowcolor": ATTRS_VAL["colors"],
+ "backarrowcolor": ATTRS_VAL["colors"],
+ "arrowsize": 1,
+ "backarrowsize": 1,
+ "arrowstyle": ATTRS_VAL["arrowstyles"],
+ "backarrowstyle": ATTRS_VAL["arrowstyles"],
+ "textmode": ATTRS_VAL["textmodes"],
+ "priority": 1,
+ "anchor": 1,
+ "horizontal_order": 1,
+}
+
+
+# Misc utilities ###############################################################
+
+
+class VCGPrinter:
+ """A vcg graph writer.
+ """
+
+ def __init__(self, output_stream):
+ self._stream = output_stream
+ self._indent = ""
+
+ def open_graph(self, **args):
+ """open a vcg graph
+ """
+ self._stream.write("%sgraph:{\n" % self._indent)
+ self._inc_indent()
+ self._write_attributes(GRAPH_ATTRS, **args)
+
+ def close_graph(self):
+ """close a vcg graph
+ """
+ self._dec_indent()
+ self._stream.write("%s}\n" % self._indent)
+
+ def node(self, title, **args):
+ """draw a node
+ """
+ self._stream.write('%snode: {title:"%s"' % (self._indent, title))
+ self._write_attributes(NODE_ATTRS, **args)
+ self._stream.write("}\n")
+
+ def edge(self, from_node, to_node, edge_type="", **args):
+ """draw an edge from a node to another.
+ """
+ self._stream.write(
+ '%s%sedge: {sourcename:"%s" targetname:"%s"'
+ % (self._indent, edge_type, from_node, to_node)
+ )
+ self._write_attributes(EDGE_ATTRS, **args)
+ self._stream.write("}\n")
+
+ # private ##################################################################
+
+ def _write_attributes(self, attributes_dict, **args):
+ """write graph, node or edge attributes
+ """
+ for key, value in args.items():
+ try:
+ _type = attributes_dict[key]
+ except KeyError:
+ raise Exception(
+ """no such attribute %s
+possible attributes are %s"""
+ % (key, attributes_dict.keys())
+ )
+
+ if not _type:
+ self._stream.write('%s%s:"%s"\n' % (self._indent, key, value))
+ elif _type == 1:
+ self._stream.write("%s%s:%s\n" % (self._indent, key, int(value)))
+ elif value in _type:
+ self._stream.write("%s%s:%s\n" % (self._indent, key, value))
+ else:
+ raise Exception(
+ """value %s isn\'t correct for attribute %s
+correct values are %s"""
+ % (value, key, _type)
+ )
+
+ def _inc_indent(self):
+ """increment indentation
+ """
+ self._indent = " %s" % self._indent
+
+ def _dec_indent(self):
+ """decrement indentation
+ """
+ self._indent = self._indent[:-2]
diff --git a/venv/Lib/site-packages/pylint/pyreverse/writer.py b/venv/Lib/site-packages/pylint/pyreverse/writer.py
new file mode 100644
index 0000000..609b1ef
--- /dev/null
+++ b/venv/Lib/site-packages/pylint/pyreverse/writer.py
@@ -0,0 +1,213 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2008-2010, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
+# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
+# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2015 Mike Frysinger <vapier@gentoo.org>
+# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
+# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
+# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
+# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+"""Utilities for creating VCG and Dot diagrams"""
+
+from pylint.graph import DotBackend
+from pylint.pyreverse.utils import is_exception
+from pylint.pyreverse.vcgutils import VCGPrinter
+
+
+class DiagramWriter:
+ """base class for writing project diagrams
+ """
+
+ def __init__(self, config, styles):
+ self.config = config
+ self.pkg_edges, self.inh_edges, self.imp_edges, self.association_edges = styles
+ self.printer = None # defined in set_printer
+
+ def write(self, diadefs):
+ """write files for <project> according to <diadefs>
+ """
+ for diagram in diadefs:
+ basename = diagram.title.strip().replace(" ", "_")
+ file_name = "%s.%s" % (basename, self.config.output_format)
+ self.set_printer(file_name, basename)
+ if diagram.TYPE == "class":
+ self.write_classes(diagram)
+ else:
+ self.write_packages(diagram)
+ self.close_graph()
+
+ def write_packages(self, diagram):
+ """write a package diagram"""
+ # sorted to get predictable (hence testable) results
+ for i, obj in enumerate(sorted(diagram.modules(), key=lambda x: x.title)):
+ self.printer.emit_node(i, label=self.get_title(obj), shape="box")
+ obj.fig_id = i
+ # package dependencies
+ for rel in diagram.get_relationships("depends"):
+ self.printer.emit_edge(
+ rel.from_object.fig_id, rel.to_object.fig_id, **self.pkg_edges
+ )
+
+ def write_classes(self, diagram):
+ """write a class diagram"""
+ # sorted to get predictable (hence testable) results
+ for i, obj in enumerate(sorted(diagram.objects, key=lambda x: x.title)):
+ self.printer.emit_node(i, **self.get_values(obj))
+ obj.fig_id = i
+ # inheritance links
+ for rel in diagram.get_relationships("specialization"):
+ self.printer.emit_edge(
+ rel.from_object.fig_id, rel.to_object.fig_id, **self.inh_edges
+ )
+ # implementation links
+ for rel in diagram.get_relationships("implements"):
+ self.printer.emit_edge(
+ rel.from_object.fig_id, rel.to_object.fig_id, **self.imp_edges
+ )
+ # generate associations
+ for rel in diagram.get_relationships("association"):
+ self.printer.emit_edge(
+ rel.from_object.fig_id,
+ rel.to_object.fig_id,
+ label=rel.name,
+ **self.association_edges
+ )
+
+ def set_printer(self, file_name, basename):
+ """set printer"""
+ raise NotImplementedError
+
+ def get_title(self, obj):
+ """get project title"""
+ raise NotImplementedError
+
+ def get_values(self, obj):
+ """get label and shape for classes."""
+ raise NotImplementedError
+
+ def close_graph(self):
+ """finalize the graph"""
+ raise NotImplementedError
+
+
+class DotWriter(DiagramWriter):
+ """write dot graphs from a diagram definition and a project
+ """
+
+ def __init__(self, config):
+ styles = [
+ dict(arrowtail="none", arrowhead="open"),
+ dict(arrowtail="none", arrowhead="empty"),
+ dict(arrowtail="node", arrowhead="empty", style="dashed"),
+ dict(
+ fontcolor="green", arrowtail="none", arrowhead="diamond", style="solid"
+ ),
+ ]
+ DiagramWriter.__init__(self, config, styles)
+
+ def set_printer(self, file_name, basename):
+ """initialize DotWriter and add options for layout.
+ """
+ layout = dict(rankdir="BT")
+ self.printer = DotBackend(basename, additional_param=layout)
+ self.file_name = file_name
+
+ def get_title(self, obj):
+ """get project title"""
+ return obj.title
+
+ def get_values(self, obj):
+ """get label and shape for classes.
+
+ The label contains all attributes and methods
+ """
+ label = obj.title
+ if obj.shape == "interface":
+ label = "«interface»\\n%s" % label
+ if not self.config.only_classnames:
+ label = r"%s|%s\l|" % (label, r"\l".join(obj.attrs))
+ for func in obj.methods:
+ args = [arg.name for arg in func.args.args if arg.name != "self"]
+ label = r"%s%s(%s)\l" % (label, func.name, ", ".join(args))
+ label = "{%s}" % label
+ if is_exception(obj.node):
+ return dict(fontcolor="red", label=label, shape="record")
+ return dict(label=label, shape="record")
+
+ def close_graph(self):
+ """print the dot graph into <file_name>"""
+ self.printer.generate(self.file_name)
+
+
+class VCGWriter(DiagramWriter):
+ """write vcg graphs from a diagram definition and a project
+ """
+
+ def __init__(self, config):
+ styles = [
+ dict(arrowstyle="solid", backarrowstyle="none", backarrowsize=0),
+ dict(arrowstyle="solid", backarrowstyle="none", backarrowsize=10),
+ dict(
+ arrowstyle="solid",
+ backarrowstyle="none",
+ linestyle="dotted",
+ backarrowsize=10,
+ ),
+ dict(arrowstyle="solid", backarrowstyle="none", textcolor="green"),
+ ]
+ DiagramWriter.__init__(self, config, styles)
+
+ def set_printer(self, file_name, basename):
+ """initialize VCGWriter for a UML graph"""
+ self.graph_file = open(file_name, "w+")
+ self.printer = VCGPrinter(self.graph_file)
+ self.printer.open_graph(
+ title=basename,
+ layoutalgorithm="dfs",
+ late_edge_labels="yes",
+ port_sharing="no",
+ manhattan_edges="yes",
+ )
+ self.printer.emit_node = self.printer.node
+ self.printer.emit_edge = self.printer.edge
+
+ def get_title(self, obj):
+ """get project title in vcg format"""
+ return r"\fb%s\fn" % obj.title
+
+ def get_values(self, obj):
+ """get label and shape for classes.
+
+ The label contains all attributes and methods
+ """
+ if is_exception(obj.node):
+ label = r"\fb\f09%s\fn" % obj.title
+ else:
+ label = r"\fb%s\fn" % obj.title
+ if obj.shape == "interface":
+ shape = "ellipse"
+ else:
+ shape = "box"
+ if not self.config.only_classnames:
+ attrs = obj.attrs
+ methods = [func.name for func in obj.methods]
+ # box width for UML like diagram
+ maxlen = max(len(name) for name in [obj.title] + methods + attrs)
+ line = "_" * (maxlen + 2)
+ label = r"%s\n\f%s" % (label, line)
+ for attr in attrs:
+ label = r"%s\n\f08%s" % (label, attr)
+ if attrs:
+ label = r"%s\n\f%s" % (label, line)
+ for func in methods:
+ label = r"%s\n\f10%s()" % (label, func)
+ return dict(label=label, shape=shape)
+
+ def close_graph(self):
+ """close graph and file"""
+ self.printer.close_graph()
+ self.graph_file.close()