diff --git a/Decorators.py b/Decorators.py index 12728e8f..f2b32148 100644 --- a/Decorators.py +++ b/Decorators.py @@ -41,7 +41,7 @@ else: import wx.lib.agw.aui.framemanager AuiFloatingFrame = wx.lib.agw.aui.framemanager.AuiFloatingFrame - + def cond_decorator(flag, dec): def decorate(fn): return dec(fn) if flag else fn @@ -143,11 +143,10 @@ def wrapper(*args): return wrapper class ThreadWithReturnValue(threading.Thread): - def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None): - threading.Thread.__init__(self, group, target, name, args, kwargs, daemon=daemon) - + def __init__(self, *args, **kwargs): + super(ThreadWithReturnValue, self).__init__(*args, **kwargs) self._return = None - + def run(self): if self._target is not None: self._return = self._target(*self._args, **self._kwargs) @@ -160,9 +159,6 @@ def join(self): def ProgressNotification(f, arg): def wrapper(*args): - thread = ThreadWithReturnValue(target = f, args = args) - thread.start() - title = arg new_path = args[-1] if isinstance(new_path, str) and os.path.isfile(new_path): @@ -170,15 +166,21 @@ def wrapper(*args): else: message = _('Please wait..') - progress_dlg = wx.ProgressDialog(title, message, style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) + # main window + mainW = wx.GetApp().GetTopWindow() + + progress_dlg = wx.ProgressDialog(title, message, style=wx.PD_APP_MODAL|wx.PD_CAN_ABORT) + + thread = ThreadWithReturnValue(target = f, args = args) + thread.start() while thread.isAlive(): wx.MilliSleep(300) - progress_dlg.Pulse() + progress_dlg.Pulse() wx.SafeYield() progress_dlg.Destroy() - + return thread.join() return wrapper diff --git a/Menu.py b/Menu.py index 59ffd1dd..0a34a03c 100644 --- a/Menu.py +++ b/Menu.py @@ -97,6 +97,7 @@ ID_HELP = wx.ID_HELP ID_API_HELP = wx.NewIdRef() ID_UPDATE_PIP_PACKAGE = wx.NewIdRef() +ID_UPDATE_FROM_GIT = wx.NewIdRef() ID_CONTACT = wx.NewIdRef() ID_ABOUT = wx.ID_ABOUT @@ -479,12 +480,14 @@ def __init__(self, parent): helpModel = wx.MenuItem(self, ID_HELP, _('&DEVSimPy Help\tF1'), _("Help for DEVSimPy user")) apiModel = wx.MenuItem(self, ID_API_HELP, _('&DEVSimPy API\tF2'), _("API for DEVSimPy user")) - updatePipPackage = wx.MenuItem(self, ID_UPDATE_PIP_PACKAGE, _('Update PIP Packages\tF3'), _("Update pip packages")) + updatePipPackage = wx.MenuItem(self, ID_UPDATE_PIP_PACKAGE, _('Update PIP Packages\tF3'), _("Update of dependant pip packages")) + updateFromGit = wx.MenuItem(self, ID_UPDATE_FROM_GIT, _('Update From Git'), _("Update of DEVSimPy from Git archive")) contactModel = wx.MenuItem(self, ID_CONTACT, _('Contact the Author...'), _("Send mail to the author")) aboutModel = wx.MenuItem(self, ID_ABOUT, _('About DEVSimPy...'), _("About DEVSimPy")) helpModel.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH,'search.png'))) updatePipPackage.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH,'update.png'))) + updateFromGit.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH,'update.png'))) apiModel.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH,'api.png'))) contactModel.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH,'mail.png'))) aboutModel.SetBitmap(wx.Bitmap(os.path.join(ICON_PATH,'info.png'))) @@ -495,13 +498,15 @@ def __init__(self, parent): AppendItem(apiModel) self.AppendSeparator() AppendItem(updatePipPackage) + AppendItem(updateFromGit) self.AppendSeparator() AppendItem(aboutModel) AppendItem(contactModel) parent.Bind(wx.EVT_MENU, parent.OnHelp, id=ID_HELP) parent.Bind(wx.EVT_MENU, parent.OnAPI, id=ID_API_HELP) - parent.Bind(wx.EVT_MENU, parent.OnUpdatePiPPackage, id=ID_UPDATE_PIP_PACKAGE) + parent.Bind(wx.EVT_MENU, parent.OnUpdatPiPPackage, id=ID_UPDATE_PIP_PACKAGE) + parent.Bind(wx.EVT_MENU, parent.OnUpdatFromGit, id=ID_UPDATE_FROM_GIT) parent.Bind(wx.EVT_MENU, parent.OnAbout, id=ID_ABOUT) parent.Bind(wx.EVT_MENU, parent.OnContact, id=ID_CONTACT) diff --git a/Utilities.py b/Utilities.py index a5f84ad0..de9f33fb 100644 --- a/Utilities.py +++ b/Utilities.py @@ -34,13 +34,14 @@ import configparser import linecache import imp +import tempfile from copy import deepcopy import gettext _ = gettext.gettext from itertools import combinations - +from zipfile import ZipFile from io import StringIO if builtins.__dict__.get('GUI_FLAG',True): @@ -63,11 +64,14 @@ # Used to recurse subdirectories import fnmatch import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, http.client +from urllib.request import urlretrieve +import requests + import pip import importlib -from subprocess import call +from subprocess import call, check_output, check_call, CalledProcessError # Used for smooth (spectrum) try: @@ -175,7 +179,63 @@ def PyBuzyInfo(msg, time): del busy def updatePiP(): - call("python -m pip install --upgrade pip", shell=True) + """ + """ + try: + check_call("python -m pip install --upgrade pip", shell=True) + except CalledProcessError as ee: + print(ee.output) + return False + else: + return True + +def downloadFromURL(url): + """ + """ + + # downloading with requests + # download the file contents in binary format + r = requests.get(url) + + if r.status_code == 200: + # 200 means a successful request + + tempdir = tempfile.gettempdir() + fn = os.path.join(tempdir, "DEVSimPy.zip") + # open method to open a file on your system and write the contents + with open(fn, "wb") as code: + code.write(r.content) + + # downloading with urllib + # Copy a network object to a local file + urlretrieve(url, fn) + + return fn + + else: + return None + +def updateFromGit(): + """ + """ + + # specifying the zip file name + fn = downloadFromURL("https://github.com/capocchi/DEVSimPy/archive/master.zip") + + if fn: + # opening the zip file in READ mode + with ZipFile(fn, 'r') as zip: + # printing all the contents of the zip file + zip.printdir() + + # extracting all the files + print('Extracting all the files now...') + #zip.extractall() + print('Done!') + + return True + else: + return False def updatePackageWithPiP(): """ Update all installed package using pip @@ -184,14 +244,18 @@ def updatePackageWithPiP(): updatePiP() if pip.__version__ > '10.0.1': - import pkg_resources - packages = [dist.project_name for dist in pkg_resources.working_set if 'PyPubSub' not in dist.project_name] - call("pip install --user --upgrade -r requirements.txt", shell=True) + command = "pip install --user --upgrade -r requirements.txt" else: packages = [dist.project_name for dist in pip.get_installed_distributions() if 'PyPubSub' not in dist.project_name] - call("pip install --user --upgrade " + ' '.join(packages), shell=True) + command = "pip install --user --upgrade " + ' '.join(packages) - NotificationMessage(_('Information'), 'All pip packages have been updated!', None, timeout=5) + try: + check_call(command, shell=True) + except CalledProcessError as ee: + print(ee.output) + return False + else: + return True def install_and_import(package): """ Install and import the package diff --git a/devsimpy.py b/devsimpy.py index 835b8bd3..b2d4e25d 100644 --- a/devsimpy.py +++ b/devsimpy.py @@ -82,6 +82,8 @@ sys.stdout.write("Importing wxPython %s%s for python %s on %s (%s) platform...\n"%(wx.version(), " from devsimpy.ini" if ini_exist else '', platform.python_version(), platform.system(), platform.version())) +_ = wx.GetTranslation + try: import wx.aui as aui except: @@ -187,7 +189,7 @@ from PreferencesGUI import PreferencesGUI from pluginmanager import load_plugins, enable_plugin from which import which -from Utilities import GetUserConfigDir, install, install_and_import, updatePackageWithPiP, NotificationMessage +from Utilities import GetUserConfigDir, install, install_and_import, updatePackageWithPiP, updateFromGit, NotificationMessage from Decorators import redirectStdout, BuzyCursorNotification, ProgressNotification, cond_decorator from DetachedFrame import DetachedFrame from LibraryTree import LibraryTree @@ -2037,9 +2039,15 @@ def OnHelp(self, event): else: self.help.Display(os.path.join('html','toc.html')) - @cond_decorator(builtins.__dict__.get('GUI_FLAG',True), ProgressNotification("DEVSimPy Update pip packages")) - def OnUpdatePiPPackage(self, event): - updatePackageWithPiP() + @cond_decorator(builtins.__dict__.get('GUI_FLAG',True), ProgressNotification(_("Update of dependant pip packages."))) + def OnUpdatPiPPackage(self, event): + if updatePackageWithPiP(): + NotificationMessage(_('Information'), _('All pip packages that DEVSimPy depends have been updated!'), None, timeout=5) + + @cond_decorator(builtins.__dict__.get('GUI_FLAG',True), ProgressNotification(_("DEVSimPy Update from git."))) + def OnUpdatFromGit(self, event): + if updateFromGit(): + NotificationMessage(_('Information'), _('Update of DEVSimPy from git done!'), parent=self, timeout=5) def OnAPI(self, event): """ Shows the DEVSimPy API help file. """