From b5506061c644d27e78396e92b5a7269c812a4c4b Mon Sep 17 00:00:00 2001 From: acollange Date: Wed, 12 Apr 2017 12:18:28 +0200 Subject: [PATCH 01/11] Update customtreectrl.py 'Classic' wx.YieldIfNeeded() was translated into wx.SafeYield(), but it is not equivalent. Cause a 'recursive Yield call' error in one of my project which works fine with Classic. Change it into wx.SafeYield(onlyIfNeeded=True) resolve the issue. --- wx/lib/agw/customtreectrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wx/lib/agw/customtreectrl.py b/wx/lib/agw/customtreectrl.py index 5f041979..d2e781f9 100644 --- a/wx/lib/agw/customtreectrl.py +++ b/wx/lib/agw/customtreectrl.py @@ -5867,7 +5867,7 @@ class CustomTreeCtrl(wx.ScrolledWindow): if wx.Platform in ["__WXMSW__", "__WXMAC__"]: self.Update() else: - wx.SafeYield() + wx.SafeYield(onlyIfNeeded=True) # now scroll to the item item_y = item.GetY() From 09d916ced7effbb3caec1cc1ae169f56071306ed Mon Sep 17 00:00:00 2001 From: acollange Date: Tue, 9 May 2017 17:23:26 +0200 Subject: [PATCH 02/11] Revert "Update customtreectrl.py" --- wx/lib/agw/customtreectrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wx/lib/agw/customtreectrl.py b/wx/lib/agw/customtreectrl.py index d2e781f9..5f041979 100644 --- a/wx/lib/agw/customtreectrl.py +++ b/wx/lib/agw/customtreectrl.py @@ -5867,7 +5867,7 @@ class CustomTreeCtrl(wx.ScrolledWindow): if wx.Platform in ["__WXMSW__", "__WXMAC__"]: self.Update() else: - wx.SafeYield(onlyIfNeeded=True) + wx.SafeYield() # now scroll to the item item_y = item.GetY() From 63293f83f5a68fc00b574841a2c6816f013b338b Mon Sep 17 00:00:00 2001 From: acollange Date: Tue, 9 May 2017 17:35:10 +0200 Subject: [PATCH 03/11] Update framemanager.py --- wx/lib/agw/aui/framemanager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wx/lib/agw/aui/framemanager.py b/wx/lib/agw/aui/framemanager.py index a2c8ea0c..8ebc3034 100644 --- a/wx/lib/agw/aui/framemanager.py +++ b/wx/lib/agw/aui/framemanager.py @@ -6346,6 +6346,7 @@ class AuiManager(wx.EvtHandler): self.DoUpdate() def DoUpdateEvt(self, evt): + self.Unbind(wx.EVT_WINDOW_CREATE) wx.CallAfter(self.DoUpdate) def DoUpdate(self): From f9b2f30a3fd111e42af1d83e708f347c20882cba Mon Sep 17 00:00:00 2001 From: Paul McCarthy Date: Tue, 9 May 2017 16:58:39 +0100 Subject: [PATCH 04/11] Extra check to avoid error under OSX when dragging AUI toolbars --- wx/lib/agw/aui/framemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wx/lib/agw/aui/framemanager.py b/wx/lib/agw/aui/framemanager.py index a2c8ea0c..b1072bcd 100644 --- a/wx/lib/agw/aui/framemanager.py +++ b/wx/lib/agw/aui/framemanager.py @@ -9940,7 +9940,7 @@ class AuiManager(wx.EvtHandler): if not pane.IsOk(): raise Exception("Pane window not found") - if pane.IsFloating(): + if pane.IsFloating() and pane.frame is not None: pane.floating_pos = pane.frame.GetPosition() if pane.frame._transparent != pane.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG: pane.frame.SetTransparent(pane.transparent) From 3c2d77ed694aa0cffd1f61aa254f375f35caba50 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Wed, 10 May 2017 12:36:06 -0700 Subject: [PATCH 05/11] Change sdist- builder names to dist- --- buildbot/master.cfg | 12 ++++++------ packaging/HOWTO-Release.rst | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/buildbot/master.cfg b/buildbot/master.cfg index 84570c85..d9c7c327 100644 --- a/buildbot/master.cfg +++ b/buildbot/master.cfg @@ -130,14 +130,14 @@ c['schedulers'].append( Nightly( branch=phoenixGitBranch, hour=1, minute=10, onlyIfChanged=True, - builderNames=["bdist-docs"])) + builderNames=["dist-docs"])) c['schedulers'].append( Nightly( name="sched-src", branch=phoenixGitBranch, hour=1, minute=10, onlyIfChanged=True, - builderNames=["bdist-src"])) + builderNames=["dist-src"])) # c['schedulers'].append( Nightly( # name="sched-vagrant", @@ -170,8 +170,8 @@ c['schedulers'].append( ForceScheduler( "dist-win64-py27", "dist-win64-py35", "dist-win64-py36", - "bdist-docs", - "bdist-src", + "dist-docs", + "dist-src", #"vagrant-bldr", ])) @@ -339,11 +339,11 @@ c['builders'] = [ factory=makeFactory('gtk3', pyVer='3.5')), - BuilderConfig(name="bdist-docs", + BuilderConfig(name="dist-docs", slavenames=["win7-py27"], factory=makeFactory('', 'docs')), - BuilderConfig(name="bdist-src", + BuilderConfig(name="dist-src", slavenames=["ubuntu-x64_86-py27"], factory=makeFactory('', 'sdist')), diff --git a/packaging/HOWTO-Release.rst b/packaging/HOWTO-Release.rst index 81a52a05..1279f388 100644 --- a/packaging/HOWTO-Release.rst +++ b/packaging/HOWTO-Release.rst @@ -15,7 +15,7 @@ HOWTO Release wxPython Phoenix 3. Log in to buildbot master -4. On the "Builders" page check the dist-* and the bdist-* builders +4. On the "Builders" page check all of the dist-* builders 5. Set a name/value pair to buildargs/--release @@ -24,7 +24,7 @@ HOWTO Release wxPython Phoenix 7. Click the Force Build button -8. Building wheel files for some linux distros can be done while the other +8. Building wheel files for selected linux distros can be done while the other builds are still running. Fetch the source tarball when it is finished and put it in Phoenix/dist. Run the following:: From ad46014aeb01b1ca28f456f3b15ae16beb350970 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Wed, 10 May 2017 12:41:42 -0700 Subject: [PATCH 06/11] Generate a zip file of the documentation suitable for use on pythonhosted.org --- build.py | 46 +++++++++++++++++++++++++++++-------- packaging/HOWTO-Release.rst | 13 +++++++---- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/build.py b/build.py index 37ce15d0..7f361062 100755 --- a/build.py +++ b/build.py @@ -990,16 +990,13 @@ def cmd_wxtools(options, args): msg('Command wxtools has been folded into command wxlib.') -def cmd_docs_bdist(options, args): - # TODO: get rid of this function after a while - cmd_bdist_docs(options, args) - def cmd_bdist_docs(options, args): - cmdTimer = CommandTimer('docs_bdist') + cmdTimer = CommandTimer('bdist_docs') pwd = pushDir(phoenixDir()) cfg = Config() + msg("Archiving wxPython Phoenix documentation...") rootname = "%s-docs-%s" % (baseName, cfg.VERSION) tarfilename = "dist/%s.tar.gz" % rootname @@ -1008,11 +1005,9 @@ def cmd_bdist_docs(options, args): if os.path.exists(tarfilename): os.remove(tarfilename) - msg("Archiving Phoenix documentation...") - tarball = tarfile.open(name=tarfilename, mode="w:gz") - tarball.add('docs/html', os.path.join(rootname, 'docs/html'), - filter=lambda info: None if '.svn' in info.name else info) - tarball.close() + with tarfile.open(name=tarfilename, mode="w:gz") as tarball: + tarball.add('docs/html', os.path.join(rootname, 'docs/html'), + filter=lambda info: None if '.svn' in info.name else info) if options.upload: uploadPackage(tarfilename, options, keep=5, @@ -1021,6 +1016,37 @@ def cmd_bdist_docs(options, args): msg('Documentation tarball built at %s' % tarfilename) + # pythonhosted.org can host the wxPython documentation for us, so let's + # use it for the docs associated with the latest release of wxPython. It + # requires that the docs be in a .zip file with an index.html file at the + # top level. To build this we'll just need to do like the above tarball + # code, except add the files from within the docs/html folder so they will + # all be at the top level of the archive. shutil.make_archive can be used + # in this case because we don't need to rewrite the pathnames in the + # archive. + if options.release: + msg("Archiving wxPython Phoenix documentation for pythonhosted.org...") + rootname = "%s-docs-pythonhosted-%s" % (baseName, cfg.VERSION) + zipfilename = "dist/%s.zip" % rootname + + if os.path.exists(zipfilename): + os.remove(zipfilename) + + # with zipfile.ZipFile(zipfilename, 'w', zipfile.ZIP_DEFLATED) as zip: + # pwd2 = pushDir('docs/html') + + zipfilename = shutil.make_archive(base_name=os.path.splitext(zipfilename)[0], + format="zip", + root_dir="docs/html") + + if options.upload: + uploadPackage(zipfilename, options, keep=5, + mask='%s-docs-pythonhosted-%s*' % (baseName, cfg.VER_MAJOR)) + + msg('Pythonhosted zip file built at %s' % zipfilename) + + + def cmd_sip(options, args): cmdTimer = CommandTimer('sip') cfg = Config() diff --git a/packaging/HOWTO-Release.rst b/packaging/HOWTO-Release.rst index 1279f388..ec357921 100644 --- a/packaging/HOWTO-Release.rst +++ b/packaging/HOWTO-Release.rst @@ -53,25 +53,28 @@ HOWTO Release wxPython Phoenix (Twine doesn't know what to do with the docs and other files so they need to be excluded by the wildcard.) -14. Upload the docs, demos and pdb archive files to wxpython.org/Phoenix/release-extras/:: +14. Upload the wxPython-docs-pythonhosted*.zip documentation file using the + form on PyPI. Remove the local copy of the file before the next step. + +15. Upload the docs, demos and pdb archive files to wxpython.org/Phoenix/release-extras/:: VERSION={current release version number} ssh wxpython-extras "mkdir -p wxpython-extras/$VERSION" scp wxPython-[^0-9]* wxpython-extras:wxpython-extras/$VERSION -15. Upload the Linux wheels:: +16. Upload the Linux wheels:: scp -r linux wxpython-extras:wxpython-extras/ -16. Tag the released revision in git, using a name like wxPython-4.0.0 (using +17. Tag the released revision in git, using a name like wxPython-4.0.0 (using the actual version number of course.) Push the tag to all remotes. -17. Bump the version numbers in buildtools/version.py appropriately for the +18. Bump the version numbers in buildtools/version.py appropriately for the next anticipated release, so future snapshot builds will be recognized as pre-release development versions for the next official release, not the one just completed. -18. If making an announcement about this release, (I think it's okay not to +19. If making an announcement about this release, (I think it's okay not to for minor releases or smallish bug fixes,) send the text in packaging/ANNOUNCE.txt to the email addresses listed at the top of the file. From 37d67272b033ff38a3ac4d4d8c840136319501b0 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Wed, 10 May 2017 12:42:48 -0700 Subject: [PATCH 07/11] Generate a different welcome paragraph on main.html dependent on whether this is a release build or a snapshot build. --- build.py | 4 ++-- docs/sphinx/_templates/main.html | 5 +---- sphinxtools/postprocess.py | 32 ++++++++++++++++++++++++-------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/build.py b/build.py index 7f361062..2db25d74 100755 --- a/build.py +++ b/build.py @@ -30,7 +30,7 @@ import datetime from distutils.dep_util import newer, newer_group from buildtools.config import Config, msg, opj, posixjoin, loadETG, etg2sip, findCmd, \ phoenixDir, wxDir, copyIfNewer, copyFile, \ - macFixDependencyInstallName, macSetLoaderNames, \ + macSetLoaderNames, \ getVcsRev, runcmd, textfile_open, getSipFiles, \ getVisCVersion, getToolsPlatformName @@ -960,7 +960,7 @@ def cmd_sphinx(options, args): del pwd2 msg('Postprocessing sphinx output...') - postProcess(htmlDir) + postProcess(htmlDir, options) def cmd_wxlib(options, args): diff --git a/docs/sphinx/_templates/main.html b/docs/sphinx/_templates/main.html index b9a03a53..74199999 100644 --- a/docs/sphinx/_templates/main.html +++ b/docs/sphinx/_templates/main.html @@ -3,10 +3,7 @@ {% block body %}

wxPython Phoenix API Documentation

-

- Welcome! This is the API documentation for wxPython Phoenix {{ release }}, - last updated |TODAY| from git revision |VCSREV|. -

+

|WELCOME|

If you are porting your code from Classic wxPython, be sure to read the diff --git a/sphinxtools/postprocess.py b/sphinxtools/postprocess.py index d55695ce..c0476707 100644 --- a/sphinxtools/postprocess.py +++ b/sphinxtools/postprocess.py @@ -15,7 +15,7 @@ import glob import random # Phoenix-specific imports -from buildtools.config import copyIfNewer, writeIfChanged, newer, getVcsRev, textfile_open +from buildtools.config import Config, writeIfChanged, newer, textfile_open, runcmd from etgtools.item_module_map import ItemModuleMap from . import templates @@ -647,7 +647,7 @@ def addJavaScript(text): # ----------------------------------------------------------------------- # -def postProcess(folder): +def postProcess(folder, options): fileNames = glob.glob(folder + "/*.html") @@ -678,8 +678,8 @@ def postProcess(folder): split = os.path.split(files)[1] - if split in ['index.html', 'main.html']: - text = changeSVNRevision(text) + if split == 'main.html': + text = changeWelcomeText(text, options) else: text = text.replace('class="headerimage"', 'class="headerimage-noshow"') @@ -734,13 +734,29 @@ def postProcess(folder): # ----------------------------------------------------------------------- # -def changeSVNRevision(text): - REVISION = getVcsRev() - text = text.replace('|TODAY|', TODAY) - text = text.replace('|VCSREV|', REVISION) + +def changeWelcomeText(text, options): + cfg = Config(noWxConfig=True) + + if options.release: + welcomeText = """ + Welcome! This is the API reference documentation for the {version} + release of wxPython Phoenix, built on {today}. + """.format(version=cfg.VERSION, today=TODAY) + else: + revhash = runcmd('git rev-parse --short HEAD', getOutput=True, echoCmd=False) + welcomeText = """ + Welcome! This is the API documentation for the wxPython Phoenix + pre-release snapshot build {version}, last updated {today} + from git revision: + {revhash}. + """.format(version=cfg.VERSION, today=TODAY, revhash=revhash) + text = text.replace('|WELCOME|', welcomeText) return text + + def tooltipsOnInheritance(text, class_summary): graphviz = re.findall(r'

(.*?)

', text, re.DOTALL) From 6a2a7aab9b3088b0d70dbd3e75727119ad4b0b9c Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Tue, 9 May 2017 17:27:06 -0700 Subject: [PATCH 08/11] Return an integer from wx.DC.GetHandle instead of a voidptr. In some cases due to unsigned values greater than signed max, converting the voidptr back to a handle overflows the receiving variable so it is not allowed. --- etg/dc.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/etg/dc.py b/etg/dc.py index e2c033f4..d7d94463 100644 --- a/etg/dc.py +++ b/etg/dc.py @@ -233,6 +233,11 @@ def run(): body="return (self.MinX(), self.MinY(), self.MaxX(), self.MaxY())") + m = c.find('GetHandle') + m.type = 'wxUIntPtr*' + m.setCppCode("return new wxUIntPtr((wxUIntPtr)self->GetHandle());") + + c.addCppMethod('long', 'GetHDC', '()', """\ #ifdef __WXMSW__ return (long)self->GetHandle(); From b4e4f48f8df90055df7668d8837acc05eab7980f Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Thu, 11 May 2017 14:29:36 -0700 Subject: [PATCH 09/11] Switch the other old GetHandle-like aliases to wxUIntPtr too --- etg/dc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/etg/dc.py b/etg/dc.py index d7d94463..a62c481b 100644 --- a/etg/dc.py +++ b/etg/dc.py @@ -245,16 +245,16 @@ def run(): wxPyRaiseNotImplemented(); return 0; #endif""") - c.addCppMethod('void*', 'GetCGContext', '()', """\ + c.addCppMethod('wxUIntPtr*', 'GetCGContext', '()', """\ #ifdef __WXMAC__ - return self->GetHandle(); + return new wxUIntPtr((wxUIntPtr)self->GetHandle()); #else wxPyRaiseNotImplemented(); return NULL; #endif""") - c.addCppMethod('void*', 'GetGdkDrawable', '()', """\ + c.addCppMethod('wxUIntPtr*', 'GetGdkDrawable', '()', """\ #ifdef __WXGTK__ - return self->GetHandle(); + return new wxUIntPtr((wxUIntPtr)self->GetHandle()); #else wxPyRaiseNotImplemented(); return NULL; From 96adef7c60b29d912f5e04b49fd588c26fe09b9c Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Wed, 17 May 2017 17:46:33 -0700 Subject: [PATCH 10/11] Fix some Py3 compatibility issues --- wx/py/shell.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wx/py/shell.py b/wx/py/shell.py index b8eed3a8..a5fa6a71 100644 --- a/wx/py/shell.py +++ b/wx/py/shell.py @@ -750,10 +750,12 @@ class Shell(editwindow.EditWindow): #unique (no duplicate words #oneliner from german python forum => unique list - unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]] + unlist = [thlist[i] for i in range(len(thlist)) if thlist[i] not in thlist[:i]] #sort lowercase - unlist.sort(lambda a, b: cmp(a.lower(), b.lower())) + def _cmp(a,b): + return ((a > b) - (a < b)) + unlist.sort(lambda a, b: _cmp(a.lower(), b.lower())) #this is more convenient, isn't it? self.AutoCompSetIgnoreCase(True) From a1bafc04dfe86fcc5a3ea51ccf667a0aebc9c734 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Thu, 18 May 2017 08:19:08 -0700 Subject: [PATCH 11/11] Make TreeItemId hashable using the internal ID for the hash value, so IDs pointing to the same item will compare as equal and have the same hash values. This enables TreeItemIDs to be dictionary keys in Py3. --- etg/treectrl.py | 12 ++++++++++++ src/treeitemdata.sip | 2 +- unittests/test_treectrl.py | 7 +++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/etg/treectrl.py b/etg/treectrl.py index b11a2ca0..fdf5bc88 100644 --- a/etg/treectrl.py +++ b/etg/treectrl.py @@ -42,6 +42,18 @@ def run(): return self->IsOk(); """) + c.addCppMethod('bool', '__eq__', '(const wxTreeItemId* other)', """\ + return *self == *other; + """) + c.addCppMethod('bool', '__neq__', '(const wxTreeItemId* other)', """\ + return *self != *other; + """) + + c.addPyMethod('__hash__', '(self)', """\ + return hash(int(self.GetID())) + """) + + td = etgtools.TypedefDef(name='wxTreeItemIdValue', type='void*') module.insertItemBefore(c, td) diff --git a/src/treeitemdata.sip b/src/treeitemdata.sip index 8ad353e5..a739511c 100644 --- a/src/treeitemdata.sip +++ b/src/treeitemdata.sip @@ -14,7 +14,7 @@ %ModuleHeaderCode #include -// A wxTreeItemData that knows what to do with PyObjects for maintianing the refcount +// A wxTreeItemData that knows what to do with PyObjects for maintaining the refcount class wxPyTreeItemData : public wxPyUserDataHelper { public: diff --git a/unittests/test_treectrl.py b/unittests/test_treectrl.py index a1750481..361a8da6 100644 --- a/unittests/test_treectrl.py +++ b/unittests/test_treectrl.py @@ -28,6 +28,13 @@ class treectrl_Tests(wtc.WidgetTestCase): self.assertTrue(child is not root) self.assertTrue(child != root) + # Can TreeItemId be a dictionary key? + d = dict() + d[root] = 'root' + d[child] = 'child' + assert d[root] == 'root' + assert d[r] == 'root' + def test_treectrlTreeItemData(self): value = 'Some Python Object'