diff options
author | Jason Madden <jamadden@gmail.com> | 2015-05-07 15:22:14 -0500 |
---|---|---|
committer | Jason Madden <jamadden@gmail.com> | 2015-05-07 15:22:14 -0500 |
commit | 934dc2fac1962e2c2443a1f62d18b0643c49201b (patch) | |
tree | 9efebfb921e844d1993db3f7652e5dfa5d2e9382 /src | |
parent | 65ebb9d1fba58423d11bb07d16684c693086db6b (diff) | |
download | zope-proxy-934dc2fac1962e2c2443a1f62d18b0643c49201b.tar.gz |
Make the C implementation proxy __unicode__, and make it use the standard methods to proxy int and float. Fixes #3 and Fixes #4.
Diffstat (limited to 'src')
-rw-r--r-- | src/zope/proxy/_compat.py | 6 | ||||
-rw-r--r-- | src/zope/proxy/_zope_proxy_proxy.c | 52 | ||||
-rw-r--r-- | src/zope/proxy/tests/test_proxy.py | 66 |
3 files changed, 95 insertions, 29 deletions
diff --git a/src/zope/proxy/_compat.py b/src/zope/proxy/_compat.py index be8d867..4b9ed15 100644 --- a/src/zope/proxy/_compat.py +++ b/src/zope/proxy/_compat.py @@ -2,3 +2,9 @@ import sys PY3 = sys.version_info[0] >= 3 +if PY3: # pragma NO COVER + def _u(s): + return s +else: + def _u(s): + return unicode(s, 'unicode_escape') diff --git a/src/zope/proxy/_zope_proxy_proxy.c b/src/zope/proxy/_zope_proxy_proxy.c index 9166976..0df67b6 100644 --- a/src/zope/proxy/_zope_proxy_proxy.c +++ b/src/zope/proxy/_zope_proxy_proxy.c @@ -420,26 +420,18 @@ wrap_call(PyObject *self, PyObject *args, PyObject *kw) static PyObject * call_int(PyObject *self) { - PyNumberMethods *nb = self->ob_type->tp_as_number; - if (nb == NULL || nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, - "object can't be converted to int"); - return NULL; - } - return nb->nb_int(self); +#if PY_MAJOR_VERSION < 3 + return PyNumber_Int(self); +#else + return PyNumber_Long(self); +#endif } #if PY_MAJOR_VERSION < 3 // Python 3 has no long, oct or hex methods. static PyObject * call_long(PyObject *self) { - PyNumberMethods *nb = self->ob_type->tp_as_number; - if (nb == NULL || nb->nb_long == NULL) { - PyErr_SetString(PyExc_TypeError, - "object can't be converted to long"); - return NULL; - } - return nb->nb_long(self); + return PyNumber_Long(self); } static PyObject * @@ -471,25 +463,13 @@ call_hex(PyObject *self) static PyObject * call_index(PyObject *self) { - PyNumberMethods *nb = self->ob_type->tp_as_number; - if (nb == NULL || nb->nb_index == NULL) { - PyErr_SetString(PyExc_TypeError, - "object can't be converted to index"); - return NULL; - } - return nb->nb_index(self); + return PyNumber_Index(self); } static PyObject * call_float(PyObject *self) { - PyNumberMethods *nb = self->ob_type->tp_as_number; - if (nb == NULL || nb->nb_float== NULL) { - PyErr_SetString(PyExc_TypeError, - "object can't be converted to float"); - return NULL; - } - return nb->nb_float(self); + return PyNumber_Float(self); } static PyObject * @@ -499,6 +479,15 @@ call_ipow(PyObject *self, PyObject *other) return PyNumber_InPlacePower(self, other, Py_None); } +#if PY_MAJOR_VERSION < 3 +static PyObject * +call_unicode(PyObject *self) +{ + return PyObject_Unicode(self); +} +#endif + + typedef PyObject *(*function1)(PyObject *); static PyObject * @@ -691,6 +680,10 @@ INPLACE(floordiv, PyNumber_InPlaceFloorDivide) INPLACE(truediv, PyNumber_InPlaceTrueDivide) UNOP(index, call_index) +#if PY_MAJOR_VERSION < 3 // Python 3 has no __unicode__ method +UNOP(unicode, call_unicode) +#endif + static int wrap_nonzero(PyObject *self) { @@ -874,6 +867,9 @@ wrap_as_mapping = { static PyMethodDef wrap_methods[] = { {"__reduce__", (PyCFunction)wrap_reduce, METH_NOARGS, reduce__doc__}, +#if PY_MAJOR_VERSION < 3 + {"__unicode__", (PyCFunction)wrap_unicode, METH_NOARGS, "" }, +#endif {NULL, NULL}, }; diff --git a/src/zope/proxy/tests/test_proxy.py b/src/zope/proxy/tests/test_proxy.py index bfd6c5b..0f2bc41 100644 --- a/src/zope/proxy/tests/test_proxy.py +++ b/src/zope/proxy/tests/test_proxy.py @@ -418,7 +418,7 @@ class PyProxyBaseTestCase(unittest.TestCase): "complex(x)", ] if not PY3: # long is gone in Python 3 - ops.append("long(x)") + ops.append("long(x)") return ops def test_unops(self): @@ -581,6 +581,70 @@ class PyProxyBaseTestCase(unittest.TestCase): w = self._makeOne(o) self.assertTrue(w.__class__ is o.__class__) + def test_string_to_int(self): + # Strings don't have the tp_number.tp_int pointer + proxy = self._makeOne("14") + self.assertEqual(14, int(proxy)) + + def test_custom_int_to_int(self): + class CustomClass(object): + def __int__(self): + return 42 + proxy = self._makeOne(CustomClass()) + self.assertEqual(42, int(proxy)) + + def test_string_to_float(self): + proxy = self._makeOne("14") + self.assertEqual(float("14"), float(proxy)) + + def test_incorrect_string_to_int(self): + proxy = self._makeOne("") + self.assertRaises(ValueError, int, proxy) + + def test_incorrect_string_to_float(self): + proxy = self._makeOne("") + self.assertRaises(ValueError, float, proxy) + + def test_custom_float_to_float(self): + class CustomClass(object): + def __float__(self): + return 42.0 + proxy = self._makeOne(CustomClass()) + self.assertEqual(42.0, float(proxy)) + + def test___unicode__of_unicode(self): + from zope.proxy._compat import PY3, _u + if PY3: # Gone in Python 3: + return + s = _u('Hello, \u2603') + proxy = self._makeOne(s) + self.assertEqual(unicode(proxy), s) + + def test___unicode__of_custom_class(self): + from zope.proxy._compat import PY3, _u + if PY3: # Gone in Python 3: + return + class CustomClass(object): + def __unicode__(self): + return _u('Hello, \u2603') + cc = CustomClass() + self.assertEqual(unicode(cc), _u('Hello, \u2603')) + proxy = self._makeOne(cc) + self.assertEqual(unicode(proxy), _u('Hello, \u2603')) + + def test___unicode__of_custom_class_no_unicode(self): + # The default behaviour should be preserved + from zope.proxy._compat import PY3, _u + if PY3: # Gone in Python 3: + return + class CustomClass(object): + pass + cc = CustomClass() + cc_unicode = unicode(cc) + self.assertEqual(type(cc_unicode), unicode) + proxy = self._makeOne(cc) + self.assertEqual(unicode(proxy), cc_unicode) + class ProxyBaseTestCase(PyProxyBaseTestCase): |