diff --git a/bin/build-sip-msw b/bin/build-sip-msw index 7700bfe3a..40b309f3c 100644 --- a/bin/build-sip-msw +++ b/bin/build-sip-msw @@ -22,9 +22,7 @@ MYBINDIR=$(dirname $(readlink -f $0)) cd /c/projects/sip/sip SIPVER=$($PYTHON -c "import sys,configure; sys.stdout.write(configure.sip_version_str);") -$PYTHON configure.py \ - --sip-module wx.siplib \ - $* +$PYTHON configure.py $* cd sipgen nmake clean all diff --git a/bin/build-sip-posix b/bin/build-sip-posix index f6b030489..d186096d5 100755 --- a/bin/build-sip-posix +++ b/bin/build-sip-posix @@ -36,15 +36,12 @@ if [ "$PLATFORM" = "darwin" ]; then --sdk=$SDK \ --arch=i386 \ --universal \ - --sip-module wx.siplib \ $* make -C sipgen clean all else - $PYTHON configure.py \ - --sip-module wx.siplib \ - $* + $PYTHON configure.py $* make -C sipgen clean all fi diff --git a/build.py b/build.py index c0aaaf62d..24ceb2239 100755 --- a/build.py +++ b/build.py @@ -391,7 +391,11 @@ def makeOptionParser(): ("debug", (False, "Build wxPython with debug symbols")), ("relwithdebug", (False, "Turn on the generation of debug info for release builds on MSW.")), ("release", (False, "Turn off some development options for a release build.")), + + ("py_limited_api", (False, "Set flags to use the Python Limited API.")), + ("keep_hash_lines",(False, "Don't remove the '#line N' lines from the SIP generated code")), + ("gtk3", (False, "On Linux build for gtk3 (default gtk2)")), ("osx_cocoa", (True, "Build the OSX Cocoa port on Mac (default)")), ("osx_carbon", (False, "Build the OSX Carbon port on Mac (unsupported)")), @@ -1398,6 +1402,9 @@ def cmd_build_py(options, args): if options.gtk3: build_options.append('--gtk3') + if options.py_limited_api: + build_options.append('--py_limited_api') + build_options.append('--python="%s"' % PYTHON) build_options.append('--out=%s' % wafBuildDir) # this needs to be the last option diff --git a/buildtools/config.py b/buildtools/config.py index ef854786e..6ffcd0797 100644 --- a/buildtools/config.py +++ b/buildtools/config.py @@ -111,6 +111,7 @@ def __init__(self, noWxConfig=False): self.includes = [phoenixDir() + '/sip/siplib', # to get our version of sip.h phoenixDir() + '/src', # for any hand-written headers + phoenixDir() + '/wxpy_api', # for our internal API module ] self.DOXY_XML_DIR = os.path.join(self.WXDIR, 'docs/doxygen/out/xml') @@ -541,7 +542,6 @@ def adjustCFLAGS(self, cflags, defines, includes): return newCFLAGS - def adjustLFLAGS(self, lflags, libdirs, libs): """ Extract the -L and -l flags from lflags and put them in libdirs and @@ -558,6 +558,20 @@ def adjustLFLAGS(self, lflags, libdirs, libs): return newLFLAGS + def set_limited_api(self, use_limited_api): + """ + Add a define for Py_LIMITED_API if the option is enabled + """ + name = 'Py_LIMITED_API' + version = '0x03040000' + if use_limited_api: + # not sure yet where it needs to go, so put it everywhere ;-) + self.defines.append( (name, version) ) + self.wafDefines.append('{}={}'.format(name, version)) + # and return it too + return '-D{}={}'.format(name, version) + + # We'll use a factory function so we can use the Configuration class as a singleton _config = None diff --git a/etg/_core.py b/etg/_core.py index df888d61e..c84f8e74d 100644 --- a/etg/_core.py +++ b/etg/_core.py @@ -39,7 +39,6 @@ 'defs', 'debug', 'object', - 'wxpy_api', 'arrayholder', 'string', 'filename', @@ -68,7 +67,8 @@ 'position', 'colour', - 'stream', 'filesys', + 'stream', + 'filesys', # GDI and graphics 'image', diff --git a/etg/accel.py b/etg/accel.py index c28f62727..e753b9dd6 100644 --- a/etg/accel.py +++ b/etg/accel.py @@ -69,7 +69,7 @@ def run(): } int idx; for (idx=0; idx( @@ -77,9 +77,9 @@ def run(): tmpEntries[idx] = *entryPtr; } else if (PySequence_Check(obj) && PySequence_Size(obj) == 3) { - PyObject* o1 = PySequence_ITEM(obj, 0); - PyObject* o2 = PySequence_ITEM(obj, 1); - PyObject* o3 = PySequence_ITEM(obj, 2); + PyObject* o1 = PySequence_GetItem(obj, 0); + PyObject* o2 = PySequence_GetItem(obj, 1); + PyObject* o3 = PySequence_GetItem(obj, 2); tmpEntries[idx].Set(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3)); Py_DECREF(o1); Py_DECREF(o2); diff --git a/etg/bitmap.py b/etg/bitmap.py index 466f263d5..deb146b92 100644 --- a/etg/bitmap.py +++ b/etg/bitmap.py @@ -69,7 +69,7 @@ def run(): cArray = new char*[count]; for(int x=0; xSetPrivData(PyBytes_AS_STRING(data), PyBytes_GET_SIZE(data)); + self->SetPrivData(PyBytes_AsString(data), PyBytes_Size(data)); """) c.addAutoProperties() diff --git a/etg/colour.py b/etg/colour.py index 8433d2d02..8c1a66fe2 100644 --- a/etg/colour.py +++ b/etg/colour.py @@ -250,13 +250,13 @@ def run(): else if (wxPyNumberSequenceCheck(sipPy)) { size_t len = PySequence_Size(sipPy); - PyObject* o1 = PySequence_ITEM(sipPy, 0); - PyObject* o2 = PySequence_ITEM(sipPy, 1); - PyObject* o3 = PySequence_ITEM(sipPy, 2); + PyObject* o1 = PySequence_GetItem(sipPy, 0); + PyObject* o2 = PySequence_GetItem(sipPy, 1); + PyObject* o3 = PySequence_GetItem(sipPy, 2); if (len == 3) *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3)); else { - PyObject* o4 = PySequence_ITEM(sipPy, 3); + PyObject* o4 = PySequence_GetItem(sipPy, 3); *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3), wxPyInt_AsLong(o4)); Py_DECREF(o4); diff --git a/etg/config.py b/etg/config.py index e045efc84..52574eff8 100644 --- a/etg/config.py +++ b/etg/config.py @@ -96,9 +96,9 @@ def run(): wxPyThreadBlocker blocker; PyObject* ret = PyTuple_New(3); if (ret) { - PyTuple_SET_ITEM(ret, 0, PyBool_FromLong(flag)); - PyTuple_SET_ITEM(ret, 1, wx2PyString(str)); - PyTuple_SET_ITEM(ret, 2, wxPyInt_FromLong(index)); + PyTuple_SetItem(ret, 0, PyBool_FromLong(flag)); + PyTuple_SetItem(ret, 1, wx2PyString(str)); + PyTuple_SetItem(ret, 2, wxPyInt_FromLong(index)); } return ret; } diff --git a/etg/dataobj.py b/etg/dataobj.py index 5d48326d0..1d71bfe08 100644 --- a/etg/dataobj.py +++ b/etg/dataobj.py @@ -60,7 +60,8 @@ def addGetAllFormats(klass, pureVirtual=False): for (size_t i=0; iWrite(PyBytes_AS_STRING(data), PyBytes_GET_SIZE(data)); + self->Write(PyBytes_AsString(data), PyBytes_Size(data)); RETURN_NONE(); """) diff --git a/etg/treelist.py b/etg/treelist.py index 7fb30971f..a4b7e2134 100644 --- a/etg/treelist.py +++ b/etg/treelist.py @@ -96,7 +96,7 @@ def run(): for (size_t i=0; i( sipConvertToType(pyItem, sipType_{ItemClass}, NULL, 0, &state, sipIsErr)); @@ -1145,7 +1145,7 @@ def ObjArrayHelperTemplate(objType, sipType, errmsg): else {{ len = PySequence_Length(source); for (idx=0; idx( diff --git a/py_limited_api.txt b/py_limited_api.txt new file mode 100644 index 000000000..aea42b300 --- /dev/null +++ b/py_limited_api.txt @@ -0,0 +1,70 @@ + + +------------------------------------------------- +Temporary notes, do not commit in the final merge +------------------------------------------------- + + +New bdist_wheel docs including the --py-limited-api option: +https://bitbucket.org/HexDecimal/wheel-fork/src/b25d28cc111f8d354e1b8d949a54ffb3c262dfce/docs/index.rst?fileviewer=file-view-default + +PEP 384: https://www.python.org/dev/peps/pep-0384/ + + +* Can I get rid of wx.siplib and just add dependency on SIP from pypi? Yes, of + course, but it would make using interim builds more difficult. + +* Can I eliminate all uses of the restricted APIs (at least the buffer related + things so far) and use equivalent APIs from siplib itself? If not then I'll + probably have to separate out the incompatible stuff into my own API module + like siplib (and could probably include siplib there if desired...) + +* How to set the tags in the wheel filename? If bdist_wheel doesn't do it + already then it looks like we can override a get_tag(self) method in the + customization of the bdist_wheel class we already have... + + For example, from py2exe's setup.py: + + class my_bdist_wheel(bdist_wheel.bdist_wheel): + """We change the bdist_wheel command so that it creates a + wheel-file compatible with CPython, 3.4, 3.5, and 3.6 only + by setting the impl_tag to 'cp33.cp34.cp35.cp36' + """ + def get_tag(self): + impl_tag, abi_tag, plat_tag = super().get_tag() + return "cp33.cp34.cp35.cp36", abi_tag, plat_tag + + +* The bdist_wheel docs say that --py-limited-api is ignored on Windows??? + +* The extension modules will need to have a different name, I think. Currently + waf is controlling that. Do current versions of waf support py-limited-api + or will something new need to be hacked into it? + +* Check into what Extension(py_limited_api=True, ...) does in recent versions + of setuptools. + + + + +Issues discovered so far +------------------------ + + * We WILL need a separate Python version-specific API module, siplib can give + us lots of help, but doesn't cover everything + + * all the PyFoo_GET_ITEM type of "faster" macros will need to be changed to + their function call equivalents, meaning that our optimizations for those + things will be undone. + + * At least most of the new buffer APIs are not available in the limited API + + * It appears that PyDateTime APIs are also not available + + * We access elements of PyMethod and such in a few places, in the limited API + those are opaque types. + + * Ditto for sipSimpleWrapper + + * There are a few things currently in wxpy_api like wxPyNoAppError that are + expected to end up in the _core module. \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 3fbc0a1ca..74409dcae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,3 +10,4 @@ pytest pytest-xdist pytest-timeout numpy +sip==4.19.2 diff --git a/setup.py b/setup.py index cda4511fc..2dee4a1f1 100644 --- a/setup.py +++ b/setup.py @@ -85,6 +85,7 @@ """ DEPENDENCIES = [ 'six', + 'sip==4.19.2' ] isWindows = sys.platform.startswith('win') diff --git a/sip/siplib/sip.h b/sip/siplib/sip.h index 4b2e363df..9ffdba573 100644 --- a/sip/siplib/sip.h +++ b/sip/siplib/sip.h @@ -250,7 +250,7 @@ extern "C" { /* The name of the sip module. */ -#define SIP_MODULE_NAME "wx.siplib" +#define SIP_MODULE_NAME "sip" /* diff --git a/sip/siplib/siplib.c b/sip/siplib/siplib.c index cb7e950bc..fc009bd4f 100644 --- a/sip/siplib/siplib.c +++ b/sip/siplib/siplib.c @@ -952,13 +952,13 @@ static int importExceptions(sipExportedModuleDef *client, * The Python module initialisation function. */ #if PY_MAJOR_VERSION >= 3 -#define SIP_MODULE_ENTRY PyInit_siplib +#define SIP_MODULE_ENTRY PyInit_sip #define SIP_MODULE_TYPE PyObject * #define SIP_MODULE_DISCARD(m) Py_DECREF(m) #define SIP_FATAL(s) return NULL #define SIP_MODULE_RETURN(m) return (m) #else -#define SIP_MODULE_ENTRY initsiplib +#define SIP_MODULE_ENTRY initsip #define SIP_MODULE_TYPE void #define SIP_MODULE_DISCARD(m) #define SIP_FATAL(s) Py_FatalError(s) diff --git a/src/__init__.py b/src/__init__.py index a07c0d008..ee6d2d081 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -11,6 +11,15 @@ import wx.__version__ __version__ = wx.__version__.VERSION_STRING +# Ensure the sip module has been installed. It should be there because of the +# dependency set in setup.py, but just in case it isn't this will result in a +# nice ImportError instead of a crash when wx.core tries to use it. +import sip + +# Ensure it's a real module and not a namespace module due to just happening +# to have a 'sip' folder on the sys.path (such as in our source tree...) +assert hasattr(sip, '__file__'), "It appears that the sip module is not installed." + # Import all items from the core wxPython module so they appear in the wx # package namespace. @@ -20,3 +29,4 @@ # Clean up the package namespace del core del wx +del sip \ No newline at end of file diff --git a/src/arrays.sip b/src/arrays.sip index 795b75666..235eb5686 100644 --- a/src/arrays.sip +++ b/src/arrays.sip @@ -64,7 +64,7 @@ } PyErr_Clear(); wxString string; - size_t len = PyUnicode_GET_SIZE(item); + size_t len = PyUnicode_GetSize(item); if (len) { wxPyUnicode_AsWideChar(item, wxStringBuffer(string, len), len); } @@ -224,7 +224,7 @@ wxArrayInt testArrayIntTypemap(const wxArrayInt& arr); Py_DECREF(item); return 0; } - array->Add(PyFloat_AS_DOUBLE(number)); + array->Add(PyFloat_AsDouble(number)); Py_DECREF(item); Py_DECREF(number); } diff --git a/src/core_ex.cpp b/src/core_ex.cpp index 8797056fa..ddbe1c397 100644 --- a/src/core_ex.cpp +++ b/src/core_ex.cpp @@ -112,9 +112,10 @@ void wxPyCoreModuleInject(PyObject* moduleDict) // Create an exception object to use when the app object hasn't been created yet - wxPyNoAppError = PyErr_NewException("wx._core.PyNoAppError", - PyExc_RuntimeError, NULL); - PyDict_SetItemString(moduleDict, "PyNoAppError", wxPyNoAppError); + // TODO + //wxPyNoAppError = PyErr_NewException("wx._core.PyNoAppError", + // PyExc_RuntimeError, NULL); + //PyDict_SetItemString(moduleDict, "PyNoAppError", wxPyNoAppError); #ifdef __WXGTK__ #define wxPort "__WXGTK__" diff --git a/src/dc_ex.cpp b/src/dc_ex.cpp index 3345e2390..653ecd460 100644 --- a/src/dc_ex.cpp +++ b/src/dc_ex.cpp @@ -31,10 +31,15 @@ PyObject* wxPyDrawXXXList(wxDC& dc, wxPyDrawListOp_t doDraw, PyObject* pyCoords, PyObject* pyPens, PyObject* pyBrushes) { wxPyBlock_t blocked = wxPyBeginBlockThreads(); - +#ifndef Py_LIMITED_API bool isFastSeq = PyList_Check(pyCoords) || PyTuple_Check(pyCoords); bool isFastPens = PyList_Check(pyPens) || PyTuple_Check(pyPens); bool isFastBrushes = PyList_Check(pyBrushes) || PyTuple_Check(pyBrushes); +#else + bool isFastSeq = false; + bool isFastPens = false; + bool isFastBrushes = false; +#endif int numObjs = 0; int numPens = 0; int numBrushes = 0; @@ -61,7 +66,9 @@ PyObject* wxPyDrawXXXList(wxDC& dc, wxPyDrawListOp_t doDraw, // Use a new pen? if (i < numPens) { if (isFastPens) { +#ifndef Py_LIMITED_API obj = PySequence_Fast_GET_ITEM(pyPens, i); +#endif } else { obj = PySequence_GetItem(pyPens, i); @@ -79,7 +86,9 @@ PyObject* wxPyDrawXXXList(wxDC& dc, wxPyDrawListOp_t doDraw, // Use a new brush? if (i < numBrushes) { if (isFastBrushes) { +#ifndef Py_LIMITED_API obj = PySequence_Fast_GET_ITEM(pyBrushes, i); +#endif } else { obj = PySequence_GetItem(pyBrushes, i); @@ -97,7 +106,9 @@ PyObject* wxPyDrawXXXList(wxDC& dc, wxPyDrawListOp_t doDraw, // Get the Coordinates if (isFastSeq) { +#ifndef Py_LIMITED_API coords = PySequence_Fast_GET_ITEM(pyCoords, i); +#endif } else { coords = PySequence_GetItem(pyCoords, i); @@ -219,10 +230,17 @@ PyObject* wxPyDrawTextList(wxDC& dc, PyObject* textList, PyObject* pyPoints, PyO { wxPyBlock_t blocked = wxPyBeginBlockThreads(); +#ifndef Py_LIMITED_API bool isFastSeq = PyList_Check(pyPoints) || PyTuple_Check(pyPoints); bool isFastText = PyList_Check(textList) || PyTuple_Check(textList); bool isFastForeground = PyList_Check(foregroundList) || PyTuple_Check(foregroundList); bool isFastBackground = PyList_Check(backgroundList) || PyTuple_Check(backgroundList); +#else + bool isFastSeq = false; + bool isFastText = false; + bool isFastForeground = false; + bool isFastBackground = false; +#endif int numText = 0; int numPoints = 0; int numForeground = 0; @@ -255,7 +273,9 @@ PyObject* wxPyDrawTextList(wxDC& dc, PyObject* textList, PyObject* pyPoints, PyO // Use a new string ? if (i < numText) { if ( isFastText ) { +#ifndef Py_LIMITED_API obj = PySequence_Fast_GET_ITEM(textList, i); +#endif } else { obj = PySequence_GetItem(textList, i); @@ -272,7 +292,9 @@ PyObject* wxPyDrawTextList(wxDC& dc, PyObject* textList, PyObject* pyPoints, PyO if (i < numForeground) { // Use a new foreground ? if ( isFastForeground ) { +#ifndef Py_LIMITED_API obj = PySequence_Fast_GET_ITEM(foregroundList, i); +#endif } else { obj = PySequence_GetItem(foregroundList, i); @@ -290,7 +312,9 @@ PyObject* wxPyDrawTextList(wxDC& dc, PyObject* textList, PyObject* pyPoints, PyO if (i < numBackground) { // Use a new background ? if ( isFastBackground ) { +#ifndef Py_LIMITED_API obj = PySequence_Fast_GET_ITEM(backgroundList, i); +#endif } else { obj = PySequence_GetItem(backgroundList, i); @@ -307,7 +331,9 @@ PyObject* wxPyDrawTextList(wxDC& dc, PyObject* textList, PyObject* pyPoints, PyO // Get the point coordinates if (isFastSeq) { +#ifndef Py_LIMITED_API obj = PySequence_Fast_GET_ITEM(pyPoints, i); +#endif } else { obj = PySequence_GetItem(pyPoints, i); @@ -364,9 +390,9 @@ bool wxPointFromObjects(PyObject* o1, PyObject* o2, wxPoint* point) { // get the x value if (wxPyInt_Check(o1)) - point->x = (int)wxPyInt_AS_LONG(o1); + point->x = (int)wxPyInt_AsLong(o1); else if (PyFloat_Check(o1)) - point->x = (int)PyFloat_AS_DOUBLE(o1); + point->x = (int)PyFloat_AsDouble(o1); else if (PyNumber_Check(o1)) point->x = (int)wxPyInt_AsLong(o1); else @@ -374,9 +400,9 @@ bool wxPointFromObjects(PyObject* o1, PyObject* o2, wxPoint* point) // get the y value if (wxPyInt_Check(o2)) - point->y = (int)wxPyInt_AS_LONG(o2); + point->y = (int)wxPyInt_AsLong(o2); else if (PyFloat_Check(o2)) - point->y = (int)PyFloat_AS_DOUBLE(o2); + point->y = (int)PyFloat_AsDouble(o2); else if (PyNumber_Check(o2)) point->y = (int)wxPyInt_AsLong(o2); else @@ -391,8 +417,11 @@ wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) int idx; wxPoint* temp; PyObject *o, *o1, *o2; +#ifndef Py_LIMITED_API bool isFast = PyList_Check(source) || PyTuple_Check(source); - +#else + bool isFast = false; +#endif if (!PySequence_Check(source)) { goto error0; } @@ -411,7 +440,9 @@ wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) for (idx=0; idx<*count; idx++) { // Get an item: try fast way first. if (isFast) { +#ifndef Py_LIMITED_API o = PySequence_Fast_GET_ITEM(source, idx); +#endif } else { o = PySequence_GetItem(source, idx); @@ -421,10 +452,10 @@ wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) } // Convert o to wxPoint. - if ((PyTuple_Check(o) && PyTuple_GET_SIZE(o) == 2) || - (PyList_Check(o) && PyList_GET_SIZE(o) == 2)) { - o1 = PySequence_Fast_GET_ITEM(o, 0); - o2 = PySequence_Fast_GET_ITEM(o, 1); + if ((PyTuple_Check(o) && PyTuple_Size(o) == 2) || + (PyList_Check(o) && PyList_Size(o) == 2)) { + o1 = PySequence_GetItem(o, 0); + o2 = PySequence_GetItem(o, 1); if (!wxPointFromObjects(o1, o2, &temp[idx])) { goto error2; } diff --git a/src/event_ex.cpp b/src/event_ex.cpp index 1f9655199..87b54547e 100644 --- a/src/event_ex.cpp +++ b/src/event_ex.cpp @@ -49,7 +49,7 @@ void wxPyCallback::EventThunker(wxEvent& event) { } else { // Call the event handler, passing the event object tuple = PyTuple_New(1); - PyTuple_SET_ITEM(tuple, 0, arg); // steals ref to arg + PyTuple_SetItem(tuple, 0, arg); // steals ref to arg result = PyEval_CallObject(func, tuple); if ( result ) { Py_DECREF(result); // result is ignored, but we still need to decref it diff --git a/src/stream_input.cpp b/src/stream_input.cpp index b22ca9c67..3ae166720 100644 --- a/src/stream_input.cpp +++ b/src/stream_input.cpp @@ -5,7 +5,7 @@ static PyObject* wxPyGetMethod(PyObject* py, char* name) if (!PyObject_HasAttrString(py, name)) return NULL; PyObject* o = PyObject_GetAttrString(py, name); - if (!PyMethod_Check(o) && !PyCFunction_Check(o)) { + if (!wxPyMethod_Check(o) && !PyCFunction_Check(o)) { Py_DECREF(o); return NULL; } @@ -116,11 +116,11 @@ class wxPyInputStream : public wxInputStream if (sizeof(wxFileOffset) > sizeof(long)) // wxFileOffset is a 64-bit value... - PyTuple_SET_ITEM(arglist, 0, PyLong_FromLongLong(off)); + PyTuple_SetItem(arglist, 0, PyLong_FromLongLong(off)); else - PyTuple_SET_ITEM(arglist, 0, wxPyInt_FromLong(off)); + PyTuple_SetItem(arglist, 0, wxPyInt_FromLong(off)); - PyTuple_SET_ITEM(arglist, 1, wxPyInt_FromLong(mode)); + PyTuple_SetItem(arglist, 1, wxPyInt_FromLong(mode)); PyObject* result = PyEval_CallObject(m_seek, arglist); diff --git a/src/stream_output.cpp b/src/stream_output.cpp index c135e2091..8e6850020 100644 --- a/src/stream_output.cpp +++ b/src/stream_output.cpp @@ -5,7 +5,7 @@ static PyObject* wxPyGetMethod(PyObject* py, char* name) if (!PyObject_HasAttrString(py, name)) return NULL; PyObject* o = PyObject_GetAttrString(py, name); - if (!PyMethod_Check(o) && !PyCFunction_Check(o)) { + if (!wxPyMethod_Check(o) && !PyCFunction_Check(o)) { Py_DECREF(o); return NULL; } @@ -90,7 +90,7 @@ class wxPyOutputStream : public wxOutputStream wxPyThreadBlocker blocker; PyObject* arglist = PyTuple_New(1); - PyTuple_SET_ITEM(arglist, 0, PyBytes_FromStringAndSize((char*)buffer, bufsize)); + PyTuple_SetItem(arglist, 0, PyBytes_FromStringAndSize((char*)buffer, bufsize)); PyObject* result = PyEval_CallObject(m_write, arglist); Py_DECREF(arglist); @@ -109,11 +109,11 @@ class wxPyOutputStream : public wxOutputStream if (sizeof(wxFileOffset) > sizeof(long)) // wxFileOffset is a 64-bit value... - PyTuple_SET_ITEM(arglist, 0, PyLong_FromLongLong(off)); + PyTuple_SetItem(arglist, 0, PyLong_FromLongLong(off)); else - PyTuple_SET_ITEM(arglist, 0, wxPyInt_FromLong(off)); + PyTuple_SetItem(arglist, 0, wxPyInt_FromLong(off)); - PyTuple_SET_ITEM(arglist, 1, wxPyInt_FromLong(mode)); + PyTuple_SetItem(arglist, 1, wxPyInt_FromLong(mode)); PyObject* result = PyEval_CallObject(m_seek, arglist); diff --git a/src/string.sip b/src/string.sip index 5bfc393f4..007aa9024 100644 --- a/src/string.sip +++ b/src/string.sip @@ -24,7 +24,7 @@ %ConvertToTypeCode #if wxUSE_UNICODE_WCHAR == 0 - #error wxString converison can only handle WCHAR wxStrings currently + #error wxString conversion can only handle WCHAR wxStrings currently #endif // Code to test a PyObject for compatibility with wxString @@ -45,7 +45,7 @@ } } *sipCppPtr = new wxString(); - size_t len = PyUnicode_GET_SIZE(uni); + size_t len = PyUnicode_GetSize(uni); if (len) { wxPyUnicode_AsWideChar(uni, wxStringBuffer(**sipCppPtr, len), len); } diff --git a/src/wxpybuffer.sip b/src/wxpybuffer.sip index 1e571b572..0e362a356 100644 --- a/src/wxpybuffer.sip +++ b/src/wxpybuffer.sip @@ -23,7 +23,7 @@ %ConvertToTypeCode // Code to test a PyObject for compatibility if (!sipIsErr) { - if (PyObject_CheckBuffer(sipPy) // New buffer interface + if (wxPyObject_CheckBuffer(sipPy) // New buffer interface || PyObject_CheckReadBuffer(sipPy)) // or old buffer interface return TRUE; return FALSE; @@ -58,7 +58,7 @@ %ConvertToTypeCode // Code to test a PyObject for compatibility if (!sipIsErr) { - if (PyObject_CheckBuffer(sipPy)) + if (wxPyObject_CheckBuffer(sipPy)) return TRUE; return FALSE; } diff --git a/wscript b/wscript index c888e05a3..60a702877 100644 --- a/wscript +++ b/wscript @@ -37,6 +37,8 @@ def options(opt): help='Turn on debug compile options.') opt.add_option('--python', dest='python', default='', action='store', help='Full path to the Python executable to use.') + opt.add_option('--py_limited_api', dest='py_limited_api', default='', action='store', + help='Turn on Py_LIMITED_API for multi-python version builds.') opt.add_option('--wx_config', dest='wx_config', default='wx-config', action='store', help='Full path to the wx-config script to be used for this build.') opt.add_option('--no_magic', dest='no_magic', action='store_true', default=False, @@ -94,12 +96,13 @@ def configure(conf): conf.env.msvc_relwithdebug = conf.options.msvc_relwithdebug # Ensure that the headers in siplib and Phoenix's src dir can be found - conf.env.INCLUDES_WXPY = ['sip/siplib', 'src'] + conf.env.INCLUDES_WXPY = ['sip/siplib', 'src', 'wxpy_api'] if isWindows: # Windows/MSVC specific stuff cfg.finishSetup(debug=conf.env.debug) + cfg.set_limited_api(conf.options.py_limited_api) conf.env.INCLUDES_WX = cfg.includes conf.env.DEFINES_WX = cfg.wafDefines @@ -180,6 +183,10 @@ def configure(conf): conf.env.wx_config = conf.options.wx_config cfg.finishSetup(conf.env.wx_config, conf.env.debug) + pla_flag = cfg.set_limited_api(conf.options.py_limited_api) + conf.env.CFLAGS_WXPY.append(pla_flag) + conf.env.CXXFLAGS_WXPY.append(pla_flag) + # Check wx-config exists and fetch some values from it rpath = ' --no-rpath' if not conf.options.no_magic else '' conf.check_cfg(path=conf.options.wx_config, package='', @@ -187,7 +194,7 @@ def configure(conf): uselib_store='WX', mandatory=True) # Run it again with different libs options to get different - # sets of flags stored to use with varous extension modules below. + # sets of flags stored to use with various extension modules below. conf.check_cfg(path=conf.options.wx_config, package='', args='--cxxflags --libs adv,core,net' + rpath, uselib_store='WXADV', mandatory=True) @@ -472,6 +479,9 @@ def build(bld): cfg.finishSetup(bld.env.wx_config) + # Is this needed here or is the flag remembered from the configure step? + # cfg.set_limited_api(conf.options.py_limited_api) + # Copy the license files from wxWidgets updateLicenseFiles(cfg) @@ -500,23 +510,24 @@ def build(bld): # Create the build tasks for each of our extension modules. - addRelwithdebugFlags(bld, 'siplib') - siplib = bld( - features = 'c cxx cshlib cxxshlib pyext', - target = makeTargetName(bld, 'siplib'), - source = ['sip/siplib/apiversions.c', - 'sip/siplib/array.c', - 'sip/siplib/bool.cpp', - 'sip/siplib/descriptors.c', - 'sip/siplib/objmap.c', - 'sip/siplib/qtlib.c', - 'sip/siplib/siplib.c', - 'sip/siplib/threads.c', - 'sip/siplib/voidptr.c', - ], - uselib = 'siplib WX WXPY', - ) - makeExtCopyRule(bld, 'siplib') + + # addRelwithdebugFlags(bld, 'siplib') + # siplib = bld( + # features = 'c cxx cshlib cxxshlib pyext', + # target = makeTargetName(bld, 'siplib'), + # source = ['sip/siplib/apiversions.c', + # 'sip/siplib/array.c', + # 'sip/siplib/bool.cpp', + # 'sip/siplib/descriptors.c', + # 'sip/siplib/objmap.c', + # 'sip/siplib/qtlib.c', + # 'sip/siplib/siplib.c', + # 'sip/siplib/threads.c', + # 'sip/siplib/voidptr.c', + # ], + # uselib = 'siplib WX WXPY', + # ) + # makeExtCopyRule(bld, 'siplib') # Add build rules for each of our ETG generated extension modules makeETGRule(bld, 'etg/_core.py', '_core', 'WX') diff --git a/src/wxpy_api.h b/wxpy_api/wxpy_api.h similarity index 97% rename from src/wxpy_api.h rename to wxpy_api/wxpy_api.h index babad3844..486ea85d1 100644 --- a/src/wxpy_api.h +++ b/wxpy_api/wxpy_api.h @@ -3,7 +3,7 @@ // Purpose: Some utility functions and such that can be used in other // snippets of C++ code to help reduce complexity, etc. They // are all either macros, inline functions, or functions that -// are exported from the core extension module. +// are exported from the wxpy_api extension module. // // Author: Robin Dunn // @@ -166,11 +166,12 @@ struct wxPyAPI { void* (*p_wxPyGetCppPtr)(sipSimpleWrapper* sipPyObj); PyObject* (*p_wxPyMethod_Self)(PyObject* method); void (*p_wxPyReinitializeModules)(); - int (*p_wxPyDateTime_Check)(PyObject *obj); int (*p_wxPyDate_Check)(PyObject *obj); wxDateTime* (*p_wxPyDateTime_ToWxDateTime)(PyObject *obj); wxDateTime* (*p_wxPyDate_ToWxDateTime)(PyObject *obj); + bool (*p_wxPyMethod_Check)(PyObject *obj); + int (*p_wxPyObject_CheckBuffer)(PyObject* obj); // Always add new items here at the end. }; @@ -274,7 +275,7 @@ inline void wxPyReinitializeModules() { return wxPyGetAPIPtr()->p_wxPyReinitializeModules(); } - +// Datetime inline int wxPyDateTime_Check(PyObject *obj) { return wxPyGetAPIPtr()->p_wxPyDateTime_Check(obj); } @@ -288,6 +289,15 @@ inline wxDateTime* wxPyDate_ToWxDateTime(PyObject *obj) { return wxPyGetAPIPtr()->p_wxPyDate_ToWxDateTime(obj); } + +inline bool wxPyMethod_Check(PyObject *obj) + { return wxPyGetAPIPtr()->p_wxPyMethod_Check(obj); } + +inline int wxPyObject_CheckBuffer(PyObject *obj) + { return wxPyGetAPIPtr()->p_wxPyObject_CheckBuffer(obj); } + + + //-------------------------------------------------------------------------- // Convenience helper for RAII-style thread blocking diff --git a/src/wxpy_api.sip b/wxpy_api/wxpy_api.sip similarity index 98% rename from src/wxpy_api.sip rename to wxpy_api/wxpy_api.sip index a3a60e639..b70b4abbb 100644 --- a/src/wxpy_api.sip +++ b/wxpy_api/wxpy_api.sip @@ -527,11 +527,13 @@ void* i_wxPyGetCppPtr(sipSimpleWrapper* sipPyObj) { // Call the PyMethod_Self API, which is not available when the Python // limited API is activated. -inline PyObject* i_wxPyMethod_Self(PyObject* method) { +PyObject* i_wxPyMethod_Self(PyObject* method) { return PyMethod_Self(method); } - +bool i_wxPyMethod_Check(PyObject* obj) { + return PyMethod_Check(obj); +} //-------------------------------------------------------------------------- // Cleanup and reinitialize the wxModules. This is needed because sometimes an @@ -578,6 +580,10 @@ wxDateTime* i_wxPyDate_ToWxDateTime(PyObject *obj) { +int i_wxPyObject_CheckBuffer(PyObject* obj) { + return PyObject_CheckBuffer(obj); +} + //-------------------------------------------------------------------------- // An instance of the API structure static wxPyAPI API = { @@ -601,7 +607,8 @@ static wxPyAPI API = { i_wxPyDateTime_Check, i_wxPyDate_Check, i_wxPyDateTime_ToWxDateTime, - i_wxPyDate_ToWxDateTime + i_wxPyDate_ToWxDateTime, + i_wxPyMethod_Check }; %End