summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Pogonyshev <pogonyshev@gmx.net>2008-08-28 19:39:40 +0000
committerPaul Pogonyshev <paulp@src.gnome.org>2008-08-28 19:39:40 +0000
commit893f5338d35152c363ead8cde593656880054f1a (patch)
tree1815562f54c1b710664d4a7d0c0c5ae6a70e1389
parentafb4ff94e80dbdc8db82b502626fd14d251d40d7 (diff)
downloadpygtk-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--ChangeLog20
-rw-r--r--docs/reference/ChangeLog8
-rw-r--r--docs/reference/pygtk-gdkcolor.xml17
-rw-r--r--docs/reference/pygtk-gdkevent.xml11
-rw-r--r--docs/reference/pygtk-gdkrectangle.xml10
-rw-r--r--gtk/gdk.override14
-rw-r--r--gtk/gdkcolor.override52
-rw-r--r--gtk/gdkevent.override153
-rw-r--r--gtk/gdkrectangle.override9
-rw-r--r--tests/test_color.py19
-rw-r--r--tests/test_rectangle.py12
11 files changed, 325 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 4e5a2750..e9fcb771 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>&lt;...&gt;</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()