def test01(self): """ """ FILE = 'python-in/testmodule08_multiple_inheritance.py' #self.p, debuginfo = old_parser(FILE) self.p, debuginfo = new_parser(FILE) #print self.p # ------------------------------------------------------- gotevent1 = 0 gotevent2 = 0 gotevent3 = 0 gotevent4 = 0 gotevent5 = 0 gotevent6 = 0 gotevent7 = 0 for classname, classentry in self.p.classlist.items(): if classname == 'Fred': gotevent1 = 1 assert classentry.classesinheritsfrom == ['Mary', 'Sam'], classentry.classesinheritsfrom if classname == 'MarySam': gotevent3 = False # should not get this assert gotevent1 assert not gotevent3
def parse_source(source_code, options): with tempfile.NamedTemporaryFile( mode="wt") as temp: # TODO use streams not temporary files temp.write(source_code) temp.flush() pmodel, debuginfo = new_parser(temp.name, options) return pmodel, debuginfo
def test01(self): """ """ FILE = PYTHON_CODE_EXAMPLES_TO_PARSE + "testmodule_bug_pyplecs.py" # Can also run using # python3 pynsource-cli.py --mode 3 --graph tests/python-in/testmodule_bug_pyplecs.py # create a html log file to contain html info log = LogWriter(FILE, print_to_console=False) log.out_html_header() # Normally debug info is false for performance reasons, so turn it on temporarily and restore it later old_debug_info_value = DEBUGINFO() set_DEBUGINFO(True) try: self.p, debuginfo = new_parser(FILE, log, options={"mode": 3}) finally: set_DEBUGINFO(old_debug_info_value) log.out("<hr><h1>Errors:</h1>") log.out_wrap_in_html(self.p.errors) log.out("<hr><h1>debuginfo:</h1>") log.out(debuginfo) log.out_html_footer() log.finish() self.assertEqual(self.p.errors, "") print(self.p)
def execute(self): workspace_was_empty: bool = len(self.context.displaymodel.graph.nodes) == 0 if self.files: for f in self.files: # pmodel, debuginfo = old_parser(f) # pmodel, debuginfo = new_parser(f) mode = getattr(self, "mode", 2) # print(f"Importing Python in syntax mode {mode}") pmodel, debuginfo = new_parser(f, options={"mode": mode}) if pmodel.errors: # print(pmodel.errors) self.context.wxapp.MessageBox(pmodel.errors) # from parsing.dump_pmodel import dump_old_structure # print(dump_old_structure(pmodel)) self.context.displaymodel.build_graphmodel(pmodel) # self.context.displaymodel.Dump(msg="import, after build_graphmodel") # translatecoords being True is the culprit which keeps resetting the node positions self.context.umlcanvas.displaymodel.build_view(translatecoords=False) # self.context.displaymodel.Dump(msg="import, after build_view") self.context.umlcanvas.GetDiagram().ShowAll(1) # need this, yes if workspace_was_empty: # don't layout if importing into canvas with existing shapes self.context.umlcanvas.layout_and_position_shapes() else: # At least remove overlaps self.context.overlap_remover.RemoveOverlaps(watch_removals=True) self.context.umlcanvas.mega_refresh() # self.context.wxapp.refresh_plantuml_view() wx.PostEvent(self.context.frame, RefreshPlantUmlEvent())
def parse_source(source_code, options, html_debug_root_name=""): old_debug_info_value = DEBUGINFO() with tempfile.NamedTemporaryFile( mode="wt") as temp: # TODO use streams not temporary files temp.write(source_code) temp.flush() if html_debug_root_name: # Normally debug info is false for performance reasons, so turn it on temporarily and restore it later set_DEBUGINFO(True) # create a html log file to contain html info log = LogWriter(html_debug_root_name, print_to_console=False) log.out_html_header() else: log = None try: pmodel, debuginfo = new_parser(temp.name, log=log, options=options) finally: set_DEBUGINFO(old_debug_info_value) if html_debug_root_name: log.out("<hr><h1>Errors:</h1>") log.out_wrap_in_html(pmodel.errors) log.out("<hr><h1>debuginfo:</h1>") log.out(debuginfo) log.out_html_footer() log.finish() print(f"html debug info is in '{log.out_filename}'") return pmodel, debuginfo
def test01(self): """ """ FILE = 'python-in/testmodule08_multiple_inheritance.py' #self.p, debuginfo = old_parser(FILE) self.p, debuginfo = new_parser(FILE) #print self.p # ------------------------------------------------------- gotevent1 = 0 gotevent2 = 0 gotevent3 = 0 gotevent4 = 0 gotevent5 = 0 gotevent6 = 0 gotevent7 = 0 for classname, classentry in self.p.classlist.items(): if classname == 'Fred': gotevent1 = 1 assert classentry.classesinheritsfrom == [ 'Mary', 'Sam' ], classentry.classesinheritsfrom if classname == 'MarySam': gotevent3 = False # should not get this assert gotevent1 assert not gotevent3
def test01(self): """ """ FILE = PYTHON_CODE_EXAMPLES_TO_PARSE + "testmodule08_multiple_inheritance.py" # self.p, debuginfo = old_parser(FILE) self.p, debuginfo = new_parser(FILE) # print self.p # ------------------------------------------------------- gotevent1 = 0 gotevent2 = 0 gotevent3 = 0 gotevent4 = 0 gotevent5 = 0 gotevent6 = 0 gotevent7 = 0 for classname, classentry in list(self.p.classlist.items()): if classname == "Fred": gotevent1 = 1 assert classentry.classesinheritsfrom == [ "Mary", "Sam", ], classentry.classesinheritsfrom if classname == "MarySam": gotevent3 = False # should not get this assert gotevent1 assert not gotevent3
def execute(self): assert self.files # these are tuples between class names. self.context.model.ClearAssociations( ) # WHY DO WE WANT TO DESTROY THIS VALUABLE INFO? if self.files: for f in self.files: #pmodel, debuginfo = old_parser(f) pmodel, debuginfo = new_parser(f) #from parsing.dump_pmodel import dump_old_structure #print dump_old_structure(pmodel) self.context.model.ConvertParseModelToUmlModel(pmodel) #p = PySourceAsJava() #p.optionModuleAsClass = 0 #p.verbose = 0 #p.Parse(f) #self.context.model.ConvertParseModelToUmlModel(p) self.context.umlwin.build_view() # Layout self.context.umlwin.layout_and_position_shapes()
def test_bug_pyplecs(self): """ """ # breakpoint() FILE = PYTHON_CODE_EXAMPLES_TO_PARSE + "testmodule_bug_pyplecs.py" # Can also run using # python3 pynsource-cli.py --mode 3 --graph tests/python-in/testmodule_bug_pyplecs.py # create a html log file to contain html info log = LogWriter(FILE, print_to_console=False) log.out_html_header() # Normally debug info is false for performance reasons, so turn it on temporarily and restore it later old_debug_info_value = DEBUGINFO() set_DEBUGINFO(True) try: pmodel, debuginfo = new_parser(FILE, log, options={"mode": 3}) finally: set_DEBUGINFO(old_debug_info_value) # this log finishing is all written out automatically in new_parser / parse / _convert_ast_to_old_parser # if there is an error- otherwise we have to do it ourselves. # if not pmodel.errors: # log.out("<hr><h1>Errors (shouldn't be any):</h1>") # log.out_wrap_in_html(pmodel.errors) log.out("<hr><h1>debuginfo:</h1>") log.out(debuginfo) log.out_html_footer() log.finish() self.assertEqual(pmodel.errors, "")
def execute(self): assert self.files # these are tuples between class names. self.context.model.ClearAssociations() # WHY DO WE WANT TO DESTROY THIS VALUABLE INFO? if self.files: for f in self.files: #pmodel, debuginfo = old_parser(f) pmodel, debuginfo = new_parser(f) #from parsing.dump_pmodel import dump_old_structure #print dump_old_structure(pmodel) self.context.model.ConvertParseModelToUmlModel(pmodel) #p = PySourceAsJava() #p.optionModuleAsClass = 0 #p.verbose = 0 #p.Parse(f) #self.context.model.ConvertParseModelToUmlModel(p) self.context.umlwin.build_view() # Layout self.context.umlwin.layout_and_position_shapes()
def reverse_engineer(files, mode, graph, methods_list, prop_decorator, version): """Pynsource CLI - Reverse engineer python source code into UML This command line tool doesn't actualy generate diagrams, but it does parse Python code into the underlying 'pmodel' (parse model) that the Pynsource GUI graphic diagrammer uses. Used for debugging. Examples of use: python3 ./src/pynsource-cli.py a.py b.py python3 ./src/pynsource-cli.py --graph src/common/command_pattern.py python3 ./src/pynsource-cli.py --methods-list src/common/*.py """ if version: click.echo(f"Pynsource CLI version {APP_VERSION}") click.echo(f"Files to parse: {files}") # click.echo(graph) # Expansion of files seems to happen magically via bash - need to check with windows # But if running via pycharm wildcards are not expanded, so play it safe and glob globbed = [] for param in files: files = glob.glob(param) globbed += files click.echo(globbed) if graph: displaymodel = DisplayModel(canvas=None) for f in globbed: pmodel, debuginfo = new_parser(f, options={ "mode": mode, "TREAT_PROPERTY_DECORATOR_AS_PROP": prop_decorator }) if pmodel.errors: print(pmodel.errors) if methods_list: # Dump simple list of methods click.echo(dump_pmodel_methods(pmodel)) else: # Dump table of underlying pmodel assert f == pmodel.filename click.echo(f"Parse model for '{pmodel.filename}':") click.echo(dump_pmodel(pmodel)) if graph: # Dump table of display model displaymodel.build_graphmodel(pmodel) # will append if graph: displaymodel.Dump( msg="Final display model Graph containing all parse models:")
def Parse(self, file): if self.ast_parsing: pmodel, debuginfo = new_parser(file) else: options = {"optionModuleAsClass": self.optionModuleAsClass} pmodel, debuginfo = old_parser(file, options) self.pmodel = pmodel # remember the parse model # break apart pmodel so that its attributes are on the report generator itself (legacy yukiness) self.classlist = pmodel.classlist self.modulemethods = pmodel.modulemethods
def execute(self): workspace_was_empty: bool = len( self.context.displaymodel.graph.nodes) == 0 pmodels = [] msgs = "" if self.files: for f in self.files: # pmodel, debuginfo = old_parser(f) # pmodel, debuginfo = new_parser(f) mode = getattr(self, "mode", 2) # print(f"Importing Python in syntax mode {mode}") pmodel, debuginfo = new_parser(f, options={"mode": mode}) if pmodel.errors: # print(pmodel.errors) msgs += pmodel.errors + "\n" else: pmodels.append(pmodel) # from parsing.dump_pmodel import dump_old_structure # print(dump_old_structure(pmodel)) self.context.displaymodel.build_graphmodel(pmodel) # self.context.displaymodel.Dump(msg="import, after build_graphmodel") msgs += "\n" for pmodel in pmodels: msgs += f"{os.path.basename(pmodel.filename)} detected {len(pmodel.classlist)} classes.\n" if msgs: dlg = wx.MessageDialog(self.context.frame, msgs, "Import Notes", wx.ICON_WARNING) dlg.ShowModal() # translatecoords being True is the culprit which keeps resetting the node positions self.context.umlcanvas.displaymodel.build_view( translatecoords=False) # self.context.displaymodel.Dump(msg="import, after build_view") self.context.umlcanvas.GetDiagram().ShowAll(1) # need this, yes if workspace_was_empty: # don't layout if importing into canvas with existing shapes self.context.umlcanvas.layout_and_position_shapes() else: # At least remove overlaps self.context.overlap_remover.RemoveOverlaps( watch_removals=True) self.context.umlcanvas.mega_refresh() # self.context.wxapp.refresh_plantuml_view() wx.PostEvent(self.context.frame, RefreshPlantUmlEvent())
def test(): # FILE = "tests/python-in/testmodule01.py" FILE = "tests/python-in/testmodule66.py" strategy = "ast_via_api" # 'old' or 'old_via_api' if strategy == "old": p = PynsourcePythonParser() # p.optionModuleAsClass = True p.Parse(FILE) pmodel = p.pmodel elif strategy == "old_via_api": pmodel, debuginfo = old_parser(FILE) elif strategy == "ast_via_api": pmodel, debuginfo = new_parser(FILE) print((dump_old_structure(pmodel))) # TODO this could be another generate code reporter plugin
def test_parse_power_operator(self): """ """ FILE = 'python-in/testmodule11_incoming_bugs.py' #self.p, debuginfo = old_parser(FILE) self.p, debuginfo = new_parser(FILE) #print self.p # ------------------------------------------------------- gotevent1 = 0 gotevent2 = 0 for classname, classentry in self.p.classlist.items(): if classname == 'Incoming1': gotevent1 = 1 assert gotevent1
def test_parse_power_operator(self): """ """ FILE = PYTHON_CODE_EXAMPLES_TO_PARSE + "testmodule11_incoming_bugs.py" # self.p, debuginfo = old_parser(FILE) self.p, debuginfo = new_parser(FILE) # print self.p # ------------------------------------------------------- gotevent1 = 0 gotevent2 = 0 for classname, classentry in list(self.p.classlist.items()): if classname == "Incoming1": gotevent1 = 1 assert gotevent1
def parse_source(source_code, options, html_debug_root_name=""): old_debug_info_value = DEBUGINFO() # Re temporary files, win10 needs delete=False otherwise other routines cannot access. # Need to pass "wt" since we're writing text, not bytes - helps python3 compatibility. with tempfile.NamedTemporaryFile( mode="wt", delete=False) as temp: # TODO use streams not temporary files temp.write(source_code) temp.flush() if html_debug_root_name: # Normally debug info is false for performance reasons, so turn it on temporarily and restore it later set_DEBUGINFO(True) # create a html log file to contain html info log = LogWriter(html_debug_root_name, print_to_console=False) log.out_html_header() else: log = None try: pmodel, debuginfo = new_parser(temp.name, log=log, options=options) finally: set_DEBUGINFO(old_debug_info_value) if html_debug_root_name: log.ensure_is_open() # file is sometimes closed, so reopen it log.out("<hr><h1>Errors:</h1>") log.out_wrap_in_html(pmodel.errors) log.out("<hr><h1>debuginfo:</h1>") log.out(debuginfo) log.out_html_footer() log.finish() print( f"\nHTML LOG parsing debug info is in {os.path.abspath(log.out_filename)}" ) return pmodel, debuginfo
def reverse_engineer(files, mode, graph, prop_decorator, version): """reverse engineer python source code""" if version: click.echo(f"Pynsource CLI version {APP_VERSION}") click.echo(f"Files to parse: {files}") # click.echo(graph) # Expansion of files seems to happen magically via bash - need to check with windows # But if running via pycharm wildcards are not expanded, so play it safe and glob globbed = [] for param in files: files = glob.glob(param) globbed += files click.echo(globbed) if graph: displaymodel = DisplayModel(canvas=None) for f in globbed: pmodel, debuginfo = new_parser(f, options={ "mode": mode, "TREAT_PROPERTY_DECORATOR_AS_PROP": prop_decorator }) if pmodel.errors: print(pmodel.errors) click.echo(f"Parse model for '{f}':") click.echo(dump_pmodel(pmodel)) if graph: displaymodel.build_graphmodel(pmodel) # will append if graph: displaymodel.Dump( msg="Final display model Graph containing all parse models:")
def test_1(self): in_filename = 'tests/testing-generate-java/python-in/utilcc.py' p, debuginfo = old_parser(in_filename) pmodel_old = p.pmodel pmodel_new, debuginfo = new_parser(in_filename) # print pmodel_old.modulemethods # print pmodel_new.modulemethods old = set(pmodel_old.modulemethods) new = set(pmodel_new.modulemethods) any_changes = old ^ new differences_expected = set(['safeconvert', 'PopFoldersTillFind']) # no_changes = set() # self.assertSetEqual(any_changes, no_changes, any_changes) # Nested methods are not picked up by the new ast parser self.assertSetEqual(any_changes, differences_expected, any_changes)
def ParseArgsAndRun(): import sys, glob import getopt # good doco http://www.doughellmann.com/PyMOTW/getopt/ # should possibly upgrade to using http://docs.python.org/library/argparse.html#module-argparse SIMPLE = 0 globbed = [] optionVerbose = 0 optionModuleAsClass = 0 optionExportToJava = 0 optionExportToDelphi = 0 optionExportToYuml = False option_export_to_plant_uml = False option_run_experiment = False option_show_parse_model = False optionExportTo_outdir = '' if SIMPLE: params = sys.argv[1] globbed = glob.glob(params) else: listofoptionvaluepairs, params = getopt.getopt(sys.argv[1:], "amvy:j:d:xp:l:") #print listofoptionvaluepairs, params #print dict(listofoptionvaluepairs) # turn e.g. [('-v', ''), ('-y', 'fred.png')] into nicer? dict e.g. {'-v': '', '-y': 'fred.png'} def EnsurePathExists(outdir, outlanguagemsg): assert outdir, 'Need to specify output folder for %s output - got %s.' % ( 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 '-x' == optionvaluepair[0]: option_run_experiment = True if '-p' == optionvaluepair[0]: # print "picked up -p parameter, globbed is", globbed, 'params', params option_show_parse_model = True if '-a' == optionvaluepair[0]: pass # default is asciart, so don't need to specify 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) if optionvaluepair[0] in ('-y'): optionExportToYuml = True optionExportTo_outpng = optionvaluepair[1] if optionvaluepair[0] in ('-l'): option_export_to_plant_uml = True optionExportTo_outpng = optionvaluepair[1] for param in params: files = glob.glob(param) globbed += files if globbed: if optionExportToJava or optionExportToDelphi: if optionExportToJava: u = CmdLinePythonToJava(globbed, treatmoduleasclass=optionModuleAsClass, verbose=optionVerbose) else: u = CmdLinePythonToDelphi( globbed, treatmoduleasclass=optionModuleAsClass, verbose=optionVerbose) u.ExportTo(optionExportTo_outdir) elif optionExportToYuml: u = CmdLinePythonToYuml(globbed, treatmoduleasclass=optionModuleAsClass, verbose=optionVerbose) u.ExportTo(optionExportTo_outpng) elif option_export_to_plant_uml: u = CmdLinePythonToPlantUml(globbed, treatmoduleasclass=optionModuleAsClass, verbose=optionVerbose) u.ExportTo(optionExportTo_outpng) elif option_show_parse_model: for f in globbed: pmodel, debuginfo = new_parser(f) print(dump_old_structure(pmodel)) else: u = CmdLinePythonToAsciiArt(globbed, treatmoduleasclass=optionModuleAsClass, verbose=optionVerbose) u.ExportTo(None) else: if option_run_experiment: test() else: print common.messages.HELP_COMMAND_LINE_USAGE
def newparse(): model, debuginfo = new_parser(in_filename, log) d2 = dump_old_structure(model) log.out_wrap_in_html(d2, style_class='dump1') return d2, debuginfo
def newparse(options): model, debuginfo = new_parser(in_filename, log, options) d2 = dump_old_structure(model) log.out_wrap_in_html(d2, style_class='dump1') return d2, debuginfo