Added optional parameter to wxversion.select and friends that makes
the options be required for a match. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34087 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -9,7 +9,8 @@ Added wx.BrushFromBitmap to create a stippled brush in a single step.
|
||||
Also added missing brysh style flags: wx.STIPPLE_MASK
|
||||
wx.STIPPLE_MASK_OPAQUE.
|
||||
|
||||
wxMSW: Fix for controls when the system text fg colour is not black.
|
||||
wxMSW: Fix for default control colours when the system text fg colour
|
||||
is not black.
|
||||
|
||||
wxGTK: Patch #1171754, It is now possible to have a menu item that
|
||||
both has an icon and is a submenu.
|
||||
@@ -56,6 +57,18 @@ Added wx.lib.hyperlink from Andrea Gavana. It is a control like
|
||||
static text that acts like a hyper-link, launching the system's
|
||||
default browser in response to the clicks.
|
||||
|
||||
Added an optional parameter to wxversion.select that allows you to
|
||||
specify that the extra components specified in the version string are
|
||||
required. For example, if you ask for "2.6-unicode" but only the ansi
|
||||
version is installed then by default the ansi version will be selected
|
||||
as it considered close enough since the version numbers match. If you
|
||||
want to force the options to be required then you can just add a True
|
||||
parameter, like this::
|
||||
|
||||
import wxversion
|
||||
wxversion.select("2.6-unicode", True)
|
||||
import wx
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -15,18 +15,34 @@
|
||||
"""
|
||||
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'. You use it like this::
|
||||
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, like this::
|
||||
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
|
||||
@@ -67,7 +83,7 @@ class VersionError(Exception):
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
def select(versions):
|
||||
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
|
||||
@@ -75,23 +91,36 @@ def select(versions):
|
||||
raised. This funciton should only be caled once at the begining
|
||||
of the application before wxPython is imported.
|
||||
|
||||
:param version: 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.
|
||||
: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.
|
||||
|
||||
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.
|
||||
"""
|
||||
if type(versions) == str:
|
||||
versions = [versions]
|
||||
@@ -101,7 +130,7 @@ def select(versions):
|
||||
# A version was previously selected, ensure that it matches
|
||||
# this new request
|
||||
for ver in versions:
|
||||
if _selected.Score(_wxPackageInfo(ver)) > 0:
|
||||
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.")
|
||||
@@ -114,7 +143,7 @@ def select(versions):
|
||||
# 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)
|
||||
bestMatch = _get_best_match(installed, versions, optionsRequired)
|
||||
|
||||
if bestMatch is None:
|
||||
raise VersionError("Requested version of wxPython not found")
|
||||
@@ -127,8 +156,9 @@ def select(versions):
|
||||
UPDATE_URL = "http://wxPython.org/"
|
||||
#UPDATE_URL = "http://sourceforge.net/project/showfiles.php?group_id=10718"
|
||||
|
||||
_EM_DEBUG=0
|
||||
|
||||
def ensureMinimal(minVersion):
|
||||
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
|
||||
@@ -145,21 +175,30 @@ def ensureMinimal(minVersion):
|
||||
|
||||
bestMatch = None
|
||||
minv = _wxPackageInfo(minVersion)
|
||||
|
||||
# check the default version first
|
||||
defaultPath = _find_default()
|
||||
if defaultPath:
|
||||
defv = _wxPackageInfo(defaultPath, True)
|
||||
if defv >= minv:
|
||||
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()
|
||||
if installed:
|
||||
# The list is in reverse sorted order, so if the first one is
|
||||
# big enough then choose it
|
||||
if installed[0] >= minv:
|
||||
bestMatch = installed[0]
|
||||
# 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()
|
||||
@@ -182,21 +221,22 @@ def ensureMinimal(minVersion):
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
def checkInstalled(versions):
|
||||
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 version: Same as in `select`, either a string or a list
|
||||
of strings specifying the version(s) to check
|
||||
for.
|
||||
: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)
|
||||
bestMatch = _get_best_match(installed, versions, optionsRequired)
|
||||
return bestMatch is not None
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
@@ -214,12 +254,12 @@ def getInstalled():
|
||||
#----------------------------------------------------------------------
|
||||
# private helpers...
|
||||
|
||||
def _get_best_match(installed, versions):
|
||||
def _get_best_match(installed, versions, optionsRequired):
|
||||
bestMatch = None
|
||||
bestScore = 0
|
||||
for pkg in installed:
|
||||
for ver in versions:
|
||||
score = pkg.Score(_wxPackageInfo(ver))
|
||||
score = pkg.Score(_wxPackageInfo(ver), optionsRequired)
|
||||
if score > bestScore:
|
||||
bestMatch = pkg
|
||||
bestScore = score
|
||||
@@ -307,7 +347,7 @@ class _wxPackageInfo(object):
|
||||
self.options = segments[1:]
|
||||
|
||||
|
||||
def Score(self, other):
|
||||
def Score(self, other, optionsRequired):
|
||||
score = 0
|
||||
|
||||
# whatever number of version components given in other must
|
||||
@@ -317,12 +357,29 @@ class _wxPackageInfo(object):
|
||||
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 \
|
||||
@@ -353,15 +410,27 @@ if __name__ == '__main__':
|
||||
#sys.exit()
|
||||
|
||||
|
||||
def test(version):
|
||||
def test(version, optionsRequired=False):
|
||||
# setup
|
||||
savepath = sys.path[:]
|
||||
|
||||
#test
|
||||
select(version)
|
||||
print "Asked for %s:\t got: %s" % (version, sys.path[0])
|
||||
pprint.pprint(sys.path)
|
||||
print
|
||||
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[:]
|
||||
@@ -370,13 +439,14 @@ if __name__ == '__main__':
|
||||
|
||||
|
||||
# make some test dirs
|
||||
names = ['wx-2.4',
|
||||
'wx-2.5.2',
|
||||
'wx-2.5.2.9-gtk2-unicode',
|
||||
'wx-2.5.2.9-gtk-ansi',
|
||||
'wx-2.5.1',
|
||||
'wx-2.5.2.8-gtk2-unicode',
|
||||
'wx-2.5.3']
|
||||
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)
|
||||
@@ -401,19 +471,26 @@ if __name__ == '__main__':
|
||||
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.6", "2.5.3", "2.5.2-gtk2"])
|
||||
test(["2.5.2", "2.5.3", "2.6"])
|
||||
|
||||
try:
|
||||
# expecting an error on this one
|
||||
test("2.6")
|
||||
test("2.9")
|
||||
except VersionError, e:
|
||||
print "Asked for 2.6:\t got Exception:", e
|
||||
print "Asked for 2.9:\t got Exception:", e
|
||||
|
||||
# check for exception when incompatible versions are requested
|
||||
try:
|
||||
@@ -422,6 +499,15 @@ if __name__ == '__main__':
|
||||
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)
|
||||
|
Reference in New Issue
Block a user