Skip to content

Commit

Permalink
Make the C implementation proxy __unicode__, and make it use the stan…
Browse files Browse the repository at this point in the history
…dard methods to proxy int and float. Fixes #3 and Fixes #4.
  • Loading branch information
jamadden committed May 7, 2015
1 parent 65ebb9d commit 934dc2f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 29 deletions.
6 changes: 6 additions & 0 deletions src/zope/proxy/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@

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')
52 changes: 24 additions & 28 deletions src/zope/proxy/_zope_proxy_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down Expand Up @@ -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 *
Expand All @@ -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 *
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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},
};

Expand Down
66 changes: 65 additions & 1 deletion src/zope/proxy/tests/test_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ def unops(self):
"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):
Expand Down Expand Up @@ -581,6 +581,70 @@ def test___class__(self):
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):

Expand Down

0 comments on commit 934dc2f

Please sign in to comment.