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
|
Also added missing brysh style flags: wx.STIPPLE_MASK
|
||||||
wx.STIPPLE_MASK_OPAQUE.
|
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
|
wxGTK: Patch #1171754, It is now possible to have a menu item that
|
||||||
both has an icon and is a submenu.
|
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
|
static text that acts like a hyper-link, launching the system's
|
||||||
default browser in response to the clicks.
|
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
|
If you have more than one version of wxPython installed this module
|
||||||
allows your application to choose which version of wxPython will be
|
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
|
import wxversion
|
||||||
wxversion.select('2.4')
|
wxversion.select('2.4')
|
||||||
import wx
|
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
|
import wxversion
|
||||||
wxversion.select('2.5.3-unicode')
|
wxversion.select('2.5.3-unicode')
|
||||||
import wx
|
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
|
Of course the default wxPython version can also be controlled by
|
||||||
setting PYTHONPATH or by editing the wx.pth path configuration file,
|
setting PYTHONPATH or by editing the wx.pth path configuration file,
|
||||||
but using wxversion will allow an application to manage the version
|
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
|
Search for a wxPython installation that matches version. If one
|
||||||
is found then sys.path is modified so that version will be
|
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
|
raised. This funciton should only be caled once at the begining
|
||||||
of the application before wxPython is imported.
|
of the application before wxPython is imported.
|
||||||
|
|
||||||
:param version: Specifies the version to look for, it can
|
:param versions: Specifies the version to look for, it can
|
||||||
either be a string or a list of strings. Each
|
either be a string or a list of strings. Each string is
|
||||||
string is compared to the installed wxPythons
|
compared to the installed wxPythons and the best match is
|
||||||
and the best match is inserted into the
|
inserted into the sys.path, allowing an 'import wx' to
|
||||||
sys.path, allowing an 'import wx' to find that
|
find that version.
|
||||||
version.
|
|
||||||
|
|
||||||
The version string is composed of the dotted
|
The version string is composed of the dotted version
|
||||||
version number (at least 2 of the 4 components)
|
number (at least 2 of the 4 components) optionally
|
||||||
optionally followed by hyphen ('-') separated
|
followed by hyphen ('-') separated options (wx port,
|
||||||
options (wx port, unicode/ansi, flavour, etc.) A
|
unicode/ansi, flavour, etc.) A match is determined by how
|
||||||
match is determined by how much of the installed
|
much of the installed version matches what is given in the
|
||||||
version matches what is given in the version
|
version parameter. If the version number components don't
|
||||||
parameter. If the version number components don't
|
match then the score is zero, otherwise the score is
|
||||||
match then the score is zero, otherwise the score
|
increased for every specified optional component that is
|
||||||
is increased for every specified optional component
|
specified and that matches.
|
||||||
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:
|
if type(versions) == str:
|
||||||
versions = [versions]
|
versions = [versions]
|
||||||
@@ -101,7 +130,7 @@ def select(versions):
|
|||||||
# A version was previously selected, ensure that it matches
|
# A version was previously selected, ensure that it matches
|
||||||
# this new request
|
# this new request
|
||||||
for ver in versions:
|
for ver in versions:
|
||||||
if _selected.Score(_wxPackageInfo(ver)) > 0:
|
if _selected.Score(_wxPackageInfo(ver), optionsRequired) > 0:
|
||||||
return
|
return
|
||||||
# otherwise, raise an exception
|
# otherwise, raise an exception
|
||||||
raise VersionError("A previously selected wx version does not match the new request.")
|
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
|
# Look for a matching version and manipulate the sys.path as
|
||||||
# needed to allow it to be imported.
|
# needed to allow it to be imported.
|
||||||
installed = _find_installed(True)
|
installed = _find_installed(True)
|
||||||
bestMatch = _get_best_match(installed, versions)
|
bestMatch = _get_best_match(installed, versions, optionsRequired)
|
||||||
|
|
||||||
if bestMatch is None:
|
if bestMatch is None:
|
||||||
raise VersionError("Requested version of wxPython not found")
|
raise VersionError("Requested version of wxPython not found")
|
||||||
@@ -127,8 +156,9 @@ def select(versions):
|
|||||||
UPDATE_URL = "http://wxPython.org/"
|
UPDATE_URL = "http://wxPython.org/"
|
||||||
#UPDATE_URL = "http://sourceforge.net/project/showfiles.php?group_id=10718"
|
#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
|
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
|
or equal to `minVersion`. If not then it will try to find an
|
||||||
@@ -145,21 +175,30 @@ def ensureMinimal(minVersion):
|
|||||||
|
|
||||||
bestMatch = None
|
bestMatch = None
|
||||||
minv = _wxPackageInfo(minVersion)
|
minv = _wxPackageInfo(minVersion)
|
||||||
|
|
||||||
|
# check the default version first
|
||||||
defaultPath = _find_default()
|
defaultPath = _find_default()
|
||||||
if defaultPath:
|
if defaultPath:
|
||||||
defv = _wxPackageInfo(defaultPath, True)
|
defv = _wxPackageInfo(defaultPath, True)
|
||||||
if defv >= minv:
|
if defv >= minv and minv.CheckOptions(defv, optionsRequired):
|
||||||
bestMatch = defv
|
bestMatch = defv
|
||||||
|
|
||||||
|
# if still no match then check look at all installed versions
|
||||||
if bestMatch is None:
|
if bestMatch is None:
|
||||||
installed = _find_installed()
|
installed = _find_installed()
|
||||||
if installed:
|
# The list is in reverse sorted order, so find the first
|
||||||
# The list is in reverse sorted order, so if the first one is
|
# one that is big enough and optionally matches the
|
||||||
# big enough then choose it
|
# options
|
||||||
if installed[0] >= minv:
|
for inst in installed:
|
||||||
bestMatch = installed[0]
|
if inst >= minv and minv.CheckOptions(inst, optionsRequired):
|
||||||
|
bestMatch = inst
|
||||||
|
break
|
||||||
|
|
||||||
|
# if still no match then prompt the user
|
||||||
if bestMatch is None:
|
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
|
import wx, webbrowser
|
||||||
versions = "\n".join([" "+ver for ver in getInstalled()])
|
versions = "\n".join([" "+ver for ver in getInstalled()])
|
||||||
app = wx.PySimpleApp()
|
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
|
Check if there is a version of wxPython installed that matches one
|
||||||
of the versions given. Returns True if so, False if not. This
|
of the versions given. Returns True if so, False if not. This
|
||||||
can be used to determine if calling `select` will succeed or not.
|
can be used to determine if calling `select` will succeed or not.
|
||||||
|
|
||||||
:param version: Same as in `select`, either a string or a list
|
:param versions: Same as in `select`, either a string or a list
|
||||||
of strings specifying the version(s) to check
|
of strings specifying the version(s) to check for.
|
||||||
for.
|
|
||||||
|
:param optionsRequired: Same as in `select`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if type(versions) == str:
|
if type(versions) == str:
|
||||||
versions = [versions]
|
versions = [versions]
|
||||||
installed = _find_installed()
|
installed = _find_installed()
|
||||||
bestMatch = _get_best_match(installed, versions)
|
bestMatch = _get_best_match(installed, versions, optionsRequired)
|
||||||
return bestMatch is not None
|
return bestMatch is not None
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
@@ -214,12 +254,12 @@ def getInstalled():
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# private helpers...
|
# private helpers...
|
||||||
|
|
||||||
def _get_best_match(installed, versions):
|
def _get_best_match(installed, versions, optionsRequired):
|
||||||
bestMatch = None
|
bestMatch = None
|
||||||
bestScore = 0
|
bestScore = 0
|
||||||
for pkg in installed:
|
for pkg in installed:
|
||||||
for ver in versions:
|
for ver in versions:
|
||||||
score = pkg.Score(_wxPackageInfo(ver))
|
score = pkg.Score(_wxPackageInfo(ver), optionsRequired)
|
||||||
if score > bestScore:
|
if score > bestScore:
|
||||||
bestMatch = pkg
|
bestMatch = pkg
|
||||||
bestScore = score
|
bestScore = score
|
||||||
@@ -307,7 +347,7 @@ class _wxPackageInfo(object):
|
|||||||
self.options = segments[1:]
|
self.options = segments[1:]
|
||||||
|
|
||||||
|
|
||||||
def Score(self, other):
|
def Score(self, other, optionsRequired):
|
||||||
score = 0
|
score = 0
|
||||||
|
|
||||||
# whatever number of version components given in other must
|
# whatever number of version components given in other must
|
||||||
@@ -316,13 +356,30 @@ class _wxPackageInfo(object):
|
|||||||
if self.version[:minlen] != other.version[:minlen]:
|
if self.version[:minlen] != other.version[:minlen]:
|
||||||
return 0
|
return 0
|
||||||
score += 1
|
score += 1
|
||||||
|
|
||||||
|
# check for matching options, if optionsRequired then the
|
||||||
|
# options are not optional ;-)
|
||||||
for opt in other.options:
|
for opt in other.options:
|
||||||
if opt in self.options:
|
if opt in self.options:
|
||||||
score += 1
|
score += 1
|
||||||
|
elif optionsRequired:
|
||||||
|
return 0
|
||||||
|
|
||||||
return score
|
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):
|
def __lt__(self, other):
|
||||||
return self.version < other.version or \
|
return self.version < other.version or \
|
||||||
@@ -353,15 +410,27 @@ if __name__ == '__main__':
|
|||||||
#sys.exit()
|
#sys.exit()
|
||||||
|
|
||||||
|
|
||||||
def test(version):
|
def test(version, optionsRequired=False):
|
||||||
# setup
|
# setup
|
||||||
savepath = sys.path[:]
|
savepath = sys.path[:]
|
||||||
|
|
||||||
#test
|
#test
|
||||||
select(version)
|
select(version, optionsRequired)
|
||||||
print "Asked for %s:\t got: %s" % (version, sys.path[0])
|
print "Asked for %s, (%s):\t got: %s" % (version, optionsRequired, sys.path[0])
|
||||||
pprint.pprint(sys.path)
|
|
||||||
print
|
# 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
|
# reset
|
||||||
sys.path = savepath[:]
|
sys.path = savepath[:]
|
||||||
@@ -370,13 +439,14 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
|
|
||||||
# make some test dirs
|
# make some test dirs
|
||||||
names = ['wx-2.4',
|
names = ['wx-2.4-gtk-ansi',
|
||||||
'wx-2.5.2',
|
'wx-2.5.2-gtk2-unicode',
|
||||||
'wx-2.5.2.9-gtk2-unicode',
|
'wx-2.5.3-gtk-ansi',
|
||||||
'wx-2.5.2.9-gtk-ansi',
|
'wx-2.6-gtk2-unicode',
|
||||||
'wx-2.5.1',
|
'wx-2.6-gtk2-ansi',
|
||||||
'wx-2.5.2.8-gtk2-unicode',
|
'wx-2.6-gtk-ansi',
|
||||||
'wx-2.5.3']
|
'wx-2.7.1-gtk2-ansi',
|
||||||
|
]
|
||||||
for name in names:
|
for name in names:
|
||||||
d = os.path.join('/tmp', name)
|
d = os.path.join('/tmp', name)
|
||||||
os.mkdir(d)
|
os.mkdir(d)
|
||||||
@@ -401,19 +471,26 @@ if __name__ == '__main__':
|
|||||||
test("2.5.2")
|
test("2.5.2")
|
||||||
test("2.5-ansi")
|
test("2.5-ansi")
|
||||||
test("2.5-unicode")
|
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
|
# 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...
|
# available 2.4. Should it give an error instead? I don't think so...
|
||||||
test("2.4-unicode")
|
test("2.4-unicode")
|
||||||
|
|
||||||
# Try asking for multiple versions
|
# 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:
|
try:
|
||||||
# expecting an error on this one
|
# expecting an error on this one
|
||||||
test("2.6")
|
test("2.9")
|
||||||
except VersionError, e:
|
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
|
# check for exception when incompatible versions are requested
|
||||||
try:
|
try:
|
||||||
@@ -422,6 +499,15 @@ if __name__ == '__main__':
|
|||||||
except VersionError, e:
|
except VersionError, e:
|
||||||
print "Asked for incompatible versions, got Exception:", 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
|
# cleanup
|
||||||
for name in names:
|
for name in names:
|
||||||
d = os.path.join('/tmp', name)
|
d = os.path.join('/tmp', name)
|
||||||
|
Reference in New Issue
Block a user