[pypy-commit] pypy cpyext-macros-cast: Cast inside of macros so that callers don't get compilation errors in PyPy.
devin.jeanpierre
pypy.commits at gmail.com
Fri May 6 20:39:11 EDT 2016
Author: Devin Jeanpierre <jeanpierreda at gmail.com>
Branch: cpyext-macros-cast
Changeset: r84272:cf292feacdbb
Date: 2016-05-06 17:37 -0700
http://bitbucket.org/pypy/pypy/changeset/cf292feacdbb/
Log: Cast inside of macros so that callers don't get compilation errors
in PyPy.
CPython defines many macros like so:
#define PyWhatever_FOO(x) (((PyWhatever*)(x))->foo)
And callers can pass in a `void*`, a `PyWhatever*`, a `PyObject*`,
and it all works assuming that the dynamic type is correct for the
cast.
In PyPy, without these casts, a warning is emitted if you pass the
"wrong" type, even though it would work in CPython. This breaks
compatibility for projects that build with -Werror.
(This used to be many commits, but I ended up gluing them all
together because I am no good at mercurial. Original is mostly at
this bitbucket repo for now:
https://bitbucket.org/devin.jeanpierre/pypy )
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -179,67 +179,67 @@
# Accessors
@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_YEAR(space, w_obj):
+def _PyDateTime_GET_YEAR(space, w_obj):
"""Return the year, as a positive int.
"""
return space.int_w(space.getattr(w_obj, space.wrap("year")))
@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_MONTH(space, w_obj):
+def _PyDateTime_GET_MONTH(space, w_obj):
"""Return the month, as an int from 1 through 12.
"""
return space.int_w(space.getattr(w_obj, space.wrap("month")))
@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_DAY(space, w_obj):
+def _PyDateTime_GET_DAY(space, w_obj):
"""Return the day, as an int from 1 through 31.
"""
return space.int_w(space.getattr(w_obj, space.wrap("day")))
@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_HOUR(space, w_obj):
+def _PyDateTime_DATE_GET_HOUR(space, w_obj):
"""Return the hour, as an int from 0 through 23.
"""
return space.int_w(space.getattr(w_obj, space.wrap("hour")))
@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_MINUTE(space, w_obj):
+def _PyDateTime_DATE_GET_MINUTE(space, w_obj):
"""Return the minute, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("minute")))
@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_SECOND(space, w_obj):
+def _PyDateTime_DATE_GET_SECOND(space, w_obj):
"""Return the second, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("second")))
@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_MICROSECOND(space, w_obj):
+def _PyDateTime_DATE_GET_MICROSECOND(space, w_obj):
"""Return the microsecond, as an int from 0 through 999999.
"""
return space.int_w(space.getattr(w_obj, space.wrap("microsecond")))
@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_HOUR(space, w_obj):
+def _PyDateTime_TIME_GET_HOUR(space, w_obj):
"""Return the hour, as an int from 0 through 23.
"""
return space.int_w(space.getattr(w_obj, space.wrap("hour")))
@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_MINUTE(space, w_obj):
+def _PyDateTime_TIME_GET_MINUTE(space, w_obj):
"""Return the minute, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("minute")))
@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_SECOND(space, w_obj):
+def _PyDateTime_TIME_GET_SECOND(space, w_obj):
"""Return the second, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("second")))
@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_MICROSECOND(space, w_obj):
+def _PyDateTime_TIME_GET_MICROSECOND(space, w_obj):
"""Return the microsecond, as an int from 0 through 999999.
"""
return space.int_w(space.getattr(w_obj, space.wrap("microsecond")))
@@ -249,13 +249,13 @@
# for types defined in a python module like lib/datetime.py.
@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DELTA_GET_DAYS(space, w_obj):
+def _PyDateTime_DELTA_GET_DAYS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("days")))
@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DELTA_GET_SECONDS(space, w_obj):
+def _PyDateTime_DELTA_GET_SECONDS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("seconds")))
@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj):
+def _PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("microseconds")))
diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -49,7 +49,7 @@
return space.float_w(space.float(w_obj))
@cpython_api([PyObject], lltype.Float, error=CANNOT_FAIL)
-def PyFloat_AS_DOUBLE(space, w_float):
+def _PyFloat_AS_DOUBLE(space, w_float):
"""Return a C double representation of the contents of w_float, but
without error checking."""
return space.float_w(w_float)
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -87,6 +87,7 @@
#include "pymath.h"
#include "pyport.h"
#include "warnings.h"
+#include "weakrefobject.h"
#include <stdarg.h>
#include <stdio.h>
@@ -102,6 +103,7 @@
#include "funcobject.h"
#include "code.h"
+#include "abstract.h"
#include "modsupport.h"
#include "pythonrun.h"
#include "pyerrors.h"
@@ -129,6 +131,7 @@
#include "fileobject.h"
#include "pysignals.h"
#include "pythread.h"
+#include "setobject.h"
#include "traceback.h"
/* Missing definitions */
diff --git a/pypy/module/cpyext/include/abstract.h b/pypy/module/cpyext/include/abstract.h
--- a/pypy/module/cpyext/include/abstract.h
+++ b/pypy/module/cpyext/include/abstract.h
@@ -1,1 +1,3 @@
-/* empty */
+#define PySequence_Fast_GET_ITEM(seq, i) _PySequence_Fast_GET_ITEM((PyObject*)(seq), (i))
+#define PySequence_Fast_GET_SIZE(seq) _PySequence_Fast_GET_SIZE((PyObject*)(seq))
+#define PySequence_ITEM(seq, i) _PySequence_ITEM((PyObject*)(seq), (i))
diff --git a/pypy/module/cpyext/include/datetime.h b/pypy/module/cpyext/include/datetime.h
--- a/pypy/module/cpyext/include/datetime.h
+++ b/pypy/module/cpyext/include/datetime.h
@@ -4,6 +4,27 @@
extern "C" {
#endif
+
+#define PyDateTime_GET_YEAR(o) _PyDateTime_GET_YEAR((PyDateTime_Date*)(o))
+#define PyDateTime_GET_MONTH(o) _PyDateTime_GET_MONTH((PyDateTime_Date*)(o))
+#define PyDateTime_GET_DAY(o) _PyDateTime_GET_DAY((PyDateTime_Date*)(o))
+
+#define PyDateTime_DATE_GET_HOUR(o) _PyDateTime_DATE_GET_HOUR((PyDateTime_DateTime*)(o))
+#define PyDateTime_DATE_GET_MINUTE(o) _PyDateTime_DATE_GET_MINUTE((PyDateTime_DateTime*)(o))
+#define PyDateTime_DATE_GET_SECOND(o) _PyDateTime_DATE_GET_SECOND((PyDateTime_DateTime*)(o))
+#define PyDateTime_DATE_GET_MICROSECOND(o) _PyDateTime_DATE_GET_MICROSECOND((PyDateTime_DateTime*)(o))
+
+#define PyDateTime_TIME_GET_HOUR(o) _PyDateTime_TIME_GET_HOUR((PyDateTime_Time*)(o))
+#define PyDateTime_TIME_GET_MINUTE(o) _PyDateTime_TIME_GET_MINUTE((PyDateTime_Time*)(o))
+#define PyDateTime_TIME_GET_SECOND(o) _PyDateTime_TIME_GET_SECOND((PyDateTime_Time*)(o))
+#define PyDateTime_TIME_GET_MICROSECOND(o) _PyDateTime_TIME_GET_MICROSECOND((PyDateTime_Time*)(o))
+
+#define PyDateTime_DELTA_GET_DAYS(o) _PyDateTime_DELTA_GET_DAYS((PyDateTime_Delta*)(o))
+#define PyDateTime_DELTA_GET_SECONDS(o) _PyDateTime_DELTA_GET_SECONDS((PyDateTime_Delta*)(o))
+#define PyDateTime_DELTA_GET_MICROSECONDS(o) _PyDateTime_DELTA_GET_MICROSECONDS((PyDateTime_Delta*)(o))
+
+
+
/* Define structure for C API. */
typedef struct {
/* type objects */
diff --git a/pypy/module/cpyext/include/floatobject.h b/pypy/module/cpyext/include/floatobject.h
--- a/pypy/module/cpyext/include/floatobject.h
+++ b/pypy/module/cpyext/include/floatobject.h
@@ -19,6 +19,8 @@
double ob_fval;
} PyFloatObject;
+#define PyFloat_AS_DOUBLE(o) _PyFloat_AS_DOUBLE((PyObject*)(o))
+
#define PyFloat_STR_PRECISION 12
#ifdef Py_NAN
diff --git a/pypy/module/cpyext/include/intobject.h b/pypy/module/cpyext/include/intobject.h
--- a/pypy/module/cpyext/include/intobject.h
+++ b/pypy/module/cpyext/include/intobject.h
@@ -7,6 +7,8 @@
extern "C" {
#endif
+#define PyInt_AS_LONG(obj) _PyInt_AS_LONG((PyObject*)obj);
+
typedef struct {
PyObject_HEAD
long ob_ival;
diff --git a/pypy/module/cpyext/include/listobject.h b/pypy/module/cpyext/include/listobject.h
--- a/pypy/module/cpyext/include/listobject.h
+++ b/pypy/module/cpyext/include/listobject.h
@@ -1,1 +1,3 @@
-#define PyList_GET_ITEM PyList_GetItem
+#define PyList_GET_ITEM(o, i) PyList_GetItem((PyObject*)(o), (i))
+#define PyList_SET_ITEM(o, i, v) _PyList_SET_ITEM((PyObject*)(o), (i), (v))
+#define PyList_GET_SIZE(o) _PyList_GET_SIZE((PyObject*)(o))
diff --git a/pypy/module/cpyext/include/setobject.h b/pypy/module/cpyext/include/setobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/setobject.h
@@ -0,0 +1,14 @@
+/* Int object interface */
+
+#ifndef Py_SETOBJECT_H
+#define Py_SETOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PySet_GET_SIZE(obj) _PySet_GET_SIZE((PyObject*)obj);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_SETOBJECT_H */
diff --git a/pypy/module/cpyext/include/unicodeobject.h b/pypy/module/cpyext/include/unicodeobject.h
--- a/pypy/module/cpyext/include/unicodeobject.h
+++ b/pypy/module/cpyext/include/unicodeobject.h
@@ -5,6 +5,10 @@
extern "C" {
#endif
+#define PyUnicode_GET_SIZE(o) _PyUnicode_GET_SIZE((PyObject*)(o))
+#define PyUnicode_GET_DATA_SIZE(o) _PyUnicode_GET_DATA_SIZE((PyObject*)(o))
+#define PyUnicode_AS_UNICODE(o) _PyUnicode_AS_UNICODE((PyObject*)(o))
+
typedef unsigned int Py_UCS4;
#ifdef HAVE_USABLE_WCHAR_T
diff --git a/pypy/module/cpyext/include/weakrefobject.h b/pypy/module/cpyext/include/weakrefobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/weakrefobject.h
@@ -0,0 +1,1 @@
+#define PyWeakref_GET_OBJECT(o) PyWeakref_GetObject((PyObject*)(o))
diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
--- a/pypy/module/cpyext/intobject.py
+++ b/pypy/module/cpyext/intobject.py
@@ -105,7 +105,7 @@
return num.ulonglongmask()
@cpython_api([PyObject], lltype.Signed, error=CANNOT_FAIL)
-def PyInt_AS_LONG(space, w_int):
+def _PyInt_AS_LONG(space, w_int):
"""Return the value of the object w_int. No error checking is performed."""
return space.int_w(w_int)
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -23,7 +23,7 @@
@cpython_api([PyObject, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL,
result_borrowed=True)
-def PyList_SET_ITEM(space, w_list, index, w_item):
+def _PyList_SET_ITEM(space, w_list, index, w_item):
"""Macro form of PyList_SetItem() without error checking. This is normally
only used to fill in new lists where there is no previous content.
@@ -88,7 +88,7 @@
return 0
@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PyList_GET_SIZE(space, w_list):
+def _PyList_GET_SIZE(space, w_list):
"""Macro form of PyList_Size() without error checking.
"""
assert isinstance(w_list, W_ListObject)
@@ -102,7 +102,7 @@
"""
if not PyList_Check(space, ref):
raise oefmt(space.w_TypeError, "expected list object")
- return PyList_GET_SIZE(space, ref)
+ return _PyList_GET_SIZE(space, ref)
@cpython_api([PyObject], PyObject)
def PyList_AsTuple(space, w_list):
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -46,7 +46,7 @@
members of the result. Returns NULL on failure. If the object is not a
sequence, raises TypeError with m as the message text."""
if isinstance(w_obj, W_ListObject):
- # make sure we can return a borrowed obj from PySequence_Fast_GET_ITEM
+ # make sure we can return a borrowed obj from _PySequence_Fast_GET_ITEM
w_obj.convert_to_cpy_strategy(space)
return w_obj
try:
@@ -55,7 +55,7 @@
raise OperationError(space.w_TypeError, space.wrap(rffi.charp2str(m)))
@cpython_api([PyObject, Py_ssize_t], PyObject, result_borrowed=True)
-def PySequence_Fast_GET_ITEM(space, w_obj, index):
+def _PySequence_Fast_GET_ITEM(space, w_obj, index):
"""Return the ith element of o, assuming that o was returned by
PySequence_Fast(), o is not NULL, and that i is within bounds.
"""
@@ -68,7 +68,7 @@
"sequence")
@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PySequence_Fast_GET_SIZE(space, w_obj):
+def _PySequence_Fast_GET_SIZE(space, w_obj):
"""Returns the length of o, assuming that o was returned by
PySequence_Fast() and that o is not NULL. The size can also be
gotten by calling PySequence_Size() on o, but
@@ -120,7 +120,7 @@
return 0
@cpython_api([PyObject, Py_ssize_t], PyObject)
-def PySequence_ITEM(space, w_obj, i):
+def _PySequence_ITEM(space, w_obj, i):
"""Return the ith element of o or NULL on failure. Macro form of
PySequence_GetItem() but without checking that
PySequence_Check(o)() is true and without adjustment for negative
@@ -134,7 +134,7 @@
def PySequence_GetItem(space, w_obj, i):
"""Return the ith element of o, or NULL on failure. This is the equivalent of
the Python expression o[i]."""
- return PySequence_ITEM(space, w_obj, i)
+ return _PySequence_ITEM(space, w_obj, i)
@cpython_api([PyObject], PyObject)
def PySequence_List(space, w_obj):
diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py
--- a/pypy/module/cpyext/setobject.py
+++ b/pypy/module/cpyext/setobject.py
@@ -75,7 +75,7 @@
return 0
@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PySet_GET_SIZE(space, w_s):
+def _PySet_GET_SIZE(space, w_s):
"""Macro form of PySet_Size() without error checking."""
return space.int_w(space.len(w_s))
@@ -86,7 +86,7 @@
or an instance of a subtype."""
if not PySet_Check(space, ref):
raise oefmt(space.w_TypeError, "expected set object")
- return PySet_GET_SIZE(space, ref)
+ return _PySet_GET_SIZE(space, ref)
@cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
def PySet_Contains(space, w_obj, w_key):
diff --git a/pypy/module/cpyext/test/test_bytesobject.py b/pypy/module/cpyext/test/test_bytesobject.py
--- a/pypy/module/cpyext/test/test_bytesobject.py
+++ b/pypy/module/cpyext/test/test_bytesobject.py
@@ -288,6 +288,24 @@
# This does not test much, but at least the refcounts are checked.
assert module.test_intern_inplace('s') == 's'
+ def test_bytes_macros(self):
+ """The PyString_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyString_FromString("");
+ PyStringObject* u = (PyStringObject*)o;
+
+ PyString_GET_SIZE(u);
+ PyString_GET_SIZE(o);
+
+ PyString_AS_STRING(o);
+ PyString_AS_STRING(u);
+
+ return o;
+ """)])
+ assert module.test_macro_invocations() == ''
+
def test_hash_and_state(self):
module = self.import_extension('foo', [
("test_hash", "METH_VARARGS",
diff --git a/pypy/module/cpyext/test/test_datetime.py b/pypy/module/cpyext/test/test_datetime.py
--- a/pypy/module/cpyext/test/test_datetime.py
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -10,9 +10,9 @@
assert api.PyDate_Check(w_date)
assert api.PyDate_CheckExact(w_date)
- assert api.PyDateTime_GET_YEAR(w_date) == 2010
- assert api.PyDateTime_GET_MONTH(w_date) == 6
- assert api.PyDateTime_GET_DAY(w_date) == 3
+ assert api._PyDateTime_GET_YEAR(w_date) == 2010
+ assert api._PyDateTime_GET_MONTH(w_date) == 6
+ assert api._PyDateTime_GET_DAY(w_date) == 3
def test_time(self, space, api):
w_time = api.PyTime_FromTime(23, 15, 40, 123456)
@@ -21,10 +21,10 @@
assert api.PyTime_Check(w_time)
assert api.PyTime_CheckExact(w_time)
- assert api.PyDateTime_TIME_GET_HOUR(w_time) == 23
- assert api.PyDateTime_TIME_GET_MINUTE(w_time) == 15
- assert api.PyDateTime_TIME_GET_SECOND(w_time) == 40
- assert api.PyDateTime_TIME_GET_MICROSECOND(w_time) == 123456
+ assert api._PyDateTime_TIME_GET_HOUR(w_time) == 23
+ assert api._PyDateTime_TIME_GET_MINUTE(w_time) == 15
+ assert api._PyDateTime_TIME_GET_SECOND(w_time) == 40
+ assert api._PyDateTime_TIME_GET_MICROSECOND(w_time) == 123456
def test_datetime(self, space, api):
w_date = api.PyDateTime_FromDateAndTime(
@@ -36,13 +36,13 @@
assert api.PyDate_Check(w_date)
assert not api.PyDate_CheckExact(w_date)
- assert api.PyDateTime_GET_YEAR(w_date) == 2010
- assert api.PyDateTime_GET_MONTH(w_date) == 6
- assert api.PyDateTime_GET_DAY(w_date) == 3
- assert api.PyDateTime_DATE_GET_HOUR(w_date) == 23
- assert api.PyDateTime_DATE_GET_MINUTE(w_date) == 15
- assert api.PyDateTime_DATE_GET_SECOND(w_date) == 40
- assert api.PyDateTime_DATE_GET_MICROSECOND(w_date) == 123456
+ assert api._PyDateTime_GET_YEAR(w_date) == 2010
+ assert api._PyDateTime_GET_MONTH(w_date) == 6
+ assert api._PyDateTime_GET_DAY(w_date) == 3
+ assert api._PyDateTime_DATE_GET_HOUR(w_date) == 23
+ assert api._PyDateTime_DATE_GET_MINUTE(w_date) == 15
+ assert api._PyDateTime_DATE_GET_SECOND(w_date) == 40
+ assert api._PyDateTime_DATE_GET_MICROSECOND(w_date) == 123456
def test_delta(self, space, api):
w_delta = space.appexec(
@@ -57,9 +57,9 @@
assert api.PyDelta_Check(w_delta)
assert api.PyDelta_CheckExact(w_delta)
- assert api.PyDateTime_DELTA_GET_DAYS(w_delta) == 10
- assert api.PyDateTime_DELTA_GET_SECONDS(w_delta) == 20
- assert api.PyDateTime_DELTA_GET_MICROSECONDS(w_delta) == 30
+ assert api._PyDateTime_DELTA_GET_DAYS(w_delta) == 10
+ assert api._PyDateTime_DELTA_GET_SECONDS(w_delta) == 20
+ assert api._PyDateTime_DELTA_GET_MICROSECONDS(w_delta) == 30
def test_fromtimestamp(self, space, api):
w_args = space.wrap((0,))
@@ -117,3 +117,106 @@
datetime.timedelta,
datetime.tzinfo)
module.clear_types()
+
+ def test_macros(self):
+ module = self.import_extension('foo', [
+ ("test_date_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyDate_FromDate(2000, 6, 6);
+ PyDateTime_Date* d = (PyDateTime_Date*)obj;
+
+ PyDateTime_GET_YEAR(obj);
+ PyDateTime_GET_YEAR(d);
+
+ PyDateTime_GET_MONTH(obj);
+ PyDateTime_GET_MONTH(d);
+
+ PyDateTime_GET_DAY(obj);
+ PyDateTime_GET_DAY(d);
+
+ return obj;
+ """),
+ ("test_datetime_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyDateTime_FromDateAndTime(2000, 6, 6, 6, 6, 6, 6);
+ PyDateTime_DateTime* dt = (PyDateTime_DateTime*)obj;
+
+ PyDateTime_GET_YEAR(obj);
+ PyDateTime_GET_YEAR(dt);
+
+ PyDateTime_GET_MONTH(obj);
+ PyDateTime_GET_MONTH(dt);
+
+ PyDateTime_GET_DAY(obj);
+ PyDateTime_GET_DAY(dt);
+
+ PyDateTime_DATE_GET_HOUR(obj);
+ PyDateTime_DATE_GET_HOUR(dt);
+
+ PyDateTime_DATE_GET_MINUTE(obj);
+ PyDateTime_DATE_GET_MINUTE(dt);
+
+ PyDateTime_DATE_GET_SECOND(obj);
+ PyDateTime_DATE_GET_SECOND(dt);
+
+ PyDateTime_DATE_GET_MICROSECOND(obj);
+ PyDateTime_DATE_GET_MICROSECOND(dt);
+
+ return obj;
+ """),
+ ("test_time_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyTime_FromTime(6, 6, 6, 6);
+ PyDateTime_Time* t = (PyDateTime_Time*)obj;
+
+ PyDateTime_TIME_GET_HOUR(obj);
+ PyDateTime_TIME_GET_HOUR(t);
+
+ PyDateTime_TIME_GET_MINUTE(obj);
+ PyDateTime_TIME_GET_MINUTE(t);
+
+ PyDateTime_TIME_GET_SECOND(obj);
+ PyDateTime_TIME_GET_SECOND(t);
+
+ PyDateTime_TIME_GET_MICROSECOND(obj);
+ PyDateTime_TIME_GET_MICROSECOND(t);
+
+ return obj;
+ """),
+ ("test_delta_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyDelta_FromDSU(6, 6, 6);
+ PyDateTime_Delta* delta = (PyDateTime_Delta*)obj;
+
+ PyDateTime_DELTA_GET_DAYS(obj);
+ PyDateTime_DELTA_GET_DAYS(delta);
+
+ PyDateTime_DELTA_GET_SECONDS(obj);
+ PyDateTime_DELTA_GET_SECONDS(delta);
+
+ PyDateTime_DELTA_GET_MICROSECONDS(obj);
+ PyDateTime_DELTA_GET_MICROSECONDS(delta);
+
+ return obj;
+ """),
+ ])
diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py
--- a/pypy/module/cpyext/test/test_floatobject.py
+++ b/pypy/module/cpyext/test/test_floatobject.py
@@ -6,7 +6,7 @@
def test_floatobject(self, space, api):
assert space.unwrap(api.PyFloat_FromDouble(3.14)) == 3.14
assert api.PyFloat_AsDouble(space.wrap(23.45)) == 23.45
- assert api.PyFloat_AS_DOUBLE(space.wrap(23.45)) == 23.45
+ assert api._PyFloat_AS_DOUBLE(space.wrap(23.45)) == 23.45
assert api.PyFloat_AsDouble(space.w_None) == -1
api.PyErr_Clear()
@@ -77,3 +77,19 @@
neginf = module.return_neginf()
assert neginf < 0
assert math.isinf(neginf)
+
+ def test_macro_accepts_wrong_pointer_type(self):
+ import math
+
+ module = self.import_extension('foo', [
+ ("test_macros", "METH_NOARGS",
+ """
+ PyObject* o = PyFloat_FromDouble(1.0);
+ // no PyFloatObject
+ char* dumb_pointer = (char*)o;
+
+ PyFloat_AS_DOUBLE(o);
+ PyFloat_AS_DOUBLE(dumb_pointer);
+
+ Py_RETURN_NONE;"""),
+ ])
diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py
--- a/pypy/module/cpyext/test/test_intobject.py
+++ b/pypy/module/cpyext/test/test_intobject.py
@@ -9,7 +9,7 @@
assert not api.PyInt_Check(space.wrap((1, 2, 3)))
for i in [3, -5, -1, -sys.maxint, sys.maxint - 1]:
x = api.PyInt_AsLong(space.wrap(i))
- y = api.PyInt_AS_LONG(space.wrap(i))
+ y = api._PyInt_AS_LONG(space.wrap(i))
assert x == i
assert y == i
w_x = api.PyInt_FromLong(x + 1)
@@ -191,3 +191,17 @@
i = mod.test_int()
assert isinstance(i, int)
assert i == 42
+
+ def test_int_macros(self):
+ mod = self.import_extension('foo', [
+ ("test_macros", "METH_NOARGS",
+ """
+ PyObject * obj = PyInt_FromLong(42);
+ PyIntObject * i = (PyIntObject*)obj;
+ PyInt_AS_LONG(obj);
+ PyInt_AS_LONG(i);
+ Py_RETURN_NONE;
+ """
+ ),
+ ])
+
diff --git a/pypy/module/cpyext/test/test_listobject.py b/pypy/module/cpyext/test/test_listobject.py
--- a/pypy/module/cpyext/test/test_listobject.py
+++ b/pypy/module/cpyext/test/test_listobject.py
@@ -22,9 +22,9 @@
def test_get_size(self, space, api):
l = api.PyList_New(0)
- assert api.PyList_GET_SIZE(l) == 0
+ assert api._PyList_GET_SIZE(l) == 0
api.PyList_Append(l, space.wrap(3))
- assert api.PyList_GET_SIZE(l) == 1
+ assert api._PyList_GET_SIZE(l) == 1
def test_size(self, space, api):
l = space.newlist([space.w_None, space.w_None])
@@ -137,6 +137,33 @@
module.setlistitem(l,0)
assert l == [None, 2, 3]
+ def test_list_macros(self):
+ """The PyList_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyList_New(2);
+ PyListObject* l = (PyListObject*)o;
+
+
+ Py_INCREF(o);
+ PyList_SET_ITEM(o, 0, o);
+ Py_INCREF(o);
+ PyList_SET_ITEM(l, 1, o);
+
+ PyList_GET_ITEM(o, 0);
+ PyList_GET_ITEM(l, 1);
+
+ PyList_GET_SIZE(o);
+ PyList_GET_SIZE(l);
+
+ return o;
+ """
+ )
+ ])
+ x = module.test_macro_invocations()
+ assert x[0] is x[1] is x
+
def test_get_item_macro(self):
module = self.import_extension('foo', [
("test_get_item", "METH_NOARGS",
diff --git a/pypy/module/cpyext/test/test_sequence.py b/pypy/module/cpyext/test/test_sequence.py
--- a/pypy/module/cpyext/test/test_sequence.py
+++ b/pypy/module/cpyext/test/test_sequence.py
@@ -14,8 +14,8 @@
w_l = space.wrap([1, 2, 3, 4])
assert api.PySequence_Fast(w_l, "message") is w_l
- assert space.int_w(api.PySequence_Fast_GET_ITEM(w_l, 1)) == 2
- assert api.PySequence_Fast_GET_SIZE(w_l) == 4
+ assert space.int_w(api._PySequence_Fast_GET_ITEM(w_l, 1)) == 2
+ assert api._PySequence_Fast_GET_SIZE(w_l) == 4
w_set = space.wrap(set((1, 2, 3, 4)))
w_seq = api.PySequence_Fast(w_set, "message")
@@ -130,7 +130,7 @@
result = api.PySequence_GetItem(w_l, 4)
assert space.is_true(space.eq(result, space.wrap(4)))
- result = api.PySequence_ITEM(w_l, 4)
+ result = api._PySequence_ITEM(w_l, 4)
assert space.is_true(space.eq(result, space.wrap(4)))
self.raises(space, api, IndexError, api.PySequence_GetItem, w_l, 9000)
@@ -155,6 +155,28 @@
result = api.PySequence_Index(w_gen, w_tofind)
assert result == 4
+class AppTestSetObject(AppTestCpythonExtensionBase):
+ def test_sequence_macro_cast(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ PyObject* o = PyList_New(0);
+ PyList_Append(o, o);
+ PyListObject* l = (PyListObject*)o;
+
+ PySequence_Fast_GET_ITEM(o, 0);
+ PySequence_Fast_GET_ITEM(l, 0);
+
+ PySequence_Fast_GET_SIZE(o);
+ PySequence_Fast_GET_SIZE(l);
+
+ PySequence_ITEM(o, 0);
+ PySequence_ITEM(l, 0);
+
+ return o;
+ """
+ )
+ ])
class TestCPyListStrategy(BaseApiTest):
def test_getitem_setitem(self, space, api):
w_l = space.wrap([1, 2, 3, 4])
diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py
--- a/pypy/module/cpyext/test/test_setobject.py
+++ b/pypy/module/cpyext/test/test_setobject.py
@@ -2,6 +2,7 @@
from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref
from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -13,7 +14,7 @@
w_set = space.call_function(space.w_set)
space.call_method(w_set, 'update', space.wrap([1,2,3,4]))
assert api.PySet_Size(w_set) == 4
- assert api.PySet_GET_SIZE(w_set) == 4
+ assert api._PySet_GET_SIZE(w_set) == 4
raises(TypeError, api.PySet_Size(space.newlist([])))
api.PyErr_Clear()
@@ -45,3 +46,20 @@
w_frozenset = space.newfrozenset([space.wrap(i) for i in [1, 2, 3, 4]])
assert api.PyAnySet_CheckExact(w_set)
assert api.PyAnySet_CheckExact(w_frozenset)
+
+class AppTestSetObject(AppTestCpythonExtensionBase):
+ def test_set_macro_cast(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ PyObject* o = PySet_New(NULL);
+ // no PySetObject
+ char* dumb_pointer = (char*) o;
+
+ PySet_GET_SIZE(o);
+ PySet_GET_SIZE(dumb_pointer);
+
+ return o;
+ """
+ )
+ ])
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -111,12 +111,32 @@
assert isinstance(res, str)
assert res == 'caf?'
+ def test_unicode_macros(self):
+ """The PyUnicode_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyUnicode_FromString("");
+ PyUnicodeObject* u = (PyUnicodeObject*)o;
+
+ PyUnicode_GET_SIZE(u);
+ PyUnicode_GET_SIZE(o);
+
+ PyUnicode_GET_DATA_SIZE(u);
+ PyUnicode_GET_DATA_SIZE(o);
+
+ PyUnicode_AS_UNICODE(o);
+ PyUnicode_AS_UNICODE(u);
+ return o;
+ """)])
+ assert module.test_macro_invocations() == u''
+
class TestUnicode(BaseApiTest):
def test_unicodeobject(self, space, api):
- assert api.PyUnicode_GET_SIZE(space.wrap(u'sp�m')) == 4
+ assert api._PyUnicode_GET_SIZE(space.wrap(u'sp�m')) == 4
assert api.PyUnicode_GetSize(space.wrap(u'sp�m')) == 4
unichar = rffi.sizeof(Py_UNICODE)
- assert api.PyUnicode_GET_DATA_SIZE(space.wrap(u'sp�m')) == 4 * unichar
+ assert api._PyUnicode_GET_DATA_SIZE(space.wrap(u'sp�m')) == 4 * unichar
encoding = rffi.charp2str(api.PyUnicode_GetDefaultEncoding())
w_default_encoding = space.call_function(
@@ -140,7 +160,7 @@
def test_AS(self, space, api):
word = space.wrap(u'spam')
array = rffi.cast(rffi.CWCHARP, api.PyUnicode_AS_DATA(word))
- array2 = api.PyUnicode_AS_UNICODE(word)
+ array2 = api._PyUnicode_AS_UNICODE(word)
array3 = api.PyUnicode_AsUnicode(word)
for (i, char) in enumerate(space.unwrap(word)):
assert array[i] == char
@@ -478,13 +498,13 @@
count1 = space.int_w(space.len(w_x))
target_chunk = lltype.malloc(rffi.CWCHARP.TO, count1, flavor='raw')
- x_chunk = api.PyUnicode_AS_UNICODE(w_x)
+ x_chunk = api._PyUnicode_AS_UNICODE(w_x)
api.Py_UNICODE_COPY(target_chunk, x_chunk, 4)
w_y = space.wrap(rffi.wcharpsize2unicode(target_chunk, 4))
assert space.eq_w(w_y, space.wrap(u"abcd"))
- size = api.PyUnicode_GET_SIZE(w_x)
+ size = api._PyUnicode_GET_SIZE(w_x)
api.Py_UNICODE_COPY(target_chunk, x_chunk, size)
w_y = space.wrap(rffi.wcharpsize2unicode(target_chunk, size))
diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py
--- a/pypy/module/cpyext/test/test_weakref.py
+++ b/pypy/module/cpyext/test/test_weakref.py
@@ -7,7 +7,6 @@
w_ref = api.PyWeakref_NewRef(w_obj, space.w_None)
assert w_ref is not None
assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj)
- assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj)
assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj)
w_obj = space.newtuple([])
@@ -34,3 +33,25 @@
del w_obj
import gc; gc.collect()
assert space.is_w(api.PyWeakref_LockObject(w_ref), space.w_None)
+
+
+class AppTestWeakReference(AppTestCpythonExtensionBase):
+
+ def test_weakref_macro(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ // PyExc_Warning is some weak-reffable PyObject*.
+ PyObject* weakref_obj = PyWeakref_NewRef(PyExc_Warning, NULL);
+ if (!weakref_obj) return weakref_obj;
+ // No public PyWeakReference type.
+ char* dumb_pointer = (char*) weakref_obj;
+
+ PyWeakref_GET_OBJECT(weakref_obj);
+ PyWeakref_GET_OBJECT(dumb_pointer);
+
+ return weakref_obj;
+ """
+ )
+ ])
+ module.test_macro_cast()
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -192,23 +192,23 @@
def PyUnicode_AS_DATA(space, ref):
"""Return a pointer to the internal buffer of the object. o has to be a
PyUnicodeObject (not checked)."""
- return rffi.cast(rffi.CCHARP, PyUnicode_AS_UNICODE(space, ref))
+ return rffi.cast(rffi.CCHARP, _PyUnicode_AS_UNICODE(space, ref))
@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PyUnicode_GET_DATA_SIZE(space, w_obj):
+def _PyUnicode_GET_DATA_SIZE(space, w_obj):
"""Return the size of the object's internal buffer in bytes. o has to be a
PyUnicodeObject (not checked)."""
- return rffi.sizeof(lltype.UniChar) * PyUnicode_GET_SIZE(space, w_obj)
+ return rffi.sizeof(lltype.UniChar) * _PyUnicode_GET_SIZE(space, w_obj)
@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PyUnicode_GET_SIZE(space, w_obj):
+def _PyUnicode_GET_SIZE(space, w_obj):
"""Return the size of the object. o has to be a PyUnicodeObject (not
checked)."""
assert isinstance(w_obj, unicodeobject.W_UnicodeObject)
return space.len_w(w_obj)
@cpython_api([PyObject], rffi.CWCHARP, error=CANNOT_FAIL)
-def PyUnicode_AS_UNICODE(space, ref):
+def _PyUnicode_AS_UNICODE(space, ref):
"""Return a pointer to the internal Py_UNICODE buffer of the object. ref
has to be a PyUnicodeObject (not checked)."""
ref_unicode = rffi.cast(PyUnicodeObject, ref)
@@ -227,7 +227,7 @@
w_type = from_ref(space, rffi.cast(PyObject, ref.c_ob_type))
if not space.is_true(space.issubtype(w_type, space.w_unicode)):
raise oefmt(space.w_TypeError, "expected unicode object")
- return PyUnicode_AS_UNICODE(space, ref)
+ return _PyUnicode_AS_UNICODE(space, ref)
@cpython_api([PyObject], Py_ssize_t, error=-1)
def PyUnicode_GetSize(space, ref):
@@ -247,7 +247,7 @@
string may or may not be 0-terminated. It is the responsibility of the caller
to make sure that the wchar_t string is 0-terminated in case this is
required by the application."""
- c_str = PyUnicode_AS_UNICODE(space, rffi.cast(PyObject, ref))
+ c_str = _PyUnicode_AS_UNICODE(space, rffi.cast(PyObject, ref))
c_length = ref.c_length
# If possible, try to copy the 0-termination as well
diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py
--- a/pypy/module/cpyext/weakrefobject.py
+++ b/pypy/module/cpyext/weakrefobject.py
@@ -37,13 +37,6 @@
"""
return space.call_function(w_ref) # borrowed ref
- at cpython_api([PyObject], PyObject, result_borrowed=True)
-def PyWeakref_GET_OBJECT(space, w_ref):
- """Similar to PyWeakref_GetObject(), but implemented as a macro that does no
- error checking.
- """
- return space.call_function(w_ref) # borrowed ref
-
@cpython_api([PyObject], PyObject)
def PyWeakref_LockObject(space, w_ref):
"""Return the referenced object from a weak reference. If the referent is
More information about the pypy-commit
mailing list