f55a17c
From 9096426603272672d9a676e8bcdcadf0a1cfa1a2 Mon Sep 17 00:00:00 2001
f55a17c
From: Robin Dunn <robin@alldunn.com>
f55a17c
Date: Wed, 26 Feb 2020 11:10:27 -0800
f55a17c
Subject: [PATCH] Add __index__ to wx.WindowID, and __bool__ to wx.Region
f55a17c
f55a17c
---
f55a17c
 etg/region.py              |  5 +++--
f55a17c
 etg/windowid.py            | 32 +++++++++++++++++---------------
f55a17c
 unittests/test_windowid.py | 23 +++++++++++++++++++++--
f55a17c
 3 files changed, 41 insertions(+), 19 deletions(-)
f55a17c
f55a17c
diff --git a/etg/region.py b/etg/region.py
f55a17c
index 0982c1fe5..d5bc45759 100644
f55a17c
--- a/etg/region.py
f55a17c
+++ b/etg/region.py
f55a17c
@@ -88,11 +88,12 @@ def next(self):
f55a17c
     c.mustHaveApp()
f55a17c
     c.find('operator++').ignore()
f55a17c
 
f55a17c
-    # SIP maps operator bool() to __int__, but Classic used __nonzero__. Does
f55a17c
-    # it make any difference either way?
f55a17c
     c.find('operator bool').ignore()
f55a17c
     c.addCppMethod('int', '__nonzero__', '()', 'return (int)self->operator bool();',
f55a17c
                    'Returns true while there are still rectangles available in the iteration.')
f55a17c
+    c.addCppMethod('int', '__bool__', '()', 'return (int)self->operator bool();',
f55a17c
+                   'Returns true while there are still rectangles available in the iteration.')
f55a17c
+
f55a17c
 
f55a17c
     c.addCppMethod('void', 'Next', '()', 'self->operator++();',
f55a17c
                    'Move the iterator to the next rectangle in the region.')
f55a17c
diff --git a/etg/windowid.py b/etg/windowid.py
f55a17c
index 27b041b3d..da2ed395e 100644
f55a17c
--- a/etg/windowid.py
f55a17c
+++ b/etg/windowid.py
f55a17c
@@ -53,12 +53,12 @@ def run():
f55a17c
                 MethodDef(name='wxWindowIDRef', className='wxWindowIDRef', isCtor=True,
f55a17c
                     briefDoc='Create reference from an ID',
f55a17c
                     items=[ ParamDef(type='int', name='id') ]),
f55a17c
-                
f55a17c
+
f55a17c
                 MethodDef(name='wxWindowIDRef', className='wxWindowIDRef', isCtor=True,
f55a17c
                     briefDoc='Copy an ID reference',
f55a17c
                     items=[ ParamDef(type='const wxWindowIDRef&', name='idref') ]),
f55a17c
                 ]),
f55a17c
-            
f55a17c
+
f55a17c
             MethodDef(name='~wxWindowIDRef', className='wxWindowIDRef', isDtor=True),
f55a17c
 
f55a17c
             MethodDef(type='int', name='GetValue',
f55a17c
@@ -73,11 +73,13 @@ def run():
f55a17c
             """)
f55a17c
 
f55a17c
     klass.addCppMethod('int', '__int__', '()',
f55a17c
-        doc="Alias for GetValue allowing the IDRef to be passed as the WindowID parameter when creating widgets or etc.",
f55a17c
-        body="""\
f55a17c
-            return self->GetValue();
f55a17c
-            """)
f55a17c
-    
f55a17c
+        doc="Alias for GetValue allowing the IDRef to be passed as the WindowID parameter when creating widgets or other places an integer type is needed.",
f55a17c
+        body="return self->GetValue();")
f55a17c
+    klass.addCppMethod('int', '__index__', '()',
f55a17c
+        doc="See :meth:`__int__`",
f55a17c
+        body="return self->GetValue();")
f55a17c
+
f55a17c
+
f55a17c
     klass.addCppMethod('bool', '__eq__', '(wxWindowID id)', "return self->GetValue() == id;")
f55a17c
     klass.addCppMethod('bool', '__ne__', '(wxWindowID id)', "return self->GetValue() != id;")
f55a17c
     klass.addCppMethod('bool', '__lt__', '(wxWindowID id)', "return self->GetValue() < id;")
f55a17c
@@ -92,17 +94,17 @@ def run():
f55a17c
     # and finish it up by adding it to the module
f55a17c
     module.addItem(klass)
f55a17c
 
f55a17c
-    # Now, let's add a new Python function to the global scope that reserves an 
f55a17c
-    # ID (or range) and returns a ref object for it. 
f55a17c
-    module.addPyFunction('NewIdRef', '(count=1)', 
f55a17c
+    # Now, let's add a new Python function to the global scope that reserves an
f55a17c
+    # ID (or range) and returns a ref object for it.
f55a17c
+    module.addPyFunction('NewIdRef', '(count=1)',
f55a17c
         doc="""\
f55a17c
-            Reserves a new Window ID (or range of WindowIDs) and returns a 
f55a17c
-            :class:`wx.WindowIDRef` object (or list of them) that will help 
f55a17c
+            Reserves a new Window ID (or range of WindowIDs) and returns a
f55a17c
+            :class:`wx.WindowIDRef` object (or list of them) that will help
f55a17c
             manage the reservation of that ID.
f55a17c
 
f55a17c
-            This function is intended to be a drop-in replacement of the old 
f55a17c
-            and deprecated :func:`wx.NewId` function, with the added benefit 
f55a17c
-            that the ID should never conflict with an in-use ID or other IDs 
f55a17c
+            This function is intended to be a drop-in replacement of the old
f55a17c
+            and deprecated :func:`wx.NewId` function, with the added benefit
f55a17c
+            that the ID should never conflict with an in-use ID or other IDs
f55a17c
             generated by this function.
f55a17c
             """,
f55a17c
         body="""\
f55a17c
diff --git a/unittests/test_windowid.py b/unittests/test_windowid.py
f55a17c
index 4593e5a69..fc36c9eb8 100644
f55a17c
--- a/unittests/test_windowid.py
f55a17c
+++ b/unittests/test_windowid.py
f55a17c
@@ -31,9 +31,9 @@ def test_newIdRef02(self):
f55a17c
     def test_newIdRef03(self):
f55a17c
         """Check that Auto ID Management is enabled (--enable-autoidman)"""
f55a17c
         # This test is expected to fail if autoID mangagement is turned on
f55a17c
-        # because a reference to the ID is not being saved, so it will be 
f55a17c
+        # because a reference to the ID is not being saved, so it will be
f55a17c
         # unreserved when the first widget is destroyed.
f55a17c
-        
f55a17c
+
f55a17c
         id = wx.Window.NewControlId()
f55a17c
         b = wx.Button(self.frame, id, 'button')
f55a17c
         b.Destroy()
f55a17c
@@ -75,6 +75,7 @@ def test_WindowIDRef01(self):
f55a17c
         val = ref1 <= ref2
f55a17c
         assert type(val) == bool
f55a17c
 
f55a17c
+
f55a17c
     def test_WindowIDRef02(self):
f55a17c
         d = {wx.NewIdRef(): 'one',
f55a17c
              wx.NewIdRef(): 'two'}
f55a17c
@@ -82,6 +83,24 @@ def test_WindowIDRef02(self):
f55a17c
         for k in keys:
f55a17c
             val = d[k]
f55a17c
 
f55a17c
+
f55a17c
+    def test_WindowIDRef03(self):
f55a17c
+        # Ensure wx.WindowIDRef can be converted to int without warning when
f55a17c
+        # making a call to warrped method. In Py3.8+ this means there needs to
f55a17c
+        # be an __index__ method.
f55a17c
+
f55a17c
+        # Turn warnings into exceptions so this test will fail if there is
f55a17c
+        # a warning
f55a17c
+        import warnings
f55a17c
+        warnings.simplefilter('error')
f55a17c
+
f55a17c
+        wid = wx.NewIdRef()
f55a17c
+        assert isinstance(wid, wx.WindowIDRef)
f55a17c
+
f55a17c
+        b = wx.Button(self.frame, wid, 'button')
f55a17c
+        assert b.GetId() == wid.GetId()
f55a17c
+
f55a17c
+
f55a17c
 #---------------------------------------------------------------------------
f55a17c
 
f55a17c