diff options
author | Paul Pogonyshev <pogonyshev@gmx.net> | 2008-08-28 19:39:40 +0000 |
---|---|---|
committer | Paul Pogonyshev <paulp@src.gnome.org> | 2008-08-28 19:39:40 +0000 |
commit | 893f5338d35152c363ead8cde593656880054f1a (patch) | |
tree | 1815562f54c1b710664d4a7d0c0c5ae6a70e1389 | |
parent | afb4ff94e80dbdc8db82b502626fd14d251d40d7 (diff) | |
download | pygtk-893f5338d35152c363ead8cde593656880054f1a.tar.gz |
Bug 526189 – add __str__ and/or __repr__ to several types
2008-08-28 Paul Pogonyshev <pogonyshev@gmx.net>
Bug 526189 – add __str__ and/or __repr__ to several types
* gtk/gdk.override (_wrap_gdk_cursor_tp_repr): New function.
* gtk/gdkcolor.override (pygdk_color_to_string_smart)
(_wrap_gdk_color_tp_repr, _wrap_gdk_color_tp_str): New functions.
* gtk/gdkevent.override (_wrap_gdk_event_tp_repr): New function.
* gtk/gdkrectangle.override (_wrap_gdk_rectangle_tp_repr): New
function.
* tests/test_color.py (Tests.test_repr, Tests.test_str): New tests.
(Tests._test_color_list): New helper method.
* tests/test_rectangle.py (Tests.test_repr): New test.
(Tests._test_rectangle_list): New helper method.
2008-08-28 Paul Pogonyshev <pogonyshev@gmx.net>
* pygtk-gdkrectangle.xml: Document __repr__.
* pygtk-gdkcolor.xml: Document __repr__ and __str__.
* pygtk-gdkevent.xml: Document __repr__.
svn path=/trunk/; revision=3029
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | docs/reference/ChangeLog | 8 | ||||
-rw-r--r-- | docs/reference/pygtk-gdkcolor.xml | 17 | ||||
-rw-r--r-- | docs/reference/pygtk-gdkevent.xml | 11 | ||||
-rw-r--r-- | docs/reference/pygtk-gdkrectangle.xml | 10 | ||||
-rw-r--r-- | gtk/gdk.override | 14 | ||||
-rw-r--r-- | gtk/gdkcolor.override | 52 | ||||
-rw-r--r-- | gtk/gdkevent.override | 153 | ||||
-rw-r--r-- | gtk/gdkrectangle.override | 9 | ||||
-rw-r--r-- | tests/test_color.py | 19 | ||||
-rw-r--r-- | tests/test_rectangle.py | 12 |
11 files changed, 325 insertions, 0 deletions
@@ -1,5 +1,25 @@ 2008-08-28 Paul Pogonyshev <pogonyshev@gmx.net> + Bug 526189 – add __str__ and/or __repr__ to several types + + * gtk/gdk.override (_wrap_gdk_cursor_tp_repr): New function. + + * gtk/gdkcolor.override (pygdk_color_to_string_smart) + (_wrap_gdk_color_tp_repr, _wrap_gdk_color_tp_str): New functions. + + * gtk/gdkevent.override (_wrap_gdk_event_tp_repr): New function. + + * gtk/gdkrectangle.override (_wrap_gdk_rectangle_tp_repr): New + function. + + * tests/test_color.py (Tests.test_repr, Tests.test_str): New tests. + (Tests._test_color_list): New helper method. + + * tests/test_rectangle.py (Tests.test_repr): New test. + (Tests._test_rectangle_list): New helper method. + +2008-08-28 Paul Pogonyshev <pogonyshev@gmx.net> + Bug 534658 – Avoid warning when compiling against Python 2.5 or older diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 00db8482..62438b31 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,11 @@ +2008-08-28 Paul Pogonyshev <pogonyshev@gmx.net> + + * pygtk-gdkrectangle.xml: Document __repr__. + + * pygtk-gdkcolor.xml: Document __repr__ and __str__. + + * pygtk-gdkevent.xml: Document __repr__. + 2008-08-02 Paul Pogonyshev <pogonyshev@gmx.net> Bug 527212 – types with well-defined equality semantics are not diff --git a/docs/reference/pygtk-gdkcolor.xml b/docs/reference/pygtk-gdkcolor.xml index efc21fd6..60d3ab53 100644 --- a/docs/reference/pygtk-gdkcolor.xml +++ b/docs/reference/pygtk-gdkcolor.xml @@ -117,6 +117,16 @@ object.</para> the constructor. </para> + <para> + Also beginning with PyGTK 2.14 <classname>gtk.gdk.Color</classname> objects have + custom support for <function>str</function> and <function>repr</function> Python + functions. For any color it holds that: + </para> + + <programlisting> + color == eval(repr(color)) + </programlisting> + </refsect1> <refsect1 id="constructor-gdkcolor"> @@ -220,6 +230,13 @@ allocated.</para> where r, g and b are hex digits representing the red, green and blue components respectively. </para> + + <note> + <para>Starting with PyGTK 2.14 you can also + use <literal>str(color)</literal> code. However, that can return a + shorter (3, 6 or 12 hexadecimal digits) string if shorter version means + the same for the constructor.</para> + </note> </refsect2> </refsect1> diff --git a/docs/reference/pygtk-gdkevent.xml b/docs/reference/pygtk-gdkevent.xml index c995aaa2..a5e2b638 100644 --- a/docs/reference/pygtk-gdkevent.xml +++ b/docs/reference/pygtk-gdkevent.xml @@ -1920,6 +1920,17 @@ method. The masks are:</para> <para><literal>gtk.gdk.ALL_EVENTS_MASK</literal> is a combination of all the event masks.</para> + <para> + Starting with PyGTK 2.14 <classname>gtk.gdk.Event</classname> objects have custom + support for <function>repr</function> Python function. Text representation will + include event type and a few most important event attributes, + e.g. <literal>x</literal>, <literal>y</literal> and <literal>button</literal> + for <literal>gtk.gdk.BUTTON_PRESS</literal> events. However, round-tripping + through <literal>eval(repr(event))</literal> is not possible: representation string + uses <literal><...></literal> form. + </para> + + </refsect1> <refsect1 id="constructor-gdkevent"> diff --git a/docs/reference/pygtk-gdkrectangle.xml b/docs/reference/pygtk-gdkrectangle.xml index 222ab3f5..b37bd3a7 100644 --- a/docs/reference/pygtk-gdkrectangle.xml +++ b/docs/reference/pygtk-gdkrectangle.xml @@ -113,6 +113,16 @@ attributes.</para> rectangle = gtk.gdk.Rectangle(*tuple) </programlisting> + <para> + Also beginning with PyGTK 2.14 <classname>gtk.gdk.Rectangle</classname> objects have + custom support for <function>repr</function> Python function. For any rectangle it + holds that: + </para> + + <programlisting> + rectangle == eval(repr(rectangle)) + </programlisting> + </refsect1> <refsect1 id="constructor-gdkrectangle"> diff --git a/gtk/gdk.override b/gtk/gdk.override index d56d4e2e..2080d708 100644 --- a/gtk/gdk.override +++ b/gtk/gdk.override @@ -503,6 +503,20 @@ _wrap_gdk_cursor_new(PyGBoxed *self, PyObject *args, PyObject *kwargs) return 0; } %% +override-slot GdkCursor.tp_repr +static PyObject * +_wrap_gdk_cursor_tp_repr(PyGObject *self) +{ + GdkCursor *cursor = pyg_boxed_get(self, GdkCursor); + GEnumValue *type = g_enum_get_value(g_type_class_peek(GDK_TYPE_CURSOR_TYPE), cursor->type); + + /* We use <...> syntax because gtk.gdk.Cursor objects are generally impossible to + * reconstruct with eval(repr(...)) round-trip. */ + return PyString_FromFormat("<%s at %p: %s>", + self->ob_type->tp_name, self, + type ? type->value_name : "UNKNOWN TYPE"); +} +%% override gdk_region_get_clipbox noargs static PyObject * _wrap_gdk_region_get_clipbox(PyGObject *self) diff --git a/gtk/gdkcolor.override b/gtk/gdkcolor.override index fe995265..496b5be1 100644 --- a/gtk/gdkcolor.override +++ b/gtk/gdkcolor.override @@ -221,6 +221,58 @@ _wrap_gdk_color_tp_richcompare(PyObject *self, PyObject *other, int op) return result; } %% +override-slot GdkColor.tp_repr +static int +pygdk_color_to_string_smart(char *buffer, int length, GdkColor *color) +{ + /* We use g_snprintf() because PyString_FromFormat() doesn't support %0Nx-like formats + * (i.e. with leading zeros). + * + * Note that numbers here are used so that there is no off-by-one errors in + * 'eval(repr(color))', i.e. so that 'eval(repr(color)) == color'. See + * pango_color_parse() for justification of these numbers. Three-nibble color + * components are deemed unimportant. + */ + if (color->red % 0x1111 == 0 && color->green % 0x1111 == 0 && color->blue % 0x1111 == 0) { + return g_snprintf(buffer, length, "#%01x%01x%01x", + color->red / 0x1111, color->green / 0x1111, color->blue / 0x1111); + } + else if (color->red % 0x0101 == 0 && color->green % 0x0101 == 0 && color->blue % 0x0101 == 0) { + return g_snprintf(buffer, length, "#%02x%02x%02x", + color->red / 0x0101, color->green / 0x0101, color->blue / 0x0101); + } + else { + return g_snprintf(buffer, length, "#%04x%04x%04x", + color->red, color->green, color->blue); + } +} +static PyObject * +_wrap_gdk_color_tp_repr(PyGBoxed *self) +{ + static char buffer[0x40]; + int length = 0; + + length += g_snprintf(buffer + length, sizeof buffer - length, "%s('", self->ob_type->tp_name); + length += pygdk_color_to_string_smart(buffer + length, sizeof buffer - length, + pyg_boxed_get(self, GdkColor)); + length += g_snprintf(buffer + length, sizeof buffer - length, "')"); + + return PyString_FromStringAndSize(buffer, length); +} +%% +override-slot GdkColor.tp_str +static PyObject * +_wrap_gdk_color_tp_str(PyGBoxed *self) +{ + /* gtk.gdk.Color has a meaningful informal representation, so we define both __repr__ + * and __str__, unlike for most other types. + */ + static char buffer[1 + 4*3 + 1]; /* # + at most 4 digits per component + \0 */ + int length = pygdk_color_to_string_smart(buffer, sizeof buffer, pyg_boxed_get(self, GdkColor)); + + return PyString_FromStringAndSize(buffer, length); +} +%% override gdk_colormap_query_color kwargs static PyObject * _wrap_gdk_colormap_query_color(PyGObject *self, PyObject *args, diff --git a/gtk/gdkevent.override b/gtk/gdkevent.override index 38fffef1..3c0501d2 100644 --- a/gtk/gdkevent.override +++ b/gtk/gdkevent.override @@ -918,3 +918,156 @@ _wrap_gdk_event_free(PyObject *self) Py_INCREF(Py_None); return Py_None; } +%% +override-slot GdkEvent.tp_repr +static PyObject * +_wrap_gdk_event_tp_repr(PyGObject *self) +{ + static char buffer[0x400]; + int length = 0; + + GdkEvent *event = pyg_boxed_get(self, GdkEvent); + GEnumValue *type = g_enum_get_value(g_type_class_peek(GDK_TYPE_EVENT_TYPE), event->type); + + length += g_snprintf(buffer + length, sizeof buffer - length, "<%s at %p: %s", + self->ob_type->tp_name, self, type ? type->value_name : "UNKNOWN TYPE"); + + /* Depending on event type we will append values of some most important attributes to + * representation string. In any case, this information is not enough to reconstruct + * the event object (and in any case gtk.gdk.Event is incapable of doing so), + * therefore the <...> syntax. + */ + switch(event->type) { + case GDK_NOTHING: break; + case GDK_DELETE: break; + case GDK_DESTROY: break; + case GDK_EXPOSE: + { + length += g_snprintf(buffer + length, sizeof buffer - length, " area=[%d, %d, %d, %d]", + event->expose.area.x, event->expose.area.y, + event->expose.area.width, event->expose.area.height); + break; + } + case GDK_MOTION_NOTIFY: + { + length += g_snprintf(buffer + length, sizeof buffer - length, " x=%.2f, y=%.2f", + event->motion.x, event->motion.y); + break; + } + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + { + length += g_snprintf(buffer + length, sizeof buffer - length, + " x=%.2f, y=%.2f, button=%d", + event->button.x, event->button.y, event->button.button); + break; + } + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + { + const gchar *key = gdk_keyval_name(event->key.keyval); + + if (key) + length += g_snprintf(buffer + length, sizeof buffer - length, " keyval=%s", key); + else + length += g_snprintf(buffer + length, sizeof buffer - length, + " keyval=%d", event->key.keyval); + break; + } + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + { + GEnumValue *mode = g_enum_get_value(g_type_class_peek(GDK_TYPE_CROSSING_MODE), + event->crossing.mode); + length += g_snprintf(buffer + length, sizeof buffer - length, + " x=%.2f, y=%.2f, mode=%s", + event->crossing.x, event->crossing.y, + mode ? mode->value_name : "UNKNOWN"); + break; + } + case GDK_FOCUS_CHANGE: break; + case GDK_CONFIGURE: + { + length += g_snprintf(buffer + length, sizeof buffer - length, + " x=%d, y=%d, width=%d, height=%d", + event->configure.x, event->configure.y, + event->configure.width, event->configure.height); + break; + } + case GDK_MAP: break; + case GDK_UNMAP: break; + case GDK_PROPERTY_NOTIFY: + { + length += g_snprintf(buffer + length, sizeof buffer - length, " atom=%s", + gdk_atom_name(event->property.atom)); + break; + } + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + { + length += g_snprintf(buffer + length, sizeof buffer - length, + " selection=%s, target=%s, property=%s", + gdk_atom_name(event->selection.selection), + gdk_atom_name(event->selection.target), + gdk_atom_name(event->selection.property)); + break; + } + case GDK_PROXIMITY_IN: break; + case GDK_PROXIMITY_OUT: break; + case GDK_DRAG_ENTER: break; + case GDK_DRAG_LEAVE: break; + case GDK_DRAG_MOTION: break; + case GDK_DRAG_STATUS: break; + case GDK_DROP_START: break; + case GDK_DROP_FINISHED: break; + case GDK_CLIENT_EVENT: break; + case GDK_VISIBILITY_NOTIFY: + { + GEnumValue *state = g_enum_get_value(g_type_class_peek(GDK_TYPE_VISIBILITY_STATE), + event->visibility.state); + length += g_snprintf(buffer + length, sizeof buffer - length, + " state=%s", state ? state->value_name : "UNKNOWN"); + break; + } + case GDK_NO_EXPOSE: break; + case GDK_SCROLL: + { + GEnumValue *direction = g_enum_get_value(g_type_class_peek(GDK_TYPE_SCROLL_DIRECTION), + event->scroll.direction); + length += g_snprintf(buffer + length, sizeof buffer - length, + " x=%.2f, y=%.2f, direction=%s", + event->scroll.x, event->scroll.y, + direction ? direction->value_name : "UNKNOWN"); + break; + } + case GDK_WINDOW_STATE: break; + case GDK_SETTING: + { + GEnumValue *action = g_enum_get_value(g_type_class_peek(GDK_TYPE_SETTING_ACTION), + event->setting.action); + length += g_snprintf(buffer + length, sizeof buffer - length, + " action=%s, name=%s", + action ? action->value_name : "UNKNOWN", + event->setting.name); + break; + } + case GDK_OWNER_CHANGE: + { + GEnumValue *reason = g_enum_get_value(g_type_class_peek(GDK_TYPE_OWNER_CHANGE), + event->owner_change.reason); + length += g_snprintf(buffer + length, sizeof buffer - length, + " reason=%s, selection=%s", + reason ? reason->value_name : "UNKNOWN", + gdk_atom_name(event->owner_change.selection)); + break; + } + default: + break; + } + + length += g_snprintf(buffer + length, sizeof buffer - length, ">"); + return PyString_FromStringAndSize(buffer, length); +} diff --git a/gtk/gdkrectangle.override b/gtk/gdkrectangle.override index 06274c42..065625fd 100644 --- a/gtk/gdkrectangle.override +++ b/gtk/gdkrectangle.override @@ -247,3 +247,12 @@ _wrap_gdk_rectangle_tp_richcompare(PyObject *self, PyObject *other, int op) Py_INCREF(result); return result; } +%% +override-slot GdkRectangle.tp_repr +static PyObject * +_wrap_gdk_rectangle_tp_repr(PyGBoxed *self) +{ + GdkRectangle *rect = pyg_boxed_get(self, GdkRectangle); + return PyString_FromFormat("%s(%d, %d, %d, %d)", self->ob_type->tp_name, + rect->x, rect->y, rect->width, rect->height); +} diff --git a/tests/test_color.py b/tests/test_color.py index 616c716e..72ad6693 100644 --- a/tests/test_color.py +++ b/tests/test_color.py @@ -55,6 +55,25 @@ class Tests(unittest.TestCase): {} [gtk.gdk.Color()] = 'must raise' self.assertRaises(TypeError, dict_key) + def test_repr(self): + for color in self._test_color_list(): + self.assertEqual(color, eval(repr(color))) + + def test_str(self): + for color in self._test_color_list(): + self.assertEqual(color, gtk.gdk.Color(str(color))) + + def _test_color_list(self): + return [gtk.gdk.Color(), + gtk.gdk.Color(10, 20, 30), + gtk.gdk.Color(65535, 65535, 65535), + gtk.gdk.Color('red'), + gtk.gdk.Color('#aaa'), + gtk.gdk.Color('#f0a000'), + gtk.gdk.Color('#123abcdef'), + gtk.gdk.Color('#123412341234'), + gtk.gdk.Color('#fedcfedcfedc')] + if __name__ == '__main__': unittest.main() diff --git a/tests/test_rectangle.py b/tests/test_rectangle.py index ab5b0646..0be89b0c 100644 --- a/tests/test_rectangle.py +++ b/tests/test_rectangle.py @@ -23,6 +23,18 @@ class Tests(unittest.TestCase): {} [gtk.gdk.Rectangle()] = 'must raise' self.assertRaises(TypeError, dict_key) + def test_repr(self): + for rectangle in self._test_rectangle_list(): + self.assertEqual(rectangle, eval(repr(rectangle))) + + def _test_rectangle_list(self): + return [gtk.gdk.Rectangle(), + gtk.gdk.Rectangle(0, 0, 100, 100), + gtk.gdk.Rectangle(-10, 10, 30, 50), + gtk.gdk.Rectangle(-100, -100, 20, 25), + gtk.gdk.Rectangle(0, 0, 0, 20), + gtk.gdk.Rectangle(1, 1, 20, 0)] + if __name__ == '__main__': unittest.main() |