diff --git a/Domain/Generator/RandomGenerator.py b/Domain/Generator/RandomGenerator.py index e1f2af8c..c30d7864 100644 --- a/Domain/Generator/RandomGenerator.py +++ b/Domain/Generator/RandomGenerator.py @@ -1,17 +1,20 @@ # -*- coding: utf-8 -*- - +""" +Name: RandomGenerator.py +Brief descritpion: Generate random message. +Author(s): L. Capocchi , B. Poggi +Version: 1.0 +Last modified: 2020.10.18 +GENERAL NOTES AND REMARKS: +GLOBAL VARIABLES AND FUNCTIONS: +""" from DomainInterface.DomainBehavior import DomainBehavior from DomainInterface.Object import Message import random class RandomGenerator(DomainBehavior): - """ - @author: Bastien POGGI - @organization: University Of Corsica - @contact: bpoggi@univ-corse.fr - @since: 2010.12.1 - @version: 1.0 + """ RandomGenerator Class. """ def __init__(self, minValue=0, maxValue=10, minStep=1, maxStep=1, start=0, choice=[]): diff --git a/Domain/Generator/XMLGenerator.py b/Domain/Generator/XMLGenerator.py index 25058f1c..faed568a 100644 --- a/Domain/Generator/XMLGenerator.py +++ b/Domain/Generator/XMLGenerator.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +''' XMLGenerator Model. +''' from Generator.Generator import * from xml.dom import minidom diff --git a/ImportLibrary.py b/ImportLibrary.py index d0ab41a6..b77b2279 100644 --- a/ImportLibrary.py +++ b/ImportLibrary.py @@ -88,6 +88,7 @@ def __init__(self, *args, **kw): # index = evt.GetItem().GetId() # self.CheckItem(index, False) + ### def AddItem(self, path, dName, check=False): """ Add item to the list. """ @@ -101,9 +102,11 @@ def AddItem(self, path, dName, check=False): self.SetData(index, path) self.SetItemData(index, index) + ### def GetData(self, id): return self.map[id] + ### def SetData(self, id, data): self.map.update({id:data}) @@ -118,6 +121,7 @@ class DeleteBox(wx.Dialog): """ Delete box for libraries manager. """ + ### def __init__(self, *args, **kwargs): """ Constructor. """ @@ -126,7 +130,8 @@ def __init__(self, *args, **kwargs): self.InitUI() self.SetSize((250, 200)) self.Centre() - + + ### def InitUI(self): """ Init the user interface. """ @@ -281,6 +286,7 @@ def __init__(self, *args, **kwargs): e = wx.SizeEvent(self.GetSize()) self.ProcessEvent(e) + ### def CheckDomainPath(self): """ """ @@ -291,6 +297,7 @@ def CheckDomainPath(self): dlg.ShowModal() dlg.Destroy() + ### def OnSelectAll(self, event): """ """ @@ -298,6 +305,7 @@ def OnSelectAll(self, event): for i in range(num): self._cb.CheckItem(i,True) + ### def OnDeselectAll(self, event): """ """ @@ -305,6 +313,7 @@ def OnDeselectAll(self, event): for i in range(num): self._cb.CheckItem(i, False) + ### def OnItemRightClick(self, evt): """Launcher creates wxMenu. """ @@ -335,6 +344,7 @@ def OnItemRightClick(self, evt): menu.Destroy() # destroy to avoid mem leak + ### def DocDirectory(self, path): """ Return doc of all modules composing path directory by reading its __ini__.py """ @@ -372,6 +382,7 @@ def DocDirectory(self, path): return doc + ### def OnDoc(self, evt): """ Documentation of item has been invocked. """ @@ -392,6 +403,7 @@ def OnDoc(self, evt): d.CenterOnParent(wx.BOTH) d.ShowModal() + ### def OnDelete(self, evt): """ Delete Button has been clicked. """ @@ -427,6 +439,7 @@ def OnDelete(self, evt): self._cb.DeleteItem(index) + ### def EvtCheckListBox(self, evt): """ """ @@ -465,6 +478,7 @@ def CreateInitFile(path): f.write("\t\t'%s', \n"%name) f.write('\t\t ]') + ### def OnNew(self, event): """ """ @@ -481,7 +495,7 @@ def OnNew(self, event): # Checking if the list is empty or not if len(dir) == 0: if not '__init__.py' in dir: - self.CreateInitFile(path) + ImportLibrary.CreateInitFile(path) self.DoAdd(path, os.path.basename(path)) @@ -504,6 +518,7 @@ def OnNew(self, event): dial = wx.MessageDialog(self, _('%s is already imported!')%dName, _('New librarie manager'), wx.OK|wx.ICON_INFORMATION) dial.ShowModal() + ### def DoAdd(self, path, dName): """ """ @@ -522,17 +537,18 @@ def DoAdd(self, path, dName): if not path.startswith('http') and (not os.path.exists(os.path.join(path,'__init__.py') and len(os.listdir(path)) == 0)): dial = wx.MessageDialog(self, _('%s directory has no __init__.py file.\nDo you want to create it?')%path, _('New librarie Manager'), wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) if dial.ShowModal() == wx.ID_YES: - self.CreateInitFile(path) + ImportLibrary.CreateInitFile(path) dial.Destroy() - NotificationMessage(_('Information'), _("Librarie %s has been succeffully added!")%dName, self, timeout=5) - + NotificationMessage(_('Information'), _("Library %s has been succeffully added!")%dName, self, timeout=5) + ### def OnAdd(self, evt): """ """ self.OnNew(evt) - + + ### def OnCloseWindow(self, event): """ """ diff --git a/LibraryTree.py b/LibraryTree.py index e4661557..27aefc22 100644 --- a/LibraryTree.py +++ b/LibraryTree.py @@ -19,10 +19,9 @@ import sys import urllib.parse import http.client -import copy import inspect import zipfile -import subprocess +#import subprocess import importlib import tempfile import shutil @@ -35,7 +34,7 @@ from Components import BlockFactory, DEVSComponent, GetClass, PyComponent, GenericComponent from ZipManager import Zip, getPythonModelFileName from ReloadModule import recompile -from ImportLibrary import DeleteBox +from ImportLibrary import DeleteBox, ImportLibrary from Complexity import GetMacCabeMetric from pubsub import pub @@ -193,14 +192,19 @@ def OnMotion(self, evt): path = self.GetItemData(item) - if os.path.isdir(path): model_list = self.GetModelList(path) domain_list = self.GetDomainList(path) - tip = '\n'.join(model_list) if model_list else "" - tip += '\n' - tip += '\n'.join(domain_list) if domain_list else "" + if model_list: + tip = _("Models:\n -") + tip += '\n -'.join(model_list) + tip += '\n' + else: + tip = "" + + tip += _("\nSub-Domains:\n") + tip += '\n -'.join(domain_list) ### is last item else: @@ -219,7 +223,8 @@ def OnMotion(self, evt): ### add maccabe metric info if item in self.MetricDico: mcc = self.MetricDico[item]['mcc'] - tip =''.join([tip,'\n','macCabe metric: %d'%mcc]) + size = self.MetricDico[item]['size'] + tip =''.join([tip,'\n\n',_('MacCabe metric: %d')%mcc,'\n\n',_('Size (bytes): %d')%size]) self.SetToolTip(tip) @@ -306,21 +311,40 @@ def OnDelete(self, evt): item = self.GetFocusedItem() if item.IsOk(): path = self.GetItemPyData(item) + + ### msgbox to select what you wan to delete: file or/and item ? + db = DeleteBox(self, wx.NewIdRef(), _("Delete Options")) - if path and os.path.exists(path): - ### msgbox to select what you wan to delete: file or/and item ? - db = DeleteBox(self, wx.NewIdRef(), _("Delete Options")) + if db.ShowModal() == wx.ID_OK: - if db.ShowModal() == wx.ID_OK: + ### delete file + if db.rb2.GetValue(): + label = os.path.basename(path) - ### delete file - if db.rb2.GetValue(): - label = os.path.basename(path) - dial = wx.MessageDialog(None, _('Are you sure to delete the python file %s ?')%(label), label, wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + if os.path.isdir(path): + + dial = wx.MessageDialog(None, _('Are you sure to delete from disk the librairie %s ?')%(label), label, wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + if dial.ShowModal() == wx.ID_YES: + try: + ### delete directory + shutil.rmtree(path) + + ### delete item + self.RemoveItem(item) + + except Exception as info: + sys.stdout.write(_("%s not deleted!\n Error: %s")%(label,info)) + + dial.Destroy() + + else: + + dial = wx.MessageDialog(None, _('Are you sure to delete from disk the python file %s ?')%(label), label, wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if dial.ShowModal() == wx.ID_YES: try: ### delete file os.remove(path) + ### delete item self.RemoveItem(item) @@ -330,13 +354,13 @@ def OnDelete(self, evt): dial.Destroy() - else: - self.RemoveItem(item) + else: + self.RemoveItem(item) - ###TODO unload associated module + ###TODO unload associated module - else: - wx.MessageBox(_("No library selected!"),_("Delete Manager")) + else: + wx.MessageBox(_("No library selected!"),_("Delete Manager")) def UpdateSubLib(self, path:str)->bool: """ Do update lib. @@ -399,11 +423,12 @@ def OnNewModel(self, evt): wx.OK | wx.ICON_ERROR) dlg.ShowModal() - item = self.ItemDico[os.path.dirname(gmwiz.model_path)] - self.UpdateDomain(self.GetPyData(item)) + else: + item = self.ItemDico[os.path.dirname(gmwiz.model_path)] + self.UpdateDomain(self.GetPyData(item)) - ### sort all item - self.SortChildren(self.root) + ### sort all item + self.SortChildren(self.root) # Cleanup if gmwiz: gmwiz.Destroy() @@ -411,7 +436,30 @@ def OnNewModel(self, evt): def OnNewDir(self, evt): """ New dir has been invoked. """ - pass + parent_item = self.GetFocusedItem() + parent_item_path = self.GetPyData(parent_item) + + dialog = wx.DirDialog(self, _("Choose a new directory:"), parent_item_path, style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON) + new_path = dialog.GetPath() if dialog.ShowModal() == wx.ID_OK else None + dialog.Destroy() + + if new_path: + # Getting the list of directories + new_dir = os.listdir(new_path) + if len(new_dir) == 0: + if not '__init__.py' in new_dir: + ImportLibrary.CreateInitFile(new_path) + + ### add the new sub librarie + self.InsertNewDomain(new_path, parent_item) + + ### update of the parent domain imply the remove of the sub directory in the tree + ### after the new sud dir creation, you must create new model inside in order take the sub directory alive in the lib tree + ### if no new model is created in the new dir, it desaper during the updated of the domain! + #self.UpdateDomain(parent_item_path) + + ### sort all item + #self.SortChildren(self.root) ### def GetDomainList(self, dName): @@ -461,6 +509,7 @@ def GetPYFileList(dName, ext=".py"): ### import are here because the simulator (PyDEVS or PyPDEVS) require it from DomainInterface.DomainBehavior import DomainBehavior + from DomainInterface.DomainStructure import DomainStructure try: name_list = getPYFileListFromInit(os.path.join(dName,'__init__.py'), ext) @@ -486,11 +535,11 @@ def GetPYFileList(dName, ext=".py"): if cls is not None and not isinstance(cls, tuple): - ### only model that herite from DomainBehavior is shown in lib - if issubclass(cls, DomainBehavior): + ### only model that herite from DomainBehavior or DomainStructure is shown in lib + if issubclass(cls, DomainBehavior) or issubclass(cls, DomainStructure): py_file_list.append(s) else: - sys.stderr.write(_("%s not imported: Class is not DomainBehavior\n"%(s))) + sys.stderr.write(_("%s not imported: Class is not DomainBehavior (atomic) or DomainStructure (coupled)\n"%(s))) ### If cls is tuple, there is an error but we load the model to correct it. ### If its not DEVS model, the Dnd don't allows the instantiation and when the error is corrected, it don't appear before a update. @@ -563,7 +612,6 @@ def AddComponent(self, item, parentPath, parent, p=None): ### check error error = isinstance(module, Exception) or not Zip.GetBehavioralPythonFile(path) - ### defalut mcc is null mcc = 0.0 ### change icon depending on the error and the presence of image in amd @@ -581,6 +629,9 @@ def AddComponent(self, item, parentPath, parent, p=None): ### insert into the tree id = self.InsertItemBefore(p if p else parent, 0, os.path.splitext(item)[0], img, img) + + ### size of model + size = 0 if error else sys.getsizeof(module) else: path = os.path.join(parentPath, "".join([item,'.py'])) if not come_from_net else "".join([parentPath,'/',item,'.py']) @@ -604,12 +655,17 @@ def AddComponent(self, item, parentPath, parent, p=None): #mcc = float(subprocess.check_output('python {} {}'.format('Complexity.py', path), shell = True)) mcc = GetMacCabeMetric(path) + ### size of model + size = sys.getsizeof(devs) if not error else 0 + self.SetPyData(id, path) - self.MetricDico.update({id:{'mcc':mcc, 'parent':parent}}) - s = sum([d['mcc'] for id,d in self.MetricDico.items() if d['parent']==parent]) - self.MetricDico.update({parent:{'mcc':s, 'parent':None}}) + self.MetricDico.update({id:{'mcc':mcc, 'parent':parent, 'size':size}}) + mcc_sum = sum([d['mcc'] for id,d in self.MetricDico.items() if d['parent']==parent]) + size_sum = sum([d['size'] for id,d in self.MetricDico.items() if d['parent']==parent]) + self.MetricDico.update({parent:{'mcc':mcc_sum, 'parent':None, 'size':size_sum}}) + return (id, error) ### @@ -687,8 +743,8 @@ def InsertNewDomain(self, dName, parent, L = []): self.ItemDico.update({parentPath:id}) self.SetPyData(id,parentPath) - self.MetricDico.update({id:{'mcc':0.0, 'parent':parent}}) - self.MetricDico.update({parent:{'mcc':0.0, 'parent':None}}) + self.MetricDico.update({id:{'mcc':0.0, 'parent':parent, 'size':0}}) + self.MetricDico.update({parent:{'mcc':0.0, 'parent':None, 'size':0}}) ### for the childrens of the sub-domain for elem in list(item.values())[0]: @@ -742,7 +798,7 @@ def InsertNewDomain(self, dName, parent, L = []): ### def GetSubDomain(self, dName, domainSubList = []): - """ Get the dico composed by all of the sub domain of dName + """ Get the dico composed by all of the sub domain of dName. (like{'../Domain/PowerSystem': ['PSDomainStructure', 'PSDomainBehavior', 'Object', 'PSSDB', {'../Domain/PowerSystem/Rt': []}, {'../Domain/PowerSystem/PowerMachine': ['toto.cmd', 'Integrator.cmd', 'titi.cmd', 'Mymodel.cmd', {'../Domain/PowerSystem/PowerMachine/TOTO': []}]}, {'../Domain/PowerSystem/Sources': ['StepGen', 'SinGen', 'CosGen', 'RampGen', 'PWMGen', 'PulseGen', 'TriphaseGen', 'ConstGen']}, {'../Domain/PowerSystem/Sinks': ['To_Disk', 'QuickScope']}, {'../Domain/PowerSystem/MyLib': ['', 'model.cmd']}, {'../Domain/PowerSystem/Hybrid': []}, {'../Domain/PowerSystem/Continuous': ['WSum', 'Integrator', 'Gain', 'Gain2', 'NLFunction']}]} ) """ @@ -961,7 +1017,7 @@ def RemoveItem(self, item): bn = os.path.basename(self.GetPyData(item)) ### delete all references from the ItemDico - for key in copy.copy(self.ItemDico): + for key in self.ItemDico.copy(): if bn in key.split(os.sep): del self.ItemDico[key] @@ -1170,10 +1226,14 @@ def OnItemDocumentation(self, evt): else: doc = inspect.getdoc(module) - ### Add maccabe complexity measure - doc += "".join([_("\n\n MacCabe Complexity: %d")%self.MetricDico[item]['mcc']]) - if doc: + + ### Add maccabe complexity measure + doc += "".join([_("\n\n MacCabe Complexity: %f")%self.MetricDico[item]['mcc']]) + + ### Add maccabe complexity measure + doc += "".join([_("\n\n Size (bytes): %d")%self.MetricDico[item]['size']]) + dlg = wx.lib.dialogs.ScrolledMessageDialog(self, doc, _("%s Documentation")%name, style=wx.OK|wx.ICON_EXCLAMATION|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) dlg.CenterOnParent(wx.BOTH) dlg.ShowModal() @@ -1189,15 +1249,19 @@ def OnLibDocumentation(self, evt): path = self.GetItemPyData(item) name = self.GetItemText(item) - doc = "Path of lib: %s\n"%path + ### Path of the lib + doc = "Path: %s"%path - if doc: - dlg = wx.lib.dialogs.ScrolledMessageDialog(self, doc, _("%s Documentation")%name, style=wx.OK|wx.ICON_EXCLAMATION|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) - dlg.CenterOnParent(wx.BOTH) - dlg.ShowModal() - else: - wx.MessageBox(_("No documentation!\nPlease define the documentation of the model %s in the header of its python file.")%name, _("%s Documentation")%name, wx.OK|wx.ICON_INFORMATION) + ### Add maccabe complexity measure + doc += "".join([_("\n\n MacCabe Complexity: %f")%self.MetricDico[item]['mcc']]) + + ### Add maccabe complexity measure + doc += "".join([_("\n\n Size (bytes): %d")%self.MetricDico[item]['size']]) + dlg = wx.lib.dialogs.ScrolledMessageDialog(self, doc, _("%s Documentation")%name, style=wx.OK|wx.ICON_EXCLAMATION|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) + dlg.CenterOnParent(wx.BOTH) + dlg.ShowModal() + ### def OnInfo(self, event): """ diff --git a/Menu.py b/Menu.py index 3f3503b8..6da57a29 100644 --- a/Menu.py +++ b/Menu.py @@ -754,21 +754,27 @@ def __init__(self, parent): path = parent.GetItemPyData(item) if os.path.isdir(path): - new_model = wx.MenuItem(self, ID_NEW_MODEL_LIB, _('New model'), _('Add a new model to the selected library')) + + new_submenu = wx.Menu() + + new_model = wx.MenuItem(new_submenu, ID_NEW_MODEL_LIB, _('Model'), _('Add a new model to the selected library')) + new_dir = wx.MenuItem(new_submenu, ID_NEW_DIR_LIB, _('Sub-directory'), _('Add a new sub directory to the selected library')) + rename_dir = wx.MenuItem(self, ID_RENAME_DIR_LIB, _('Rename'), _('Rename selected librarie')) + update_lib = wx.MenuItem(self, ID_UPDATE_SUBLIB, _('Update'), _('Update all models of the selected library')) + doc = wx.MenuItem(self, wx.NewIdRef(), _('Documentation'), _('Documentation of selected library')) + new_model.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH_16_16, 'new.png'))) - InsertItem(0, new_model) - new_dir = wx.MenuItem(self, ID_NEW_DIR_LIB, _('New sub directory'), _('Add a directory to the selected library')) new_dir.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH_16_16, 'new.png'))) - InsertItem(1, new_dir) - rename_dir = wx.MenuItem(self, ID_RENAME_DIR_LIB, _('Rename'), _('Rename selected librarie')) rename_dir.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH_16_16,'rename.png'))) - InsertItem(2, rename_dir) - update_lib = wx.MenuItem(self, ID_UPDATE_SUBLIB, _('Update'), _('Update all models of the selected library')) update_lib.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH_16_16, 'db_refresh2.png'))) - InsertItem(3, update_lib) - doc = wx.MenuItem(self, wx.NewIdRef(), _('Documentation'), _('Documentation of selected library')) doc.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH_16_16,'doc.png'))) - InsertItem(4, doc) + + new_submenu.Append(new_model) + new_submenu.Append(new_dir) + AppendMenu(self, -1, _('Add'), new_submenu) + AppendItem(rename_dir) + AppendItem(update_lib) + AppendItem(doc) self.Bind(wx.EVT_MENU, parent.OnNewModel, id=ID_NEW_MODEL_LIB) self.Bind(wx.EVT_MENU, parent.OnDirRename, id=ID_RENAME_DIR_LIB) diff --git a/Utilities.py b/Utilities.py index d9ad7889..24f541e2 100644 --- a/Utilities.py +++ b/Utilities.py @@ -74,7 +74,7 @@ import pip import importlib -from subprocess import call, check_output, check_call, Popen, PIPE +from subprocess import call, check_call, Popen, PIPE # Used for smooth (spectrum) try: