Add magic methods to wx.Size and add unit tests for wx.Size. Also a bit of related refactoring and cleanup.

git-svn-id: https://svn.wxwidgets.org/svn/wx/sandbox/trunk/Phoenix@66147 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2010-11-14 01:29:52 +00:00
parent 70fdcc702e
commit 24c86126d9
9 changed files with 306 additions and 56 deletions

View File

@@ -29,9 +29,9 @@ etgtools.parseDoxyXML(module, ITEMS)
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
import etgtools.tweaker_tools
etgtools.tweaker_tools.ignoreAssignmentOperators(module)
etgtools.tweaker_tools.removeWxPrefixes(module)
import etgtools.tweaker_tools as tools
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
# These items are in their own etg scripts for easier maintainability,

View File

@@ -32,9 +32,9 @@ etgtools.parseDoxyXML(module, ITEMS)
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
import etgtools.tweaker_tools
etgtools.tweaker_tools.ignoreAssignmentOperators(module)
etgtools.tweaker_tools.removeWxPrefixes(module)
import etgtools.tweaker_tools as tools
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
module.addHeaderCode('#include <wx/wx.h>')
@@ -73,7 +73,7 @@ c = module.find('wxPoint')
# Some operators are documented within the class that shouldn't be, so just
# ignore them all.
etgtools.tweaker_tools.ignoreAllOperators(c)
tools.ignoreAllOperators(c)
# Undo a few of those ignores for legitimate items that were
# documented correctly
@@ -100,46 +100,12 @@ module.insertItemAfter(c, wc)
# wxPoint typemap
c.convertFromPyObject = """\
// is it just a typecheck?
if (!sipIsErr) {
if (sipCanConvertToType(sipPy, sipType_wxPoint, SIP_NO_CONVERTORS))
return 1;
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxPoint')
if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 2) {
int rval = 1;
PyObject* o1 = PySequence_ITEM(sipPy, 0);
PyObject* o2 = PySequence_ITEM(sipPy, 1);
if (!PyNumber_Check(o1) || !PyNumber_Check(o2))
rval = 0;
Py_DECREF(o1);
Py_DECREF(o2);
return rval;
}
return 0;
}
// otherwise do the conversion
if (PySequence_Check(sipPy)) {
PyObject* o1 = PySequence_ITEM(sipPy, 0);
PyObject* o2 = PySequence_ITEM(sipPy, 1);
*sipCppPtr = new wxPoint(PyInt_AsLong(o1), PyInt_AsLong(o2));
Py_DECREF(o1);
Py_DECREF(o2);
return sipGetState(sipTransferObj);
}
*sipCppPtr = reinterpret_cast<wxPoint*>(sipConvertToType(
sipPy, sipType_wxPoint, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return 0;
"""
# Helper to convert a Point to a tuple
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->x, sipCpp->y);
""", briefDoc="""\
Get() -> (x,y)
Get() -> (x,y)\n
Return the x and y properties as a tuple.""")
# Add sequence protocol methods and other goodies
@@ -168,7 +134,7 @@ c.addProperty("width GetWidth SetWidth")
c.addProperty("height GetHeight SetHeight")
# take care of the same issues as wxPoint
etgtools.tweaker_tools.ignoreAllOperators(c)
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator-=').all() + \
c.find('operator*=').all() + \
@@ -186,12 +152,38 @@ wxSize operator/(const wxSize& s, int i);
module.insertItemAfter(c, wc)
# wxSize typemap
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxSize')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->GetWidth(), sipCpp->GetHeight());
""", briefDoc="""\
Get() -> (width, height)\n
Return the width and height properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Size"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Size, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.width = val
elif idx == 1: self.height = val
else: raise IndexError
""")
c.addPyCode('Size.__safe_for_unpickling__ = True')
#---------------------------------------
# wxRect tweaks
c = module.find('wxRect')
# take care of the same issues as wxPoint
etgtools.tweaker_tools.ignoreAllOperators(c)
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator*=').all():
f.ignore(False)
@@ -216,7 +208,7 @@ module.find('wxRect.Intersect').findOverload(') const').ignore()
c = module.find('wxRealPoint')
# take care of the same issues as wxPoint
etgtools.tweaker_tools.ignoreAllOperators(c)
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator-=').all():
f.ignore(False)

View File

@@ -30,9 +30,9 @@ etgtools.parseDoxyXML(module, ITEMS)
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
import etgtools.tweaker_tools
etgtools.tweaker_tools.ignoreAssignmentOperators(module)
etgtools.tweaker_tools.removeWxPrefixes(module)
import etgtools.tweaker_tools as tools
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
module.addHeaderCode('#include <wx/wx.h>')

View File

@@ -31,9 +31,9 @@ etgtools.parseDoxyXML(module, ITEMS)
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
import etgtools.tweaker_tools
etgtools.tweaker_tools.ignoreAssignmentOperators(module)
etgtools.tweaker_tools.removeWxPrefixes(module)
import etgtools.tweaker_tools as tools
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
module.find('wxObject.operator delete').ignore()

View File

@@ -27,9 +27,9 @@ etgtools.parseDoxyXML(module, ITEMS)
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
import etgtools.tweaker_tools
etgtools.tweaker_tools.ignoreAssignmentOperators(module)
etgtools.tweaker_tools.removeWxPrefixes(module)
import etgtools.tweaker_tools as tools
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)

View File

@@ -326,7 +326,7 @@ from %s import *
stream.write(')')
if prop.briefDoc:
stream.write(' // %s' % prop.briefDoc)
stream.write('\n')
stream.write('\n\n')
def generateMethod(self, method, stream, indent):

View File

@@ -54,3 +54,39 @@ def createPyArgsStrings(node):
items that can be used as part of the docstring.
"""
pass
def convertTwoIntegersTemplate(CLASS):
return """\
// is it just a typecheck?
if (!sipIsErr) {{
if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS))
return 1;
if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 2) {{
int rval = 1;
PyObject* o1 = PySequence_ITEM(sipPy, 0);
PyObject* o2 = PySequence_ITEM(sipPy, 1);
if (!PyNumber_Check(o1) || !PyNumber_Check(o2))
rval = 0;
Py_DECREF(o1);
Py_DECREF(o2);
return rval;
}}
return 0;
}}
// otherwise do the conversion
if (PySequence_Check(sipPy)) {{
PyObject* o1 = PySequence_ITEM(sipPy, 0);
PyObject* o2 = PySequence_ITEM(sipPy, 1);
*sipCppPtr = new {CLASS}(PyInt_AsLong(o1), PyInt_AsLong(o2));
Py_DECREF(o1);
Py_DECREF(o2);
return sipGetState(sipTransferObj);
}}
*sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType(
sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return 0;
""".format(**locals())

View File

@@ -271,10 +271,105 @@ public:
);
%Property(name=width, get=GetWidth, set=SetWidth)
%Property(name=height, get=GetHeight, set=SetHeight)
SIP_PYOBJECT Get();
%MethodCode
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->GetWidth(), sipCpp->GetHeight());
%End
%ConvertToTypeCode
// is it just a typecheck?
if (!sipIsErr) {
if (sipCanConvertToType(sipPy, sipType_wxSize, SIP_NO_CONVERTORS))
return 1;
if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 2) {
int rval = 1;
PyObject* o1 = PySequence_ITEM(sipPy, 0);
PyObject* o2 = PySequence_ITEM(sipPy, 1);
if (!PyNumber_Check(o1) || !PyNumber_Check(o2))
rval = 0;
Py_DECREF(o1);
Py_DECREF(o2);
return rval;
}
return 0;
}
// otherwise do the conversion
if (PySequence_Check(sipPy)) {
PyObject* o1 = PySequence_ITEM(sipPy, 0);
PyObject* o2 = PySequence_ITEM(sipPy, 1);
*sipCppPtr = new wxSize(PyInt_AsLong(o1), PyInt_AsLong(o2));
Py_DECREF(o1);
Py_DECREF(o2);
return sipGetState(sipTransferObj);
}
*sipCppPtr = reinterpret_cast<wxSize*>(sipConvertToType(
sipPy, sipType_wxSize, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return 0;
%End
}; // end of class wxSize
%Extract pycode
def _Size___str__(self):
return str(self.Get())
Size.__str__ = _Size___str__
%End
%Extract pycode
def _Size___repr__(self):
return "wx.Size"+str(self.Get())
Size.__repr__ = _Size___repr__
%End
%Extract pycode
def _Size___len__(self):
return len(self.Get())
Size.__len__ = _Size___len__
%End
%Extract pycode
def _Size___nonzero__(self):
return self.Get() != (0,0)
Size.__nonzero__ = _Size___nonzero__
%End
%Extract pycode
def _Size___reduce__(self):
return (Size, self.Get())
Size.__reduce__ = _Size___reduce__
%End
%Extract pycode
def _Size___getitem__(self, idx):
return self.Get()[idx]
Size.__getitem__ = _Size___getitem__
%End
%Extract pycode
def _Size___setitem__(self, idx, val):
if idx == 0: self.width = val
elif idx == 1: self.height = val
else: raise IndexError
Size.__setitem__ = _Size___setitem__
%End
%Extract pycode
Size.__safe_for_unpickling__ = True
%End
bool operator==(const wxSize& s1, const wxSize& s2);
bool operator!=(const wxSize& s1, const wxSize& s2);
wxSize operator*(const wxSize& s, int i);

View File

@@ -1,6 +1,9 @@
import unittest2
import wx
#---------------------------------------------------------------------------
class Point(unittest2.TestCase):
def test_default_ctor(self):
@@ -80,8 +83,132 @@ class Point(unittest2.TestCase):
with self.assertRaises(IndexError):
p[2]
#---------------------------------------------------------------------------
class Size(unittest2.TestCase):
def test_default_ctor(self):
s = wx.Size()
self.assertTrue(s == (0,0))
def test_wh_ctor(self):
s = wx.Size(100,200)
def test_copy_ctor(self):
s1 = wx.Size(100,200)
s2 = wx.Size(s1)
self.assertTrue(s1 is not s2)
self.assertTrue(s1 == s2)
def test_bogus_ctor(self):
with self.assertRaises(TypeError):
s = wx.Size("aa", "bb")
def test_DecBy(self):
s = wx.Size(100,100)
s.DecBy(wx.Point(5,5))
self.assertTrue(s == (95,95))
s.DecBy(wx.Size(5,5))
self.assertTrue(s == (90,90))
s.DecBy(5,5)
self.assertTrue(s == (85,85))
s.DecBy(5)
self.assertTrue(s == (80,80))
s.DecBy( (5,5) )
self.assertTrue(s == (75,75))
def test_IncBy(self):
s = wx.Size(50,50)
s.IncBy(wx.Point(5,5))
self.assertTrue(s == (55,55))
s.IncBy(wx.Size(5,5))
self.assertTrue(s == (60,60))
s.IncBy(5,5)
self.assertTrue(s == (65,65))
s.IncBy(5)
self.assertTrue(s == (70,70))
s.IncBy( (5,5) )
self.assertTrue(s == (75,75))
def test_DecTo(self):
s = wx.Size(5, 15)
s.DecTo( (10,10) )
self.assertTrue(s == (5,10))
def test_IncTo(self):
s = wx.Size(5, 15)
s.IncTo( (10,10) )
self.assertTrue(s == (10,15))
def test_properties(self):
s = wx.Size(23,34)
self.assertTrue(s.width == 23 and s.height == 34)
s.width += 1
s.height += 1
self.assertTrue(s == (24,35))
def test_operators(self):
s1 = wx.Size(100,200)
s2 = wx.Size(30,40)
s1 += s2
s1 -= s2
s1 *= 5
s1 /= 5
s1 == s2
s1 != s2
s = s1 * 5
s = 5 * s1
s = s1 + s2
s = s1 - s2
s = s1 / 5
def test_GetSet(self):
s = wx.Size(100,200)
t = s.Get()
self.assertTrue(type(t) == tuple)
self.assertTrue(t == (100,200))
s.Set(5,10)
self.assertTrue(s.Get() == (5,10))
def test_SetDefaults(self):
s = wx.Size(50, -1)
s.SetDefaults( (25,25) )
self.assertTrue(s == (50,25))
def test_FullySpecified(self):
self.assertTrue(wx.Size(40,50).IsFullySpecified())
self.assertTrue(not wx.Size(-1,50).IsFullySpecified())
self.assertTrue(not wx.Size(40,-1).IsFullySpecified())
def test_magic(self):
s = wx.Size(5,6)
self.assertTrue(str(s) == "(5, 6)")
self.assertTrue(repr(s) == "wx.Size(5, 6)")
self.assertTrue(len(s) == 2)
w, h = s
self.assertTrue(5 == 5 and h == 6)
s[0] += 1 # tests both getitem and setitem
s[1] += 2
self.assertTrue(s == (6,8))
with self.assertRaises(IndexError):
s[2]
#---------------------------------------------------------------------------
if __name__ == '__main__':
unittest2.main()