Refactor custom Create code to a separate helper function.

Add a replacement for the constructor taking arrays of rgb values.
Update and expand tests.
This commit is contained in:
Robin Dunn
2016-08-05 12:08:21 -07:00
parent 1429bb0dd2
commit a672913e97
3 changed files with 120 additions and 68 deletions

View File

@@ -661,7 +661,7 @@
"DirPickerWidgetNameStr":"wx.",
"DirSelector":"wx.",
"DirSelectorPromptStr":"wx.",
"Direction":"wx.",
"Direction":"wx.DataObject.",
"DisableAsserts":"wx.",
"Display":"wx.",
"DisplayChangedEvent":"wx.",

View File

@@ -30,8 +30,88 @@ def run():
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxPalette')
tools.removeVirtuals(c)
# Add a helper function for use with the Create method and the Ctor
# accepting RGB data.
c.addCppCode("""\
// a helper function to be used in the Create method and one of the Ctors
bool _paletteCreateHelper(wxPalette* self,
PyObject* red, PyObject* green, PyObject* blue) {
bool rval = false;
wxPyThreadBlocker blocker;
char* errMsg = "Expected a sequence of integer objects";
if (!PySequence_Check(red) || !PySequence_Check(green) || !PySequence_Check(blue)) {
PyErr_SetString(PyExc_TypeError, errMsg);
return rval;
}
Py_ssize_t count = PySequence_Size(red);
if (PySequence_Size(green) != count || PySequence_Size(blue) != count) {
PyErr_SetString(PyExc_ValueError, "Sequence lengths must be equal");
return rval;
}
unsigned char* redArray = new unsigned char[count];
unsigned char* greenArray = new unsigned char[count];
unsigned char* blueArray = new unsigned char[count];
for (Py_ssize_t i = 0; i < count; i++) {
PyObject* redItem = PySequence_ITEM(red, i);
PyObject* greenItem = PySequence_ITEM(green, i);
PyObject* blueItem = PySequence_ITEM(blue, i);
if (!wxPyInt_Check(redItem) || !wxPyInt_Check(greenItem) || !wxPyInt_Check(blueItem)) {
PyErr_SetString(PyExc_TypeError, errMsg);
goto pch_exit;
}
long redLong = wxPyInt_AsLong(redItem);
long greenLong = wxPyInt_AsLong(greenItem);
long blueLong = wxPyInt_AsLong(blueItem);
Py_DECREF(redItem);
Py_DECREF(greenItem);
Py_DECREF(blueItem);
if (redLong < 0 || redLong > 255 || greenLong < 0 || greenLong > 255 || blueLong < 0 || blueLong > 255) {
PyErr_SetString(PyExc_ValueError, "Sequence values must be in the 0..255 range");
goto pch_exit;
}
redArray[i] = redLong;
greenArray[i] = greenLong;
blueArray[i] = blueLong;
}
rval = self->Create(count, redArray, greenArray, blueArray);
pch_exit:
delete[] redArray;
delete[] greenArray;
delete[] blueArray;
return rval;
}
""")
#-----------------------------------------------------------------
# Replace the constructor accepting the arrays of RGB values with one that
# understands any Python sequence.
c.find('wxPalette').findOverload('red').ignore()
c.addCppCtor('(PyObject* red, PyObject* green, PyObject* blue)',
doc="""\
Creates a palette from a set of sequences of integers,
one for each red, green and blue color components.""",
body="""\
wxPalette* pal = new wxPalette;
_paletteCreateHelper(pal, red, green, blue);
if (PyErr_Occurred()) {
delete pal;
return NULL;
}
return pal;
""")
c.find('GetPixel.red').pyInt = True
c.find('GetPixel.green').pyInt = True
c.find('GetPixel.blue').pyInt = True
@@ -55,68 +135,19 @@ def run():
return rv;
""")
# Replace the Create method with one that understands any kind of Python sequence
c.find('Create').ignore()
c.addCppMethod('PyObject*', 'Create', '(PyObject* red, PyObject* green, PyObject* blue)',
doc="Creates a palette from 3 sequences of integers, one for each red, blue or green component.",
body="""\
bool rval = _paletteCreateHelper(self, red, green, blue);
wxPyThreadBlocker blocker;
PyObject* rval;
char* errMsg = "Expected a sequence of integer objects";
if (!PySequence_Check(red) || !PySequence_Check(green) || !PySequence_Check(blue)) {
PyErr_SetString(PyExc_TypeError, errMsg);
if (PyErr_Occurred())
return NULL;
}
Py_ssize_t count = PySequence_Size(red);
if (PySequence_Size(green) != count || PySequence_Size(blue) != count) {
PyErr_SetString(PyExc_ValueError, "Sequence lengths must be equal");
return NULL;
}
unsigned char* redArray = new unsigned char[count];
unsigned char* greenArray = new unsigned char[count];
unsigned char* blueArray = new unsigned char[count];
for (Py_ssize_t i = 0; i < count; i++) {
PyObject* redItem = PySequence_ITEM(red, i);
PyObject* greenItem = PySequence_ITEM(green, i);
PyObject* blueItem = PySequence_ITEM(blue, i);
if (!wxPyInt_Check(redItem) || !wxPyInt_Check(greenItem) || !wxPyInt_Check(blueItem)) {
PyErr_SetString(PyExc_TypeError, errMsg);
rval = NULL;
goto exit;
}
long redLong = wxPyInt_AsLong(redItem);
long greenLong = wxPyInt_AsLong(greenItem);
long blueLong = wxPyInt_AsLong(blueItem);
Py_DECREF(redItem);
Py_DECREF(greenItem);
Py_DECREF(blueItem);
if (redLong < 0 || redLong > 255 || greenLong < 0 || greenLong > 255 || blueLong < 0 || blueLong > 255) {
PyErr_SetString(PyExc_ValueError, "Sequence values must be >= 0 and < 256");
rval = NULL;
goto exit;
}
redArray[i] = redLong;
greenArray[i] = greenLong;
blueArray[i] = blueLong;
}
if (self->Create(count, redArray, greenArray, blueArray)) {
rval = Py_True;
Py_INCREF(rval);
} else {
rval = Py_False;
Py_INCREF(rval);
}
exit:
delete[] redArray;
delete[] greenArray;
delete[] blueArray;
return rval;
if (rval)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
""")

View File

@@ -6,9 +6,10 @@ import wx
class palette_Tests(wtc.WidgetTestCase):
def test_palette1(self):
def test_paletteCtor1(self):
# test with a bytearray like the original impl
rgb = bytearray(range(256))
p = wx.Palette(256, rgb, rgb, rgb)
p = wx.Palette(rgb, rgb, rgb)
self.assertTrue(p.IsOk())
self.assertTrue(p.GetColoursCount() == 256)
self.assertTrue(p.GetPixel(42, 42, 42) == 42)
@@ -17,28 +18,48 @@ class palette_Tests(wtc.WidgetTestCase):
p.GetRGB(257)
# def test_palette2(self):
# rgb = list(range(256))
# p = wx.Palette(len(rgb), rgb, rgb, rgb)
# self.assertTrue(p.IsOk())
def test_paletteCtor2(self):
# and do the same using a list
rgb = list(range(256))
p = wx.Palette(rgb, rgb, rgb)
self.assertTrue(p.IsOk())
self.assertTrue(p.GetColoursCount() == 256)
self.assertTrue(p.GetPixel(42, 42, 42) == 42)
self.assertTrue(p.GetRGB(64) == (64, 64, 64))
with self.assertRaises(IndexError):
p.GetRGB(257)
def test_paletteCtor3(self):
p = wx.Palette()
def test_paletteCtor4(self):
p1 = wx.Palette()
p2 = wx.Palette(p1)
def test_paletteCreate1(self):
p = wx.Palette()
with self.assertRaises(TypeError):
with self.assertRaises(TypeError): # not sequences
p.Create(1, 2, 3)
with self.assertRaises(ValueError):
with self.assertRaises(ValueError): # not the same length
p.Create((1, 2, 3), (1, 2, 3), (1, 2))
with self.assertRaises(TypeError):
with self.assertRaises(TypeError): # not integers
p.Create((1, 2, 3), ("1", "2", "3"), (1, 2, 3))
with self.assertRaises(ValueError):
with self.assertRaises(ValueError): # outside of 0..255 range
p.Create((257, 2, 3), (1, 2, 3), (1, 2, 3))
with self.assertRaises(ValueError):
with self.assertRaises(ValueError): # outside of 0..255 range
p.Create((1, 2, 3), (-1, 2, 3), (1, 2, 3))
# range is okay, checking start and end
p.Create((1, 2, 3, 0), (1, 2, 3, 4), (1, 2, 3, 4))
p.Create((1, 2, 3, 255), (1, 2, 3, 4), (1, 2, 3, 4))
def test_paletteCreate2(self):
p = wx.Palette()
# 3 different kinds of sequences :)
self.assertTrue(p.Create((1, 2, 3), [4, 5, 6], bytearray([7, 8, 9])))
self.assertTrue(p.GetRGB(1) == (2, 5, 8))