diff options
author | rahulp13 | 2020-03-17 14:55:41 +0530 |
---|---|---|
committer | rahulp13 | 2020-03-17 14:55:41 +0530 |
commit | 296443137f4288cb030e92859ccfbe3204bc1088 (patch) | |
tree | ca4798c2da1e7244edc3bc108d81b462b537aea2 /lib/python2.7/site-packages/wxversion.py | |
parent | 0db48f6533517ecebfd9f0693f89deca28408b76 (diff) | |
download | KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.tar.gz KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.tar.bz2 KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.zip |
initial commit
Diffstat (limited to 'lib/python2.7/site-packages/wxversion.py')
-rw-r--r-- | lib/python2.7/site-packages/wxversion.py | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/wxversion.py b/lib/python2.7/site-packages/wxversion.py new file mode 100644 index 0000000..94fd881 --- /dev/null +++ b/lib/python2.7/site-packages/wxversion.py @@ -0,0 +1,528 @@ +#---------------------------------------------------------------------- +# Name: wxversion +# Purpose: Allows a wxPython program to search for alternate +# installations of the wxPython packages and modify sys.path +# so they will be found when "import wx" is done. +# +# Author: Robin Dunn +# +# Created: 24-Sept-2004 +# RCS-ID: $Id$ +# Copyright: (c) 2004 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------- + +""" +If you have more than one version of wxPython installed this module +allows your application to choose which version of wxPython will be +imported when it does 'import wx'. The main function of this module +is `select` and you use it like this:: + + import wxversion + wxversion.select('2.4') + import wx + +Or additional build options can also be selected, although they will +not be required if they are not installed, like this:: + + import wxversion + wxversion.select('2.5.3-unicode') + import wx + +Or you can require an exact match on the build options like this:: + + import wxversion + wxversion.select('2.5.3-unicode', optionsRequired=True) + import wx + +Finally you can also specify a collection of versions that are allowed +by your application, like this:: + + import wxversion + wxversion.select(['2.5.4', '2.5.5', '2.6']) + import wx + + +Of course the default wxPython version can also be controlled by +setting PYTHONPATH or by editing the wx.pth path configuration file, +but using wxversion will allow an application to manage the version +selection itself rather than depend on the user to setup the +environment correctly. + +It works by searching the sys.path for directories matching wx-* and +then comparing them to what was passed to the select function. If a +match is found then that path is inserted into sys.path. + +NOTE: If you are making a 'bundle' of your application with a tool +like py2exe then you should *not* use the wxversion module since it +looks at the filesystem for the directories on sys.path, it will fail +in a bundled environment. Instead you should simply ensure that the +version of wxPython that you want is found by default on the sys.path +when making the bundled version by setting PYTHONPATH. Then that +version will be included in your bundle and your app will work as +expected. Py2exe and the others usually have a way to tell at runtime +if they are running from a bundle or running raw, so you can check +that and only use wxversion if needed. For example, for py2exe:: + + if not hasattr(sys, 'frozen'): + import wxversion + wxversion.select('2.5') + import wx + +More documentation on wxversion and multi-version installs can be +found at: http://wiki.wxpython.org/index.cgi/MultiVersionInstalls + +""" + +import re, sys, os, glob, fnmatch + + +_selected = None +class VersionError(Exception): + pass + +class AlreadyImportedError(VersionError): + pass + +#---------------------------------------------------------------------- + +def select(versions, optionsRequired=False): + """ + Search for a wxPython installation that matches version. If one + is found then sys.path is modified so that version will be + imported with a 'import wx', otherwise a VersionError exception is + raised. This function should only be called once at the beginning + of the application before wxPython is imported. + + :param versions: Specifies the version to look for, it can + either be a string or a list of strings. Each string is + compared to the installed wxPythons and the best match is + inserted into the sys.path, allowing an 'import wx' to + find that version. + + The version string is composed of the dotted version + number (at least 2 of the 4 components) optionally + followed by hyphen ('-') separated options (wx port, + unicode/ansi, flavour, etc.) A match is determined by how + much of the installed version matches what is given in the + version parameter. If the version number components don't + match then the score is zero, otherwise the score is + increased for every specified optional component that is + specified and that matches. + + Please note, however, that it is possible for a match to + be selected that doesn't exactly match the versions + requested. The only component that is required to be + matched is the version number. If you need to require a + match on the other components as well, then please use the + optional ``optionsRequired`` parameter described next. + + :param optionsRequired: Allows you to specify that the other + components of the version string (such as the port name + or character type) are also required to be present for an + installed version to be considered a match. Using this + parameter allows you to change the selection from a soft, + as close as possible match to a hard, exact match. + + """ + if type(versions) == str: + versions = [versions] + + global _selected + if _selected is not None: + # A version was previously selected, ensure that it matches + # this new request + for ver in versions: + if _selected.Score(_wxPackageInfo(ver), optionsRequired) > 0: + return + # otherwise, raise an exception + raise VersionError("A previously selected wx version does not match the new request.") + + # If we get here then this is the first time wxversion is used, + # ensure that wxPython hasn't been imported yet. + if sys.modules.has_key('wx') or sys.modules.has_key('wxPython'): + raise AlreadyImportedError("wxversion.select() must be called before wxPython is imported") + + # Look for a matching version and manipulate the sys.path as + # needed to allow it to be imported. + installed = _find_installed(True) + bestMatch = _get_best_match(installed, versions, optionsRequired) + + if bestMatch is None: + raise VersionError("Requested version of wxPython not found") + + sys.path.insert(0, bestMatch.pathname) + # q.v. Bug #1409256 + path64 = re.sub('/lib/','/lib64/',bestMatch.pathname) + if os.path.isdir(path64): + sys.path.insert(0, path64) + _selected = bestMatch + +#---------------------------------------------------------------------- + +UPDATE_URL = "http://wxPython.org/" +#UPDATE_URL = "http://sourceforge.net/project/showfiles.php?group_id=10718" + +_EM_DEBUG=0 + +def ensureMinimal(minVersion, optionsRequired=False): + """ + Checks to see if the default version of wxPython is greater-than + or equal to `minVersion`. If not then it will try to find an + installed version that is >= minVersion. If none are available + then a message is displayed that will inform the user and will + offer to open their web browser to the wxPython downloads page, + and will then exit the application. + """ + assert type(minVersion) == str + + # ensure that wxPython hasn't been imported yet. + if sys.modules.has_key('wx') or sys.modules.has_key('wxPython'): + raise AlreadyImportedError("wxversion.ensureMinimal() must be called before wxPython is imported") + + bestMatch = None + minv = _wxPackageInfo(minVersion) + + # check the default version first + defaultPath = _find_default() + if defaultPath: + defv = _wxPackageInfo(defaultPath, True) + if defv >= minv and minv.CheckOptions(defv, optionsRequired): + bestMatch = defv + + # if still no match then check look at all installed versions + if bestMatch is None: + installed = _find_installed() + # The list is in reverse sorted order, so find the first + # one that is big enough and optionally matches the + # options + for inst in installed: + if inst >= minv and minv.CheckOptions(inst, optionsRequired): + bestMatch = inst + break + + # if still no match then prompt the user + if bestMatch is None: + if _EM_DEBUG: # We'll do it this way just for the test code below + raise VersionError("Requested version of wxPython not found") + + import wx, webbrowser + versions = "\n".join([" "+ver for ver in getInstalled()]) + app = wx.App() + result = wx.MessageBox("This application requires a version of wxPython " + "greater than or equal to %s, but a matching version " + "was not found.\n\n" + "You currently have these version(s) installed:\n%s\n\n" + "Would you like to download a new version of wxPython?\n" + % (minVersion, versions), + "wxPython Upgrade Needed", style=wx.YES_NO) + if result == wx.YES: + webbrowser.open(UPDATE_URL) + app.MainLoop() + sys.exit() + + sys.path.insert(0, bestMatch.pathname) + # q.v. Bug #1409256 + path64 = re.sub('/lib/','/lib64/',bestMatch.pathname) + if os.path.isdir(path64): + sys.path.insert(0, path64) + global _selected + _selected = bestMatch + + +#---------------------------------------------------------------------- + +def checkInstalled(versions, optionsRequired=False): + """ + Check if there is a version of wxPython installed that matches one + of the versions given. Returns True if so, False if not. This + can be used to determine if calling `select` will succeed or not. + + :param versions: Same as in `select`, either a string or a list + of strings specifying the version(s) to check for. + + :param optionsRequired: Same as in `select`. + """ + + if type(versions) == str: + versions = [versions] + installed = _find_installed() + bestMatch = _get_best_match(installed, versions, optionsRequired) + return bestMatch is not None + +#---------------------------------------------------------------------- + +def getInstalled(): + """ + Returns a list of strings representing the installed wxPython + versions that are found on the system. + """ + installed = _find_installed() + return [os.path.basename(p.pathname)[3:] for p in installed] + + + +#---------------------------------------------------------------------- +# private helpers... + +def _get_best_match(installed, versions, optionsRequired): + bestMatch = None + bestScore = 0 + for pkg in installed: + for ver in versions: + score = pkg.Score(_wxPackageInfo(ver), optionsRequired) + if score > bestScore: + bestMatch = pkg + bestScore = score + return bestMatch + + +_pattern = "wx-[0-9].*" +def _find_installed(removeExisting=False): + installed = [] + toRemove = [] + for pth in sys.path: + + # empty means to look in the current dir + if not pth: + pth = '.' + + # skip it if it's not a package dir + if not os.path.isdir(pth): + continue + + base = os.path.basename(pth) + + # if it's a wx path that's already in the sys.path then mark + # it for removal and then skip it + if fnmatch.fnmatchcase(base, _pattern): + toRemove.append(pth) + continue + + # now look in the dir for matching subdirs + for name in glob.glob(os.path.join(pth, _pattern)): + # make sure it's a directory + if not os.path.isdir(name): + continue + # and has a wx subdir + if not os.path.exists(os.path.join(name, 'wx')): + continue + installed.append(_wxPackageInfo(name, True)) + + if removeExisting: + for rem in toRemove: + del sys.path[sys.path.index(rem)] + + installed.sort() + installed.reverse() + return installed + + +# Scan the sys.path looking for either a directory matching _pattern, +# or a wx.pth file +def _find_default(): + for pth in sys.path: + # empty means to look in the current dir + if not pth: + pth = '.' + + # skip it if it's not a package dir + if not os.path.isdir(pth): + continue + + # does it match the pattern? + base = os.path.basename(pth) + if fnmatch.fnmatchcase(base, _pattern): + return pth + + for pth in sys.path: + if not pth: + pth = '.' + if not os.path.isdir(pth): + continue + if os.path.exists(os.path.join(pth, 'wx.pth')): + base = open(os.path.join(pth, 'wx.pth')).read() + return os.path.join(pth, base) + + return None + + +class _wxPackageInfo(object): + def __init__(self, pathname, stripFirst=False): + self.pathname = pathname + base = os.path.basename(pathname) + segments = base.split('-') + if stripFirst: + segments = segments[1:] + self.version = tuple([int(x) for x in segments[0].split('.')]) + self.options = segments[1:] + + + def Score(self, other, optionsRequired): + score = 0 + + # whatever number of version components given in other must + # match exactly + minlen = min(len(self.version), len(other.version)) + if self.version[:minlen] != other.version[:minlen]: + return 0 + score += 1 + + # check for matching options, if optionsRequired then the + # options are not optional ;-) + for opt in other.options: + if opt in self.options: + score += 1 + elif optionsRequired: + return 0 + + return score + + + def CheckOptions(self, other, optionsRequired): + # if options are not required then this always succeeds + if not optionsRequired: + return True + # otherwise, if we have any option not present in other, then + # the match fails. + for opt in self.options: + if opt not in other.options: + return False + return True + + + + def __lt__(self, other): + return self.version < other.version or \ + (self.version == other.version and self.options < other.options) + def __le__(self, other): + return self.version <= other.version or \ + (self.version == other.version and self.options <= other.options) + + def __gt__(self, other): + return self.version > other.version or \ + (self.version == other.version and self.options > other.options) + def __ge__(self, other): + return self.version >= other.version or \ + (self.version == other.version and self.options >= other.options) + + def __eq__(self, other): + return self.version == other.version and self.options == other.options + + + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + import pprint + + #ensureMinimal('2.5') + #pprint.pprint(sys.path) + #sys.exit() + + + def test(version, optionsRequired=False): + # setup + savepath = sys.path[:] + + #test + select(version, optionsRequired) + print "Asked for %s, (%s):\t got: %s" % (version, optionsRequired, sys.path[0]) + + # reset + sys.path = savepath[:] + global _selected + _selected = None + + + def testEM(version, optionsRequired=False): + # setup + savepath = sys.path[:] + + #test + ensureMinimal(version, optionsRequired) + print "EM: Asked for %s, (%s):\t got: %s" % (version, optionsRequired, sys.path[0]) + + # reset + sys.path = savepath[:] + global _selected + _selected = None + + + # make some test dirs + names = ['wx-2.4-gtk-ansi', + 'wx-2.5.2-gtk2-unicode', + 'wx-2.5.3-gtk-ansi', + 'wx-2.6-gtk2-unicode', + 'wx-2.6-gtk2-ansi', + 'wx-2.6-gtk-ansi', + 'wx-2.7.1-gtk2-ansi', + ] + for name in names: + d = os.path.join('/tmp', name) + os.mkdir(d) + os.mkdir(os.path.join(d, 'wx')) + + # setup sys.path to see those dirs + sys.path.append('/tmp') + + + # now run some tests + pprint.pprint( getInstalled()) + print checkInstalled("2.4") + print checkInstalled("2.5-unicode") + print checkInstalled("2.99-bogus") + print "Current sys.path:" + pprint.pprint(sys.path) + print + + test("2.4") + test("2.5") + test("2.5-gtk2") + test("2.5.2") + test("2.5-ansi") + test("2.5-unicode") + test("2.6") + test("2.6-ansi") + test(["2.6-unicode", "2.7-unicode"]) + test(["2.6", "2.7"]) + test(["2.6-unicode", "2.7-unicode"], optionsRequired=True) + + + + # There isn't a unicode match for this one, but it will give the best + # available 2.4. Should it give an error instead? I don't think so... + test("2.4-unicode") + + # Try asking for multiple versions + test(["2.5.2", "2.5.3", "2.6"]) + + try: + # expecting an error on this one + test("2.9") + except VersionError, e: + print "Asked for 2.9:\t got Exception:", e + + # check for exception when incompatible versions are requested + try: + select("2.4") + select("2.5") + except VersionError, e: + print "Asked for incompatible versions, got Exception:", e + + _EM_DEBUG=1 + testEM("2.6") + testEM("2.6-unicode") + testEM("2.6-unicode", True) + try: + testEM("2.9") + except VersionError, e: + print "EM: Asked for 2.9:\t got Exception:", e + + # cleanup + for name in names: + d = os.path.join('/tmp', name) + os.rmdir(os.path.join(d, 'wx')) + os.rmdir(d) + + |