Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

writer.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2008-2010, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
  3. # Copyright (c) 2014 Arun Persaud <arun@nubati.net>
  4. # Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
  5. # Copyright (c) 2015 Mike Frysinger <vapier@gentoo.org>
  6. # Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
  7. # Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
  8. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  9. # For details: https://github.com/PyCQA/pylint/blob/master/COPYING
  10. """Utilities for creating VCG and Dot diagrams"""
  11. from pylint.pyreverse.utils import is_exception
  12. from pylint.pyreverse.vcgutils import VCGPrinter
  13. from pylint.graph import DotBackend
  14. class DiagramWriter(object):
  15. """base class for writing project diagrams
  16. """
  17. def __init__(self, config, styles):
  18. self.config = config
  19. self.pkg_edges, self.inh_edges, self.imp_edges, self.ass_edges = styles
  20. self.printer = None # defined in set_printer
  21. def write(self, diadefs):
  22. """write files for <project> according to <diadefs>
  23. """
  24. for diagram in diadefs:
  25. basename = diagram.title.strip().replace(' ', '_')
  26. file_name = '%s.%s' % (basename, self.config.output_format)
  27. self.set_printer(file_name, basename)
  28. if diagram.TYPE == 'class':
  29. self.write_classes(diagram)
  30. else:
  31. self.write_packages(diagram)
  32. self.close_graph()
  33. def write_packages(self, diagram):
  34. """write a package diagram"""
  35. # sorted to get predictable (hence testable) results
  36. for i, obj in enumerate(sorted(diagram.modules(), key=lambda x: x.title)):
  37. self.printer.emit_node(i, label=self.get_title(obj), shape='box')
  38. obj.fig_id = i
  39. # package dependencies
  40. for rel in diagram.get_relationships('depends'):
  41. self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
  42. **self.pkg_edges)
  43. def write_classes(self, diagram):
  44. """write a class diagram"""
  45. # sorted to get predictable (hence testable) results
  46. for i, obj in enumerate(sorted(diagram.objects, key=lambda x: x.title)):
  47. self.printer.emit_node(i, **self.get_values(obj))
  48. obj.fig_id = i
  49. # inheritance links
  50. for rel in diagram.get_relationships('specialization'):
  51. self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
  52. **self.inh_edges)
  53. # implementation links
  54. for rel in diagram.get_relationships('implements'):
  55. self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
  56. **self.imp_edges)
  57. # generate associations
  58. for rel in diagram.get_relationships('association'):
  59. self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
  60. label=rel.name, **self.ass_edges)
  61. def set_printer(self, file_name, basename):
  62. """set printer"""
  63. raise NotImplementedError
  64. def get_title(self, obj):
  65. """get project title"""
  66. raise NotImplementedError
  67. def get_values(self, obj):
  68. """get label and shape for classes."""
  69. raise NotImplementedError
  70. def close_graph(self):
  71. """finalize the graph"""
  72. raise NotImplementedError
  73. class DotWriter(DiagramWriter):
  74. """write dot graphs from a diagram definition and a project
  75. """
  76. def __init__(self, config):
  77. styles = [dict(arrowtail='none', arrowhead="open"),
  78. dict(arrowtail='none', arrowhead='empty'),
  79. dict(arrowtail='node', arrowhead='empty', style='dashed'),
  80. dict(fontcolor='green', arrowtail='none',
  81. arrowhead='diamond', style='solid'),
  82. ]
  83. DiagramWriter.__init__(self, config, styles)
  84. def set_printer(self, file_name, basename):
  85. """initialize DotWriter and add options for layout.
  86. """
  87. layout = dict(rankdir="BT")
  88. self.printer = DotBackend(basename, additional_param=layout)
  89. self.file_name = file_name
  90. def get_title(self, obj):
  91. """get project title"""
  92. return obj.title
  93. def get_values(self, obj):
  94. """get label and shape for classes.
  95. The label contains all attributes and methods
  96. """
  97. label = obj.title
  98. if obj.shape == 'interface':
  99. label = u'«interface»\\n%s' % label
  100. if not self.config.only_classnames:
  101. label = r'%s|%s\l|' % (label, r'\l'.join(obj.attrs))
  102. for func in obj.methods:
  103. label = r'%s%s()\l' % (label, func.name)
  104. label = '{%s}' % label
  105. if is_exception(obj.node):
  106. return dict(fontcolor='red', label=label, shape='record')
  107. return dict(label=label, shape='record')
  108. def close_graph(self):
  109. """print the dot graph into <file_name>"""
  110. self.printer.generate(self.file_name)
  111. class VCGWriter(DiagramWriter):
  112. """write vcg graphs from a diagram definition and a project
  113. """
  114. def __init__(self, config):
  115. styles = [dict(arrowstyle='solid', backarrowstyle='none',
  116. backarrowsize=0),
  117. dict(arrowstyle='solid', backarrowstyle='none',
  118. backarrowsize=10),
  119. dict(arrowstyle='solid', backarrowstyle='none',
  120. linestyle='dotted', backarrowsize=10),
  121. dict(arrowstyle='solid', backarrowstyle='none',
  122. textcolor='green'),
  123. ]
  124. DiagramWriter.__init__(self, config, styles)
  125. def set_printer(self, file_name, basename):
  126. """initialize VCGWriter for a UML graph"""
  127. self.graph_file = open(file_name, 'w+')
  128. self.printer = VCGPrinter(self.graph_file)
  129. self.printer.open_graph(title=basename, layoutalgorithm='dfs',
  130. late_edge_labels='yes', port_sharing='no',
  131. manhattan_edges='yes')
  132. self.printer.emit_node = self.printer.node
  133. self.printer.emit_edge = self.printer.edge
  134. def get_title(self, obj):
  135. """get project title in vcg format"""
  136. return r'\fb%s\fn' % obj.title
  137. def get_values(self, obj):
  138. """get label and shape for classes.
  139. The label contains all attributes and methods
  140. """
  141. if is_exception(obj.node):
  142. label = r'\fb\f09%s\fn' % obj.title
  143. else:
  144. label = r'\fb%s\fn' % obj.title
  145. if obj.shape == 'interface':
  146. shape = 'ellipse'
  147. else:
  148. shape = 'box'
  149. if not self.config.only_classnames:
  150. attrs = obj.attrs
  151. methods = [func.name for func in obj.methods]
  152. # box width for UML like diagram
  153. maxlen = max(len(name) for name in [obj.title] + methods + attrs)
  154. line = '_' * (maxlen + 2)
  155. label = r'%s\n\f%s' % (label, line)
  156. for attr in attrs:
  157. label = r'%s\n\f08%s' % (label, attr)
  158. if attrs:
  159. label = r'%s\n\f%s' % (label, line)
  160. for func in methods:
  161. label = r'%s\n\f10%s()' % (label, func)
  162. return dict(label=label, shape=shape)
  163. def close_graph(self):
  164. """close graph and file"""
  165. self.printer.close_graph()
  166. self.graph_file.close()