diff --git a/gaphor/plugins/diagramlayout/__init__.py b/gaphor/plugins/diagramlayout/__init__.py deleted file mode 100644 index 3b879e493..000000000 --- a/gaphor/plugins/diagramlayout/__init__.py +++ /dev/null @@ -1,244 +0,0 @@ -""" -This module provides a means to automatically layout diagrams. - -The layout is done like this: - - First all nodes (Classes, packages, comments) on a diagram are determined - - A vertical ordering is determined based on the inheritance - - A horizontal ordering is determined based on associations and dependencies - - The nodes are moved to their place - - Lines are reconnected to the nodes, so everything looks pretty. - -""" - -import logging -import random - -from gaphor.core import action, transactional -from gaphor.diagram.presentation import LinePresentation -from gaphor.diagram.classes import GeneralizationItem, ImplementationItem -from gaphor.abc import Service, ActionProvider -from gaphor.plugins.diagramlayout import toposort -from gaphor.ui.abc import UIComponent - -log = logging.getLogger(__name__) - - -class DiagramLayout(Service, ActionProvider): - def __init__(self, component_registry): - self.component_registry = component_registry - - def shutdown(self): - pass - - def get_current_diagram(self): - return self.component_registry.get( - UIComponent, "diagrams" - ).get_current_diagram() - - def update(self): - self.sensitive = bool(self.get_current_diagram()) - - @action( - name="diagram-layout", label="La_yout diagram", tooltip="simple diagram layout" - ) - def execute(self): - d = self.get_current_diagram() - self.layout_diagram(d) - - @transactional - def layout_diagram(self, diag): - layout_diagram(diag) - - -MARGIN = 100 - - -def layout_diagram(diag): - """ - So an attempt to layout (order) the items on a diagram. The items - should already be placed on the diagram and the items should already be - connected. - - This function works on the diagram items (hence it does not check relations - in the datamodel, only the ones drawn on the diagram) to produce a - decent layout. - """ - nodes = [] - primary_nodes = [] - relations = [] - other_relations = [] - - # Make sure all items are updated - diag.canvas.update_now() - - # First extract data from the diagram (which ones are the nodes, and - # the relationships). - for item in diag.canvas.get_root_items(): - if isinstance(item, (GeneralizationItem, ImplementationItem)): - # Primary relationships, should be drawn top-down - try: - relations.append( - (item.handles[0].connected_to, item.handles[-1].connected_to) - ) - primary_nodes.extend(relations[-1]) - except Exception as e: - log.error(e) - elif isinstance(item, LinePresentation): - # Secondary (associations, dependencies) may be drawn top-down - # or left-right - try: - other_relations.append( - (item.handles[0].connected_to, item.handles[-1].connected_to) - ) - # other_relations.append((item.handles[-1].connected_to, - # item.handles[0].connected_to)) - except Exception as e: - log.error(e) - else: - nodes.append(item) - - # Add some randomness: - random.shuffle(other_relations) - primary_nodes = uniq(primary_nodes) - - # Find out our horizontal and vertical sorting - sorted = toposort.toposort(nodes, relations, 0) - other_sorted = toposort.toposort(nodes, other_relations, 0) - - if not sorted: - return - - # Move nodes from the first (generalization) row to the other rows - # if they are not superclasses for some other class - # Run the list twice, just to ensure no items are left behind. - for item in list(sorted[0]) * 2: - if item not in primary_nodes and item in sorted[0]: - # Find nodes that do have a relation to this one - related = find_related_nodes(item, other_relations) - # Figure out what row(s) they're on - row = find_row(item, related, sorted[1:]) - if row: - # print 'moving', item.subject.name, 'to row', sorted.index(row) - sorted[0].remove(item) - row.append(item) - - # Order each row based on the sort order of other_sorted - # (the secondary sort alg.). - for row in sorted: - for other_row in other_sorted: - for other_item in other_row: - if other_item in row: - row.remove(other_item) - row.append(other_item) - - # Place the nodes on the diagram. - y = MARGIN / 2 - for row in sorted: - x = MARGIN / 2 - maxy = 0 - for item in row: - if not item: - continue - maxy = max(maxy, item.height) - a = item.matrix - a = (a[0], a[1], a[2], a[3], x, y) - item.matrix = a - item.request_update() - x += item.width + MARGIN - y += maxy + MARGIN - - # Reattach the relationships to the nodes, in a way that it looks nice. - simple_layout_lines(diag) - - -def simple_layout_lines(diag): - """ - Just do the layout of the lines in a diagram. The nodes (class, package) - are left where they are (use layout_diagram() if you want to reorder - everything). - - The line layout is basically very simple: just draw straight lines - between nodes on the diagram. - """ - lines = {} - for item in diag.canvas.get_root_items(): - if isinstance(item, LinePresentation): - # Secondary (associations, dependencies) may be drawn top-down - # or left-right - try: - lines[item] = ( - item.handles[0].connected_to, - item.handles[-1].connected_to, - ) - except Exception as e: - log.error(e) - - # Now we have the lines, let's first ensure we only have a begin and an - # end handle - for line in list(lines.keys()): - while len(line.handles) > 2: - line.set_property("del_segment", 0) - - # Strategy 1: - # Now we have nice short lines. Let's move them to a point between - # both nodes and let the connect() do the work: - for line, nodes in list(lines.items()): - if not nodes[0] or not nodes[1]: - # loose end - continue - center0 = find_center(nodes[0]) - center1 = find_center(nodes[1]) - center = ((center0[0] + center1[0]) / 2.0, (center0[1] + center1[1]) / 2.0) - line.handles[0].set_pos_w(*center) - line.handles[-1].set_pos_w(*center) - nodes[0].connect_handle(line.handles[0]) - nodes[1].connect_handle(line.handles[-1]) - - -def uniq(lst): - d = {} - for l in lst: - d[l] = None - return list(d.keys()) - - -def find_related_nodes(item, relations): - """ - Find related nodes of item, given a list of tuples. - References to itself are ignored. - """ - related = [] - for pair in relations: - if pair[0] is item: - if pair[1] is not item: - related.append(pair[1]) - elif pair[1] is item: - if pair[0] is not item: - related.append(pair[0]) - return uniq(related) - - -def find_row(item, related_items, sorted): - """ - Find the row that contains the most references to item. - """ - max_refs = 0 - max_row = None - for row in sorted: - cnt = len([i for i in row if i in related_items]) - if cnt > max_refs: - max_row = row - max_refs = cnt - return max_row - - -def find_center(item): - """ - Find the center point of the item, in world coordinates - """ - x = item.width / 2.0 - y = item.height / 2.0 - return item.canvas.get_matrix_i2c(item).transform_point(x, y) - - -# vim:sw=4:et diff --git a/gaphor/plugins/diagramlayout/tests/__init__.py b/gaphor/plugins/diagramlayout/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/gaphor/plugins/diagramlayout/tests/test_diagramlayout.py b/gaphor/plugins/diagramlayout/tests/test_diagramlayout.py deleted file mode 100644 index 36bc2b9b8..000000000 --- a/gaphor/plugins/diagramlayout/tests/test_diagramlayout.py +++ /dev/null @@ -1,29 +0,0 @@ -from gaphor import UML -from gaphor.application import Application -from gaphor.diagram.classes import ClassItem -from gaphor.tests.testcase import TestCase - - -class DiagramLayoutTestCase(TestCase): - - services = TestCase.services + [ - "main_window", - "properties", - "diagram_layout", - "import_menu", - "export_menu", - "tools_menu", - ] - - def testDiagramLayout(self): - elemfact = Application.get_service("element_factory") - diagram_layout = Application.get_service("diagram_layout") - - diagram = elemfact.create(UML.Diagram) - c1 = diagram.create(ClassItem, subject=elemfact.create(UML.Class)) - c2 = diagram.create(ClassItem, subject=elemfact.create(UML.Class)) - - c2.matrix.translate(100, 100) - c2.request_update() - - diagram_layout.layout_diagram(diagram) diff --git a/gaphor/plugins/diagramlayout/toposort.py b/gaphor/plugins/diagramlayout/toposort.py deleted file mode 100644 index 204a9a48c..000000000 --- a/gaphor/plugins/diagramlayout/toposort.py +++ /dev/null @@ -1,210 +0,0 @@ -class RecursionError(OverflowError, ValueError): - """Unable to calculate result because of recursive structure""" - - -def sort(nodes, routes, noRecursion=1): - """Passed a list of node IDs and a list of source,dest ID routes - attempt to create a list of stages where each sub list - is one stage in a process. - """ - children, parents = _buildChildrenLists(routes) - # first stage is those nodes - # having no incoming routes... - stage = [] - stages = [stage] - taken = [] - for node in nodes: - if not parents.get(node): - stage.append(node) - if nodes and not stage: - # there is no element which does not depend on - # some other element!!! - stage.append(nodes[0]) - taken.extend(stage) - nodes = list(filter(lambda x, l=stage: x not in l, nodes)) - while nodes: - previousStageChildren = [] - nodelen = len(nodes) - # second stage are those nodes - # which are direct children of the first stage - for node in stage: - for child in children.get(node, []): - if child not in previousStageChildren and child not in taken: - previousStageChildren.append(child) - elif child in taken and noRecursion: - raise RecursionError((child, node)) - # unless they are children of other direct children... - # TODO, actually do that... - stage = previousStageChildren - removes = [] - for current in stage: - currentParents = parents.get(current, []) - for parent in currentParents: - if parent in stage and parent != current: - # might wind up removing current... - if not current in parents.get(parent, []): - # is not mutually dependent... - removes.append(current) - for remove in removes: - while remove in stage: - stage.remove(remove) - stages.append(stage) - taken.extend(stage) - nodes = list(filter(lambda x, l=stage: x not in l, nodes)) - if nodelen == len(nodes): - if noRecursion: - raise RecursionError(nodes) - else: - stages.append(nodes[:]) - nodes = [] - return stages - - -def _buildChildrenLists(routes): - childrenTable = {} - parentTable = {} - for sourceID, destinationID in routes: - currentChildren = childrenTable.get(sourceID, []) - currentParents = parentTable.get(destinationID, []) - if not destinationID in currentChildren: - currentChildren.append(destinationID) - if not sourceID in currentParents: - currentParents.append(sourceID) - childrenTable[sourceID] = currentChildren - parentTable[destinationID] = currentParents - return childrenTable, parentTable - - -def toposort(nodes, routes, noRecursion=1): - """Topological sort from Tim Peters, fairly efficient - in comparison (it seems).""" - # first calculate the recursion depth - - dependencies = {} - inversedependencies = {} - if not nodes: - return [] - if not routes: - return [nodes] - for node in nodes: - dependencies[node] = (0, node) - inversedependencies[node] = [] - - for depended, depends in routes: - # is it a null rule - try: - newdependencylevel, object = dependencies.get(depends, (0, depends)) - except TypeError: - print(depends) - raise - dependencies[depends] = (newdependencylevel + 1, depends) - # "dependency (existence) of depended-on" - newdependencylevel, object = dependencies.get(depended, (0, depended)) - dependencies[depended] = (newdependencylevel, depended) - # Inverse dependency set up - dependencieslist = inversedependencies.get(depended, []) - dependencieslist.append(depends) - inversedependencies[depended] = dependencieslist - ### Now we do the actual sorting - # The first task is to create the sortable - # list of dependency-levels - sortinglist = sorted(dependencies.values()) - output = [] - while sortinglist: - deletelist = [] - generation = [] - output.append(generation) - while sortinglist and sortinglist[0][0] == 0: - number, object = sortinglist[0] - generation.append(object) - deletelist.append(object) - for inverse in inversedependencies.get(object, ()): - try: - oldcount, inverse = dependencies[inverse] - if oldcount > 0: - # will be dealt with on later pass - dependencies[inverse] = (oldcount - 1, inverse) - else: - # will be dealt with on this pass, - # so needs not to be in the sorting list next time - deletelist.append(inverse) - # just in case a loop comes through - inversedependencies[object] = [] - except KeyError: - # dealing with a recursion-breaking run... - pass - del sortinglist[0] - # if no elements could be deleted, then - # there is something which depends upon itself - if not deletelist: - if noRecursion: - raise RecursionError(sortinglist) - else: - # hack so that something gets deleted... - ## import pdb - ## pdb.set_trace() - dependencies[sortinglist[0][1]] = (0, sortinglist[0][1]) - # delete the items that were dealt with - for item in deletelist: - try: - del dependencies[item] - except KeyError: - pass - # need to recreate the sortinglist - sortinglist = list(dependencies.values()) - if not generation: - output.remove(generation) - sortinglist.sort() - return output - - -if __name__ == "__main__": - - pass - - nodes = [0, 1, 2, 3, 4, 5] - testingValues = [ - [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)], - [(0, 1), (0, 2), (1, 2), (3, 4), (4, 5)], - [(0, 1), (0, 2), (0, 2), (2, 4), (2, 5), (3, 2), (0, 3)], - [ - (0, 1), # 3-element cycle test, no orphan nodes - (1, 2), - (2, 0), - (2, 4), - (2, 5), - (3, 2), - (0, 3), - ], - [(0, 1), (1, 1), (1, 1), (1, 4), (1, 5), (1, 2), (3, 1), (2, 1), (2, 0)], - [(0, 1), (1, 0), (0, 2), (0, 3)], - [(0, 1), (1, 0), (0, 2), (3, 1)], - ] - print("sort, no recursion allowed") - for index in range(len(testingValues)): - ## print ' %s -- %s'%( index, testingValues[index]) - try: - print(" ", sort(nodes, testingValues[index])) - except: - print("exception raised") - print("toposort, no recursion allowed") - for index in range(len(testingValues)): - ## print ' %s -- %s'%( index, testingValues[index]) - try: - print(" ", toposort(nodes, testingValues[index])) - except: - print("exception raised") - print("sort, recursion allowed") - for index in range(len(testingValues)): - ## print ' %s -- %s'%( index, testingValues[index]) - try: - print(" ", sort(nodes, testingValues[index], 0)) - except: - print("exception raised") - print("toposort, recursion allowed") - for index in range(len(testingValues)): - ## print ' %s -- %s'%( index, testingValues[index]) - try: - print(" ", toposort(nodes, testingValues[index], 0)) - except: - print("exception raised") diff --git a/gaphor/plugins/pynsource/Readme.txt b/gaphor/plugins/pynsource/Readme.txt deleted file mode 100644 index 55f71df5a..000000000 --- a/gaphor/plugins/pynsource/Readme.txt +++ /dev/null @@ -1,109 +0,0 @@ -PyNSource -http://www.atug.com/andypatterns/pynsource.htm - -(c) 2003, 2004, 2005, 2006 Andy Bulka -License: Free to use as long as acknowledgement is made in source code. -abulka@netspace.net.au -http://www.atug.com/andypatterns - - -Version 1.4c -- Fixed some parsing bugs. -- Parsing now more correct under python 2.4 (python changed token.py !!) -- Unit tests now all pass - - -Version 1.4b -- Added wxpython 2.5 compatibility (thanks Thomas Margraf!) - - -Version 1.4a - -GUI changes: -- Right Click on a node to delete it. -- Run Layout anytime from menu. -- Left click on background will deselect any selected shapes - -Version 1.4 - -- Fixed indentation error causing more output than normal in text ouput -- Module level functions not treated as classes any more -- Smarter detection of composition relationships, as long as classname - and variable name are the same (ignoring case) then PyNSource will detect e.g. - - class Cat: - pass - - class A: - def __init__(self, cat): - self.cats.append(Cat()) # always has worked, composition detected. - self.cats.append(cat) # new 1.4 feature, composition detected here too. - - -Version 1.3a - -A reverse engineering tool for Python source code - - UML diagram models that you can layout, arrange and print out. - - UML text diagrams, which you can paste into your source code for documentation purposes. - - Java or Delphi code (which can be subsequently imported into more sophisticated UML - modeling tools, like Enterprise Architect or ESS-Model (free).) - -Features - - Resilient: doesn't import the python files, thus will never get "stuck" when syntax is wrong.� - - Fast - - Recognises inheritance and composition relationships - - Detects the cardinality of associations e.g. one to one or 1..* etc - - Optionally treat modules as classes - creating a pseudo class for each - module - module variables and functions are treated as attributes and methods of a class - - Has been developed using unit tests (supplied) so that you can trust it just that little bit more ;-) - - -GUI FRONT END -------------- - -The PyNSource Gui is started in two ways: - * By running the standalone pynsourceGui.exe via the shortcut created by the standalone installer. or - * By running pynsourceGui.py ( you need wxpython installed. See http://www.wxpython.org ) - e.g. \Python22\python.exe \Python22\Lib\site-packages\pynsource\pyNsourceGui.py - -The PyNSource command line tool is pynsource.py - -Command line Usage ------------------- - -�pynsource -v -m [-j outdir] sourceDirOrListOfPythonFiles...��� - - no options - generate Ascii UML --j generate java files, specify output folder for java files --d generate pascal files, specify output folder for pascal files --v verbose --m create psuedo class for each module, - module attrs/defs etc treated as class attrs/defs - -Examples - -e.g. - \python22\python.exe \Python22\Lib\site-packages\pynsource\pynsource.py -d c:\delphiouputdir c:\pythoninputdir\*.py - -The above line will scan all the files in c:\pythoninputdir and generate -a bunch of delphi files in the folder c:\delphiouputdir - -BASIC ASCII UML OUTPUT from PYTHON - EXAMPLES -e.g. pynsource Test/testmodule01.py -e.g. pynsource -m Test/testmodule03.py - -GENERATE JAVA FILES from PYTHON - EXAMPLES -e.g. pynsource -j c:/try c:/try -e.g. pynsource -v -m -j c:/try c:/try -e.g. pynsource -v -m -j c:/try c:/try/s*.py -e.g. pynsource -j c:/try c:/try/s*.py Tests/u*.py -e.g. pynsource -v -m -j c:/try c:/try/s*.py Tests/u*.py c:\cc\Devel\Client\w*.py - -GENERATE DELPHI FILES from PYTHON - EXAMPLE -e.g. pynsource -d c:/delphiouputdir c:/pythoninputdir/*.py - - - -see http://www.atug.com/andypatterns/pynsource.htm for more documentation. - -Bugs to abulka@netspace.net.au diff --git a/gaphor/plugins/pynsource/__init__.py b/gaphor/plugins/pynsource/__init__.py deleted file mode 100644 index 36b4d8b06..000000000 --- a/gaphor/plugins/pynsource/__init__.py +++ /dev/null @@ -1,242 +0,0 @@ -""" -Code reverse engineer plugin for Python source code. - -This plugin uses PyNSource, written by Andy Bulka -[http://www.atug.com/andypatterns/pynsource.htm]. - -Depends on the Diagram Layout plugin. -""" - -from gi.repository import GObject -from gi.repository import Gtk - -from gaphor.core import action -from gaphor.abc import Service, ActionProvider -from gaphor.plugins.pynsource.engineer import Engineer - -NAME_COLUMN = 0 - - -class PyNSource(Service, ActionProvider): - def __init__(self, element_factory, diagram_layout, main_window): - self.element_factory = element_factory - self.diagram_layout = diagram_layout - self.main_window = main_window - self.win = None - - def shutdown(self): - pass - - @action( - name="file-import-pynsource", - label="Python source code", - tooltip="Import Python source code", - ) - def execute(self): - dialog = self.create_dialog() - response = dialog.run() - - if response != Gtk.ResponseType.OK: - dialog.destroy() - self.reset() - return - - files = [] - for row in self.filelist: - files.append(row[0]) - - dialog.destroy() - - self.process(files) - self.reset() - - def process(self, files): - """Create a diagram based on a list of files. - """ - engineer = Engineer(self.element_factory, self.diagram_layout) - engineer.process(files) - - main_window = self.main_window - # Open and select the new diagram in the main window: - main_window.select_element(engineer.diagram) - main_window.show_diagram(engineer.diagram) - - def create_dialog(self): - dialog = Gtk.Dialog( - "Import Python files", - self.main_window.window, - Gtk.DialogFlags.MODAL, - ( - Gtk.STOCK_OK, - Gtk.ResponseType.OK, - Gtk.STOCK_CANCEL, - Gtk.ResponseType.CANCEL, - ), - ) - dialog.set_default_response(Gtk.ResponseType.OK) - - filelist = Gtk.ListStore(GObject.TYPE_STRING) - filelist.connect("row-inserted", self.on_view_rows_changed) - filelist.connect("row-deleted", self.on_view_rows_changed) - - hbox = Gtk.HBox() - - frame = Gtk.Frame.new("Files to reverse-engineer") - frame.set_border_width(8) - frame.set_size_request(500, 300) - frame.show() - hbox.pack_start(frame, True, True, 0) - - treeview = Gtk.TreeView(filelist) - treeview.set_property("headers-visible", False) - selection = treeview.get_selection() - selection.set_mode(Gtk.SelectionMode.SINGLE) - treeview.set_size_request(200, -1) - treeview.connect_after("cursor_changed", self.on_view_cursor_changed) - - scrolled_window = Gtk.ScrolledWindow() - scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) - scrolled_window.set_shadow_type(Gtk.ShadowType.IN) - scrolled_window.set_border_width(4) - scrolled_window.add(treeview) - frame.add(scrolled_window) - scrolled_window.show() - - cell = Gtk.CellRendererText() - column = Gtk.TreeViewColumn("Filename", cell, text=NAME_COLUMN) - treeview.append_column(column) - - bbox = Gtk.VButtonBox() - bbox.set_layout(Gtk.ButtonBoxStyle.SPREAD) - bbox.set_border_width(10) - button = Gtk.Button(stock="gtk-add") - button.connect("clicked", self.on_add_dir_clicked) - bbox.add(button) - self.add_button = button - - # button = Gtk.Button('Add dir...') - # button.connect('clicked', self.on_add_dir_clicked) - # bbox.add(button) - # self.add_dir_button = button - - button = Gtk.Button(stock="gtk-remove") - button.connect("clicked", self.on_remove_clicked) - button.set_property("sensitive", False) - bbox.add(button) - self.remove_button = button - - # button = Gtk.Button(stock='gtk-execute') - # button.connect('clicked', self.on_execute_clicked) - # button.set_property('sensitive', False) - # bbox.add(button) - # self.execute_button = button - - hbox.pack_start(bbox, False, True, 0) - hbox.show_all() - - dialog.vbox.pack_start(hbox, True, True, 0) - - self.filelist = filelist - self.treeview = treeview - - return dialog - - def reset(self): - self.add_button = None - self.add_dir_button = None - self.remove_button = None - self.treeview = None - self.filelist = None - - def Walk(self, root, recurse=0, pattern="*", return_folders=0): - import fnmatch - import os - import string - - # initialize - result = [] - - # must have at least root folder - try: - names = os.listdir(root) - except os.error: - return result - - # expand pattern - pattern = pattern or "*" - pat_list = string.splitfields(pattern, ";") - - # check each file - for name in names: - fullname = os.path.normpath(os.path.join(root, name)) - - # grab if it matches our pattern and entry type - for pat in pat_list: - if fnmatch.fnmatch(name, pat): - if os.path.isfile(fullname) or ( - return_folders and os.path.isdir(fullname) - ): - result.append(fullname) - continue - - # recursively scan other folders, appending results - if recurse: - if os.path.isdir(fullname) and not os.path.islink(fullname): - result = result + self.Walk( - fullname, recurse, pattern, return_folders - ) - - return result - - def on_view_cursor_changed(self, view): - selection = view.get_selection() - filelist, iter = selection.get_selected() - if not iter: - self.remove_button.set_property("sensitive", False) - return - # element = filelist.get_value(iter, NAME_COLUMN) - self.remove_button.set_property("sensitive", True) - # self.update_detail(element) - - def on_view_rows_changed(self, view, *args): - iter = None - try: - iter = view.get_iter("0") - except ValueError: - pass - # self.execute_button.set_property('sensitive', bool(iter)) - - def on_add_dir_clicked(self, button): - import os - - filesel = Gtk.FileChooserNative( - title="Add Source Code", action=Gtk.FileChooserAction.OPEN - ) - - filesel.set_select_multiple(True) - filesel.set_filename("~/") - - response = filesel.run() - selection = filesel.get_filenames() - filesel.destroy() - - if response == Gtk.ResponseType.ACCEPT: - for filename in selection: - if os.path.isdir(filename): - list = self.Walk(filename, 1, "*.py", 1) - for file in list: - iter = self.filelist.append() - self.filelist.set_value(iter, NAME_COLUMN, file) - else: - list = filename - iter = self.filelist.append() - self.filelist.set_value(iter, NAME_COLUMN, list) - - def on_remove_clicked(self, button): - selection = self.treeview.get_selection() - filelist, iter = selection.get_selected() - if not iter: - return - element = filelist.remove(iter) - - self.remove_button.set_property("sensitive", False) diff --git a/gaphor/plugins/pynsource/engineer.py b/gaphor/plugins/pynsource/engineer.py deleted file mode 100644 index 894edf181..000000000 --- a/gaphor/plugins/pynsource/engineer.py +++ /dev/null @@ -1,249 +0,0 @@ -"""The code reverse engineer. -""" - -from gaphas.aspect import ConnectionSink, Connector - -from gaphor import UML -from gaphor.diagram.classes import AssociationItem, ClassItem, GeneralizationItem -from gaphor.diagram.connectors import IConnect -from gaphor.plugins.pynsource.pynsource import PySourceAsText - -BASE_CLASSES = ("object", "type", "dict", "list", "tuple", "int", "float") - - -class Engineer: - """ - The Engineer class will create a Gaphor model based on a list of Python - files. - """ - - def process(self, element_factory, diagram_layout, files=None): - self.element_factory = element_factory - self.diagram_layout = diagram_layout - # these are tuples between class names. - # self.associations_generalisation = [] - # self.associations_composition = [] - - p = PySourceAsText() - self.parser = p - - if files: - # u = PythonToJava(None, treatmoduleasclass=0, verbose=0) - for f in files: - # Build a shape with all attrs and methods, and prepare association dict - p.Parse(f) - - print(p) - - try: - self._root_package = self.element_factory.lselect( - lambda e: isinstance(e, UML.Package) and not e.namespace - )[0] - except IndexError: - pass # running as test? - - for m in p.modulemethods: - print("ModuleMethod:", m) - - # Step 0: create a diagram to put the newly created elements on - self.diagram = self.element_factory.create(UML.Diagram) - self.diagram.name = "New classes" - self.diagram.package = self._root_package - - # Step 1: create the classes - for name, clazz in list(p.classlist.items()): - print(type(clazz), dir(clazz)) - self._create_class(clazz, name) - - # Create generalization relationships: - for name, clazz in list(p.classlist.items()): - self._create_generalization(clazz) - - # Create attributes (and associations) on the classes - for name, clazz in list(p.classlist.items()): - self._create_attributes(clazz) - - # Create operations - for name, clazz in list(p.classlist.items()): - self._create_methods(clazz) - - self.diagram_layout.layout_diagram(self.diagram) - - def _create_class(self, clazz, name): - c = self.element_factory.create(UML.Class) - c.name = name - c.package = self.diagram.namespace - ci = self.diagram.create(ClassItem) - ci.subject = c - clazz.gaphor_class = c - clazz.gaphor_class_item = ci - - def _create_generalization(self, clazz): - if not clazz.ismodulenotrealclass: - for superclassname in clazz.classesinheritsfrom: - if superclassname in BASE_CLASSES: - continue - try: - superclass = self.parser.classlist[superclassname].gaphor_class - superclass_item = self.parser.classlist[ - superclassname - ].gaphor_class_item - except KeyError as e: - print("No class found named", superclassname) - others = self.element_factory.lselect( - lambda e: isinstance(e, UML.Class) and e.name == superclassname - ) - if others: - superclass = others[0] - print(f"Found class in factory: {superclass.name}") - superclass_item = self.diagram.create(ClassItem) - superclass_item.subject = superclass - else: - continue - # Finally, create the generalization relationship - print(f"Creating Generalization for {clazz}", superclass) - # gen = self.element_factory.create(UML.Generalization) - # gen.general = superclass - # gen.specific = clazz.gaphor_class - geni = self.diagram.create(GeneralizationItem) - # geni.subject = gen - - self.connect(geni, geni.tail, clazz.gaphor_class_item) - self.connect(geni, geni.head, superclass_item) - - # adapter = IConnect(superclass_item, geni) - # assert adapter - # handle = geni.handles()[0] - # adapter.connect(handle) - # clazz.gaphor_class_item.connect_handle(geni.handles[-1]) - # adapter = IConnect(clazz.gaphor_class_item, geni) - # assert adapter - # handle = geni.handles()[-1] - # adapter.connect(handle) - - def connect(self, line, handle, item, port=None): - """ - Connect line's handle to an item. - - If port is not provided, then first port is used. - """ - canvas = line.canvas - - if port is None and len(item.ports()) > 0: - port = item.ports()[0] - - sink = ConnectionSink(item, port) - connector = Connector(line, handle) - - connector.connect(sink) - - def _create_attributes(self, clazz): - for attrobj in clazz.attrs: - # TODO: Check object type and figure out if it should be an - # attribute or an association. - self._create_attribute(clazz, attrobj) - - def _create_methods(self, clazz): - for adef in clazz.defs: - op = self.element_factory.create(UML.Operation) - op.name = adef - clazz.gaphor_class.ownedOperation = op - - def _find_class_by_name(self, classname): - try: - superclass = self.parser.classlist[classname].gaphor_class - superclass_item = self.parser.classlist[classname].gaphor_class_item - except KeyError as e: - print("No class found named", classname) - others = self.element_factory.lselect( - lambda e: isinstance(e, UML.Class) and e.name == classname - ) - if others: - superclass = others[0] - print(f"Found class in factory: {superclass.name}") - superclass_item = self.diagram.create(ClassItem) - superclass_item.subject = superclass - else: - return None, None - return superclass, superclass_item - - def _visibility(self, attrname): - if attrname.startswith("__"): - return "private" - elif attrname.startswith("_"): - return "protected" - return "public" - - def _create_attribute(self, clazz, attr): - static = False - many = False - if "static" in attr.attrtype: - static = True - if "many" in attr.attrtype: - many = True - compositescreated = self.parser.GetCompositeClassesForAttr(attr.attrname, clazz) - tail_type = None - if compositescreated: - tail_type, tail_type_item = self._find_class_by_name(compositescreated[0]) - - if tail_type: - # Create an association: - # print "%s %s <@>----> %s" % (attr.attrname, static, str(compositescreated)) - # The property on the tail of the association (tail_end) is owned - # by the class connected on the head_end (head_type) - head_type = clazz.gaphor_class - head_type_item = clazz.gaphor_class_item - - # relation = self.element_factory.create(UML.Association) - # head_end = self.element_factory.create(UML.Property) - # head_end.lowerValue = self.element_factory.create(UML.LiteralSpecification) - # tail_end = self.element_factory.create(UML.Property) - # tail_end.name = attr.attrname - # tail_end.visibility = self._visibility(attr.attrname) - # tail_end.aggregation = 'composite' - # tail_end.lowerValue = self.element_factory.create(UML.LiteralSpecification) - # relation.package = self.diagram.namespace - # relation.memberEnd = head_end - # relation.memberEnd = tail_end - # head_end.type = head_type - # tail_end.type = tail_type - # head_type.ownedAttribute = tail_end - # tail_type.ownedAttribute = head_end - - # Now the subject - # association.subject = relation - # association.head_end.subject = head_end - # association.tail_end.subject = tail_end - - # Create the diagram item: - association = self.diagram.create(AssociationItem) - - adapter = IConnect(head_type_item, association) - assert adapter - handle = association.handles()[0] - adapter.connect(handle) - - adapter = IConnect(tail_type_item, association) - assert adapter - handle = association.handles()[-1] - adapter.connect(handle) - - # Apply attribute information to the association (ends) - association.head_end.navigability = False - tail_prop = association.tail_end.subject - tail_prop.name = attr.attrname - tail_prop.visibility = self._visibility(attr.attrname) - tail_prop.aggregation = "composite" - else: - # Create a simple attribute: - # print "%s %s" % (attr.attrname, static) - prop = self.element_factory.create(UML.Property) - prop.name = attr.attrname - prop.visibility = self._visibility(attr.attrname) - prop.isStatic = static - clazz.gaphor_class.ownedAttribute = prop - # print many - import pprint - - pprint.pprint(attr) - # print dir(attr) diff --git a/gaphor/plugins/pynsource/keywords.py b/gaphor/plugins/pynsource/keywords.py deleted file mode 100644 index c03ea0828..000000000 --- a/gaphor/plugins/pynsource/keywords.py +++ /dev/null @@ -1,571 +0,0 @@ -"""Definitions of Python, Java and Delphi keywords. - -The definitions are used so that pynsource can skip these and not treat them -like you are creating an instance of a locally defined class. -""" - -pythonbuiltinfunctions_txt = """ -ArithmeticError -AssertionError -AttributeError -DeprecationWarning -EOFError -EnvironmentError -Exception -FloatingPointError -FutureWarning -IOError -ImportError -IndentationError -IndexError -KeyError -KeyboardInterrupt -LookupError -MemoryError -NameError -NotImplementedError -OSError -OverflowError -OverflowWarning -PendingDeprecationWarning -ReferenceError -RuntimeError -RuntimeWarning -StandardError -StopIteration -SyntaxError -SyntaxWarning -SystemError -SystemExit -TabError -TypeError -UnboundLocalError -UnicodeError -UserWarning -ValueError -Warning -WindowsError -ZeroDivisionError -Ellipsis -False -None -NotImplemented -True -UnicodeDecodeError -UnicodeEncodeError -UnicodeTranslateError -__debug__ -__import__ -abs -apply -basestring -bool -buffer -callable -chr -classmethod -cmp -coerce -compile -complex -copyright -credits -delattr -dict -dir -divmod -enumerate -eval -execfile -exit -file -filter -float -getattr -globals -hasattr -hash -help -hex -id -input -int -intern -isinstance -issubclass -iter -len -license -list -locals -long -map -max -min -object -oct -open -ord -pow -property -quit -range -raw_input -reduce -reload -repr -round -setattr -slice -staticmethod -str -sum -super -tuple -type -unichr -unicode -vars -xrange -zip -__base__ -__bases__ -__basicsize__ -__class__ -__dict__ -__dictoffset__ -__doc__ -__flags__ -__itemsize__ -__module__ -__mro__ -__name__ -__self__ -__weakrefoffset__ -__abs__ -__add__ -__and__ -__call__ -__cmp__ -__coerce__ -__complex__ -__contains__ -__del__ -__delattr__ -__delitem__ -__delslice__ -__div__ -__divmod__ -__eq__ -__float__ -__floordiv__ -__ge__ -__get__ -__getattribute__ -__getitem__ -__getnewargs__ -__getslice__ -__gt__ -__hash__ -__hex__ -__iadd__ -__iand__ -__idiv__ -__ifloordiv__ -__ilshift__ -__imod__ -__imul__ -__init__ -__int__ -__invert__ -__ior__ -__ipow__ -__irshift__ -__isub__ -__iter__ -__itruediv__ -__ixor__ -__le__ -__len__ -__long__ -__lshift__ -__lt__ -__mod__ -__mul__ -__ne__ -__neg__ -__new__ -__nonzero__ -__oct__ -__or__ -__pos__ -__pow__ -__radd__ -__rand__ -__rdiv__ -__rdivmod__ -__reduce__ -__reduce_ex__ -__repr__ -__rfloordiv__ -__rlshift__ -__rmod__ -__rmul__ -__ror__ -__rpow__ -__rrshift__ -__rshift__ -__rsub__ -__rtruediv__ -__rxor__ -__setattr__ -__setitem__ -__setslice__ -__str__ -__sub__ -__subclasses__ -__truediv__ -__xor__ -append -capitalize -center -clear -close -conjugate -copy -count -decode -encode -endswith -expandtabs -extend -fileno -find -flush -fromkeys -get -has_key -index -indices -insert -isalnum -isalpha -isatty -isdecimal -isdigit -islower -isnumeric -isspace -istitle -isupper -items -iteritems -iterkeys -itervalues -join -keys -ljust -lower -lstrip -mro -next -pop -popitem -read -readinto -readline -readlines -remove -replace -reverse -rfind -rindex -rjust -rstrip -seek -setdefault -sort -split -splitlines -startswith -strip -swapcase -tell -title -translate -truncate -update -upper -values -write -writelines -xreadlines -zfill -closed -co_argcount -co_cellvars -co_code -co_consts -co_filename -co_firstlineno -co_flags -co_freevars -co_lnotab -co_name -co_names -co_nlocals -co_stacksize -co_varnames -f_back -f_builtins -f_code -f_exc_traceback -f_exc_type -f_exc_value -f_globals -f_lasti -f_lineno -f_locals -f_restricted -f_trace -func_closure -func_code -func_defaults -func_dict -func_doc -func_globals -func_name -gi_frame -gi_running -im_class -im_func -im_self -imag -mode -name -newlines -real -softspace -start -step -stop -BooleanType -BufferType -BuiltinFunctionType -BuiltinMethodType -ClassType -CodeType -ComplexType -DictProxyType -DictType -DictionaryType -EllipsisType -FileType -FloatType -FrameType -FunctionType -GeneratorType -InstanceType -IntType -LambdaType -ListType -LongType -MethodType -ModuleType -NoneType -NotImplementedType -ObjectType -SliceType -StringType -StringTypes -TracebackType -TupleType -TypeType -UnboundMethodType -UnicodeType -XRangeType -__builtins__ -__file__ -""" -pythonbuiltinfunctions = pythonbuiltinfunctions_txt.split() - -javakeywords_txt = """ -abstract -boolean -break -byte -case -catch -char -class -continue -default -delegate -do -double -else -extends -false -final -finally -float -for -if -implements -import -instanceof -int -interface -long -native -new -null -package -private -protected -public -return -short -static -super -switch -synchronized -this -throw -throws -transient -true -try -void -volatile -while -goto -const -strictfp -""" -javakeywords = javakeywords_txt.split() - - -delphikeywords_txt = """ -And -Array -As -Begin -Case -Class -Const -Constructor -Destructor -Div -Do -DownTo -Else -End -Except -File -Finally -For -System -Goto -If -Implementation -In -Inherited -Interface -System -Is -Mod -Not -System -Of -On -Or -Packed -System -System -System -Raise -Record -Repeat -Set -Shl -Shr -Then -ThreadVar -To -Try -Type -Unit -Until -Uses -Var -While -With -Xor -""" -delphikeywords = delphikeywords_txt.split() -delphikeywords = [ - x.lower() for x in delphikeywords -] # delphi is case insensitive, so convert everything to lowercase for comparisons - -# See Token.py in \python2x\Lib - -TOKEN_MEANINGS_FORDOCO_ONLY = """ -AMPER = 19 -AMPEREQUAL = 42 -AT = 50 -BACKQUOTE = 25 -CIRCUMFLEX = 33 -CIRCUMFLEXEQUAL = 44 -COLON = 11 -COMMA = 12 -COMMENT = 53 -DEDENT = 6 -DOT = 23 -DOUBLESLASH = 48 -DOUBLESLASHEQUAL = 49 -DOUBLESTAR = 36 -DOUBLESTAREQUAL = 47 -ENDMARKER = 0 -EQEQUAL = 28 -EQUAL = 22 -ERRORTOKEN = 52 -GREATER = 21 -GREATEREQUAL = 31 -INDENT = 5 -LBRACE = 26 -LEFTSHIFT = 34 -LEFTSHIFTEQUAL = 45 -LESS = 20 -LESSEQUAL = 30 -LPAR = 7 -LSQB = 9 -MINEQUAL = 38 -MINUS = 15 -NAME = 1 -NEWLINE = 4 -NL = 54 -NOTEQUAL = 29 -NT_OFFSET = 256 -NUMBER = 2 -N_TOKENS = 55 -OP = 51 -PERCENT = 24 -PERCENTEQUAL = 41 -PLUS = 14 -PLUSEQUAL = 37 -RBRACE = 27 -RIGHTSHIFT = 35 -RIGHTSHIFTEQUAL = 46 -RPAR = 8 -RSQB = 10 -SEMI = 13 -SLASH = 17 -SLASHEQUAL = 40 -STAR = 16 -STAREQUAL = 39 -STRING = 3 -TILDE = 32 -VBAR = 18 -VBAREQUAL = 43 -""" diff --git a/gaphor/plugins/pynsource/pynsource.py b/gaphor/plugins/pynsource/pynsource.py deleted file mode 100644 index f51c4c39c..000000000 --- a/gaphor/plugins/pynsource/pynsource.py +++ /dev/null @@ -1,1293 +0,0 @@ -""" -PyNSource -Version 1.4c -(c) Andy Bulka 2004-2006 -abulka@netspace.net.au -http://www.atug.com/andypatterns/pynsource.htm - -A python source code scanner that generates - - UML pictures (as text) - - Java code (which can be imported into UML modeling tools.) - - UML diagrams in wxpython (see associated module pyNsourceGui.py) - - -GUI FRONT END -------------- - -Simply run - C:/Python22/Lib/site-packages/pynsource/pyNsourceGui.py - -you need wxpython installed. See http://www.wxpython.org - -SOURCE GENERATOR ----------------- - -Example Usage: C:/Python22/Lib/site-packages/pynsource/pynsource -v -m -j outdir sourcedirorpythonfiles... - --j generate java files, specify output folder for java files --v verbose --m create psuedo class for each module, - module attrs/defs etc treated as class attrs/defs - -BASIC EXAMPLES -e.g. pynsource Test/testmodule01.py -e.g. pynsource -m Test/testmodule03.py -JAVA EXAMPLES -e.g. pynsource -j c:/try c:/try -e.g. pynsource -v -m -j c:/try c:/try -e.g. pynsource -v -m -j c:/try c:/try/s*.py -e.g. pynsource -j c:/try c:/try/s*.py Tests/u*.py -e.g. pynsource -v -m -j c:/try c:/try/s*.py Tests/u*.py c:/cc/Devel/Client/w*.py -DELPHI EXAMPLE -e.g. pynsource -d c:/delphiouputdir c:/pythoninputdir/*.py - -INSTALLATION -------------- - -python setup.py install - -or run the windows .exe installer. - -JBUILDER TIPS -------------- -Consider some folder e.g. .../Tests/ and create a jbuilder project based off there called -PythonToJavaTest01 which will -actually create a folder called PythonToJavaTest01 plus -subfolders called src and classes etc. The Borland project file - -will also live in .../Tests/PythonToJavaTest01/ with a name PythonToJavaTest01.jpx - -Run pynsource so that it dumps the output into the src folder - -e.g. assuming the batch file is in the PythonToJavaTest01 folder and the python source is in - .../Tests/PythonToJavaTest01/pythoninput01 -then the command is - pynsource -j src pythoninput01/*.py - -""" - -from functools import cmp_to_key -from typing import List -import os -import pprint -import token -import tokenize - -from gaphor.plugins.pynsource.keywords import ( - pythonbuiltinfunctions, - javakeywords, - delphikeywords, -) - -DEBUG_DUMPTOKENS = False - - -class AndyBasicParseEngine: - def __init__(self): - self.meat = 0 - self.tokens = None - self.isfreshline = 1 - self.indentlevel = 0 - - def _ReadAllTokensFromFile(self, file): - fp = open(file, "r") - try: - self.tokens = [x[0:2] for x in tokenize.generate_tokens(fp.readline)] - finally: - fp.close() - if DEBUG_DUMPTOKENS: - pprint.pprint(self.tokens) - - def Parse(self, file): - self._ReadAllTokensFromFile(file) - self.meat = 0 - self._ParseLoop() - - def _ParseLoop(self): - maxtokens = len(self.tokens) - for i in range(0, maxtokens): - - tokentype, token = self.tokens[i] - if tokentype == 5: - self.indentlevel += 1 - continue - elif tokentype == 6: - self.indentlevel -= 1 - self.On_deindent() - continue - - if tokentype == 0: # End Marker. - break - - assert token, ( - "Not expecting blank token, once have detected in & out dents. tokentype=%d, token=%s" - % (tokentype, token) - ) - - self.tokentype, self.token = tokentype, token - if i + 1 < maxtokens: - self.nexttokentype, self.nexttoken = self.tokens[i + 1] - else: - self.nexttokentype, self.nexttoken = (0, None) - - if self._Isblank(): - continue - else: - # print 'MEAT', self.token - self._Gotmeat() - - def On_deindent(self): - pass - - def On_newline(self): - pass - - def On_meat(self): - pass - - def _Gotmeat(self): - self.meat = 1 - self.On_meat() - self.isfreshline = 0 # must be here, at the end. - - def _Isblank(self): - if self._Isnewline(): - return 1 - if self._Ispadding(): - return 1 - return 0 - - def _Isnewline(self): - if self.token == "\n" or self.tokentype == token.N_TOKENS: - if self.tokentype == token.N_TOKENS: - assert "#" in self.token - self.meat = 0 - self.isfreshline = 1 - self.On_newline() - return 1 - else: - return 0 - - def _Ispadding(self): - if not self.token.strip(): - self.meat = 0 - return 1 - else: - return 0 - - -class ClassEntry: - def __init__(self): - self.defs = [] - self.attrs = [] - self.classdependencytuples = [] - self.classesinheritsfrom = [] - self.ismodulenotrealclass = 0 - - def FindAttribute(self, attrname): - """ - Return - boolean hit, index pos - """ - for attrobj in self.attrs: - if attrname == attrobj.attrname: - return 1, attrobj - return 0, None - - def AddAttribute(self, attrname, attrtype): - """ - If the new info is different to the old, and there is more info - in it, then replace the old entry. - e.g. oldattrtype may be ['normal' - and new may be ['normal', 'many'] - """ - haveEncounteredAttrBefore, attrobj = self.FindAttribute(attrname) - if not haveEncounteredAttrBefore: - self.attrs.append(Attribute(attrname, attrtype)) - else: - # See if there is more info to add re this attr. - if len(attrobj.attrtype) < len(attrtype): - attrobj.attrtype = attrtype # Update it. - - # OLD CODE - # if not self.FindAttribute(attrname): - # self.attrs.append(Attribute(attrname, attrtype)) - - -class Attribute: - def __init__(self, attrname, attrtype="normal"): - self.attrname = attrname - self.attrtype = attrtype - - -class HandleClasses(AndyBasicParseEngine): - def __init__(self): - AndyBasicParseEngine.__init__(self) - self.currclasslist = [] - self._currclass = None - self.nexttokenisclass = 0 - self.classlist = {} - self.modulemethods = [] - self.optionModuleAsClass = 0 - self.inbetweenClassAndFirstDef = 0 - - def On_deindent(self): - if self.currclassindentlevel and self.indentlevel <= self.currclassindentlevel: - ## print 'popping class', self.currclass, 'from', self.currclasslist - self.PopCurrClass() - - ## print - ## print 'deindent!!', self.indentlevel, 'class indentlevel =', self.currclassindentlevel - - def _DeriveNestedClassName(self, currclass): - if not self.currclasslist: - return currclass - else: - classname, indentlevel = self.currclasslist[-1] - return ( - classname + "_" + currclass - ) # Cannot use :: since java doesn't like this name, nor does the file system. - - def PushCurrClass(self, currclass): - # print 'pushing currclass', currclass, 'self.currclasslist', self.currclasslist - currclass = self._DeriveNestedClassName(currclass) - self.currclasslist.append((currclass, self.indentlevel)) - # print 'result of pushing = ', self.currclasslist - - def PopCurrClass(self): - # __import__("traceback").print_stack(limit=6) - self.currclasslist.pop() - - def GetCurrClassIndentLevel(self): - if not self.currclasslist: - return None - currclassandindentlevel = self.currclasslist[-1] - return currclassandindentlevel[1] - - def GetCurrClass(self): - if not self.currclasslist: - return None - currclassandindentlevel = self.currclasslist[-1] - return currclassandindentlevel[0] - - currclass = property(GetCurrClass) - - currclassindentlevel = property(GetCurrClassIndentLevel) - - def _JustThenGotclass(self): - self.PushCurrClass(self.token) - self.nexttokenisclass = 0 - if self.currclass not in self.classlist: - self.classlist[self.currclass] = ClassEntry() - # print 'class', self.currclass - self.inbetweenClassAndFirstDef = 1 - - def On_newline(self): - pass - - def On_meat(self): - if self.token == "class": - ## print 'meat found class', self.token - self.nexttokenisclass = 1 - elif self.nexttokenisclass: - ## print 'meat found class name ', self.token - self._JustThenGotclass() - - -class HandleInheritedClasses(HandleClasses): - def __init__(self): - HandleClasses.__init__(self) - self._ClearwaitingInheriteClasses() - - def _JustThenGotclass(self): - HandleClasses._JustThenGotclass(self) - self.currsuperclass = "" - self.nexttokenisBracketOpenOrColon = 1 - - def _ClearwaitingInheriteClasses(self): - self.nexttokenisBracketOpenOrColon = 0 - self.nexttokenisSuperclass = 0 - self.nexttokenisComma = 0 - - def On_newline(self): - self._ClearwaitingInheriteClasses() - - def On_meat(self): - HandleClasses.On_meat(self) - if self.nexttokenisBracketOpenOrColon and self.token == "(": - assert ( - self.tokentype == token.OP - ) # unecessary, just practicing refering to tokens via names not numbers - self.nexttokenisBracketOpen = 0 - self.nexttokenisSuperclass = 1 - - elif self.nexttokenisBracketOpenOrColon and self.token == ":": - self._ClearwaitingInheriteClasses() - - elif self.nexttokenisSuperclass and self.token == ")": - self._ClearwaitingInheriteClasses() - - elif self.nexttokenisSuperclass: - self.currsuperclass += self.token - if self.token == "." or self.nexttoken == ".": - # print 'processing multi part superclass detected!', self.token, self.nexttoken - self.nexttokenisSuperclass = 1 - else: - self.nexttokenisSuperclass = 0 - self.nexttokenisComma = 1 - self.classlist[self.currclass].classesinheritsfrom.append( - self.currsuperclass - ) - - elif self.nexttokenisComma and self.token == ",": - self.nexttokenisSuperclass = 1 - self.nexttokenisComma = 0 - - -class HandleDefs(HandleInheritedClasses): - def __init__(self): - HandleInheritedClasses.__init__(self) - self.currdef = None - self.nexttokenisdef = 0 - - def _Gotdef(self): - self.currdef = self.token - self.nexttokenisdef = 0 - # print 'ADDING def', self.currdef, 'to', self.currclass - ## if self.currclass and self.indentlevel == 1: - if self.currclass: - self.classlist[self.currclass].defs.append(self.currdef) - elif self.optionModuleAsClass and self.indentlevel == 0: - assert self.moduleasclass - assert self.classlist[self.moduleasclass] - self.classlist[self.moduleasclass].defs.append(self.currdef) - else: - self.modulemethods.append(self.currdef) - self.inbetweenClassAndFirstDef = 0 - - def On_meat(self): - HandleInheritedClasses.On_meat(self) - - ## if self.token == 'def' and self.indentlevel == 1: - if self.token == "def": - ## print 'DEF FOUND AT LEVEL', self.indentlevel - self.nexttokenisdef = 1 - elif self.nexttokenisdef: - self._Gotdef() - - -## self.meat = 1 - - -class HandleClassAttributes(HandleDefs): - def __init__(self): - HandleDefs.__init__(self) - self.attrslist = [] - self._Clearwaiting() - - def On_newline(self): - HandleInheritedClasses.On_newline(self) - self._Clearwaiting() - - def _Clearwaiting(self): - self.waitingfordot = 0 - self.waitingforsubsequentdot = 0 - self.waitingforvarname = 0 - self.waitingforequalsymbol = 0 - self.currvarname = None - self.lastcurrvarname = None - self.waitforappendopenbracket = 0 - self.nextvarnameisstatic = 0 - self.nextvarnameismany = 0 - - def JustGotASelfAttr(self, selfattrname): - pass - - def On_meat(self): - HandleDefs.On_meat(self) - - if self.isfreshline and self.token == "self" and self.nexttoken == ".": - self.waitingfordot = 1 - - elif self.waitingfordot and self.token == ".": - self.waitingfordot = 0 - self.waitingforvarname = 1 - - elif self.waitingforvarname: - # We now have the possible class attribute name. :-) - self.waitingforvarname = 0 - self.currvarname = self.token - """ - At this point we have the x in the expression self.x - - A. We could find self.x = in which case we have a valid class attribute. - B. We could find self.x.append( in which case we have a valid class attribute list/vector. - C. We could find self.__class__.x = in which case we have a valid STATIC class attribute. - - D. We could find self.x.y = in which case we skip. - E. We could find self.x.y.append( in which case we skip. - F. We could find self.x.y.Blah( in which case we skip. - - G. We could find self.numberOfFlags = read16(fp) - skip cos read16 is a module function. - """ - if self.nexttoken == "=": - self.waitingforequalsymbol = 1 # Case A - elif self.nexttoken == ".": - self.waitingforsubsequentdot = 1 # Cases B,C, D,E,F pending - - elif self.waitingforsubsequentdot and self.token == ".": - self.waitingfordot = 0 - self.waitingforsubsequentdot = 0 - self.waitingforequalsymbol = 0 - if self.nexttoken.lower() in ("append", "add", "insert"): # Case B - # keep the class attribute name we have, wait till bracket - self.waitforappendopenbracket = 1 - elif self.currvarname in ("__class__",): # Case C - self.currvarname = None - self.waitingforvarname = 1 - self.nextvarnameisstatic = 1 - else: - # Skip cases D, E, F - self._Clearwaiting() - - elif self.waitforappendopenbracket and self.token == "(": - self.waitforappendopenbracket = 0 - self.nextvarnameismany = 1 - self._AddAttribute() - self._Clearwaiting() - - elif self.waitingforequalsymbol and self.token == "=": - self.waitingforequalsymbol = 0 - self._AddAttribute() - self._Clearwaiting() - - def _AddAttribute(self): - classentry = self.classlist[self.currclass] - if self.nextvarnameisstatic: - attrtype = ["static"] - else: - attrtype = ["normal"] - - if self.nextvarnameismany: - attrtype.append("many") - - classentry.AddAttribute(self.currvarname, attrtype) - # print ' ATTR ', self.currvarname - self.JustGotASelfAttr(self.currvarname) - - -class HandleComposites(HandleClassAttributes): - def __init__(self): - HandleClassAttributes.__init__(self) - self._ClearwaitingOnComposites() - self.dummy = ClassEntry() - self.dummy2 = [()] - - def JustGotASelfAttr(self, selfattrname): - assert selfattrname != "self" - self.lastselfattrname = selfattrname - self.waitingforclassname = 1 - self.waitingforOpenBracket = 0 - self.possibleclassname = None - self.dontdoanythingnow = 1 - - def _ClearwaitingOnComposites(self): - self.lastselfattrname = None - self.waitingforclassname = 0 - self.possibleclassname = None - self.waitingforOpenBracket = 0 - self.dontdoanythingnow = 0 - - def On_newline(self): - HandleClassAttributes.On_newline(self) - self._ClearwaitingOnComposites() - - def On_meat(self): - self.dontdoanythingnow = 0 - HandleClassAttributes.On_meat(self) - - # At this point we may have had a "self.blah = " encountered, and blah is saved in self.lastselfattrname - - if self.dontdoanythingnow: - pass - - elif ( - self.waitingforclassname - and self.token not in ("(", "[") - and self.token not in pythonbuiltinfunctions - and self.tokentype not in (token.NUMBER, token.STRING) - and self.token not in self.modulemethods - ): - self.possibleclassname = self.token - self.waitingforclassname = 0 - self.waitingforOpenBracket = 1 - - elif self.waitingforOpenBracket and self.token == "(": - self.waitingforclassname = 0 - self.waitingforOpenBracket = 0 - - dependency = (self.lastselfattrname, self.possibleclassname) - self.classlist[self.currclass].classdependencytuples.append(dependency) - # print '*** dependency - created instance of', self.possibleclassname, 'assigned to', self.lastselfattrname - - elif self.waitingforOpenBracket and self.token == ")": - """ - New - we haven't got a class being created but instead have a variable. - Note that the above code detects - self.flag.append(Flag()) # notice instance creation inside append - but the following code detects - self.flag.append(flag) # and assumes flag variable is an instance of Flag class - """ - # we don't have class being created but have a variable name instead - variablename = self.possibleclassname - - # try to find a class with the same name. - correspondingClassName = variablename[0].upper() + variablename[1:] # HACK - # print 'correspondingClassName', correspondingClassName - - dependency = (self.lastselfattrname, correspondingClassName) - self.classlist[self.currclass].classdependencytuples.append(dependency) - - else: - self._ClearwaitingOnComposites() - - -class HandleClassStaticAttrs(HandleComposites): - def __init__(self): - HandleComposites.__init__(self) - self.__Clearwaiting() - - def __Clearwaiting(self): - self.__waitingforequalsymbol = 0 - self.__staticattrname = "" - - def On_meat(self): - HandleComposites.On_meat(self) - - if ( - self.isfreshline - and self.currclass - and self.inbetweenClassAndFirstDef - and self.tokentype == 1 - and self.indentlevel != 0 - and self.nexttoken == "=" - ): - self.__waitingforequalsymbol = 1 - self.__staticattrname = self.token - - elif self.__waitingforequalsymbol and self.token == "=": - self.__waitingforequalsymbol = 0 - # print 'have static level attr', self.__staticattrname - self.__AddAttrModuleLevel() - self.__Clearwaiting() - - def __AddAttrModuleLevel(self): - # Should re-use the logic in HandleClassAttributes for both parsing - # (getting more info on multiplicity but not static - cos static not relevant?) and - # also should be able to reuse most of _AddAttr() - # - classentry = self.classlist[self.currclass] - attrtype = ["static"] - - classentry.AddAttribute(self.__staticattrname, attrtype) - # print ' STATIC ATTR ', self.__staticattrname - - -class HandleModuleLevelDefsAndAttrs(HandleClassStaticAttrs): - def __init__(self): - HandleClassStaticAttrs.__init__(self) - self.moduleasclass = "" - self.__Clearwaiting() - - def __Clearwaiting(self): - self.waitingforequalsymbolformoduleattr = 0 - self.modulelevelattrname = "" - - def Parse(self, file): - self.moduleasclass = "Module_" + os.path.splitext(os.path.basename(file))[0] - if self.optionModuleAsClass: - self.classlist[self.moduleasclass] = ClassEntry() - self.classlist[self.moduleasclass].ismodulenotrealclass = 1 - - HandleComposites.Parse(self, file) - - def On_meat(self): - HandleClassStaticAttrs.On_meat(self) - - if ( - self.isfreshline - and self.tokentype == 1 - and self.indentlevel == 0 - and self.nexttoken == "=" - ): - self.waitingforequalsymbolformoduleattr = 1 - self.modulelevelattrname = self.token - - elif self.waitingforequalsymbolformoduleattr and self.token == "=": - self.waitingforequalsymbolformoduleattr = 0 - # print 'have module level attr', self.modulelevelattrname - self._AddAttrModuleLevel() - self.__Clearwaiting() - - def On_newline(self): - HandleClassStaticAttrs.On_newline(self) - self.__Clearwaiting() - - def _AddAttrModuleLevel(self): - if not self.optionModuleAsClass: - return - - # Should re-use the logic in HandleClassAttributes for both parsing - # (getting more info on multiplicity but not static - cos static not relevant?) and - # also should be able to reuse most of _AddAttr() - # - classentry = self.classlist[self.moduleasclass] - attrtype = ["normal"] - - ## if self.nextvarnameisstatic: - ## attrtype = ['static'] - ## else: - ## attrtype = ['normal'] - ## - ## if self.nextvarnameismany: - ## attrtype.append('many') - - classentry.AddAttribute(self.modulelevelattrname, attrtype) - # print ' ATTR ', self.currvarname - # self.JustGotASelfAttr(self.currvarname) - - -class PySourceAsText(HandleModuleLevelDefsAndAttrs): - def __init__(self): - HandleModuleLevelDefsAndAttrs.__init__(self) - self.listcompositesatend = 0 - self.embedcompositeswithattributelist = 1 - self.result = "" - self.aclass = None - self.classentry = None - self.staticmessage = "" - self.manymessage = "" - self.verbose = 0 - - def GetCompositeClassesForAttr(self, classname, classentry): - resultlist = [] - for dependencytuple in classentry.classdependencytuples: - if dependencytuple[0] == classname: - resultlist.append(dependencytuple[1]) - return resultlist - - def _GetCompositeCreatedClassesFor(self, classname): - return self.GetCompositeClassesForAttr(classname, self.classentry) - - def _DumpAttribute(self, attrobj): - compositescreated = self._GetCompositeCreatedClassesFor(attrobj.attrname) - if compositescreated and self.embedcompositeswithattributelist: - self.result += "{} {} <@>----> {}".format( - attrobj.attrname, self.staticmessage, str(compositescreated) - ) - else: - self.result += f"{attrobj.attrname} {self.staticmessage}" - self.result += self.manymessage - self.result += "\n" - - def _DumpCompositeExtraFooter(self): - if self.classentry.classdependencytuples and self.listcompositesatend: - for dependencytuple in self.classentry.classdependencytuples: - self.result += "%s <*>---> %s\n" % dependencytuple - self.result += "-" * 20 + "\n" - - def _DumpClassNameAndGeneralisations(self): - self._Line() - if self.classentry.ismodulenotrealclass: - self.result += f"{self.aclass} (file)\n" - else: - self.result += "{} --------|> {}\n".format( - self.aclass, self.classentry.classesinheritsfrom - ) - self._Line() - - def _DumpAttributes(self): - for attrobj in self.classentry.attrs: - self.staticmessage = "" - self.manymessage = "" - if "static" in attrobj.attrtype: - self.staticmessage = " static" - if "many" in attrobj.attrtype: - self.manymessage = " 1..*" - self._DumpAttribute(attrobj) - - def _DumpMethods(self): - for adef in self.classentry.defs: - self.result += adef + "\n" - - def _Line(self): - self.result += "-" * 20 + "\n" - - def _DumpClassHeader(self): - self.result += "\n" - - def _DumpClassFooter(self): - self.result += "\n" - self.result += "\n" - - def _DumpModuleMethods(self): - if self.modulemethods: - self.result += " ModuleMethods = %s\n" % repr(self.modulemethods) - - ## self.result += '\n' - - def __str__(self): - self.result = "" - self._DumpClassHeader() - self._DumpModuleMethods() - - optionAlphabetic = 0 - classnames = list(self.classlist.keys()) - if optionAlphabetic: - classnames.sort() - else: - - def cmpfunc(a, b): - if a.find("Module_") != -1: - return -1 - else: - if a < b: - return -1 - elif a == b: - return 0 - else: - return 1 - - classnames.sort(key=cmp_to_key(cmpfunc)) - for self.aclass in classnames: - self.classentry = self.classlist[self.aclass] - - ## for self.aclass, self.classentry in self.classlist.items(): - self._DumpClassNameAndGeneralisations() - self._DumpAttributes() - self._Line() - self._DumpMethods() - self._Line() - self._DumpCompositeExtraFooter() - self._DumpClassFooter() - return self.result - - -class PySourceAsJava(PySourceAsText): - def __init__(self, outdir=None): - PySourceAsText.__init__(self) - self.outdir = outdir - self.fp = None - - def _DumpClassFooter(self): - self.result += "}\n" - - if self.fp: - self.fp.write(self.result) - self.fp.close() - self.fp = None - self.result = "" - - def _DumpModuleMethods(self): - self.result += "/*\n" - PySourceAsText._DumpModuleMethods(self) - self.result += "*/\n" - - def _OpenNextFile(self): - filepath = f"{self.outdir}/{self.aclass}.java" - self.fp = open(filepath, "w") - - def _NiceNameToPreventCompilerErrors(self, attrname): - """ - Prevent compiler errors on the java side by checking and modifying attribute name - """ - # only emit the rhs of a multi part name e.g. undo.UndoItem will appear only as UndoItem - if attrname.find(".") != -1: - attrname = attrname.split(".")[-1] # take the last - # Prevent compiler errors on the java side by avoiding the generating of java keywords as attribute names - if attrname in javakeywords: - attrname = "_" + attrname - return attrname - - def _DumpAttribute(self, attrobj): - compositescreated = self._GetCompositeCreatedClassesFor(attrobj.attrname) - if compositescreated: - compositecreated = compositescreated[0] - else: - compositecreated = None - - # Extra processing on the attribute name, to avoid java compiler errors - attrname = self._NiceNameToPreventCompilerErrors(attrobj.attrname) - - if compositecreated and self.embedcompositeswithattributelist: - self.result += " public {} {} {} = new {}();\n".format( - self.staticmessage, compositecreated, attrname, compositecreated - ) - else: - ## self.result += " public %s void %s;\n" % (self.staticmessage, attrobj.attrname) - ## self.result += " public %s int %s;\n" % (self.staticmessage, attrname) - self.result += " public {} variant {};\n".format( - self.staticmessage, attrname - ) - - """ - import java.util.Vector; - - private java.util.Vector lnkClass4; - - private Vector lnkClass4; - """ - - def _DumpCompositeExtraFooter(self): - pass - - def _DumpClassNameAndGeneralisations(self): - if self.verbose: - print(" Generating Java class", self.aclass) - self._OpenNextFile() - - self.result += "// Generated by PyNSource http://www.atug.com/andypatterns/pynsource.htm \n\n" - - ## self.result += "import javax.swing.Icon; // Not needed, just testing pyNSource's ability to generate import statements.\n\n" # NEW package support! - - self.result += f"public class {self.aclass} " - if self.classentry.classesinheritsfrom: - self.result += "extends %s " % self._NiceNameToPreventCompilerErrors( - self.classentry.classesinheritsfrom[0] - ) - self.result += "{\n" - - def _DumpMethods(self): - for adef in self.classentry.defs: - self.result += " public void %s() {\n }\n" % adef - - def _Line(self): - pass - - -def unique(s): - """ Return a list of the elements in list s in arbitrary order, but without duplicates """ - n = len(s) - if n == 0: - return [] - u = {} - try: - for x in s: - u[x] = 1 - except TypeError: - del u # move onto the next record - else: - return list(u.keys()) - - raise KeyError("uniqueness algorithm failed .. type more of it in please") - - -class PySourceAsDelphi(PySourceAsText): - """ - Example Delphi source file: - - unit test000123; - - interface - - uses - SysUtils, Windows, Messages, Classes, Graphics, Controls, - Forms, Dialogs; - - type - TDefault1 = class (TObject) - private - field0012: Variant; - public - class var field0123434: Variant; - procedure Member1; - class procedure Member2; - end; - - - procedure Register; - - implementation - - procedure Register; - begin - end; - - { - ********************************** TDefault1 *********************************** - } - procedure TDefault1.Member1; - begin - end; - - class procedure TDefault1.Member2; - begin - end; - - - end. - - """ - - def __init__(self, outdir=None): - PySourceAsText.__init__(self) - self.outdir = outdir - self.fp = None - - def _DumpClassFooter(self): - self.result += "\n\n" - - self.result += "implementation\n\n" - - self.DumpImplementationMethods() - - self.result += "\nend.\n\n" - - if self.fp: - self.fp.write(self.result) - self.fp.close() - self.fp = None - self.result = "" - - def _DumpModuleMethods(self): - self.result += "(*\n" - PySourceAsText._DumpModuleMethods(self) - self.result += "*)\n\n" - - def _OpenNextFile(self): - filepath = f"{self.outdir}/unit_{self.aclass}.pas" - self.fp = open(filepath, "w") - - def _NiceNameToPreventCompilerErrors(self, attrname): - """ - Prevent compiler errors on the java side by checking and modifying attribute name - """ - # only emit the rhs of a multi part name e.g. undo.UndoItem will appear only as UndoItem - if attrname.find(".") != -1: - attrname = attrname.split(".")[-1] # take the last - - # Prevent compiler errors on the Delphi side by avoiding the generating of delphi keywords as attribute names - if ( - attrname.lower() in delphikeywords - ): # delphi is case insensitive, so convert everything to lowercase for comparisons - attrname = "_" + attrname - - return attrname - - def _DumpAttribute(self, attrobj): - """ - Figure out what type the attribute is only in those cases where - we are later going to assign to these variables using .Create() in the constructor. - The rest we make Variants. - """ - compositescreated = self._GetCompositeCreatedClassesFor(attrobj.attrname) - if compositescreated: - compositecreated = compositescreated[0] - else: - compositecreated = None - - # Extra processing on the attribute name, to avoid delphi compiler errors - attrname = self._NiceNameToPreventCompilerErrors(attrobj.attrname) - - self.result += " " - if self.staticmessage: - self.result += "class var" - - if compositecreated: - vartype = compositecreated - else: - vartype = "Variant" - self.result += f"{attrname} : {vartype};\n" - - # generate more complex stuff in the implementation section... - - ## if compositecreated and self.embedcompositeswithattributelist: - ## self.result += " public %s %s %s = new %s();\n" % (self.staticmessage, compositecreated, attrname, compositecreated) - ## else: - ## self.result += "%s : Variant;\n"%attrname - - def _DumpCompositeExtraFooter(self): - pass - - def _DumpClassNameAndGeneralisations(self): - if self.verbose: - print(" Generating Delphi class", self.aclass) - self._OpenNextFile() - - self.result += "// Generated by PyNSource http://www.atug.com/andypatterns/pynsource.htm \n\n" - - self.result += f"unit unit_{self.aclass};\n\n" - self.result += "interface\n\n" - - uses = unique(self.GetUses()) - if uses: - self.result += "uses\n " - self.result += ", ".join(uses) - self.result += ";\n\n" - - self.result += "type\n\n" - self.result += f"{self.aclass} = class" - if self.classentry.classesinheritsfrom: - self.result += "(%s)" % self._NiceNameToPreventCompilerErrors( - self.classentry.classesinheritsfrom[0] - ) - self.result += "\n" - self.result += "public\n" - - def _DumpMethods(self): - if self.classentry.attrs: # if there were any atributes... - self.result += ( - "\n" - ) # a little bit of a separator between attributes and methods. - - for adef in self.classentry.defs: - if adef == "__init__": - self.result += " constructor Create;\n" - else: - ## self.result += " function %s(): void; virtual;\n" % adef - self.result += f" procedure {adef}(); virtual;\n" - - self.result += "end;\n" # end of class - - def DumpImplementationMethods(self): - for adef in self.classentry.defs: - if adef == "__init__": - self.result += ( - f"constructor {self.aclass}.Create;\n" - ) # replace __init__ with the word 'Create' - else: - ## self.result += "function %s.%s(): void;\n" % (self.aclass, adef) - self.result += f"procedure {self.aclass}.{adef}();\n" - self.result += "begin\n" - if adef == "__init__": - self.CreateCompositeAttributeClassCreationAndAssignmentInImplementation() - self.result += "end;\n\n" - - def CreateCompositeAttributeClassCreationAndAssignmentInImplementation(self): - # Only do those attributes that are composite and need to create an instance of something - for attrobj in self.classentry.attrs: - compositescreated = self._GetCompositeCreatedClassesFor(attrobj.attrname) - if ( - compositescreated and self.embedcompositeswithattributelist - ): # latter variable always seems to be true! Never reset!? - compositecreated = compositescreated[0] - self.result += " {} := {}.Create();\n".format( - attrobj.attrname, compositecreated - ) - - def GetUses(self): - result = [] - for attrobj in self.classentry.attrs: - compositescreated = self._GetCompositeCreatedClassesFor(attrobj.attrname) - if ( - compositescreated and self.embedcompositeswithattributelist - ): # latter variable always seems to be true! Never reset!? - compositecreated = compositescreated[0] - result.append(compositecreated) - - # Also use any inherited calss modules. - if self.classentry.classesinheritsfrom: - result.append( - self._NiceNameToPreventCompilerErrors( - self.classentry.classesinheritsfrom[0] - ) - ) - - return ["unit_" + u for u in result] - - def _Line(self): - pass - - -class PythonToJava: - def __init__(self, directories, treatmoduleasclass=0, verbose=0): - self.directories = directories - self.optionModuleAsClass = treatmoduleasclass - self.verbose = verbose - - def _GenerateAuxilliaryClasses(self): - classestocreate = ( - "variant", - "unittest", - "list", - "object", - "dict", - ) # should add more classes and add them to a jar file to avoid namespace pollution. - for aclass in classestocreate: - fp = open(os.path.join(self.outpath, aclass + ".java"), "w") - fp.write(self.GenerateSourceFileForAuxClass(aclass)) - fp.close() - - def GenerateSourceFileForAuxClass(self, aclass): - return "\npublic class %s {\n}\n" % aclass - - def ExportTo(self, outpath): - self.outpath = outpath - - self._GenerateAuxilliaryClasses() - - for directory in self.directories: - if "*" in directory or "." in directory: - filepath = directory - else: - filepath = os.path.join(directory, "*.py") - if self.verbose: - print("Processing directory", filepath) - globbed = glob.glob(filepath) - # print 'Java globbed is', globbed - for f in globbed: - self._Process(f) - - def _Process(self, filepath): - if self.verbose: - padding = " " - else: - padding = "" - thefile = os.path.basename(filepath) - if thefile[0] == "_": - print(" ", "Skipped", thefile, "cos begins with underscore.") - return - print(f"{padding}Processing {thefile}...") - p = self._CreateParser() - p.Parse(filepath) - str(p) # triggers the output. - - def _CreateParser(self): - p = PySourceAsJava(self.outpath) - p.optionModuleAsClass = self.optionModuleAsClass - p.verbose = self.verbose - return p - - -class PythonToDelphi(PythonToJava): - def _GenerateAuxilliaryJavaClasses(self): - pass - - def _CreateParser(self): - p = PySourceAsDelphi(self.outpath) - p.optionModuleAsClass = self.optionModuleAsClass - p.verbose = self.verbose - return p - - def _GenerateAuxilliaryClasses(self): - # Delphi version omits the class 'object' and 'variant' since these already are pre-defined in Delphi. - classestocreate = ("unittest", "list", "dict") # should add more classes - for aclass in classestocreate: - fp = open(os.path.join(self.outpath, "unit_" + aclass + ".pas"), "w") - fp.write(self.GenerateSourceFileForAuxClass(aclass)) - fp.close() - - def GenerateSourceFileForAuxClass(self, aclass): - template = """ -unit unit_%s; - -interface - -type - - %s = class - public - end; - -implementation - -end. - """ - return template % (aclass, aclass) - - -if __name__ == "__main__": - # run() - import sys, glob, getopt - - SIMPLE = 0 - globbed: List[str] = [] - - optionVerbose = 0 - optionModuleAsClass = 0 - optionExportToJava = 0 - optionExportToDelphi = 0 - optionExportTo_outdir = "" - - if SIMPLE: - params = sys.argv[1] - globbed = glob.glob(params) - else: - listofoptionvaluepairs, params = getopt.getopt(sys.argv[1:], "mvj:d:") - print(listofoptionvaluepairs, params) - - def EnsurePathExists(outdir, outlanguagemsg): - assert ( - outdir - ), "Need to specify output folder for {} output - got {}.".format( - outlanguagemsg, outdir - ) - if not os.path.exists(outdir): - raise RuntimeError( - "Output directory %s for %s file output does not exist." - % (outdir, outlanguagemsg) - ) - - for optionvaluepair in listofoptionvaluepairs: - if "-m" == optionvaluepair[0]: - optionModuleAsClass = 1 - if "-v" == optionvaluepair[0]: - optionVerbose = 1 - if optionvaluepair[0] in ("-j", "-d"): - if optionvaluepair[0] == "-j": - optionExportToJava = 1 - language = "Java" - else: - optionExportToDelphi = 1 - language = "Delphi" - optionExportTo_outdir = optionvaluepair[1] - EnsurePathExists(optionExportTo_outdir, language) - - for param in params: - files = glob.glob(param) - globbed += files - - if globbed: - if optionExportToJava or optionExportToDelphi: - if optionExportToJava: - u = PythonToJava( - globbed, - treatmoduleasclass=optionModuleAsClass, - verbose=optionVerbose, - ) - else: - u = PythonToDelphi( - globbed, - treatmoduleasclass=optionModuleAsClass, - verbose=optionVerbose, - ) - u.ExportTo(optionExportTo_outdir) - else: - p = PySourceAsText() - p.optionModuleAsClass = optionModuleAsClass - p.verbose = optionVerbose - for f in globbed: - p.Parse(f) - print(p) - else: - print( - """Usage: pynsource -v -m -j outdir sourcedirorpythonfiles... - --j generate java files, specify output folder for java files --v verbose --m create psuedo class for each module, - module attrs/defs etc treated as class attrs/defs - -BASIC EXAMPLES -e.g. pynsource Test/testmodule01.py -e.g. pynsource -m Test/testmodule03.py -JAVA EXAMPLES -e.g. pynsource -j c:/try c:/try -e.g. pynsource -v -m -j c:/try c:/try -e.g. pynsource -v -m -j c:/try c:/try/s*.py -e.g. pynsource -j c:/try c:/try/s*.py Tests/u*.py -e.g. pynsource -v -m -j c:/try c:/try/s*.py Tests/u*.py c:/cc/Devel/Client/w*.py -DELPHI EXAMPLE -e.g. pynsource -d c:/delphiouputdir c:/pythoninputdir/*.py -""" - ) diff --git a/gaphor/services/tests/test_copyservice.py b/gaphor/services/tests/test_copyservice.py index 878539e0b..67b80b367 100644 --- a/gaphor/services/tests/test_copyservice.py +++ b/gaphor/services/tests/test_copyservice.py @@ -12,7 +12,6 @@ class CopyServiceTestCase(TestCase): "main_window", "properties", "undo_manager", - "import_menu", "export_menu", "tools_menu", ] diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index d6323f375..9d3969b94 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -73,7 +73,7 @@ def hamburger_menu(hamburger_model): return button -def create_hamburger_model(import_menu, export_menu, tools_menu): +def create_hamburger_model(export_menu, tools_menu): model = Gio.Menu.new() part = Gio.Menu.new() @@ -83,10 +83,6 @@ def create_hamburger_model(import_menu, export_menu, tools_menu): part = Gio.Menu.new() part.append(_("Save As..."), "win.file-save-as") - model.append_section(None, part) - - part = Gio.Menu.new() - part.append_submenu(_("Import"), import_menu) part.append_submenu(_("Export"), export_menu) model.append_section(None, part) @@ -134,7 +130,6 @@ class MainWindow(Service, ActionProvider): component_registry, element_factory, properties, - import_menu, export_menu, tools_menu, ): @@ -142,7 +137,6 @@ class MainWindow(Service, ActionProvider): self.component_registry = component_registry self.element_factory = element_factory self.properties = properties - self.import_menu = import_menu self.export_menu = export_menu self.tools_menu = tools_menu @@ -213,9 +207,7 @@ class MainWindow(Service, ActionProvider): header.pack_end( hamburger_menu( - create_hamburger_model( - self.import_menu.menu, self.export_menu.menu, self.tools_menu.menu - ) + create_hamburger_model(self.export_menu.menu, self.tools_menu.menu) ) ) header.pack_end(button(_("Save"), "win.file-save")) diff --git a/gaphor/ui/tests/test_diagrampage.py b/gaphor/ui/tests/test_diagrampage.py index 7078f89d2..b09d4e2d1 100644 --- a/gaphor/ui/tests/test_diagrampage.py +++ b/gaphor/ui/tests/test_diagrampage.py @@ -21,7 +21,6 @@ class DiagramPageTestCase(unittest.TestCase): "diagrams", "toolbox", "elementeditor", - "import_menu", "export_menu", "tools_menu", ] diff --git a/gaphor/ui/tests/test_diagramtoolbox.py b/gaphor/ui/tests/test_diagramtoolbox.py index e1a34064f..237e12c5a 100644 --- a/gaphor/ui/tests/test_diagramtoolbox.py +++ b/gaphor/ui/tests/test_diagramtoolbox.py @@ -21,7 +21,6 @@ class DiagramToolboxTestCase(TestCase): "element_factory", "properties", "main_window", - "import_menu", "export_menu", "tools_menu", ] diff --git a/gaphor/ui/tests/test_diagramtools.py b/gaphor/ui/tests/test_diagramtools.py index 15ae25765..083d52b30 100644 --- a/gaphor/ui/tests/test_diagramtools.py +++ b/gaphor/ui/tests/test_diagramtools.py @@ -18,7 +18,6 @@ class DiagramItemConnectorTestCase(TestCase): "namespace", "diagrams", "toolbox", - "import_menu", "export_menu", "tools_menu", "elementeditor", diff --git a/gaphor/ui/tests/test_handletool.py b/gaphor/ui/tests/test_handletool.py index 635adc913..497d46164 100644 --- a/gaphor/ui/tests/test_handletool.py +++ b/gaphor/ui/tests/test_handletool.py @@ -33,7 +33,6 @@ def application(): "diagrams", "toolbox", "elementeditor", - "import_menu", "export_menu", "tools_menu", ] @@ -114,7 +113,6 @@ class HandleToolTestCase(unittest.TestCase): "diagrams", "toolbox", "elementeditor", - "import_menu", "export_menu", "tools_menu", ] diff --git a/gaphor/ui/tests/test_mainwindow.py b/gaphor/ui/tests/test_mainwindow.py index 4467ea74e..b679f2faa 100644 --- a/gaphor/ui/tests/test_mainwindow.py +++ b/gaphor/ui/tests/test_mainwindow.py @@ -19,7 +19,6 @@ def application(): "diagrams", "toolbox", "elementeditor", - "import_menu", "export_menu", "tools_menu", ] diff --git a/pyproject.toml b/pyproject.toml index 4983595d2..0e013ac85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,6 @@ gaphorconvert = 'gaphor.tools.gaphorconvert:main' "main_window" = "gaphor.ui.mainwindow:MainWindow" "preferences" = "gaphor.ui.preferences:Preferences" "export_menu" = "gaphor.ui.menufragment:MenuFragment" -"import_menu" = "gaphor.ui.menufragment:MenuFragment" "tools_menu" = "gaphor.ui.menufragment:MenuFragment" "copy" = "gaphor.services.copyservice:CopyService" "sanitizer" = "gaphor.services.sanitizerservice:SanitizerService" @@ -81,8 +80,6 @@ gaphorconvert = 'gaphor.tools.gaphorconvert:main' "elementeditor" = "gaphor.ui.elementeditor:ElementEditor" "diagram_export" = "gaphor.plugins.diagramexport:DiagramExport" "xmi_export" = "gaphor.plugins.xmiexport:XMIExport" -"diagram_layout" = "gaphor.plugins.diagramlayout:DiagramLayout" -"pynsource" = "gaphor.plugins.pynsource:PyNSource" [build-system] requires = ["poetry==1.0.0b2"] diff --git a/setup.py b/setup.py index 9817b4135..26959bb1f 100644 --- a/setup.py +++ b/setup.py @@ -100,7 +100,6 @@ setup( "main_window = gaphor.ui.mainwindow:MainWindow", "preferences = gaphor.ui.preferences:Preferences", "export_menu = gaphor.ui.menufragment:MenuFragment", - "import_menu = gaphor.ui.menufragment:MenuFragment", "tools_menu = gaphor.ui.menufragment:MenuFragment", "copy = gaphor.services.copyservice:CopyService", "sanitizer = gaphor.services.sanitizerservice:SanitizerService", @@ -112,8 +111,6 @@ setup( "elementeditor = gaphor.ui.elementeditor:ElementEditor", "diagram_export = gaphor.plugins.diagramexport:DiagramExport", "xmi_export = gaphor.plugins.xmiexport:XMIExport", - "diagram_layout = gaphor.plugins.diagramlayout:DiagramLayout", - "pynsource = gaphor.plugins.pynsource:PyNSource", ], }, cmdclass={ diff --git a/win-installer/gaphor-script.py b/win-installer/gaphor-script.py index 8cf9161ad..909e6ca05 100644 --- a/win-installer/gaphor-script.py +++ b/win-installer/gaphor-script.py @@ -3,8 +3,6 @@ if __name__ == "__main__": from gaphor import core from gaphor.UML.elementfactory import ElementFactory from gaphor.plugins.diagramexport import DiagramExport - from gaphor.plugins.diagramlayout import DiagramLayout - from gaphor.plugins.pynsource import PyNSource from gaphor.plugins.xmiexport import XMIExport from gaphor.services.componentregistry import ComponentRegistry from gaphor.services.copyservice import CopyService