From 34c7075ab73e6a9ed9b8cdc15730a96fba18c407 Mon Sep 17 00:00:00 2001 From: Bryan Petty Date: Thu, 19 May 2005 10:18:11 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'WX_2_4_BRANCH'. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@34165 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- debian/lintian-override.in | 2 + debian/wx-doc.doc-base | 10 + samples/rotate/duck.png | Bin 0 -> 7754 bytes wxPython/wxversion/wxversion.py | 517 ++++++++++++++++++++++++++++++++ 4 files changed, 529 insertions(+) create mode 100644 debian/lintian-override.in create mode 100644 debian/wx-doc.doc-base create mode 100644 samples/rotate/duck.png create mode 100644 wxPython/wxversion/wxversion.py diff --git a/debian/lintian-override.in b/debian/lintian-override.in new file mode 100644 index 0000000000..7eb2344f9b --- /dev/null +++ b/debian/lintian-override.in @@ -0,0 +1,2 @@ +libwxgtk=V-dbg: non-dev-pkg-with-shlib-symlink + diff --git a/debian/wx-doc.doc-base b/debian/wx-doc.doc-base new file mode 100644 index 0000000000..6cdb592b44 --- /dev/null +++ b/debian/wx-doc.doc-base @@ -0,0 +1,10 @@ +Document: wx=V-manual +Title: wxWidgets=V Programming Manual +Author: The wxWidgets Cabal +Abstract: This manual describes the wxWidgets=V cross-platform GUI toolkit. +Section: Apps/Programming + +Format: HTML +Index: /usr/share/doc/wx=V-doc/wx-manual.html/wx=V-manual_contents.html +Files: /usr/share/doc/wx=V-doc/wx-manual.html/* + diff --git a/samples/rotate/duck.png b/samples/rotate/duck.png new file mode 100644 index 0000000000000000000000000000000000000000..19721266e9574051a5f9ccf9672906a3001538fb GIT binary patch literal 7754 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 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 VersionError("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) + _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 VersionError("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.PySimpleApp() + 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) + 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) + +