From f778ee19dfbcbf9cca4f202a59be6ac6175cd8c6 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Tue, 16 Aug 2016 19:39:51 +0100 Subject: [PATCH 01/13] Python builtin hashfunc closure fix If the wrong return type in the hash function was used, an error: SystemError: error return without exception set was raised Add some tests for testing builtin slots --- Examples/test-suite/python/Makefile.in | 1 + .../test-suite/python/python_builtin_runme.py | 26 +++++++ Examples/test-suite/python_builtin.i | 74 +++++++++++++++++++ Lib/python/builtin.swg | 6 +- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 Examples/test-suite/python/python_builtin_runme.py create mode 100644 Examples/test-suite/python_builtin.i diff --git a/Examples/test-suite/python/Makefile.in b/Examples/test-suite/python/Makefile.in index a7993b0b8..bfc5450b0 100644 --- a/Examples/test-suite/python/Makefile.in +++ b/Examples/test-suite/python/Makefile.in @@ -58,6 +58,7 @@ CPP_TEST_CASES += \ primitive_types \ python_abstractbase \ python_append \ + python_builtin \ python_destructor_exception \ python_director \ python_docstring \ diff --git a/Examples/test-suite/python/python_builtin_runme.py b/Examples/test-suite/python/python_builtin_runme.py new file mode 100644 index 000000000..6258534c7 --- /dev/null +++ b/Examples/test-suite/python/python_builtin_runme.py @@ -0,0 +1,26 @@ +from python_builtin import * + +if is_python_builtin(): + # Test 1 for tp_hash + if hash(SimpleValue(222)) != 222: + raise RuntimeError("tp_hash not working") + + # Test 2 for tp_hash + try: + # Was incorrectly raising: SystemError: error return without exception set + h = hash(BadHashFunctionReturnType()) + raise RuntimeError("Missing TypeError") + except TypeError: + pass + + # Test 3 for tp_hash + passed = False + try: + h = hash(ExceptionHashFunction()) + except RuntimeError, e: + passed = str(e).find("oops") != -1 + pass + + if not passed: + raise RuntimeError("did not catch exception in hash()") + diff --git a/Examples/test-suite/python_builtin.i b/Examples/test-suite/python_builtin.i new file mode 100644 index 000000000..977b57ec7 --- /dev/null +++ b/Examples/test-suite/python_builtin.i @@ -0,0 +1,74 @@ +// Test customizing slots when using the -builtin option + +%module python_builtin + +%inline %{ +#ifdef SWIGPYTHON_BUILTIN +bool is_python_builtin() { return true; } +#else +bool is_python_builtin() { return false; } +#endif +%} + +// Test 1 for tp_hash +#if defined(SWIGPYTHON_BUILTIN) +%feature("python:tp_hash") SimpleValue "SimpleValueHashFunction" +#endif + +%inline %{ +struct SimpleValue { + int value; + SimpleValue(int value) : value(value) {} + static SimpleValue *inout(SimpleValue *sv) { + return sv; + } +}; +%} + +%{ +#if PY_VERSION_HEX >= 0x03020000 +Py_hash_t SimpleValueHashFunction(PyObject *v) +#else +long SimpleValueHashFunction(PyObject *v) +#endif +{ + SwigPyObject *sobj = (SwigPyObject *) v; + SimpleValue *p = (SimpleValue *)sobj->ptr; + return p->value; +} +hashfunc test_hashfunc_cast() { + return SimpleValueHashFunction; +} +%} + +// Test 2 for tp_hash +#if defined(SWIGPYTHON_BUILTIN) +%feature("python:slot", "tp_hash", functype="hashfunc") BadHashFunctionReturnType::bad_hash_function; +#endif + +%inline %{ +struct BadHashFunctionReturnType { + static const char * bad_hash_function() { + return "bad hash function"; + } +}; +%} + +// Test 3 for tp_hash +#if defined(SWIGPYTHON_BUILTIN) +%feature("python:slot", "tp_hash", functype="hashfunc") ExceptionHashFunction::exception_hash_function; +#endif + +%catches(const char *) exception_hash_function; + +%inline %{ +#if PY_VERSION_HEX < 0x03020000 + #define Py_hash_t long +#endif +struct ExceptionHashFunction { + static Py_hash_t exception_hash_function() { + throw "oops"; + } +}; +%} + diff --git a/Lib/python/builtin.swg b/Lib/python/builtin.swg index 5767a1422..abf5f71cb 100644 --- a/Lib/python/builtin.swg +++ b/Lib/python/builtin.swg @@ -192,9 +192,11 @@ wrapper##_closure(PyObject *a) { \ PyObject *pyresult; \ long result; \ pyresult = wrapper(a, NULL); \ - if (!pyresult || !PyLong_Check(pyresult)) \ - return -1; \ + if (!pyresult) \ + return -1; \ result = PyLong_AsLong(pyresult); \ + if (PyErr_Occurred()) \ + result = -1; \ Py_DECREF(pyresult); \ return result; \ } From 4f681f751de28a2e74b5a8fb2e5954e8b184cbd9 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Thu, 18 Aug 2016 07:09:52 +0100 Subject: [PATCH 02/13] Update Python docs on builtin slots --- Doc/Manual/Contents.html | 4 +- Doc/Manual/Python.html | 130 ++++++++++++++++++++++++++++----------- Lib/python/pyopers.swg | 24 +++++--- 3 files changed, 110 insertions(+), 48 deletions(-) diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index 0b456fca7..3f283ecb9 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -310,7 +310,7 @@
  • General-purpose smart pointers
  • Extensible random number facility
  • Wrapper reference -
  • Polymorphous wrappers for function objects +
  • Polymorphic wrappers for function objects
  • Type traits for metaprogramming
  • Uniform method for computing return type of function objects @@ -1529,7 +1529,7 @@
  • Built-in Types
  • Memory management
  • Python 2.2 and classic classes diff --git a/Doc/Manual/Python.html b/Doc/Manual/Python.html index ce7f9fe5a..cf0f86024 100644 --- a/Doc/Manual/Python.html +++ b/Doc/Manual/Python.html @@ -51,7 +51,7 @@
  • Built-in Types
  • Memory management
  • Python 2.2 and classic classes @@ -2442,7 +2442,7 @@ assert(issubclass(B.Derived, A.Base))
  • -

    36.4.2.2 Operator overloads -- use them!

    +

    36.4.2.2 Operator overloads and slots -- use them!

    The entire justification for the -builtin option is improved @@ -2494,52 +2494,110 @@ automatically converted to python slot operators, refer to the file python/pyopers.swig in the SWIG library.

    -

    There are other very useful python slots that you -may explicitly define using %feature directives. For example, -suppose you want to use instances of a wrapped class as keys in a native python -dict. That will work as long as you define a hash function for -instances of your class, and use it to define the python tp_hash -slot: + +

    +Read about all of the available python slots here: +http://docs.python.org/c-api/typeobj.html

    + +

    +There are two ways to define a python slot function: dispatch to a +statically defined function; or dispatch to a method defined on the +operand. +

    + +

    +To dispatch to a statically defined function, use %feature("python:<slot>"), +where <slot> is the name of a field in a PyTypeObject, PyNumberMethods, +PyMappingMethods, PySequenceMethods or PyBufferProcs. +You may override (almost) all of these slots. +

    + + +

    +Let's consider an example setting the tp_hash slot for the MyClass type. +This is akin to providing a __hash__ method (for non-builtin types) to make a type hashable. +The hashable type can then for example be added to a Python dict.

    -%feature("python:slot", "tp_hash", functype="hashfunc") Cheese::cheeseHashFunc;
    +%feature("python:tp_hash") MyClass "myHashFunc";
     
    -class Cheese {
    +class MyClass {
     public:
    -    Cheese (const char *name);
    -    long cheeseHashFunc () const;
    +  long field1;
    +  long field2;
    +  ...
    +};
    +
    +%{
    +#if PY_VERSION_HEX >= 0x03020000
    +  static Py_hash_t myHashFunc(PyObject *pyobj)
    +#else
    +  static long myHashFunc(PyObject *pyobj)
    +#endif
    +  {
    +    MyClass *cobj;
    +    // Convert pyobj to cobj
    +    return (cobj->field1 * (cobj->field2 << 7));
    +  }
    +%}
    +
    +
    + +

    +If you examine the generated code, the supplied hash function will now be +the function callback in the tp_hash slot for the builtin type for MyClass: +

    + +
    +
    +static PyHeapTypeObject SwigPyBuiltin__MyClass_type = {
    +    ...
    +    (hashfunc) myHashFunc,       /* tp_hash */
    +    ...
    +
    +
    + +

    +NOTE: It is the responsibility of the programmer (that's you!) to ensure +that a statically defined slot function has the correct signature, the hashfunc +typedef in this case. +

    + +

    +If, instead, you want to dispatch to an instance method, you can +use %feature("python:slot"). For example: +

    + +
    +
    +%feature("python:slot", "tp_hash", functype="hashfunc") MyClass::myHashFunc;
    +
    +#if PY_VERSION_HEX < 0x03020000
    +  #define Py_hash_t long
    +#endif
    +
    +class MyClass {
    +  public:
    +    Py_hash_t myHashFunc() const;
    +    ...
     };
     
    -

    This will allow you to write python code like this:

    +

    +NOTE: Some python slots use a method signature which does not +match the signature of SWIG-wrapped methods. For those slots, +SWIG will automatically generate a "closure" function to re-marshal +the arguments before dispatching to the wrapped method. Setting +the "functype" attribute of the feature enables SWIG to generate +the chosen closure function. +

    -
    -
    -from my MyPackage import Cheese
    -
    -inventory = {
    -    Cheese("cheddar") : 0,
    -    Cheese("gouda") : 0,
    -    Cheese("camembert") : 0
    -}
    -
    -
    - -

    Because you defined the tp_hash slot, Cheese objects may -be used as hash keys; and when the cheeseHashFunc method is invoked -by a python dict, it will not go through named method dispatch. -A more detailed discussion about %feature("python:slot") can be found +

    +There is further information on %feature("python:slot") in the file python/pyopers.swig in the SWIG library. -You can read about all of the available python slots here:

    - -

    http://docs.python.org/c-api/typeobj.html

    - -

    You may override (almost) all of the slots defined in the PyTypeObject, -PyNumberMethods, PyMappingMethods, PySequenceMethods, and PyBufferProcs -structs.

    diff --git a/Lib/python/pyopers.swg b/Lib/python/pyopers.swg index 292c593a8..9e3d2a125 100644 --- a/Lib/python/pyopers.swg +++ b/Lib/python/pyopers.swg @@ -19,30 +19,34 @@ PyMappingMethods, PySequenceMethods, or PyBufferProcs. For example: %{ - - static long myHashFunc (PyObject *pyobj) { - MyClass *cobj; - // Convert pyobj to cobj - return (cobj->field1 * (cobj->field2 << 7)); - } - + // Note: Py_hash_t was introduced in Python 3.2 + static Py_hash_t myHashFunc(PyObject *pyobj) { + MyClass *cobj; + // Convert pyobj to cobj + return (cobj->field1 * (cobj->field2 << 7)); + } %} %feature("python:tp_hash") MyClass "myHashFunc"; + class MyClass { + public: + ... + }; + NOTE: It is the responsibility of the programmer (that's you) to ensure that a statically defined slot function has the correct signature. If, instead, you want to dispatch to an instance method, you can use %feature("python:slot"). For example: + %feature("python:slot", "tp_hash", functype="hashfunc") MyClass::myHashFunc; + class MyClass { public: - long myHashFunc () const; + Py_hash_t myHashFunc () const; ... }; - - %feature("python:slot", "tp_hash", functype="hashfunc") MyClass::myHashFunc; NOTE: Some python slots use a method signature which does not match the signature of SWIG-wrapped methods. For those slots, From a3fc743f325a7089191004f17e70a65d8cab9fa7 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Thu, 18 Aug 2016 08:41:07 +0100 Subject: [PATCH 03/13] Add Python builtin closure method in comment For less mystifying code and easier code searching --- Source/Modules/python.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index b42cf022f..82385d4c1 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -3321,7 +3321,7 @@ public: } if (in_class && builtin) { - /* Handle operator overloads overloads for builtin types */ + /* Handle operator overloads for builtin types */ String *slot = Getattr(n, "feature:python:slot"); if (slot) { String *func_type = Getattr(n, "feature:python:slot:functype"); @@ -3329,9 +3329,9 @@ public: String *feature_name = NewStringf("feature:python:%s", slot); String *closure_name = Copy(wrapper_name); if (closure_decl) { - if (!Getattr(n, "sym:overloaded") || !Getattr(n, "sym:nextSibling")) - Printv(f_wrappers, closure_decl, "\n\n", NIL); Append(closure_name, "_closure"); + if (!Getattr(n, "sym:overloaded") || !Getattr(n, "sym:nextSibling")) + Printf(f_wrappers, "%s /* defines %s */\n\n", closure_decl, closure_name); Delete(closure_decl); } if (func_type) { From 67ece1d2bf4d3e04209f792c272162adfc818d15 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Thu, 18 Aug 2016 19:21:39 +0100 Subject: [PATCH 04/13] Python getSlot() refactor getSlot() now takes a default that can override "0" default - simpler code and for future commits to override some currently non-overridable slots. --- Source/Modules/python.cxx | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 82385d4c1..fb71a7299 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -167,10 +167,10 @@ static const char *usage3 = "\ Function annotation \n\ \n"; -static String *getSlot(Node *n = NULL, const char *key = NULL) { - static String *slot_default = NewString("0"); - String *val = key && *key ? Getattr(n, key) : NULL; - return val ? val : slot_default; +static String *getSlot(Node *n = NULL, const char *key = NULL, String *default_slot = NULL) { + static String *zero = NewString("0"); + String *val = n && key && *key ? Getattr(n, key) : NULL; + return val ? val : default_slot ? default_slot : zero; } static void printSlot(File *f, const String *slotval, const char *slotname, const char *functype = NULL) { @@ -3956,13 +3956,7 @@ public: // Check for non-public destructor, in which case tp_dealloc will issue // a warning and allow the memory to leak. Any class that doesn't explicitly // have a private/protected destructor has an implicit public destructor. - String *tp_dealloc = Getattr(n, "feature:python:tp_dealloc"); - if (tp_dealloc) { - Printf(f, "SWIGPY_DESTRUCTOR_CLOSURE(%s)\n", tp_dealloc); - tp_dealloc = NewStringf("%s_closure", tp_dealloc); - } else { - tp_dealloc = NewString("SwigPyBuiltin_BadDealloc"); - } + static String *tp_dealloc_bad = NewString("SwigPyBuiltin_BadDealloc"); String *getset_name = NewStringf("%s_getset", templ); String *methods_name = NewStringf("%s_methods", templ); @@ -4075,7 +4069,7 @@ public: printSlot(f, quoted_symname, "tp_name"); printSlot(f, "sizeof(SwigPyObject)", "tp_basicsize"); printSlot(f, getSlot(n, "feature:python:tp_itemsize"), "tp_itemsize"); - printSlot(f, tp_dealloc, "tp_dealloc", "destructor"); + printSlot(f, getSlot(n, "feature:python:tp_dealloc", tp_dealloc_bad), "tp_dealloc", "destructor"); printSlot(f, getSlot(n, "feature:python:tp_print"), "tp_print", "printfunc"); printSlot(f, getSlot(n, "feature:python:tp_getattr"), "tp_getattr", "getattrfunc"); printSlot(f, getSlot(n, "feature:python:tp_setattr"), "tp_setattr", "setattrfunc"); @@ -4306,7 +4300,6 @@ public: Delete(mname); Delete(pmname); Delete(templ); - Delete(tp_dealloc); Delete(tp_flags); Delete(py3_tp_flags); Delete(quoted_symname); @@ -4967,12 +4960,10 @@ public: if (builtin && in_class) { Node *cls = Swig_methodclass(n); + // Use the destructor for the tp_dealloc slot unless a user overrides it with another method if (!Getattr(cls, "feature:python:tp_dealloc")) { - String *dealloc = Swig_name_destroy(NSPACE_TODO, symname); - String *wdealloc = Swig_name_wrapper(dealloc); - Setattr(cls, "feature:python:tp_dealloc", wdealloc); - Delete(wdealloc); - Delete(dealloc); + Setattr(n, "feature:python:slot", "tp_dealloc"); + Setattr(n, "feature:python:slot:functype", "destructor"); } } From 4c0c802aa06ea4717c1567a5f0a642fe4e5acf6a Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 19 Aug 2016 18:35:51 +0100 Subject: [PATCH 05/13] Add Python builtin tp_dealloc override test --- .../test-suite/python/python_builtin_runme.py | 21 ++++++++++ Examples/test-suite/python_builtin.i | 40 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/Examples/test-suite/python/python_builtin_runme.py b/Examples/test-suite/python/python_builtin_runme.py index 6258534c7..89d2b6b64 100644 --- a/Examples/test-suite/python/python_builtin_runme.py +++ b/Examples/test-suite/python/python_builtin_runme.py @@ -24,3 +24,24 @@ if is_python_builtin(): if not passed: raise RuntimeError("did not catch exception in hash()") + # Test 4 for tp_dealloc (which is handled differently to other slots in the SWIG source) + d = Dealloc1() + if cvar.Dealloc1CalledCount != 0: + raise RuntimeError("count should be 0") + del d + if cvar.Dealloc1CalledCount != 1: + raise RuntimeError("count should be 1") + + d = Dealloc2() + if cvar.Dealloc2CalledCount != 0: + raise RuntimeError("count should be 0") + del d + if cvar.Dealloc2CalledCount != 1: + raise RuntimeError("count should be 1") + + d = Dealloc3() + if cvar.Dealloc3CalledCount != 0: + raise RuntimeError("count should be 0") + del d + if cvar.Dealloc3CalledCount != 1: + raise RuntimeError("count should be 1") diff --git a/Examples/test-suite/python_builtin.i b/Examples/test-suite/python_builtin.i index 977b57ec7..db4c94a52 100644 --- a/Examples/test-suite/python_builtin.i +++ b/Examples/test-suite/python_builtin.i @@ -72,3 +72,43 @@ struct ExceptionHashFunction { }; %} +// Test 4 for tp_dealloc (which is handled differently to other slots in the SWIG source) +#if defined(SWIGPYTHON_BUILTIN) +%feature("python:tp_dealloc") Dealloc1 "Dealloc1Destroyer" +%feature("python:tp_dealloc") Dealloc2 "Dealloc2Destroyer" +%feature("python:slot", "tp_dealloc", functype="destructor") Dealloc3::Destroyer; +#endif + +%inline %{ +static int Dealloc1CalledCount = 0; +static int Dealloc2CalledCount = 0; +static int Dealloc3CalledCount = 0; + +struct Dealloc1 { +}; +struct Dealloc2 { + ~Dealloc2() {} +}; +struct Dealloc3 { + void Destroyer() { + Dealloc3CalledCount++; + delete this; + } +}; +%} + +%{ +void Dealloc1Destroyer(PyObject *v) { + SwigPyObject *sobj = (SwigPyObject *) v; + Dealloc1 *p = (Dealloc1 *)sobj->ptr; + delete p; + Dealloc1CalledCount++; +} +void Dealloc2Destroyer(PyObject *v) { + SwigPyObject *sobj = (SwigPyObject *) v; + Dealloc2 *p = (Dealloc2 *)sobj->ptr; + delete p; + Dealloc2CalledCount++; +} +%} + From 239785ce7d2153383ac72e5f754f357b7e649ea1 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 19 Aug 2016 19:47:09 +0100 Subject: [PATCH 06/13] Additional Python builtin slot overrides and slightly better formatted Python generated code The following slots can now be overidden by users if they know what they are doing: - tp_dictoffset - tp_init - tp_new - tp_as_number - tp_as_sequence - tp_as_mapping - tp_as_buffer --- Source/Modules/python.cxx | 41 +++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index fb71a7299..81a534e7c 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -173,13 +173,13 @@ static String *getSlot(Node *n = NULL, const char *key = NULL, String *default_s return val ? val : default_slot ? default_slot : zero; } -static void printSlot(File *f, const String *slotval, const char *slotname, const char *functype = NULL) { - String *slotval_override = functype ? NewStringf("(%s) %s", functype, slotval) : 0; - if (slotval_override) - slotval = slotval_override; +static void printSlot(File *f, String *slotval, const char *slotname, const char *functype = NULL) { + String *slotval_override = 0; + if (functype) + slotval = slotval_override = NewStringf("(%s) %s", functype, slotval); int len = Len(slotval); - int fieldwidth = len > 40 ? 0 : 40 - len; - Printf(f, " %s, %*s/* %s */\n", slotval, fieldwidth, "", slotname); + int fieldwidth = len > 41 ? (len > 61 ? 0 : 61 - len) : 41 - len; + Printf(f, " %s,%*s/* %s */\n", slotval, fieldwidth, "", slotname); Delete(slotval_override); } @@ -4051,10 +4051,16 @@ public: quoted_symname = NewStringf("\"%s\"", symname); } String *quoted_tp_doc_str = NewStringf("\"%s\"", getSlot(n, "feature:python:tp_doc")); - char const *tp_init = builtin_tp_init ? Char(builtin_tp_init) : Swig_directorclass(n) ? "0" : "SwigPyBuiltin_BadInit"; + String *tp_init = NewString(builtin_tp_init ? Char(builtin_tp_init) : Swig_directorclass(n) ? "0" : "SwigPyBuiltin_BadInit"); String *tp_flags = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); String *py3_tp_flags = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE"); + static String *tp_basicsize = NewStringf("sizeof(SwigPyObject)"); + static String *tp_dictoffset_default = NewString("(Py_ssize_t)offsetof(SwigPyObject, dict)"); + String *tp_as_number = NewStringf("&%s_type.as_number", templ); + String *tp_as_sequence = NewStringf("&%s_type.as_sequence", templ); + String *tp_as_mapping = NewStringf("&%s_type.as_mapping", templ); + String *tp_as_buffer = NewStringf("&%s_type.as_buffer", templ); Printf(f, "static PyHeapTypeObject %s_type = {\n", templ); @@ -4067,7 +4073,7 @@ public: printSlot(f, getSlot(), "ob_size"); Printv(f, "#endif\n", NIL); printSlot(f, quoted_symname, "tp_name"); - printSlot(f, "sizeof(SwigPyObject)", "tp_basicsize"); + printSlot(f, tp_basicsize, "tp_basicsize"); printSlot(f, getSlot(n, "feature:python:tp_itemsize"), "tp_itemsize"); printSlot(f, getSlot(n, "feature:python:tp_dealloc", tp_dealloc_bad), "tp_dealloc", "destructor"); printSlot(f, getSlot(n, "feature:python:tp_print"), "tp_print", "printfunc"); @@ -4079,15 +4085,15 @@ public: printSlot(f, getSlot(n, "feature:python:tp_compare"), "tp_compare", "cmpfunc"); Printv(f, "#endif\n", NIL); printSlot(f, getSlot(n, "feature:python:tp_repr"), "tp_repr", "reprfunc"); - Printf(f, " &%s_type.as_number, /* tp_as_number */\n", templ); - Printf(f, " &%s_type.as_sequence, /* tp_as_sequence */\n", templ); - Printf(f, " &%s_type.as_mapping, /* tp_as_mapping */\n", templ); + printSlot(f, getSlot(n, "feature:python:tp_as_number", tp_as_number), "tp_as_number"); + printSlot(f, getSlot(n, "feature:python:tp_as_sequence", tp_as_sequence), "tp_as_sequence"); + printSlot(f, getSlot(n, "feature:python:tp_as_mapping", tp_as_mapping), "tp_as_mapping"); printSlot(f, getSlot(n, "feature:python:tp_hash"), "tp_hash", "hashfunc"); printSlot(f, getSlot(n, "feature:python:tp_call"), "tp_call", "ternaryfunc"); printSlot(f, getSlot(n, "feature:python:tp_str"), "tp_str", "reprfunc"); printSlot(f, getSlot(n, "feature:python:tp_getattro"), "tp_getattro", "getattrofunc"); printSlot(f, getSlot(n, "feature:python:tp_setattro"), "tp_setattro", "setattrofunc"); - Printf(f, " &%s_type.as_buffer, /* tp_as_buffer */\n", templ); + printSlot(f, getSlot(n, "feature:python:tp_as_buffer", tp_as_buffer), "tp_as_buffer"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); printSlot(f, py3_tp_flags, "tp_flags"); Printv(f, "#else\n", NIL); @@ -4107,10 +4113,10 @@ public: printSlot(f, getSlot(n, "feature:python:tp_dict"), "tp_dict"); printSlot(f, getSlot(n, "feature:python:tp_descr_get"), "tp_descr_get", "descrgetfunc"); printSlot(f, getSlot(n, "feature:python:tp_descr_set"), "tp_descr_set", "descrsetfunc"); - Printf(f, " (Py_ssize_t)offsetof(SwigPyObject, dict), /* tp_dictoffset */\n"); - printSlot(f, tp_init, "tp_init", "initproc"); + printSlot(f, getSlot(n, "feature:python:tp_dictoffset", tp_dictoffset_default), "tp_dictoffset"); + printSlot(f, getSlot(n, "feature:python:tp_init", tp_init), "tp_init", "initproc"); printSlot(f, getSlot(n, "feature:python:tp_alloc"), "tp_alloc", "allocfunc"); - printSlot(f, "0", "tp_new", "newfunc"); + printSlot(f, getSlot(n, "feature:python:tp_new"), "tp_new", "newfunc"); printSlot(f, getSlot(n, "feature:python:tp_free"), "tp_free", "freefunc"); printSlot(f, getSlot(), "tp_is_gc", "inquiry"); printSlot(f, getSlot(), "tp_bases", "PyObject*"); @@ -4302,8 +4308,13 @@ public: Delete(templ); Delete(tp_flags); Delete(py3_tp_flags); + Delete(tp_as_buffer); + Delete(tp_as_mapping); + Delete(tp_as_sequence); + Delete(tp_as_number); Delete(quoted_symname); Delete(quoted_tp_doc_str); + Delete(tp_init); Delete(clientdata_klass); Delete(richcompare_func); Delete(getset_name); From 3744c45082dec123b96c0559d50569ef5be7efa7 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 19 Aug 2016 23:46:50 +0100 Subject: [PATCH 07/13] Customize slots tp_basicsize tp_methods tp_getset --- Source/Modules/python.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 81a534e7c..d86931673 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -4073,7 +4073,7 @@ public: printSlot(f, getSlot(), "ob_size"); Printv(f, "#endif\n", NIL); printSlot(f, quoted_symname, "tp_name"); - printSlot(f, tp_basicsize, "tp_basicsize"); + printSlot(f, getSlot(n, "feature:python:tp_basicsize", tp_basicsize), "tp_basicsize"); printSlot(f, getSlot(n, "feature:python:tp_itemsize"), "tp_itemsize"); printSlot(f, getSlot(n, "feature:python:tp_dealloc", tp_dealloc_bad), "tp_dealloc", "destructor"); printSlot(f, getSlot(n, "feature:python:tp_print"), "tp_print", "printfunc"); @@ -4106,9 +4106,9 @@ public: printSlot(f, getSlot(n, "feature:python:tp_weaklistoffset"), "tp_weaklistoffset"); printSlot(f, getSlot(n, "feature:python:tp_iter"), "tp_iter", "getiterfunc"); printSlot(f, getSlot(n, "feature:python:tp_iternext"), "tp_iternext", "iternextfunc"); - printSlot(f, methods_name, "tp_methods"); + printSlot(f, getSlot(n, "feature:python:tp_methods", methods_name), "tp_methods"); printSlot(f, getSlot(n, "feature:python:tp_members"), "tp_members"); - printSlot(f, getset_name, "tp_getset"); + printSlot(f, getSlot(n, "feature:python:tp_getset", getset_name), "tp_getset"); printSlot(f, getSlot(n, "feature:python:tp_base"), "tp_base"); printSlot(f, getSlot(n, "feature:python:tp_dict"), "tp_dict"); printSlot(f, getSlot(n, "feature:python:tp_descr_get"), "tp_descr_get", "descrgetfunc"); From 3b6f4af15cd65b47900a267bf99617bd69ed439c Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Sun, 21 Aug 2016 14:29:27 +0100 Subject: [PATCH 08/13] Set tp_new statically rather than during initialisation --- Source/Modules/python.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index d86931673..31889a83c 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -3919,7 +3919,6 @@ public: int funpack = modernargs && fastunpack; Printv(f_init, " SwigPyBuiltin_SetMetaType(builtin_pytype, metatype);\n", NIL); - Printf(f_init, " builtin_pytype->tp_new = PyType_GenericNew;\n"); Printv(f_init, " builtin_base_count = 0;\n", NIL); List *baselist = Getattr(n, "bases"); if (baselist) { @@ -4057,6 +4056,7 @@ public: static String *tp_basicsize = NewStringf("sizeof(SwigPyObject)"); static String *tp_dictoffset_default = NewString("(Py_ssize_t)offsetof(SwigPyObject, dict)"); + static String *tp_new = NewString("PyType_GenericNew"); String *tp_as_number = NewStringf("&%s_type.as_number", templ); String *tp_as_sequence = NewStringf("&%s_type.as_sequence", templ); String *tp_as_mapping = NewStringf("&%s_type.as_mapping", templ); @@ -4102,7 +4102,7 @@ public: printSlot(f, quoted_tp_doc_str, "tp_doc"); printSlot(f, getSlot(n, "feature:python:tp_traverse"), "tp_traverse", "traverseproc"); printSlot(f, getSlot(n, "feature:python:tp_clear"), "tp_clear", "inquiry"); - printSlot(f, richcompare_func, "feature:python:tp_richcompare", "richcmpfunc"); + printSlot(f, getSlot(n, "feature:python:tp_richcompare", richcompare_func), "tp_richcompare", "richcmpfunc"); printSlot(f, getSlot(n, "feature:python:tp_weaklistoffset"), "tp_weaklistoffset"); printSlot(f, getSlot(n, "feature:python:tp_iter"), "tp_iter", "getiterfunc"); printSlot(f, getSlot(n, "feature:python:tp_iternext"), "tp_iternext", "iternextfunc"); @@ -4116,7 +4116,7 @@ public: printSlot(f, getSlot(n, "feature:python:tp_dictoffset", tp_dictoffset_default), "tp_dictoffset"); printSlot(f, getSlot(n, "feature:python:tp_init", tp_init), "tp_init", "initproc"); printSlot(f, getSlot(n, "feature:python:tp_alloc"), "tp_alloc", "allocfunc"); - printSlot(f, getSlot(n, "feature:python:tp_new"), "tp_new", "newfunc"); + printSlot(f, getSlot(n, "feature:python:tp_new", tp_new), "tp_new", "newfunc"); printSlot(f, getSlot(n, "feature:python:tp_free"), "tp_free", "freefunc"); printSlot(f, getSlot(), "tp_is_gc", "inquiry"); printSlot(f, getSlot(), "tp_bases", "PyObject*"); From 4f777b181cc7be7bb88d438bc308c2815615b914 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 22 Aug 2016 07:22:40 +0100 Subject: [PATCH 09/13] Correct notes on customising Python builtin comparison operators Also add example for python:compare feature --- .../test-suite/python/python_builtin_runme.py | 23 +++++++++++++++++ Examples/test-suite/python_builtin.i | 16 ++++++++++++ Lib/python/pyopers.swg | 25 ++++++++++--------- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/Examples/test-suite/python/python_builtin_runme.py b/Examples/test-suite/python/python_builtin_runme.py index 89d2b6b64..c41dfc0b1 100644 --- a/Examples/test-suite/python/python_builtin_runme.py +++ b/Examples/test-suite/python/python_builtin_runme.py @@ -45,3 +45,26 @@ if is_python_builtin(): del d if cvar.Dealloc3CalledCount != 1: raise RuntimeError("count should be 1") + + # Test 5 for python:compare feature + m10 = MyClass(10) + m20 = MyClass(20) + m15 = MyClass(15) + + if not m10 < m15: + raise RuntimeError("m10 < m15") + if not m10 < m20: + raise RuntimeError("m10 < m20") + if not m15 < m20: + raise RuntimeError("m15 < m20") + + if m10 > m15: + raise RuntimeError("m10 > m15") + if m10 > m20: + raise RuntimeError("m10 > m20") + if m15 > m20: + raise RuntimeError("m15 > m20") + + if MyClass.less_than_counts != 6: + raise RuntimeError("python:compare feature not working") + diff --git a/Examples/test-suite/python_builtin.i b/Examples/test-suite/python_builtin.i index db4c94a52..ac1ad9c2d 100644 --- a/Examples/test-suite/python_builtin.i +++ b/Examples/test-suite/python_builtin.i @@ -112,3 +112,19 @@ void Dealloc2Destroyer(PyObject *v) { } %} +// Test 5 for python:compare feature +%feature("python:compare", "Py_LT") MyClass::lessThan; + +%inline %{ + class MyClass { + public: + MyClass(int val = 0) : val(val) {} + bool lessThan(const MyClass& other) const { + less_than_counts++; + return val < other.val; + } + int val; + static int less_than_counts; + }; + int MyClass::less_than_counts = 0; +%} diff --git a/Lib/python/pyopers.swg b/Lib/python/pyopers.swg index 9e3d2a125..5fb22354b 100644 --- a/Lib/python/pyopers.swg +++ b/Lib/python/pyopers.swg @@ -18,6 +18,13 @@ where is the name of a field in a PyTypeObject, PyNumberMethods, PyMappingMethods, PySequenceMethods, or PyBufferProcs. For example: + %feature("python:tp_hash") MyClass "myHashFunc"; + + class MyClass { + public: + ... + }; + %{ // Note: Py_hash_t was introduced in Python 3.2 static Py_hash_t myHashFunc(PyObject *pyobj) { @@ -27,13 +34,6 @@ } %} - %feature("python:tp_hash") MyClass "myHashFunc"; - - class MyClass { - public: - ... - }; - NOTE: It is the responsibility of the programmer (that's you) to ensure that a statically defined slot function has the correct signature. @@ -62,20 +62,21 @@ operator overloads for comparison (operator==, operator<, etc.), they will be called from the generated rich compare function. If you want to explicitly choose a method to handle a certain comparison - operation, you may use %feature("python:slot") like this: + operation, you may use a different feature, %feature("python:compare") + like this: + + %feature("python:compare", "Py_LT") MyClass::lessThan; class MyClass { public: - bool lessThan (const MyClass& x) const; + bool lessThan(const MyClass& other) const; ... }; - %feature("python:slot", "Py_LT") MyClass::lessThan; - ... where "Py_LT" is one of the rich comparison opcodes defined in the python header file object.h. - If there's no method defined to handle a particular comparsion operation, + If there's no method defined to handle a particular comparison operation, the default behavior is to compare pointer values of the wrapped C++ objects. From e5a09c4141b5a055438a2682449a3af1ad478453 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 22 Aug 2016 07:51:42 +0100 Subject: [PATCH 10/13] Add additional Python builtin slots as features for user customization Added: - tp_is_gc - tp_bases - tp_mro - tp_cache - tp_subclasses - tp_weaklist - tp_del - tp_allocs - tp_frees - tp_maxalloc - tp_prev - tp_next --- Source/Modules/python.cxx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 31889a83c..6f1582619 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -4118,13 +4118,13 @@ public: printSlot(f, getSlot(n, "feature:python:tp_alloc"), "tp_alloc", "allocfunc"); printSlot(f, getSlot(n, "feature:python:tp_new", tp_new), "tp_new", "newfunc"); printSlot(f, getSlot(n, "feature:python:tp_free"), "tp_free", "freefunc"); - printSlot(f, getSlot(), "tp_is_gc", "inquiry"); - printSlot(f, getSlot(), "tp_bases", "PyObject*"); - printSlot(f, getSlot(), "tp_mro", "PyObject*"); - printSlot(f, getSlot(), "tp_cache", "PyObject*"); - printSlot(f, getSlot(), "tp_subclasses", "PyObject*"); - printSlot(f, getSlot(), "tp_weaklist", "PyObject*"); - printSlot(f, getSlot(), "tp_del", "destructor"); + printSlot(f, getSlot(n, "feature:python:tp_is_gc"), "tp_is_gc", "inquiry"); + printSlot(f, getSlot(n, "feature:python:tp_bases"), "tp_bases", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:tp_mro"), "tp_mro", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:tp_cache"), "tp_cache", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:tp_subclasses"), "tp_subclasses", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:tp_weaklist"), "tp_weaklist", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:tp_del"), "tp_del", "destructor"); Printv(f, "#if PY_VERSION_HEX >= 0x02060000\n", NIL); printSlot(f, getSlot(n, "feature:python:tp_version_tag"), "tp_version_tag", "int"); Printv(f, "#endif\n", NIL); @@ -4132,13 +4132,13 @@ public: printSlot(f, getSlot(n, "feature:python:tp_finalize"), "tp_finalize", "destructor"); Printv(f, "#endif\n", NIL); Printv(f, "#ifdef COUNT_ALLOCS\n", NIL); - printSlot(f, getSlot(), "tp_allocs", "Py_ssize_t"); - printSlot(f, getSlot(), "tp_frees", "Py_ssize_t"); - printSlot(f, getSlot(), "tp_maxalloc", "Py_ssize_t"); + printSlot(f, getSlot(n, "feature:python:tp_allocs"), "tp_allocs", "Py_ssize_t"); + printSlot(f, getSlot(n, "feature:python:tp_frees"), "tp_frees", "Py_ssize_t"); + printSlot(f, getSlot(n, "feature:python:tp_maxalloc"), "tp_maxalloc", "Py_ssize_t"); Printv(f, "#if PY_VERSION_HEX >= 0x02050000\n", NIL); - printSlot(f, getSlot(), "tp_prev", "struct _typeobject*"); + printSlot(f, getSlot(n, "feature:python:tp_prev"), "tp_prev", "struct _typeobject*"); Printv(f, "#endif\n", NIL); - printSlot(f, getSlot(), "tp_next", "struct _typeobject*"); + printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next", "struct _typeobject*"); Printv(f, "#endif\n", NIL); Printf(f, " },\n"); From bf4174d121bd4b51747d9114ac86568be2f30595 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 22 Aug 2016 08:39:24 +0100 Subject: [PATCH 11/13] Further additional Python builtin slots as features for user customization Added: - tp_flags - was_sq_slice - was_sq_ass_slice --- Source/Modules/python.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 6f1582619..8ac721404 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -4052,7 +4052,7 @@ public: String *quoted_tp_doc_str = NewStringf("\"%s\"", getSlot(n, "feature:python:tp_doc")); String *tp_init = NewString(builtin_tp_init ? Char(builtin_tp_init) : Swig_directorclass(n) ? "0" : "SwigPyBuiltin_BadInit"); String *tp_flags = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); - String *py3_tp_flags = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE"); + String *tp_flags_py3 = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE"); static String *tp_basicsize = NewStringf("sizeof(SwigPyObject)"); static String *tp_dictoffset_default = NewString("(Py_ssize_t)offsetof(SwigPyObject, dict)"); @@ -4095,9 +4095,9 @@ public: printSlot(f, getSlot(n, "feature:python:tp_setattro"), "tp_setattro", "setattrofunc"); printSlot(f, getSlot(n, "feature:python:tp_as_buffer", tp_as_buffer), "tp_as_buffer"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); - printSlot(f, py3_tp_flags, "tp_flags"); + printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags_py3), "tp_flags"); Printv(f, "#else\n", NIL); - printSlot(f, tp_flags, "tp_flags"); + printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags), "tp_flags"); Printv(f, "#endif\n", NIL); printSlot(f, quoted_tp_doc_str, "tp_doc"); printSlot(f, getSlot(n, "feature:python:tp_traverse"), "tp_traverse", "traverseproc"); @@ -4226,13 +4226,13 @@ public: printSlot(f, getSlot(n, "feature:python:sq_repeat"), "sq_repeat", "ssizeargfunc"); printSlot(f, getSlot(n, "feature:python:sq_item"), "sq_item", "ssizeargfunc"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); - printSlot(f, getSlot(n, "feature:was_sq_slice"), "was_sq_slice", "void*"); + printSlot(f, getSlot(n, "feature:python:was_sq_slice"), "was_sq_slice", "void*"); Printv(f, "#else\n", NIL); printSlot(f, getSlot(n, "feature:python:sq_slice"), "sq_slice", "ssizessizeargfunc"); Printv(f, "#endif\n", NIL); printSlot(f, getSlot(n, "feature:python:sq_ass_item"), "sq_ass_item", "ssizeobjargproc"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); - printSlot(f, getSlot(n, "feature:was_sq_ass_slice"), "was_sq_ass_slice", "void*"); + printSlot(f, getSlot(n, "feature:python:was_sq_ass_slice"), "was_sq_ass_slice", "void*"); Printv(f, "#else\n", NIL); printSlot(f, getSlot(n, "feature:python:sq_ass_slice"), "sq_ass_slice", "ssizessizeobjargproc"); Printv(f, "#endif\n", NIL); @@ -4307,7 +4307,7 @@ public: Delete(pmname); Delete(templ); Delete(tp_flags); - Delete(py3_tp_flags); + Delete(tp_flags_py3); Delete(tp_as_buffer); Delete(tp_as_mapping); Delete(tp_as_sequence); From ad452edf3eaeee426dc45a431a1a4217e46de64a Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 22 Aug 2016 08:48:04 +0100 Subject: [PATCH 12/13] Cosmetic code formatting corrections --- Source/Modules/python.cxx | 86 +++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 8ac721404..72da66f66 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -2037,7 +2037,7 @@ public: // Disregard optional "f" suffix, it can be just dropped in Python as it // uses doubles for everything anyhow. - for (char* p = end; *p != '\0'; ++p) { + for (char * p = end; *p != '\0'; ++p) { switch (*p) { case 'f': case 'F': @@ -2083,7 +2083,7 @@ public: // combination of "l" and "u", but not anything else (again, stuff like // "LL" could be handled, but we don't bother to do it currently). bool seen_long = false; - for (char* p = end; *p != '\0'; ++p) { + for (char * p = end; *p != '\0'; ++p) { switch (*p) { case 'l': case 'L': @@ -3392,7 +3392,7 @@ public: Python dictionary. */ if (!have_globals) { - Printf(f_init, "\t PyDict_SetItemString(md,(char*)\"%s\", SWIG_globals());\n", global_name); + Printf(f_init, "\t PyDict_SetItemString(md,(char *)\"%s\", SWIG_globals());\n", global_name); if (builtin) Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", global_name); have_globals = 1; @@ -3480,9 +3480,9 @@ public: Wrapper_print(getf, f_wrappers); /* Now add this to the variable linking mechanism */ - Printf(f_init, "\t SWIG_addvarlink(SWIG_globals(),(char*)\"%s\",%s, %s);\n", iname, vargetname, varsetname); + Printf(f_init, "\t SWIG_addvarlink(SWIG_globals(),(char *)\"%s\",%s, %s);\n", iname, vargetname, varsetname); if (builtin && shadow && !assignable && !in_class) { - Printf(f_init, "\t PyDict_SetItemString(md, (char*)\"%s\", PyObject_GetAttrString(SWIG_globals(), \"%s\"));\n", iname, iname); + Printf(f_init, "\t PyDict_SetItemString(md, (char *)\"%s\", PyObject_GetAttrString(SWIG_globals(), \"%s\"));\n", iname, iname); Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", iname); } Delete(vargetname); @@ -3499,7 +3499,7 @@ public: * ------------------------------------------------------------ */ /* Determine if the node requires the _swigconstant code to be generated */ - bool needs_swigconstant(Node* n) { + bool needs_swigconstant(Node *n) { SwigType *type = Getattr(n, "type"); SwigType *qtype = SwigType_typedef_resolve_all(type); SwigType *uqtype = SwigType_strip_qualifiers(qtype); @@ -3576,12 +3576,12 @@ public: Printf(f_wrappers, tab2 "PyObject *d;\n"); if (modernargs) { if (fastunpack) { - Printf(f_wrappers, tab2 "if (!SWIG_Python_UnpackTuple(args,(char*)\"swigconstant\", 1, 1,&module)) return NULL;\n"); + Printf(f_wrappers, tab2 "if (!SWIG_Python_UnpackTuple(args,(char *)\"swigconstant\", 1, 1,&module)) return NULL;\n"); } else { - Printf(f_wrappers, tab2 "if (!PyArg_UnpackTuple(args,(char*)\"swigconstant\", 1, 1,&module)) return NULL;\n"); + Printf(f_wrappers, tab2 "if (!PyArg_UnpackTuple(args,(char *)\"swigconstant\", 1, 1,&module)) return NULL;\n"); } } else { - Printf(f_wrappers, tab2 "if (!PyArg_ParseTuple(args,(char*)\"O:swigconstant\", &module)) return NULL;\n"); + Printf(f_wrappers, tab2 "if (!PyArg_ParseTuple(args,(char *)\"O:swigconstant\", &module)) return NULL;\n"); } Printf(f_wrappers, tab2 "d = PyModule_GetDict(module);\n"); Printf(f_wrappers, tab2 "if (!d) return NULL;\n"); @@ -3737,13 +3737,13 @@ public: Node *parent = Swig_methodclass(n); String *basetype = Getattr(parent, "classtype"); Wrapper *w = NewWrapper(); - Printf(w->def, "SwigDirector_%s::SwigDirector_%s(PyObject* self) : Swig::Director(self) { \n", classname, classname); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(PyObject *self) : Swig::Director(self) { \n", classname, classname); Printf(w->def, " SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); Append(w->def, "}\n"); Wrapper_print(w, f_directors); DelWrapper(w); } - Printf(f_directors_h, " SwigDirector_%s(PyObject* self);\n", classname); + Printf(f_directors_h, " SwigDirector_%s(PyObject *self);\n", classname); Delete(classname); return Language::classDirectorDefaultConstructor(n); } @@ -3932,8 +3932,8 @@ public: SwigType_add_pointer(base_name); String *base_mname = SwigType_manglestr(base_name); Printf(f_init, " builtin_basetype = SWIG_MangledTypeQuery(\"%s\");\n", base_mname); - Printv(f_init, " if (builtin_basetype && builtin_basetype->clientdata && ((SwigPyClientData*) builtin_basetype->clientdata)->pytype) {\n", NIL); - Printv(f_init, " builtin_bases[builtin_base_count++] = ((SwigPyClientData*) builtin_basetype->clientdata)->pytype;\n", NIL); + Printv(f_init, " if (builtin_basetype && builtin_basetype->clientdata && ((SwigPyClientData *) builtin_basetype->clientdata)->pytype) {\n", NIL); + Printv(f_init, " builtin_bases[builtin_base_count++] = ((SwigPyClientData *) builtin_basetype->clientdata)->pytype;\n", NIL); Printv(f_init, " } else {\n", NIL); Printf(f_init, " PyErr_SetString(PyExc_TypeError, \"Could not create type '%s' as base '%s' has not been initialized.\\n\");\n", symname, bname); Printv(f_init, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); @@ -3977,12 +3977,12 @@ public: String *gspair = NewStringf("%s_%s_getset", symname, memname); Printf(f, "static SwigPyGetSet %s = { %s, %s };\n", gspair, getter ? getter : "0", setter ? setter : "0"); String *entry = - NewStringf("{ (char*) \"%s\", (getter) %s, (setter) %s, (char*)\"%s.%s\", (void*) &%s }\n", memname, getter_closure, + NewStringf("{ (char *) \"%s\", (getter) %s, (setter) %s, (char *)\"%s.%s\", (void *) &%s }\n", memname, getter_closure, setter_closure, name, memname, gspair); if (GetFlag(mgetset, "static")) { Printf(f, "static PyGetSetDef %s_def = %s;\n", gspair, entry); Printf(f_init, "static_getset = SwigPyStaticVar_new_getset(metatype, &%s_def);\n", gspair); - Printf(f_init, "PyDict_SetItemString(d, static_getset->d_getset->name, (PyObject*) static_getset);\n", memname); + Printf(f_init, "PyDict_SetItemString(d, static_getset->d_getset->name, (PyObject *) static_getset);\n", memname); Printf(f_init, "Py_DECREF(static_getset);\n"); } else { Printf(getset_def, " %s,\n", entry); @@ -4119,11 +4119,11 @@ public: printSlot(f, getSlot(n, "feature:python:tp_new", tp_new), "tp_new", "newfunc"); printSlot(f, getSlot(n, "feature:python:tp_free"), "tp_free", "freefunc"); printSlot(f, getSlot(n, "feature:python:tp_is_gc"), "tp_is_gc", "inquiry"); - printSlot(f, getSlot(n, "feature:python:tp_bases"), "tp_bases", "PyObject*"); - printSlot(f, getSlot(n, "feature:python:tp_mro"), "tp_mro", "PyObject*"); - printSlot(f, getSlot(n, "feature:python:tp_cache"), "tp_cache", "PyObject*"); - printSlot(f, getSlot(n, "feature:python:tp_subclasses"), "tp_subclasses", "PyObject*"); - printSlot(f, getSlot(n, "feature:python:tp_weaklist"), "tp_weaklist", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:tp_bases"), "tp_bases", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_mro"), "tp_mro", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_cache"), "tp_cache", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_subclasses"), "tp_subclasses", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_weaklist"), "tp_weaklist", "PyObject *"); printSlot(f, getSlot(n, "feature:python:tp_del"), "tp_del", "destructor"); Printv(f, "#if PY_VERSION_HEX >= 0x02060000\n", NIL); printSlot(f, getSlot(n, "feature:python:tp_version_tag"), "tp_version_tag", "int"); @@ -4136,9 +4136,9 @@ public: printSlot(f, getSlot(n, "feature:python:tp_frees"), "tp_frees", "Py_ssize_t"); printSlot(f, getSlot(n, "feature:python:tp_maxalloc"), "tp_maxalloc", "Py_ssize_t"); Printv(f, "#if PY_VERSION_HEX >= 0x02050000\n", NIL); - printSlot(f, getSlot(n, "feature:python:tp_prev"), "tp_prev", "struct _typeobject*"); + printSlot(f, getSlot(n, "feature:python:tp_prev"), "tp_prev", "struct _typeobject *"); Printv(f, "#endif\n", NIL); - printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next", "struct _typeobject*"); + printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next", "struct _typeobject *"); Printv(f, "#endif\n", NIL); Printf(f, " },\n"); @@ -4177,7 +4177,7 @@ public: Printv(f, "#endif\n", NIL); printSlot(f, getSlot(n, "feature:python:nb_int"), "nb_int", "unaryfunc"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); - printSlot(f, getSlot(n, "feature:python:nb_reserved"), "nb_reserved", "void*"); + printSlot(f, getSlot(n, "feature:python:nb_reserved"), "nb_reserved", "void *"); Printv(f, "#else\n", NIL); printSlot(f, getSlot(n, "feature:python:nb_long"), "nb_long", "unaryfunc"); Printv(f, "#endif\n", NIL); @@ -4226,13 +4226,13 @@ public: printSlot(f, getSlot(n, "feature:python:sq_repeat"), "sq_repeat", "ssizeargfunc"); printSlot(f, getSlot(n, "feature:python:sq_item"), "sq_item", "ssizeargfunc"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); - printSlot(f, getSlot(n, "feature:python:was_sq_slice"), "was_sq_slice", "void*"); + printSlot(f, getSlot(n, "feature:python:was_sq_slice"), "was_sq_slice", "void *"); Printv(f, "#else\n", NIL); printSlot(f, getSlot(n, "feature:python:sq_slice"), "sq_slice", "ssizessizeargfunc"); Printv(f, "#endif\n", NIL); printSlot(f, getSlot(n, "feature:python:sq_ass_item"), "sq_ass_item", "ssizeobjargproc"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); - printSlot(f, getSlot(n, "feature:python:was_sq_ass_slice"), "was_sq_ass_slice", "void*"); + printSlot(f, getSlot(n, "feature:python:was_sq_ass_slice"), "was_sq_ass_slice", "void *"); Printv(f, "#else\n", NIL); printSlot(f, getSlot(n, "feature:python:sq_ass_slice"), "sq_ass_slice", "ssizessizeobjargproc"); Printv(f, "#endif\n", NIL); @@ -4256,13 +4256,13 @@ public: Printf(f, " },\n"); // PyObject *ht_name, *ht_slots, *ht_qualname; - printSlot(f, getSlot(n, "feature:python:ht_name"), "ht_name", "PyObject*"); - printSlot(f, getSlot(n, "feature:python:ht_slots"), "ht_slots", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:ht_name"), "ht_name", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:ht_slots"), "ht_slots", "PyObject *"); Printv(f, "#if PY_VERSION_HEX >= 0x03030000\n", NIL); - printSlot(f, getSlot(n, "feature:python:ht_qualname"), "ht_qualname", "PyObject*"); + printSlot(f, getSlot(n, "feature:python:ht_qualname"), "ht_qualname", "PyObject *"); // struct _dictkeysobject *ht_cached_keys; - printSlot(f, getSlot(n, "feature:python:ht_cached_keys"), "ht_cached_keys", "struct _dictkeysobject*"); + printSlot(f, getSlot(n, "feature:python:ht_cached_keys"), "ht_cached_keys", "struct _dictkeysobject *"); Printv(f, "#endif\n", NIL); Printf(f, "};\n\n"); @@ -4281,7 +4281,7 @@ public: String *clientdata_klass = NewString("0"); if (GetFlag(n, "feature:implicitconv")) { Clear(clientdata_klass); - Printf(clientdata_klass, "(PyObject*) &%s_type", templ); + Printf(clientdata_klass, "(PyObject *) &%s_type", templ); } Printf(f, "SWIGINTERN SwigPyClientData %s_clientdata = {%s, 0, 0, 0, 0, 0, (PyTypeObject *)&%s_type};\n\n", templ, clientdata_klass, templ); @@ -4295,7 +4295,7 @@ public: Printv(f_init, "#endif\n", NIL); Printv(f_init, " }\n", NIL); Printv(f_init, " Py_INCREF(builtin_pytype);\n", NIL); - Printf(f_init, " PyModule_AddObject(m, \"%s\", (PyObject*) builtin_pytype);\n", symname); + Printf(f_init, " PyModule_AddObject(m, \"%s\", (PyObject *)builtin_pytype);\n", symname); Printf(f_init, " SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", symname); Printv(f_init, " d = md;\n", NIL); @@ -4487,7 +4487,7 @@ public: SwigType_add_pointer(p_real_classname); String *mangle = SwigType_manglestr(p_real_classname); String *descriptor = NewStringf("SWIGTYPE%s", mangle); - Printv(none_comparison, "self->ob_type != ((SwigPyClientData*) (", descriptor, ")->clientdata)->pytype", NIL); + Printv(none_comparison, "self->ob_type != ((SwigPyClientData *)(", descriptor, ")->clientdata)->pytype", NIL); Delete(descriptor); Delete(mangle); Delete(p_real_classname); @@ -4514,12 +4514,12 @@ public: Printv(f_wrappers, " PyObject *obj;\n", NIL); if (modernargs) { if (fastunpack) { - Printv(f_wrappers, " if (!SWIG_Python_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); + Printv(f_wrappers, " if (!SWIG_Python_UnpackTuple(args,(char *)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); } else { - Printv(f_wrappers, " if (!PyArg_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); + Printv(f_wrappers, " if (!PyArg_UnpackTuple(args,(char *)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); } } else { - Printv(f_wrappers, " if (!PyArg_ParseTuple(args,(char*)\"O:swigregister\", &obj)) return NULL;\n", NIL); + Printv(f_wrappers, " if (!PyArg_ParseTuple(args,(char *)\"O:swigregister\", &obj)) return NULL;\n", NIL); } Printv(f_wrappers, @@ -4662,13 +4662,13 @@ public: int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2; String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_FUNC) : NewString(""); if (check_kwargs(n)) { - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS|METH_KEYWORDS, (char*) \"%s\" },\n", symname, wname, ds); + Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS|METH_KEYWORDS, (char *) \"%s\" },\n", symname, wname, ds); } else if (argcount == 0) { - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_NOARGS, (char*) \"%s\" },\n", symname, wname, ds); + Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_NOARGS, (char *) \"%s\" },\n", symname, wname, ds); } else if (argcount == 1) { - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_O, (char*) \"%s\" },\n", symname, wname, ds); + Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_O, (char *) \"%s\" },\n", symname, wname, ds); } else { - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS, (char*) \"%s\" },\n", symname, wname, ds); + Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS, (char *) \"%s\" },\n", symname, wname, ds); } Delete(fullname); Delete(wname); @@ -4769,7 +4769,7 @@ public: Append(pyflags, "METH_VARARGS"); if (have_docstring(n)) { String *ds = cdocstring(n, AUTODOC_STATICFUNC); - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, %s, (char*) \"%s\" },\n", symname, wname, pyflags, ds); + Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, %s, (char *) \"%s\" },\n", symname, wname, pyflags, ds); Delete(ds); } else { Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, %s, \"\" },\n", symname, wname, pyflags); @@ -5554,9 +5554,9 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { Append(w->code, "}\n"); Append(w->code, "#if defined(SWIG_PYTHON_DIRECTOR_VTABLE)\n"); Printf(w->code, "const size_t swig_method_index = %d;\n", director_method_index++); - Printf(w->code, "const char * const swig_method_name = \"%s\";\n", pyname); + Printf(w->code, "const char *const swig_method_name = \"%s\";\n", pyname); - Append(w->code, "PyObject* method = swig_get_method(swig_method_index, swig_method_name);\n"); + Append(w->code, "PyObject *method = swig_get_method(swig_method_index, swig_method_name);\n"); if (Len(parse_args) > 0) { if (use_parse || !modernargs) { Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunction(method, (char *)\"(%s)\" %s);\n", Swig_cresult_name(), parse_args, arglist); @@ -5566,7 +5566,7 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { } else { if (modernargs) { Append(w->code, "swig::SwigVar_PyObject args = PyTuple_New(0);\n"); - Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_Call(method, (PyObject*) args, NULL);\n", Swig_cresult_name()); + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_Call(method, (PyObject *) args, NULL);\n", Swig_cresult_name()); } else { Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunction(method, NULL, NULL);\n", Swig_cresult_name()); } From ae32fb4f9acba9d285ca6c98bd4492a337e52f1d Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 22 Aug 2016 19:27:39 +0100 Subject: [PATCH 13/13] Python builtin minor tweaks Remove internal Python struct names from generated code Cosmetic code formatting --- Lib/python/builtin.swg | 9 ++++----- Lib/python/pyinit.swg | 1 - Lib/python/pyrun.swg | 8 +++----- Source/Modules/python.cxx | 10 +++++----- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Lib/python/builtin.swg b/Lib/python/builtin.swg index abf5f71cb..6085980d4 100644 --- a/Lib/python/builtin.swg +++ b/Lib/python/builtin.swg @@ -389,16 +389,15 @@ SwigPyStaticVar_Type(void) { static int type_init = 0; if (!type_init) { const PyTypeObject tmp = { - /* PyObject header changed in Python 3 */ #if PY_VERSION_HEX >= 0x03000000 PyVarObject_HEAD_INIT(&PyType_Type, 0) #else PyObject_HEAD_INIT(&PyType_Type) - 0, + 0, /* ob_size */ #endif - "swig_static_var_getset_descriptor", - sizeof(PyGetSetDescrObject), - 0, + "swig_static_var_getset_descriptor", /* tp_name */ + sizeof(PyGetSetDescrObject), /* tp_basicsize */ + 0, /* tp_itemsize */ (destructor)SwigPyStaticVar_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ diff --git a/Lib/python/pyinit.swg b/Lib/python/pyinit.swg index 2e21b8265..e671731ac 100644 --- a/Lib/python/pyinit.swg +++ b/Lib/python/pyinit.swg @@ -145,7 +145,6 @@ swig_varlink_type(void) { static int type_init = 0; if (!type_init) { const PyTypeObject tmp = { - /* PyObject header changed in Python 3 */ #if PY_VERSION_HEX >= 0x03000000 PyVarObject_HEAD_INIT(NULL, 0) #else diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index 08f0848d4..ab1237f62 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -758,7 +758,6 @@ SwigPyObject_TypeOnce(void) { static int type_init = 0; if (!type_init) { const PyTypeObject tmp = { - /* PyObject header changed in Python 3 */ #if PY_VERSION_HEX >= 0x03000000 PyVarObject_HEAD_INIT(NULL, 0) #else @@ -769,7 +768,7 @@ SwigPyObject_TypeOnce(void) { sizeof(SwigPyObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)SwigPyObject_dealloc, /* tp_dealloc */ - 0, /* tp_print */ + 0, /* tp_print */ #if PY_VERSION_HEX < 0x02020000 (getattrfunc)SwigPyObject_getattr, /* tp_getattr */ #else @@ -777,7 +776,7 @@ SwigPyObject_TypeOnce(void) { #endif (setattrfunc)0, /* tp_setattr */ #if PY_VERSION_HEX >= 0x03000000 - 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */ + 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */ #else (cmpfunc)SwigPyObject_compare, /* tp_compare */ #endif @@ -787,7 +786,7 @@ SwigPyObject_TypeOnce(void) { 0, /* tp_as_mapping */ (hashfunc)0, /* tp_hash */ (ternaryfunc)0, /* tp_call */ - 0, /* tp_str */ + 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -950,7 +949,6 @@ SwigPyPacked_TypeOnce(void) { static int type_init = 0; if (!type_init) { const PyTypeObject tmp = { - /* PyObject header changed in Python 3 */ #if PY_VERSION_HEX>=0x03000000 PyVarObject_HEAD_INIT(NULL, 0) #else diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 72da66f66..d31554071 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -4055,7 +4055,7 @@ public: String *tp_flags_py3 = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE"); static String *tp_basicsize = NewStringf("sizeof(SwigPyObject)"); - static String *tp_dictoffset_default = NewString("(Py_ssize_t)offsetof(SwigPyObject, dict)"); + static String *tp_dictoffset_default = NewString("offsetof(SwigPyObject, dict)"); static String *tp_new = NewString("PyType_GenericNew"); String *tp_as_number = NewStringf("&%s_type.as_number", templ); String *tp_as_sequence = NewStringf("&%s_type.as_sequence", templ); @@ -4113,7 +4113,7 @@ public: printSlot(f, getSlot(n, "feature:python:tp_dict"), "tp_dict"); printSlot(f, getSlot(n, "feature:python:tp_descr_get"), "tp_descr_get", "descrgetfunc"); printSlot(f, getSlot(n, "feature:python:tp_descr_set"), "tp_descr_set", "descrsetfunc"); - printSlot(f, getSlot(n, "feature:python:tp_dictoffset", tp_dictoffset_default), "tp_dictoffset"); + printSlot(f, getSlot(n, "feature:python:tp_dictoffset", tp_dictoffset_default), "tp_dictoffset", "Py_ssize_t"); printSlot(f, getSlot(n, "feature:python:tp_init", tp_init), "tp_init", "initproc"); printSlot(f, getSlot(n, "feature:python:tp_alloc"), "tp_alloc", "allocfunc"); printSlot(f, getSlot(n, "feature:python:tp_new", tp_new), "tp_new", "newfunc"); @@ -4136,9 +4136,9 @@ public: printSlot(f, getSlot(n, "feature:python:tp_frees"), "tp_frees", "Py_ssize_t"); printSlot(f, getSlot(n, "feature:python:tp_maxalloc"), "tp_maxalloc", "Py_ssize_t"); Printv(f, "#if PY_VERSION_HEX >= 0x02050000\n", NIL); - printSlot(f, getSlot(n, "feature:python:tp_prev"), "tp_prev", "struct _typeobject *"); + printSlot(f, getSlot(n, "feature:python:tp_prev"), "tp_prev"); Printv(f, "#endif\n", NIL); - printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next", "struct _typeobject *"); + printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next"); Printv(f, "#endif\n", NIL); Printf(f, " },\n"); @@ -4262,7 +4262,7 @@ public: printSlot(f, getSlot(n, "feature:python:ht_qualname"), "ht_qualname", "PyObject *"); // struct _dictkeysobject *ht_cached_keys; - printSlot(f, getSlot(n, "feature:python:ht_cached_keys"), "ht_cached_keys", "struct _dictkeysobject *"); + printSlot(f, getSlot(n, "feature:python:ht_cached_keys"), "ht_cached_keys"); Printv(f, "#endif\n", NIL); Printf(f, "};\n\n");