diff options
Diffstat (limited to 'Source/Modules/python.cxx')
-rw-r--r-- | Source/Modules/python.cxx | 1905 |
1 files changed, 892 insertions, 1013 deletions
diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index a6801fc4e..ea31af029 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * This file is part of SWIG, which is licensed as a whole under version 3 + * This file is part of SWIG, which is licensed as a whole under version 3 * (or any later version) of the GNU General Public License. Some additional * terms also apply to certain portions of SWIG. The full details of the SWIG * license and copyrights can be found in the LICENSE and COPYRIGHT files @@ -16,11 +16,16 @@ #include "cparse.h" #include <ctype.h> #include <errno.h> -#include <stdlib.h> +#include "pydoc.h" + +#include <stdint.h> #define PYSHADOW_MEMBER 0x2 #define WARN_PYTHON_MULTIPLE_INH 405 +#define PYTHON_INT_MAX (2147483647) +#define PYTHON_INT_MIN (-2147483647-1) + static String *const_code = 0; static String *module = 0; static String *package = 0; @@ -56,12 +61,10 @@ static String *builtin_default_unref = 0; static String *builtin_closures_code = 0; static String *methods; +static String *methods_proxydocs; static String *class_name; static String *shadow_indent = 0; static int in_class = 0; -static int classic = 0; -static int modern = 0; -static int new_repr = 1; static int no_header_file = 0; static int max_bases = 0; static int builtin_bases_needed = 0; @@ -77,24 +80,15 @@ static String *real_classname; /* Thread Support */ static int threads = 0; static int nothreads = 0; -static int classptr = 0; + /* Other options */ -static int shadowimport = 1; -static int buildnone = 0; -static int nobuildnone = 0; -static int safecstrings = 0; static int dirvtable = 0; -static int proxydel = 1; -static int fastunpack = 0; +static int doxygen = 0; +static int fastunpack = 1; static int fastproxy = 0; -static int fastquery = 0; -static int fastinit = 0; static int olddefs = 0; -static int modernargs = 0; -static int aliasobj0 = 0; static int castmode = 0; static int extranative = 0; -static int outputtuple = 0; static int nortti = 0; static int relativeimport = 0; @@ -105,68 +99,38 @@ enum autodoc_t { AUTODOC_DTOR, AUTODOC_STATICFUNC, AUTODOC_FUNC, - AUTODOC_METHOD + AUTODOC_METHOD, + AUTODOC_CONST, + AUTODOC_VAR }; static const char *usage1 = "\ Python Options (available with -python)\n\ - -aliasobj0 - Alias obj0 when using fastunpack, needed for some old typemaps \n\ - -buildnone - Use Py_BuildValue(" ") to obtain Py_None (default in Windows)\n\ - -builtin - Create new python built-in types, rather than proxy classes, for better performance\n\ - -castmode - Enable the casting mode, which allows implicit cast between types in python\n\ - -classic - Use classic classes only\n\ - -classptr - Generate shadow 'ClassPtr' as in older swig versions\n\ - -cppcast - Enable C++ casting operators (default) \n\ - -dirvtable - Generate a pseudo virtual table for directors for faster dispatch \n\ - -extranative - Return extra native C++ wraps for std containers when possible \n\ - -fastinit - Use fast init mechanism for classes (default)\n\ - -fastunpack - Use fast unpack mechanism to parse the argument functions \n\ - -fastproxy - Use fast proxy mechanism for member methods \n\ - -fastquery - Use fast query mechanism for types \n\ - -globals <name> - Set <name> used to access C global variable [default: 'cvar']\n\ - -interface <lib>- Set the lib name to <lib>\n\ - -keyword - Use keyword arguments\n\ - -modern - Use modern python features only, without compatibility code\n\ - -modernargs - Use \"modern\" args mechanism to pack/unpack the function arguments\n"; + -builtin - Create Python built-in types rather than proxy classes, for better performance\n\ + -castmode - Enable the casting mode, which allows implicit cast between types in Python\n\ + -debug-doxygen-parser - Display doxygen parser module debugging information\n\ + -debug-doxygen-translator - Display doxygen translator module debugging information\n\ + -dirvtable - Generate a pseudo virtual table for directors for faster dispatch\n\ + -doxygen - Convert C++ doxygen comments to pydoc comments in proxy classes\n\ + -extranative - Return extra native wrappers for C++ std containers wherever possible\n\ + -fastproxy - Use fast proxy mechanism for member methods\n\ + -globals <name> - Set <name> used to access C global variable (default: 'cvar')\n\ + -interface <mod>- Set low-level C/C++ module name to <mod> (default: module name prefixed by '_')\n\ + -keyword - Use keyword arguments\n"; static const char *usage2 = "\ - -newrepr - Use more informative version of __repr__ in proxy classes (default) \n\ - -newvwm - New value wrapper mode, use only when everything else fails \n\ - -noaliasobj0 - Don't generate an obj0 alias when using fastunpack (default) \n\ - -nobuildnone - Access Py_None directly (default in non-Windows systems)\n\ - -nocastmode - Disable the casting mode (default)\n\ - -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ - -nodirvtable - Don't use the virtual table feature, resolve the python method each time (default)\n\ - -noexcept - No automatic exception handling\n\ - -noextranative - Don't use extra native C++ wraps for std containers when possible (default) \n\ - -nofastinit - Use traditional init mechanism for classes \n\ - -nofastunpack - Use traditional UnpackTuple method to parse the argument functions (default) \n\ - -nofastproxy - Use traditional proxy mechanism for member methods (default) \n\ - -nofastquery - Use traditional query mechanism for types (default) \n\ - -noh - Don't generate the output header file\n\ - -nomodern - Don't use modern python features which are not backwards compatible \n\ - -nomodernargs - Use classic ParseTuple/CallFunction methods to pack/unpack the function arguments (default) \n"; + -nofastunpack - Use traditional UnpackTuple method to parse the argument functions\n\ + -noh - Don't generate the output header file\n"; static const char *usage3 = "\ - -noolddefs - Don't emit the old method definitions even when using fastproxy (default) \n\ - -nooutputtuple - Use a PyList for appending output values (default) \n\ - -noproxy - Don't generate proxy classes \n\ - -noproxydel - Don't generate the redundant __del__ method \n\ - -noproxyimport - Don't insert proxy import statements derived from the %import directive \n\ + -noproxy - Don't generate proxy classes\n\ -nortti - Disable the use of the native C++ RTTI with directors\n\ - -nosafecstrings - Avoid extra strings copies when possible (default)\n\ -nothreads - Disable thread support for the entire interface\n\ - -olddefs - Keep the old method definitions even when using fastproxy\n\ - -oldrepr - Use shorter and old version of __repr__ in proxy classes\n\ - -outputtuple - Use a PyTuple for outputs instead of a PyList (use carefully with legacy interfaces) \n\ - -proxydel - Generate a __del__ method even though it is now redundant (default) \n\ - -relativeimport - Use relative python imports \n\ - -safecstrings - Use safer (but slower) C string mapping, generating copies from Python -> C/C++\n\ + -olddefs - Keep the old method definitions when using -fastproxy\n\ + -py3 - Generate code with Python 3 specific features and syntax\n\ + -relativeimport - Use relative Python imports\n\ -threads - Add thread support for all the interface\n\ - -O - Enable the following optimization options: \n\ - -modern -fastdispatch -nosafecstrings -fvirtual -noproxydel \n\ - -fastproxy -fastinit -fastunpack -fastquery -modernargs -nobuildnone \n\ - -py3 - Generate code with Python 3 specific features:\n\ - Function annotation \n\ + -O - Enable the following optimization options:\n\ + -fastdispatch -fastproxy -fvirtual\n\ \n"; static String *getSlot(Node *n = NULL, const char *key = NULL, String *default_slot = NULL) { @@ -177,7 +141,7 @@ static String *getSlot(Node *n = NULL, const char *key = NULL, String *default_s static void printSlot(File *f, String *slotval, const char *slotname, const char *functype = NULL) { String *slotval_override = 0; - if (functype) + if (functype && Strcmp(slotval, "0") == 0) slotval = slotval_override = NewStringf("(%s) %s", functype, slotval); int len = Len(slotval); int fieldwidth = len > 41 ? (len > 61 ? 0 : 61 - len) : 41 - len; @@ -199,6 +163,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) { "ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE", "ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE", "ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE", + "objobjproc", "SWIGPY_OBJOBJPROC_CLOSURE", "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", @@ -218,6 +183,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) { "ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE", "ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE", "ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE", + "objobjproc", "SWIGPY_FUNPACK_OBJOBJPROC_CLOSURE", "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", @@ -255,6 +221,11 @@ public: director_multiple_inheritance = 1; director_language = 1; } + + ~PYTHON() { + delete doxygenTranslator; + } + /* ------------------------------------------------------------ * Thread Implementation * ------------------------------------------------------------ */ @@ -326,10 +297,11 @@ public: * ------------------------------------------------------------ */ virtual void main(int argc, char *argv[]) { - int cppcast = 1; SWIG_library_directory("python"); + int doxygen_translator_flags = 0; + for (int i = 1; i < argc; i++) { if (argv[i]) { if (strcmp(argv[i], "-interface") == 0) { @@ -354,42 +326,13 @@ public: } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { shadow = 1; Swig_mark_arg(i); - } else if ((strcmp(argv[i], "-new_repr") == 0) || (strcmp(argv[i], "-newrepr") == 0)) { - new_repr = 1; - Swig_mark_arg(i); - } else if ((strcmp(argv[i], "-old_repr") == 0) || (strcmp(argv[i], "-oldrepr") == 0)) { - new_repr = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-classptr") == 0) { - classptr = 1; - Swig_mark_arg(i); } else if ((strcmp(argv[i], "-noproxy") == 0)) { shadow = 0; Swig_mark_arg(i); - } else if ((strcmp(argv[i], "-noproxyimport") == 0)) { - shadowimport = 0; - Swig_mark_arg(i); } else if (strcmp(argv[i], "-keyword") == 0) { use_kw = 1; SWIG_cparse_set_compact_default_args(1); Swig_mark_arg(i); - } else if (strcmp(argv[i], "-classic") == 0) { - classic = 1; - modernargs = 0; - modern = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-cppcast") == 0) { - cppcast = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nocppcast") == 0) { - cppcast = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-outputtuple") == 0) { - outputtuple = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nooutputtuple") == 0) { - outputtuple = 0; - Swig_mark_arg(i); } else if (strcmp(argv[i], "-nortti") == 0) { nortti = 1; Swig_mark_arg(i); @@ -397,31 +340,21 @@ public: threads = 1; Swig_mark_arg(i); } else if (strcmp(argv[i], "-nothreads") == 0) { - /* Turn off thread suppor mode */ + /* Turn off thread support mode */ nothreads = 1; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-safecstrings") == 0) { - safecstrings = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nosafecstrings") == 0) { - safecstrings = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-buildnone") == 0) { - buildnone = 1; - nobuildnone = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nobuildnone") == 0) { - buildnone = 0; - nobuildnone = 1; - Swig_mark_arg(i); } else if (strcmp(argv[i], "-dirvtable") == 0) { dirvtable = 1; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nodirvtable") == 0) { - dirvtable = 0; + } else if (strcmp(argv[i], "-doxygen") == 0) { + doxygen = 1; + scan_doxygen_comments = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-doxygen-translator") == 0) { + doxygen_translator_flags |= DoxygenTranslator::debug_translator; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-fastunpack") == 0) { - fastunpack = 1; + } else if (strcmp(argv[i], "-debug-doxygen-parser") == 0) { + doxygen_translator_flags |= DoxygenTranslator::debug_parser; Swig_mark_arg(i); } else if (strcmp(argv[i], "-nofastunpack") == 0) { fastunpack = 0; @@ -429,87 +362,26 @@ public: } else if (strcmp(argv[i], "-fastproxy") == 0) { fastproxy = 1; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nofastproxy") == 0) { - fastproxy = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-fastquery") == 0) { - fastquery = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nofastquery") == 0) { - fastquery = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-fastinit") == 0) { - fastinit = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nofastinit") == 0) { - fastinit = 0; - Swig_mark_arg(i); } else if (strcmp(argv[i], "-olddefs") == 0) { olddefs = 1; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-noolddefs") == 0) { - olddefs = 0; - Swig_mark_arg(i); } else if (strcmp(argv[i], "-castmode") == 0) { castmode = 1; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nocastmode") == 0) { - castmode = 0; - Swig_mark_arg(i); } else if (strcmp(argv[i], "-extranative") == 0) { extranative = 1; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-noextranative") == 0) { - extranative = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-modernargs") == 0) { - modernargs = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nomodernargs") == 0) { - modernargs = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-aliasobj0") == 0) { - aliasobj0 = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-noaliasobj0") == 0) { - aliasobj0 = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-proxydel") == 0) { - proxydel = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-noproxydel") == 0) { - proxydel = 0; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-modern") == 0) { - classic = 0; - modern = 1; - modernargs = 1; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-nomodern") == 0) { - modern = 0; - modernargs = 0; - Swig_mark_arg(i); } else if (strcmp(argv[i], "-noh") == 0) { no_header_file = 1; Swig_mark_arg(i); - } else if ((strcmp(argv[i], "-new_vwm") == 0) || (strcmp(argv[i], "-newvwm") == 0)) { - /* Turn on new value wrapper mpde */ + } else if (strcmp(argv[i], "-newvwm") == 0) { + /* Turn on new value wrapper mode */ + /* Undocumented option, did have -help text: New value wrapper mode, use only when everything else fails */ Swig_value_wrapper_mode(1); no_header_file = 1; Swig_mark_arg(i); } else if (strcmp(argv[i], "-O") == 0) { - classic = 0; - modern = 1; - safecstrings = 0; - buildnone = 0; - nobuildnone = 1; - classptr = 0; - proxydel = 0; - fastunpack = 1; fastproxy = 1; - fastinit = 1; - fastquery = 1; - modernargs = 1; Wrapper_fast_dispatch_mode_set(1); Wrapper_virtual_elimination_mode_set(1); Swig_mark_arg(i); @@ -528,19 +400,52 @@ public: } else if (strcmp(argv[i], "-relativeimport") == 0) { relativeimport = 1; Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0 || + strcmp(argv[i], "-fastinit") == 0 || + strcmp(argv[i], "-fastquery") == 0 || + strcmp(argv[i], "-fastunpack") == 0 || + strcmp(argv[i], "-modern") == 0 || + strcmp(argv[i], "-modernargs") == 0 || + strcmp(argv[i], "-noproxydel") == 0 || + strcmp(argv[i], "-safecstrings") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-aliasobj0") == 0 || + strcmp(argv[i], "-buildnone") == 0 || + strcmp(argv[i], "-classic") == 0 || + strcmp(argv[i], "-classptr") == 0 || + strcmp(argv[i], "-new_repr") == 0 || + strcmp(argv[i], "-new_vwm") == 0 || + strcmp(argv[i], "-newrepr") == 0 || + strcmp(argv[i], "-noaliasobj0") == 0 || + strcmp(argv[i], "-nobuildnone") == 0 || + strcmp(argv[i], "-nocastmode") == 0 || + strcmp(argv[i], "-nocppcast") == 0 || + strcmp(argv[i], "-nodirvtable") == 0 || + strcmp(argv[i], "-noextranative") == 0 || + strcmp(argv[i], "-nofastinit") == 0 || + strcmp(argv[i], "-nofastproxy") == 0 || + strcmp(argv[i], "-nofastquery") == 0 || + strcmp(argv[i], "-nomodern") == 0 || + strcmp(argv[i], "-nomodernargs") == 0 || + strcmp(argv[i], "-noolddefs") == 0 || + strcmp(argv[i], "-nooutputtuple") == 0 || + strcmp(argv[i], "-noproxyimport") == 0 || + strcmp(argv[i], "-nosafecstrings") == 0 || + strcmp(argv[i], "-old_repr") == 0 || + strcmp(argv[i], "-oldrepr") == 0 || + strcmp(argv[i], "-outputtuple") == 0 || + strcmp(argv[i], "-proxydel") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + SWIG_exit(EXIT_FAILURE); } } } - if (py3) { - /* force disable features that not compatible with Python 3.x */ - classic = 0; - } - - if (cppcast) { - Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); - } + if (doxygen) + doxygenTranslator = new PyDocConverter(doxygen_translator_flags); if (!global_name) global_name = NewString("cvar"); @@ -556,12 +461,12 @@ public: * ------------------------------------------------------------ */ virtual int top(Node *n) { - /* check if directors are enabled for this module. note: this + /* check if directors are enabled for this module. note: this * is a "master" switch, without which no director code will be * emitted. %feature("director") statements are also required * to enable directors for individual classes or methods. * - * use %module(directors="1") modulename at the start of the + * use %module(directors="1") modulename at the start of the * interface file to enable director generation. */ String *mod_docstring = NULL; @@ -590,19 +495,23 @@ public: castmode = 1; } if (Getattr(options, "nocastmode")) { - castmode = 0; + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nocastmode"); + SWIG_exit(EXIT_FAILURE); } if (Getattr(options, "extranative")) { extranative = 1; } if (Getattr(options, "noextranative")) { - extranative = 0; + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "noextranative"); + SWIG_exit(EXIT_FAILURE); } if (Getattr(options, "outputtuple")) { - outputtuple = 1; + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "outputtuple"); + SWIG_exit(EXIT_FAILURE); } if (Getattr(options, "nooutputtuple")) { - outputtuple = 0; + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nooutputtuple"); + SWIG_exit(EXIT_FAILURE); } mod_docstring = Getattr(options, "docstring"); package = Getattr(options, "package"); @@ -663,6 +572,7 @@ public: const_code = NewString(""); methods = NewString(""); + methods_proxydocs = NewString(""); Swig_banner(f_begin); @@ -678,26 +588,10 @@ public: Printf(f_runtime, "#define SWIG_PYTHON_THREADS\n"); } - if (safecstrings) { - Printf(f_runtime, "#define SWIG_PYTHON_SAFE_CSTRINGS\n"); - } - - if (buildnone) { - Printf(f_runtime, "#define SWIG_PYTHON_BUILD_NONE\n"); - } - - if (nobuildnone) { - Printf(f_runtime, "#define SWIG_PYTHON_NO_BUILD_NONE\n"); - } - if (!dirvtable) { Printf(f_runtime, "#define SWIG_PYTHON_DIRECTOR_NO_VTABLE\n"); } - if (outputtuple) { - Printf(f_runtime, "#define SWIG_PYTHON_OUTPUT_TUPLE\n"); - } - if (nortti) { Printf(f_runtime, "#ifndef SWIG_DIRECTOR_NORTTI\n"); Printf(f_runtime, "#define SWIG_DIRECTOR_NORTTI\n"); @@ -713,46 +607,16 @@ public: Printf(f_runtime, "#define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS\n"); } - if (classic) { - Printf(f_runtime, "#define SWIG_PYTHON_CLASSIC\n"); - } - if (builtin) { Printf(f_runtime, "#define SWIGPYTHON_BUILTIN\n"); } Printf(f_runtime, "\n"); - Printf(f_header, "#if (PY_VERSION_HEX <= 0x02000000)\n"); - Printf(f_header, "# if !defined(SWIG_PYTHON_CLASSIC)\n"); - Printf(f_header, "# error \"This python version requires swig to be run with the '-classic' option\"\n"); - Printf(f_header, "# endif\n"); + Printf(f_header, "#ifdef SWIG_TypeQuery\n"); + Printf(f_header, "# undef SWIG_TypeQuery\n"); Printf(f_header, "#endif\n"); - - if (modern) { - Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n"); - Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodern' option\"\n"); - Printf(f_header, "#endif\n"); - } - - if (modernargs) { - Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n"); - Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodernargs' option\"\n"); - Printf(f_header, "#endif\n"); - } - - if (fastunpack) { - Printf(f_header, "#ifndef METH_O\n"); - Printf(f_header, "# error \"This python version requires swig to be run with the '-nofastunpack' option\"\n"); - Printf(f_header, "#endif\n"); - } - - if (fastquery) { - Printf(f_header, "#ifdef SWIG_TypeQuery\n"); - Printf(f_header, "# undef SWIG_TypeQuery\n"); - Printf(f_header, "#endif\n"); - Printf(f_header, "#define SWIG_TypeQuery SWIG_Python_TypeQuery\n"); - } + Printf(f_header, "#define SWIG_TypeQuery SWIG_Python_TypeQuery\n"); /* Set module name */ @@ -805,184 +669,95 @@ public: Swig_register_filebyname("shadow", f_shadow); Swig_register_filebyname("python", f_shadow); - if (mod_docstring) { - if (Len(mod_docstring)) { - const char *triple_double = "\"\"\""; - // follow PEP257 rules: https://www.python.org/dev/peps/pep-0257/ - // reported by pep257: https://github.com/GreenSteam/pep257 - bool multi_line_ds = Strchr(mod_docstring, '\n') != 0; - Printv(f_shadow_after_begin, "\n", triple_double, multi_line_ds ? "\n":"", mod_docstring, multi_line_ds ? "\n":"", triple_double, "\n", NIL); - } - Delete(mod_docstring); - mod_docstring = NULL; - } - - Printv(default_import_code, "\nfrom sys import version_info as _swig_python_version_info\n", NULL); - - if (!builtin && fastproxy) { - Printv(default_import_code, "if _swig_python_version_info >= (3, 0, 0):\n", NULL); - Printf(default_import_code, tab4 "new_instancemethod = lambda func, inst, cls: %s.SWIG_PyInstanceMethod_New(func)\n", module); - Printv(default_import_code, "else:\n", NULL); - Printv(default_import_code, tab4, "from new import instancemethod as new_instancemethod\n", NULL); - } - - /* Import the C-extension module. This should be a relative import, - * since the shadow module may also have been imported by a relative - * import, and there is thus no guarantee that the C-extension is on - * sys.path. Relative imports must be explicitly specified from 2.6.0 - * onwards (implicit relative imports will raise a DeprecationWarning - * in 2.6, and fail in 2.7 onwards), but the relative import syntax - * isn't available in python 2.4 or earlier, so we have to write some - * code conditional on the python version. - * - * For python 2.7.0 and newer, first determine the shadow wrappers package - * based on the __name__ it was given by the importer that loaded it. - * Then construct a name for the module based on the package name and the - * module name (we know the module name). Use importlib to try and load - * it. If an attempt to load the module with importlib fails with an - * ImportError then fallback and try and load just the module name from - * the global namespace. - */ - Printv(default_import_code, "if _swig_python_version_info >= (2, 7, 0):\n", NULL); - Printv(default_import_code, tab4, "def swig_import_helper():\n", NULL); - Printv(default_import_code, tab8, "import importlib\n", NULL); - Printv(default_import_code, tab8, "pkg = __name__.rpartition('.')[0]\n", NULL); - Printf(default_import_code, tab8 "mname = '.'.join((pkg, '%s')).lstrip('.')\n", module); - Printv(default_import_code, tab8, "try:\n", NULL); - Printv(default_import_code, tab8, tab4, "return importlib.import_module(mname)\n", NULL); - Printv(default_import_code, tab8, "except ImportError:\n", NULL); - Printf(default_import_code, tab8 tab4 "return importlib.import_module('%s')\n", module); - Printf(default_import_code, tab4 "%s = swig_import_helper()\n", module); - Printv(default_import_code, tab4, "del swig_import_helper\n", NULL); - Printv(default_import_code, "elif _swig_python_version_info >= (2, 6, 0):\n", NULL); - Printv(default_import_code, tab4, "def swig_import_helper():\n", NULL); - Printv(default_import_code, tab8, "from os.path import dirname\n", NULL); - Printv(default_import_code, tab8, "import imp\n", NULL); - Printv(default_import_code, tab8, "fp = None\n", NULL); - Printv(default_import_code, tab8, "try:\n", NULL); - Printf(default_import_code, tab4 tab8 "fp, pathname, description = imp.find_module('%s', [dirname(__file__)])\n", module); - Printf(default_import_code, tab8 "except ImportError:\n"); - /* At here, the module may already loaded, so simply import it. */ - Printf(default_import_code, tab4 tab8 "import %s\n", module); - Printf(default_import_code, tab4 tab8 "return %s\n", module); - Printv(default_import_code, tab8 "try:\n", NULL); - /* imp.load_module() handles fp being None. */ - Printf(default_import_code, tab4 tab8 "_mod = imp.load_module('%s', fp, pathname, description)\n", module); - Printv(default_import_code, tab8, "finally:\n", NULL); - Printv(default_import_code, tab4 tab8 "if fp is not None:\n", NULL); - Printv(default_import_code, tab8 tab8, "fp.close()\n", NULL); - Printv(default_import_code, tab8, "return _mod\n", NULL); - Printf(default_import_code, tab4 "%s = swig_import_helper()\n", module); - Printv(default_import_code, tab4, "del swig_import_helper\n", NULL); - Printv(default_import_code, "else:\n", NULL); - Printf(default_import_code, tab4 "import %s\n", module); - - if (builtin) { - /* - * Pull in all the attributes from the C module. - * - * An alternative approach to doing this if/else chain was - * proposed by Michael Thon. Someone braver than I may try it out. - * I fear some current swig user may depend on some side effect - * of from _foo import * - * - * for attr in _foo.__all__: - * globals()[attr] = getattr(_foo, attr) - * - */ - Printf(default_import_code, "# pull in all the attributes from %s\n", module); - Printv(default_import_code, "if __name__.rpartition('.')[0] != '':\n", NULL); - Printv(default_import_code, tab4, "if _swig_python_version_info >= (2, 7, 0):\n", NULL); - Printv(default_import_code, tab8, "try:\n", NULL); - Printf(default_import_code, tab8 tab4 "from .%s import *\n", module); - Printv(default_import_code, tab8 "except ImportError:\n", NULL); - Printf(default_import_code, tab8 tab4 "from %s import *\n", module); - Printv(default_import_code, tab4, "else:\n", NULL); - Printf(default_import_code, tab8 "from %s import *\n", module); + if (!builtin) { + /* Import the low-level C/C++ module. This should be a relative import, + * since the shadow module may also have been imported by a relative + * import, and there is thus no guarantee that the low-level C/C++ module is on + * sys.path. Relative imports must be explicitly specified from 2.6.0 + * onwards (implicit relative imports raised a DeprecationWarning in 2.6, + * and fail in 2.7 onwards). + * + * First check for __package__ which is available from 2.6 onwards, see PEP366. + * Next try determine the shadow wrapper's package based on the __name__ it + * was given by the importer that loaded it. + * If the module is in a package, load the low-level C/C++ module from the + * same package, otherwise load it as a global module. + */ + Printv(default_import_code, "# Import the low-level C/C++ module\n", NULL); + Printv(default_import_code, "if __package__ or \".\" in __name__:\n", NULL); + Printv(default_import_code, tab4, "from . import ", module, "\n", NULL); Printv(default_import_code, "else:\n", NULL); - Printf(default_import_code, tab4 "from %s import *\n", module); - } - - /* Delete the _swig_python_version_info symbol since we don't use it elsewhere in the - * module. */ - Printv(default_import_code, "del _swig_python_version_info\n\n", NULL); - - if (modern || !classic) { - Printv(f_shadow, "try:\n", tab4, "_swig_property = property\n", "except NameError:\n", tab4, "pass # Python < 2.2 doesn't have 'property'.\n\n", NULL); + Printv(default_import_code, tab4, "import ", module, "\n", NULL); + } else { + Printv(default_import_code, "# Pull in all the attributes from the low-level C/C++ module\n", NULL); + Printv(default_import_code, "if __package__ or \".\" in __name__:\n", NULL); + Printv(default_import_code, tab4, "from .", module, " import *\n", NULL); + Printv(default_import_code, "else:\n", NULL); + Printv(default_import_code, tab4, "from ", module, " import *\n", NULL); } /* Need builtins to qualify names like Exception that might also be defined in this module (try both Python 3 and Python 2 names) */ Printv(f_shadow, "try:\n", tab4, "import builtins as __builtin__\n", "except ImportError:\n", tab4, "import __builtin__\n", NULL); - /* if (!modern) */ - /* always needed, a class can be forced to be no-modern, such as an exception */ - { - // Python-2.2 object hack - Printv(f_shadow, - "\n", "def _swig_setattr_nondynamic(self, class_type, name, value, static=1):\n", - tab4, "if (name == \"thisown\"):\n", tab8, "return self.this.own(value)\n", - tab4, "if (name == \"this\"):\n", tab8, "if type(value).__name__ == 'SwigPyObject':\n", tab4, tab8, "self.__dict__[name] = value\n", -#ifdef USE_THISOWN - tab4, tab8, "if hasattr(value,\"thisown\"):\n", tab8, tab8, "self.__dict__[\"thisown\"] = value.thisown\n", tab4, tab8, "del value.thisown\n", -#endif - tab4, tab8, "return\n", tab4, "method = class_type.__swig_setmethods__.get(name, None)\n", tab4, "if method:\n", tab4, tab4, "return method(self, value)\n", -#ifdef USE_THISOWN - tab4, "if (not static) or (name == \"thisown\"):\n", -#else - tab4, "if (not static):\n", -#endif - NIL); - if (!classic) { - if (!modern) - Printv(f_shadow, tab4, tab4, "if _newclass:\n", tab4, NIL); - Printv(f_shadow, tab4, tab4, "object.__setattr__(self, name, value)\n", NIL); - if (!modern) - Printv(f_shadow, tab4, tab4, "else:\n", tab4, NIL); - } - if (classic || !modern) - Printv(f_shadow, tab4, tab4, "self.__dict__[name] = value\n", NIL); - Printv(f_shadow, - tab4, "else:\n", - tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n\n", - "\n", "def _swig_setattr(self, class_type, name, value):\n", tab4, "return _swig_setattr_nondynamic(self, class_type, name, value, 0)\n\n", NIL); - - Printv(f_shadow, - "\n", "def _swig_getattr(self, class_type, name):\n", - tab4, "if (name == \"thisown\"):\n", tab8, "return self.this.own()\n", - tab4, "method = class_type.__swig_getmethods__.get(name, None)\n", - tab4, "if method:\n", tab8, "return method(self)\n", - tab4, "raise AttributeError(\"'%s' object has no attribute '%s'\" % (class_type.__name__, name))\n\n", NIL); - - Printv(f_shadow, - "\n", "def _swig_repr(self):\n", - tab4, "try:\n", tab8, "strthis = \"proxy of \" + self.this.__repr__()\n", - tab4, "except __builtin__.Exception:\n", tab8, "strthis = \"\"\n", tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL); - - if (!classic && !modern) { - Printv(f_shadow, - "try:\n", - tab4, "_object = object\n", tab4, "_newclass = 1\n", - "except __builtin__.Exception:\n", - tab4, "class _object:\n", tab8, "pass\n", tab4, "_newclass = 0\n\n", NIL); - } - } - if (modern) { - Printv(f_shadow, "\n", "def _swig_setattr_nondynamic_method(set):\n", tab4, "def set_attr(self, name, value):\n", + if (!builtin && fastproxy) { + Printf(f_shadow, "\n"); + Printf(f_shadow, "_swig_new_instance_method = %s.SWIG_PyInstanceMethod_New\n", module); + Printf(f_shadow, "_swig_new_static_method = %s.SWIG_PyStaticMethod_New\n", module); + } + + Printv(f_shadow, "\n", + "def _swig_repr(self):\n", + tab4, "try:\n", + tab4, tab4, "strthis = \"proxy of \" + self.this.__repr__()\n", + tab4, "except __builtin__.Exception:\n", + tab4, tab4, "strthis = \"\"\n", + tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL); + + Printv(f_shadow, "\n", + "def _swig_setattr_nondynamic_instance_variable(set):\n", + tab4, "def set_instance_attr(self, name, value):\n", #ifdef USE_THISOWN - tab4, tab4, "if hasattr(self, name) or (name in (\"this\", \"thisown\")):\n", + tab4, tab4, "if name in (\"this\", \"thisown\"):\n", + tab4, tab4, tab4, "set(self, name, value)\n", #else - tab4, tab4, "if (name == \"thisown\"):\n", tab8, tab4, "return self.this.own(value)\n", tab4, tab4, "if hasattr(self, name) or (name == \"this\"):\n", + tab4, tab4, "if name == \"thisown\":\n", + tab4, tab4, tab4, "self.this.own(value)\n", + tab4, tab4, "elif name == \"this\":\n", + tab4, tab4, tab4, "set(self, name, value)\n", #endif - tab4, tab4, tab4, "set(self, name, value)\n", - tab4, tab4, "else:\n", - tab4, tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n", tab4, "return set_attr\n\n\n", NIL); - } + tab4, tab4, "elif hasattr(self, name) and isinstance(getattr(type(self), name), property):\n", + tab4, tab4, tab4, "set(self, name, value)\n", + tab4, tab4, "else:\n", + tab4, tab4, tab4, "raise AttributeError(\"You cannot add instance attributes to %s\" % self)\n", + tab4, "return set_instance_attr\n\n", NIL); + + Printv(f_shadow, "\n", + "def _swig_setattr_nondynamic_class_variable(set):\n", + tab4, "def set_class_attr(cls, name, value):\n", + tab4, tab4, "if hasattr(cls, name) and not isinstance(getattr(cls, name), property):\n", + tab4, tab4, tab4, "set(cls, name, value)\n", + tab4, tab4, "else:\n", + tab4, tab4, tab4, "raise AttributeError(\"You cannot add class attributes to %s\" % cls)\n", + tab4, "return set_class_attr\n\n", NIL); + + Printv(f_shadow, "\n", + "def _swig_add_metaclass(metaclass):\n", + tab4, "\"\"\"Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass\"\"\"\n", + tab4, "def wrapper(cls):\n", + tab4, tab4, "return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())\n", + tab4, "return wrapper\n\n", NIL); + + Printv(f_shadow, "\n", + "class _SwigNonDynamicMeta(type):\n", + tab4, "\"\"\"Meta class to enforce nondynamic attributes (no new attributes) for a class\"\"\"\n", + tab4, "__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)\n", + "\n", NIL); + + Printv(f_shadow, "\n", NIL); if (directorsEnabled()) { - // Try loading weakref.proxy, which is only available in Python 2.1 and higher - Printv(f_shadow, - "try:\n", tab4, "import weakref\n", tab4, "weakref_proxy = weakref.proxy\n", "except __builtin__.Exception:\n", tab4, "weakref_proxy = lambda x: x\n", "\n\n", NIL); + Printv(f_shadow, "import weakref\n\n", NIL); } } // Include some information in the code @@ -1001,9 +776,11 @@ public: Printf(f_wrappers, "#endif\n"); Append(const_code, "static swig_const_info swig_const_table[] = {\n"); Append(methods, "static PyMethodDef SwigMethods[] = {\n"); + Append(methods_proxydocs, "static PyMethodDef SwigMethods_proxydocs[] = {\n"); /* the method exported for replacement of new.instancemethod in Python 3 */ add_pyinstancemethod_new(); + add_pystaticmethod_new(); if (builtin) { SwigType *s = NewString("SwigPyObject"); @@ -1025,6 +802,9 @@ public: Append(methods, "\t { NULL, NULL, 0, NULL }\n"); Append(methods, "};\n"); Printf(f_wrappers, "%s\n", methods); + Append(methods_proxydocs, "\t { NULL, NULL, 0, NULL }\n"); + Append(methods_proxydocs, "};\n"); + Printf(f_wrappers, "%s\n", methods_proxydocs); if (builtin) { Dump(f_builtins, f_wrappers); @@ -1049,20 +829,37 @@ public: if (shadow) { Swig_banner_target_lang(f_shadow_py, "#"); - if (!modern && !classic) { - Printv(f_shadow, "# This file is compatible with both classic and new-style classes.\n", NIL); + + if (mod_docstring) { + if (Len(mod_docstring)) { + const char *triple_double = "\"\"\""; + // follow PEP257 rules: https://www.python.org/dev/peps/pep-0257/ + // reported by pep257: https://github.com/GreenSteam/pep257 + bool multi_line_ds = Strchr(mod_docstring, '\n') != 0; + Printv(f_shadow_py, "\n", triple_double, multi_line_ds ? "\n":"", mod_docstring, multi_line_ds ? "\n":"", triple_double, "\n", NIL); + } + Delete(mod_docstring); + mod_docstring = NULL; } + if (Len(f_shadow_begin) > 0) Printv(f_shadow_py, "\n", f_shadow_begin, "\n", NIL); + + Printv(f_shadow_py, "\nfrom sys import version_info as _swig_python_version_info\n", NULL); + Printv(f_shadow_py, "if _swig_python_version_info < (2, 7, 0):\n", NULL); + Printv(f_shadow_py, tab4, "raise RuntimeError(\"Python 2.7 or later required\")\n\n", NULL); + if (Len(f_shadow_after_begin) > 0) - Printv(f_shadow_py, f_shadow_after_begin, "\n", NIL); + Printv(f_shadow_py, f_shadow_after_begin, "\n", NIL); + if (moduleimport) { Replaceall(moduleimport, "$module", module); - Printv(f_shadow_py, "\n", moduleimport, "\n", NIL); + Printv(f_shadow_py, moduleimport, "\n", NIL); } else { Printv(f_shadow_py, default_import_code, NIL); } - Printv(f_shadow_py, f_shadow, "\n", NIL); + + Printv(f_shadow_py, "\n", f_shadow, "\n", NIL); Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); Delete(f_shadow_py); } @@ -1109,12 +906,36 @@ public: * ------------------------------------------------------------ */ int add_pyinstancemethod_new() { String *name = NewString("SWIG_PyInstanceMethod_New"); - Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, NULL},\n", name, name); + String *line = NewString(""); + Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); + Append(methods, line); + if (fastproxy) { + Append(methods_proxydocs, line); + } + Delete(line); Delete(name); return 0; } /* ------------------------------------------------------------ + * Emit the wrapper for PyStaticMethod_New to MethodDef array. + * This wrapper is used to ensure the correct documentation is + * generated for static methods when using -fastproxy + * ------------------------------------------------------------ */ + int add_pystaticmethod_new() { + if (fastproxy) { + String *name = NewString("SWIG_PyStaticMethod_New"); + String *line = NewString(""); + Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); + Append(methods, line); + Append(methods_proxydocs, line); + Delete(line); + Delete(name); + } + return 0; + } + + /* ------------------------------------------------------------ * subpkg_tail() * * Return the name of 'other' package relative to 'base'. @@ -1269,14 +1090,9 @@ public: Printf(out, "import %s%s%s%s\n", apkg, *Char(apkg) ? "." : "", pfx, mod); Delete(apkg); } else { - Printf(out, "from sys import version_info as _swig_python_version_info\n"); - Printf(out, "if _swig_python_version_info >= (2, 7, 0):\n"); if (py3_rlen1) - Printf(out, tab4 "from . import %.*s\n", py3_rlen1, rpkg); - Printf(out, tab4 "from .%s import %s%s\n", rpkg, pfx, mod); - Printf(out, "else:\n"); - Printf(out, tab4 "import %s%s%s%s\n", rpkg, *Char(rpkg) ? "." : "", pfx, mod); - Printf(out, "del _swig_python_version_info\n"); + Printf(out, "from . import %.*s\n", py3_rlen1, rpkg); + Printf(out, "from .%s import %s%s\n", rpkg, pfx, mod); Delete(rpkg); } return out; @@ -1393,18 +1209,18 @@ public: Node *options = Getattr(mod, "options"); String *pkg = options ? Getattr(options, "package") : 0; - if (shadowimport) { - if (!options || (!Getattr(options, "noshadow") && !Getattr(options, "noproxy"))) { - String *_import = import_directive_string(package, pkg, modname, "_"); - if (!GetFlagAttr(f_shadow_imports, _import)) { - String *import = import_directive_string(package, pkg, modname); - Printf(builtin ? f_shadow_after_begin : f_shadow, "%s", import); - Delete(import); - SetFlag(f_shadow_imports, _import); - } - Delete(_import); + + if (!options || (!Getattr(options, "noshadow") && !Getattr(options, "noproxy"))) { + String *_import = import_directive_string(package, pkg, modname, "_"); + if (!GetFlagAttr(f_shadow_imports, _import)) { + String *import = import_directive_string(package, pkg, modname); + Printf(builtin ? f_shadow_after_begin : f_shadow, "%s", import); + Delete(import); + SetFlag(f_shadow_imports, _import); } + Delete(_import); } + } } return Language::importDirective(n); @@ -1648,37 +1464,76 @@ public: bool have_docstring(Node *n) { String *str = Getattr(n, "feature:docstring"); - return (str && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + return ((str && Len(str) > 0) + || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) + || (doxygen && doxygenTranslator->hasDocumentation(n)) + ); } /* ------------------------------------------------------------ - * docstring() + * build_combined_docstring() * - * Get the docstring text, stripping off {} if necessary, - * and enclose in triple double quotes. If autodoc is also - * set then it will build a combined docstring. + * Build the full docstring which may be a combination of the + * explicit docstring and autodoc string or, if none of them + * is specified, obtained by translating Doxygen comment to + * Python. + * + * Return new string to be deleted by caller (never NIL but + * may be empty if there is no docstring). * ------------------------------------------------------------ */ - String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool use_triple = true) { - String *str = Getattr(n, "feature:docstring"); - bool have_ds = (str && Len(str) > 0); - bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); - const char *triple_double = use_triple ? "\"\"\"" : ""; - String *autodoc = NULL; - String *doc = NULL; - - if (have_ds) { - char *t = Char(str); + String *build_combined_docstring(Node *n, autodoc_t ad_type, const String *indent = "", bool low_level = false) { + String *docstr = Getattr(n, "feature:docstring"); + if (docstr && Len(docstr)) { + docstr = Copy(docstr); + char *t = Char(docstr); if (*t == '{') { - Delitem(str, 0); - Delitem(str, DOH_END); + Delitem(docstr, 0); + Delitem(docstr, DOH_END); + } + } + + if (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) { + String *autodoc = make_autodoc(n, ad_type, low_level); + if (autodoc && Len(autodoc) > 0) { + if (docstr && Len(docstr)) { + Append(autodoc, "\n"); + Append(autodoc, docstr); + } + + String *tmp = autodoc; + autodoc = docstr; + docstr = tmp; } + + Delete(autodoc); } - if (have_auto) { - autodoc = make_autodoc(n, ad_type); - have_auto = (autodoc && Len(autodoc) > 0); + if (!docstr || !Len(docstr)) { + if (doxygen) { + docstr = Getattr(n, "python:docstring"); + if (!docstr && doxygenTranslator->hasDocumentation(n)) { + docstr = doxygenTranslator->getDocumentation(n, 0); + + // Avoid rebuilding it again the next time: notice that we can't do + // this for the combined doc string as autodoc part of it depends on + // the sym:name of the node and it is changed while handling it, so + // the cached results become incorrect. But Doxygen docstring only + // depends on the comment which is not going to change, so we can + // safely cache it. + Setattr(n, "python:docstring", Copy(docstr)); + } else { + // Must copy here since if the docstring is multi-line, the String* + // here will get Deleted below, which is bad if it is a pointer to + // the cached object! + docstr = Copy(docstr); + } + } } + + if (!docstr) + docstr = NewString(""); + // If there is more than one line then make docstrings like this: // // """ @@ -1687,82 +1542,79 @@ public: // """ // // otherwise, put it all on a single line + if (Strchr(docstr, '\n')) { + String *tmp = NewString(""); + Append(tmp, "\n"); + Append(tmp, indent_docstring(docstr, indent)); + Append(tmp, indent); + Delete(docstr); + docstr = tmp; + } + + return docstr; + } + + /* ------------------------------------------------------------ + * docstring() + * + * Get the docstring text, stripping off {} if necessary, + * and enclose in triple double quotes. If autodoc is also + * set then it will build a combined docstring. + * ------------------------------------------------------------ */ + + String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool low_level = false) { + String *docstr = build_combined_docstring(n, ad_type, indent, low_level); + if (!Len(docstr)) + return docstr; + + // Notice that all comments are created as raw strings (prefix "r"), + // because '\' is used often in comments, but may break Python module from + // loading. For example, in doxy comment one may write path in quotes: // - if (have_auto && have_ds) { // Both autodoc and docstring are present - doc = NewString(""); - Printv(doc, triple_double, "\n", - indent_docstring(autodoc, indent), "\n", - indent_docstring(str, indent), indent, triple_double, NIL); - } else if (!have_auto && have_ds) { // only docstring - if (Strchr(str, '\n') == 0) { - doc = NewStringf("%s%s%s", triple_double, str, triple_double); - } else { - doc = NewString(""); - Printv(doc, triple_double, "\n", indent_docstring(str, indent), indent, triple_double, NIL); - } - } else if (have_auto && !have_ds) { // only autodoc - if (Strchr(autodoc, '\n') == 0) { - doc = NewStringf("%s%s%s", triple_double, autodoc, triple_double); - } else { - doc = NewString(""); - Printv(doc, triple_double, "\n", indent_docstring(autodoc, indent), indent, triple_double, NIL); - } - } else - doc = NewString(""); + // This is path to file "C:\x\file.txt" + // + // Python will not load the module with such comment because of illegal + // escape '\x'. '\' may additionally appear in verbatim or htmlonly sections + // of doxygen doc, Latex expressions, ... + String *doc = NewString(""); + Append(doc, "r\"\"\""); + Append(doc, docstr); + Append(doc, "\"\"\""); + Delete(docstr); - // Save the generated strings in the parse tree in case they are used later - // by post processing tools - Setattr(n, "python:docstring", doc); - Setattr(n, "python:autodoc", autodoc); return doc; - } + } /* ------------------------------------------------------------ * cdocstring() * * Get the docstring text as it would appear in C-language - * source code. + * source code (but without quotes around it). * ------------------------------------------------------------ */ - String *cdocstring(Node *n, autodoc_t ad_type) - { - String *ds = docstring(n, ad_type, "", false); + String *cdocstring(Node *n, autodoc_t ad_type, bool low_level = false) { + String *ds = build_combined_docstring(n, ad_type, "", low_level); Replaceall(ds, "\\", "\\\\"); Replaceall(ds, "\"", "\\\""); Replaceall(ds, "\n", "\\n\"\n\t\t\""); return ds; } - virtual String *makeParameterName(Node *n, Parm *p, int arg_num, bool = false) const { - // For the keyword arguments, we want to preserve the names as much as possible, - // so we only minimally rename them in Swig_name_make(), e.g. replacing "keyword" - // with "_keyword" if they have any name at all. - if (check_kwargs(n)) { - String *name = Getattr(p, "name"); - if (name) - return Swig_name_make(p, 0, name, 0, 0); - } - - // For the other cases use the general function which replaces arguments whose - // names clash with keywords with (less useful) "argN". - return Language::makeParameterName(n, p, arg_num); - } - /* ----------------------------------------------------------------------------- * addMissingParameterNames() * * For functions that have not had nameless parameters set in the Language class. * - * Inputs: + * Inputs: * plist - entire parameter list - * arg_offset - argument number for first parameter + * arg_num - the number to start from when naming arguments * Side effects: * The "lname" attribute in each parameter in plist will be contain a parameter name * ----------------------------------------------------------------------------- */ - void addMissingParameterNames(Node *n, ParmList *plist, int arg_offset) { + void addMissingParameterNames(Node *n, ParmList *plist, int arg_num) { Parm *p = plist; - int i = arg_offset; + int i = arg_num; while (p) { if (!Getattr(p, "lname")) { String *name = makeParameterName(n, p, i); @@ -1779,10 +1631,11 @@ public: * * Generate the documentation for the function parameters * Parameters: + * arg_num: The number to start assigning unnamed arguments from * func_annotation: Function annotation support * ------------------------------------------------------------ */ - String *make_autodocParmList(Node *n, bool showTypes, bool calling = false, bool func_annotation = false) { + String *make_autodocParmList(Node *n, bool showTypes, int arg_num = 1, bool calling = false, bool func_annotation = false) { String *doc = NewString(""); String *pdocs = 0; @@ -1790,15 +1643,6 @@ public: Parm *p; Parm *pnext; - - // Normally we start counting auto-generated argument names from 1, but we should do it from 2 - // if the first argument is "self", i.e. if we're handling a non-static member function. - int arg_num = 1; - if (is_wrapping_class()) { - if (Cmp(Getattr(n, "storage"), "static") != 0) - arg_num++; - } - if (calling) func_annotation = false; @@ -1811,8 +1655,7 @@ public: return doc; } - for (p = plist; p; p = pnext, arg_num++) { - + for (p = plist; p; p = pnext) { String *tm = Getattr(p, "tmap:in"); if (tm) { pnext = Getattr(p, "tmap:in:next"); @@ -1833,12 +1676,21 @@ public: value = Getattr(p, "tmap:doc:value"); } + // Skip the "self" argument - it is added to the parameter list automatically + // and shouldn't be included in the Parameters block + if (Getattr(p, "self")) { + continue; + } + // Note: the generated name should be consistent with that in kwnames[] String *made_name = 0; if (!name) { name = made_name = makeParameterName(n, p, arg_num); } + // Increment the argument number once we are sure this is a real argument to count + arg_num++; + type = type ? type : Getattr(p, "type"); value = value ? value : Getattr(p, "value"); @@ -1867,13 +1719,24 @@ public: } // Write the function annotation if (func_annotation) - Printf(doc, ": '%s'", type_str); + Printf(doc, ": \"%s\"", type_str); // Write default value if (value && !calling) { String *new_value = convertValue(value, Getattr(p, "type")); + if (new_value) { + value = new_value; + } else { + // Even if the value is not representable in the target language, still use it in the documentation, for compatibility with the previous SWIG versions + // and because it can still be useful to see the C++ expression there. + Node *lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(doc, "=%s", value); + if (new_value) - Printf(doc, "=%s", new_value); + Delete(new_value); } Delete(type_str); Delete(made_name); @@ -1895,8 +1758,9 @@ public: * and use it directly. * ------------------------------------------------------------ */ - String *make_autodoc(Node *n, autodoc_t ad_type) { + String *make_autodoc(Node *n, autodoc_t ad_type, bool low_level = false) { int extended = 0; + bool first_func = true; // If the function is overloaded then this function is called // for the last one. Rewind to the first so the docstrings are // in order. @@ -1933,10 +1797,24 @@ public: } if (!skipAuto) { - String *symname = Getattr(n, "sym:name"); + /* Check if a documentation name was given for either the low-level C API or high-level Python shadow API */ + String *symname = Getattr(n, low_level ? "doc:low:name" : "doc:high:name"); + if (!symname) { + symname = Getattr(n, "sym:name"); + } + SwigType *type = Getattr(n, "type"); String *type_str = NULL; + // If the function has default arguments, then that documentation covers this version too + if (Getattr(n, "defaultargs") != NULL) { + n = Getattr(n, "sym:nextSibling"); + continue; + } + + if (!first_func) + Append(doc, "\n"); + if (type) { if (Strcmp(type, "void") == 0) { type_str = NULL; @@ -1946,6 +1824,21 @@ public: } } + /* Treat the low-level C API functions for getting/setting variables as methods for documentation purposes */ + String *kind = Getattr(n, "kind"); + if (kind && Strcmp(kind, "variable") == 0) { + if (ad_type == AUTODOC_FUNC) { + ad_type = AUTODOC_METHOD; + } + } + /* Treat destructors as methods for documentation purposes */ + String *nodeType = Getattr(n, "nodeType"); + if (nodeType && Strcmp(nodeType, "destructor") == 0) { + if (ad_type == AUTODOC_FUNC) { + ad_type = AUTODOC_METHOD; + } + } + switch (ad_type) { case AUTODOC_CLASS: { @@ -1959,9 +1852,9 @@ public: Delete(rname); } else { if (CPlusPlus) { - Printf(doc, "Proxy of C++ %s class.", real_classname); + Printf(doc, "Proxy of C++ %s class.", SwigType_namestr(real_classname)); } else { - Printf(doc, "Proxy of C %s struct.", real_classname); + Printf(doc, "Proxy of C %s struct.", SwigType_namestr(real_classname)); } } } @@ -1969,10 +1862,10 @@ public: break; case AUTODOC_CTOR: if (Strcmp(class_name, symname) == 0) { - String *paramList = make_autodocParmList(n, showTypes); + String *paramList = make_autodocParmList(n, showTypes, 2); Printf(doc, "__init__("); if (showTypes) - Printf(doc, "%s ", getClassName()); + Printf(doc, "%s ", class_name); if (Len(paramList)) Printf(doc, "self, %s) -> %s", paramList, class_name); else @@ -1983,7 +1876,7 @@ public: case AUTODOC_DTOR: if (showTypes) - Printf(doc, "__del__(%s self)", getClassName()); + Printf(doc, "__del__(%s self)", class_name); else Printf(doc, "__del__(self)"); break; @@ -2001,36 +1894,134 @@ public: break; case AUTODOC_METHOD: - String *paramList = make_autodocParmList(n, showTypes); - Printf(doc, "%s(", symname); - if (showTypes) - Printf(doc, "%s ", class_name); - if (Len(paramList)) - Printf(doc, "self, %s)", paramList); - else - Printf(doc, "self)"); - if (type_str) - Printf(doc, " -> %s", type_str); + { + String *paramList = make_autodocParmList(n, showTypes, 2); + Printf(doc, "%s(", symname); + if (showTypes) + Printf(doc, "%s ", class_name); + if (Len(paramList)) + Printf(doc, "self, %s)", paramList); + else + Printf(doc, "self)"); + if (type_str) + Printf(doc, " -> %s", type_str); + } + break; + + case AUTODOC_CONST: + // There is no autodoc support for constants currently, this enum + // element only exists to allow calling docstring() with it. + return NULL; + case AUTODOC_VAR: + // Variables can also be documented (e.g. through the property() function in python) + Printf(doc, "%s", symname); + if (showTypes) { + String *type = Getattr(n, "tmap:doc:type"); + if (!type) + type = Getattr(n, "membervariableHandler:type"); + if (!type) + type = Getattr(n, "type"); + Printf(doc, " : %s", type); + } break; } Delete(type_str); - } - if (extended) { - String *pdocs = Getattr(n, "feature:pdocs"); - if (pdocs) { - Printv(doc, "\n", pdocs, NULL); + + // Special case: wrapper functions to get a variable should have no parameters. + // Because the node is re-used for the setter and getter, the feature:pdocs field will + // exist for the getter function, so explicitly avoid printing parameters in this case. + bool variable_getter = kind && Strcmp(kind, "variable") == 0 && Getattr(n, "memberget"); + if (extended && ad_type != AUTODOC_VAR && !variable_getter) { + String *pdocs = Getattr(n, "feature:pdocs"); + if (pdocs) { + Printv(doc, "\n", pdocs, NULL); + } } } // if it's overloaded then get the next decl and loop around again n = Getattr(n, "sym:nextSibling"); if (n) - Append(doc, "\n"); + first_func = false; } return doc; } /* ------------------------------------------------------------ + * convertIntegerValue() + * + * Check if string v is an integer and can be represented in + * Python. If so, return an appropriate Python representation, + * otherwise (or if we are unsure), return NIL. + * ------------------------------------------------------------ */ + String *convertIntegerValue(String *v, SwigType *resolved_type) { + const char *const s = Char(v); + char *end; + String *result = NIL; + + // Check if this is an integer number in any base. + errno = 0; + long value = strtol(s, &end, 0); + if (errno == ERANGE || end == s) + return NIL; + + if (*end != '\0') { + // If there is a suffix after the number, we can safely ignore "l" + // and (provided the number is unsigned) "u", and also combinations of + // these, but not anything else. + for (char *p = end; *p != '\0'; ++p) { + switch (*p) { + case 'l': + case 'L': + break; + case 'u': + case 'U': + if (value < 0) + return NIL; + break; + default: + return NIL; + } + } + } + // So now we are certain that we are indeed dealing with an integer + // that has a representation as long given by value. + + // Restrict to guaranteed supported range in Python, see maxint docs: https://docs.python.org/2/library/sys.html#sys.maxint + // Don't do this pointless check when long is 32 bits or smaller as strtol will have already failed with ERANGE +#if LONG_MAX > PYTHON_INT_MAX || LONG_MIN < PYTHON_INT_MIN + if (value > PYTHON_INT_MAX || value < PYTHON_INT_MIN) { + return NIL; + } +#endif + + if (Cmp(resolved_type, "bool") == 0) + // Allow integers as the default value for a bool parameter. + return NewString(value ? "True" : "False"); + + if (value == 0) + return NewString(SwigType_ispointer(resolved_type) ? "None" : "0"); + + // v may still be octal or hexadecimal: + const char *p = s; + if (*p == '+' || *p == '-') + ++p; + if (*p == '0' && *(p+1) != 'x' && *(p+1) != 'X') { + // This must have been an octal number. This is the only case we + // cannot use in Python directly, since Python 2 and 3 use non- + // compatible representations. + result = NewString(*s == '-' ? "int(\"-" : "int(\""); + String *octal_string = NewStringWithSize(p, (int) (end - p)); + Append(result, octal_string); + Append(result, "\", 8)"); + Delete(octal_string); + return result; + } + result = *end == '\0' ? Copy(v) : NewStringWithSize(s, (int) (end - s)); + return result; + } + + /* ------------------------------------------------------------ * convertDoubleValue() * * Check if the given string looks like a decimal floating point constant @@ -2040,6 +2031,7 @@ public: const char *const s = Char(v); char *end; + errno = 0; double value = strtod(s, &end); (void) value; if (errno != ERANGE && end != s) { @@ -2068,7 +2060,7 @@ public: // Avoid unnecessary string allocation in the common case when we don't // need to remove any suffix. - return *end == '\0' ? v : NewStringWithSize(s, (int)(end - s)); + return *end == '\0' ? Copy(v) : NewStringWithSize(s, (int)(end - s)); } return NIL; @@ -2078,109 +2070,24 @@ public: * convertValue() * * Check if string v can be a Python value literal or a - * constant. Return NIL if it isn't. + * constant. Return an equivalent Python representation, + * or NIL if it isn't, or we are unsure. * ------------------------------------------------------------ */ String *convertValue(String *v, SwigType *type) { const char *const s = Char(v); - char *end; String *result = NIL; - bool fail = false; - SwigType *resolved_type = 0; - - // Check if this is a number in any base. - long value = strtol(s, &end, 0); - (void) value; - if (end != s) { - if (errno == ERANGE) { - // There was an overflow, we could try representing the value as Python - // long integer literal, but for now don't bother with it. - fail = true; - } else { - if (*end != '\0') { - // If there is a suffix after the number, we can safely ignore any - // 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) { - switch (*p) { - case 'l': - case 'L': - // Bail out on "LL". - if (seen_long) { - fail = true; - break; - } - seen_long = true; - break; - - case 'u': - case 'U': - break; - - default: - // Except that our suffix could actually be the fractional part of - // a floating point number, so we still have to check for this. - result = convertDoubleValue(v); - } - } - } - - if (!fail) { - // Allow integers as the default value for a bool parameter. - resolved_type = SwigType_typedef_resolve_all(type); - if (Cmp(resolved_type, "bool") == 0) { - result = NewString(value ? "True" : "False"); - } else { - // Deal with the values starting with 0 first as they can be octal or - // hexadecimal numbers or even pointers. - if (s[0] == '0') { - if (Len(v) == 1) { - // This is just a lone 0, but it needs to be represented differently - // in Python depending on whether it's a zero or a null pointer. - if (SwigType_ispointer(resolved_type)) - result = NewString("None"); - else - result = v; - } else if (s[1] == 'x' || s[1] == 'X') { - // This must have been a hex number, we can use it directly in Python, - // so nothing to do here. - } else { - // This must have been an octal number, we have to change its prefix - // to be "0o" in Python 3 only (and as long as we still support Python - // 2.5, this can't be done unconditionally). - if (py3) { - if (end - s > 1) { - result = NewString("0o"); - Append(result, NewStringWithSize(s + 1, (int)(end - s - 1))); - } - } - } - } - - // Avoid unnecessary string allocation in the common case when we don't - // need to remove any suffix. - if (!result) - result = *end == '\0' ? v : NewStringWithSize(s, (int)(end - s)); - } - } - } - } + SwigType *resolved_type = SwigType_typedef_resolve_all(type); - // Check if this is a floating point number (notice that it wasn't - // necessarily parsed as a long above, consider e.g. ".123"). - if (!fail && !result) { + result = convertIntegerValue(v, resolved_type); + if (!result) { result = convertDoubleValue(v); if (!result) { - if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0) + if (Strcmp(v, "true") == 0) result = NewString("True"); - else if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0) + else if (Strcmp(v, "false") == 0) result = NewString("False"); - else if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) { - if (!resolved_type) - resolved_type = SwigType_typedef_resolve_all(type); + else if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) result = SwigType_ispointer(resolved_type) ? NewString("None") : NewString("0"); - } - // This could also be an enum type, default value of which could be // representable in Python if it doesn't include any scope (which could, // but currently is not, translated). @@ -2188,7 +2095,7 @@ public: Node *lookup = Swig_symbol_clookup(v, 0); if (lookup) { if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0) - result = Getattr(lookup, "sym:name"); + result = Copy(Getattr(lookup, "sym:name")); } } } @@ -2235,10 +2142,12 @@ public: if (Getattr(p, "tmap:default")) return false; - if (String *value = Getattr(p, "value")) { - String *type = Getattr(p, "type"); - if (!convertValue(value, type)) + String *value = Getattr(p, "value"); + if (value) { + String *convertedValue = convertValue(value, Getattr(p, "type")); + if (!convertedValue) return false; + Delete(convertedValue); } } @@ -2250,7 +2159,7 @@ public: * is_real_overloaded() * * Check if the function is overloaded, but not just have some - * siblings generated due to the original function have + * siblings generated due to the original function having * default arguments. * ------------------------------------------------------------ */ bool is_real_overloaded(Node *n) { @@ -2263,7 +2172,7 @@ public: while (i) { Node *nn = Getattr(i, "defaultargs"); if (nn != h) { - /* Check if overloaded function has defaultargs and + /* Check if overloaded function has defaultargs and * pointed to the first overloaded. */ return true; } @@ -2279,13 +2188,16 @@ public: * Generate parameter list for Python functions or methods, * reuse make_autodocParmList() to do so. * ------------------------------------------------------------ */ - String *make_pyParmList(Node *n, bool in_class, bool is_calling, int kw) { - /* Get the original function for a defaultargs copy, + String *make_pyParmList(Node *n, bool in_class, bool is_calling, int kw, bool has_self_for_count = false) { + /* Get the original function for a defaultargs copy, * see default_arguments() in parser.y. */ Node *nn = Getattr(n, "defaultargs"); if (nn) n = nn; + Parm *parms = Getattr(n, "parms"); + int varargs = parms ? emit_isvarargs(parms) : 0; + /* We prefer to explicitly list all parameters of the C function in the generated Python code as this makes the function more convenient to use, however in some cases we must replace the real parameters list with just @@ -2295,8 +2207,9 @@ public: 2. We were explicitly asked to use the "compact" arguments form. 3. We were explicitly asked to use default args from C via the "python:cdefaultargs" feature. 4. One of the default argument values can't be represented in Python. + 5. Varargs that haven't been forced to use a fixed number of arguments with %varargs. */ - if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || GetFlag(n, "feature:python:cdefaultargs") || !is_representable_as_pyargs(n)) { + if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || GetFlag(n, "feature:python:cdefaultargs") || !is_representable_as_pyargs(n) || varargs) { String *parms = NewString(""); if (in_class) Printf(parms, "self, "); @@ -2308,7 +2221,7 @@ public: bool funcanno = py3 ? true : false; String *params = NewString(""); - String *_params = make_autodocParmList(n, false, is_calling, funcanno); + String *_params = make_autodocParmList(n, false, ((in_class || has_self_for_count)? 2 : 1), is_calling, funcanno); if (in_class) { Printf(params, "self"); @@ -2387,7 +2300,7 @@ public: * ------------------------------------------------------------ */ bool have_addtofunc(Node *n) { - return have_pythonappend(n) || have_pythonprepend(n) || have_docstring(n); + return have_pythonappend(n) || have_pythonprepend(n); } @@ -2437,21 +2350,28 @@ public: void emitFunctionShadowHelper(Node *n, File *f_dest, String *name, int kw) { String *parms = make_pyParmList(n, false, false, kw); String *callParms = make_pyParmList(n, false, true, kw); - /* Make a wrapper function to insert the code into */ - Printv(f_dest, "\ndef ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); - if (have_docstring(n)) - Printv(f_dest, tab4, docstring(n, AUTODOC_FUNC, tab4), "\n", NIL); - if (have_pythonprepend(n)) - Printv(f_dest, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); - if (have_pythonappend(n)) { - Printv(f_dest, tab4 "val = ", funcCall(name, callParms), "\n", NIL); - Printv(f_dest, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); - Printv(f_dest, tab4 "return val\n", NIL); - } else { - Printv(f_dest, tab4 "return ", funcCall(name, callParms), "\n", NIL); + + // Callbacks need the C function in order to extract the pointer from the swig_ptr: string + bool fast = (fastproxy && !have_addtofunc(n)) || Getattr(n, "feature:callback"); + + if (!fast || olddefs) { + /* Make a wrapper function to insert the code into */ + Printv(f_dest, "\n", "def ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_dest, tab4, docstring(n, AUTODOC_FUNC, tab4, true), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_dest, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_dest, tab4 "val = ", funcCall(name, callParms), "\n", NIL); + Printv(f_dest, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); + Printv(f_dest, tab4 "return val\n", NIL); + } else { + Printv(f_dest, tab4 "return ", funcCall(name, callParms), "\n", NIL); + } } - if (!have_addtofunc(n)) { + // Below may result in a 2nd definition of the method when -olddefs is used. The Python interpreter will use the second definition as it overwrites the first. + if (fast) { /* If there is no addtofunc directive then just assign from the extension module (for speed up) */ Printv(f_dest, name, " = ", module, ".", name, "\n", NIL); } @@ -2475,36 +2395,64 @@ public: * add_method() * ------------------------------------------------------------ */ - void add_method(String *name, String *function, int kw, Node *n = 0, int funpack= 0, int num_required= -1, int num_arguments = -1) { + void add_method(String *name, String *function, int kw, Node *n = 0, int funpack = 0, int num_required = -1, int num_arguments = -1) { + String * meth_str = NewString(""); if (!kw) { - if (n && funpack) { + if (funpack) { if (num_required == 0 && num_arguments == 0) { - Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_NOARGS, ", name, function); + Printf(meth_str, "\t { \"%s\", %s, METH_NOARGS, ", name, function); } else if (num_required == 1 && num_arguments == 1) { - Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, ", name, function); + Printf(meth_str, "\t { \"%s\", %s, METH_O, ", name, function); } else { - Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function); + Printf(meth_str, "\t { \"%s\", %s, METH_VARARGS, ", name, function); } } else { - Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function); + Printf(meth_str, "\t { \"%s\", %s, METH_VARARGS, ", name, function); } } else { - Printf(methods, "\t { (char *)\"%s\", (PyCFunction) %s, METH_VARARGS | METH_KEYWORDS, ", name, function); + // Cast via void(*)(void) to suppress GCC -Wcast-function-type warning. + // Python should always call the function correctly, but the Python C API + // requires us to store it in function pointer of a different type. + Printf(meth_str, "\t { \"%s\", (PyCFunction)(void(*)(void))%s, METH_VARARGS|METH_KEYWORDS, ", name, function); + } + Append(methods, meth_str); + if (fastproxy) { + Append(methods_proxydocs, meth_str); } + Delete(meth_str); if (!n) { Append(methods, "NULL"); + if (fastproxy) { + Append(methods_proxydocs, "NULL"); + } } else if (have_docstring(n)) { - String *ds = cdocstring(n, AUTODOC_FUNC); - Printf(methods, "(char *)\"%s\"", ds); + /* Use the low-level docstring here since this is the docstring that will be used for the C API */ + String *ds = cdocstring(n, Getattr(n, "memberfunction") ? AUTODOC_METHOD : AUTODOC_FUNC, true); + Printf(methods, "\"%s\"", ds); + if (fastproxy) { + /* In the fastproxy case, we must also record the high-level docstring for use in the Python shadow API */ + Delete(ds); + ds = cdocstring(n, Getattr(n, "memberfunction") ? AUTODOC_METHOD : AUTODOC_FUNC); + Printf(methods_proxydocs, "\"%s\"", ds); + } Delete(ds); } else if (Getattr(n, "feature:callback")) { - Printf(methods, "(char *)\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + Printf(methods, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + if (fastproxy) { + Printf(methods_proxydocs, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + } } else { Append(methods, "NULL"); + if (fastproxy) { + Append(methods_proxydocs, "NULL"); + } } Append(methods, "},\n"); + if (fastproxy) { + Append(methods_proxydocs, "},\n"); + } } /* ------------------------------------------------------------ @@ -2519,12 +2467,24 @@ public: String *tmp = NewString(""); String *dispatch; - const char *dispatch_code = funpack ? "return %s(self, argc, argv);" : "return %s(self, args);"; + + const char *dispatch_call = funpack ? "%s(self, argc, argv);" : (builtin_ctor ? "%s(self, args, NULL);" : "%s(self, args);"); + String *dispatch_code = NewStringf("return %s", dispatch_call); if (castmode) { dispatch = Swig_overload_dispatch_cast(n, dispatch_code, &maxargs); } else { - dispatch = Swig_overload_dispatch(n, dispatch_code, &maxargs); + String *fastdispatch_code; + if (builtin_ctor) + fastdispatch_code = NewStringf("int retval = %s\nif (retval == 0 || !SWIG_Python_TypeErrorOccurred(NULL)) return retval;\nSWIG_fail;", dispatch_call); + else + fastdispatch_code = NewStringf("PyObject *retobj = %s\nif (!SWIG_Python_TypeErrorOccurred(retobj)) return retobj;\nSWIG_fail;", dispatch_call); + if (!CPlusPlus) { + Insert(fastdispatch_code, 0, "{\n"); + Append(fastdispatch_code, "\n}"); + } + dispatch = Swig_overload_dispatch(n, dispatch_code, &maxargs, fastdispatch_code); + Delete(fastdispatch_code); } /* Generate a dispatch wrapper for all overloaded functions */ @@ -2533,7 +2493,8 @@ public: String *symname = Getattr(n, "sym:name"); String *wname = Swig_name_wrapper(symname); - Printv(f->def, linkage, builtin_ctor ? "int " : "PyObject *", wname, "(PyObject *self, PyObject *args) {", NIL); + const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : ""; + Printv(f->def, linkage, builtin_ctor ? "int " : "PyObject *", wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); Wrapper_add_local(f, "argc", "Py_ssize_t argc"); Printf(tmp, "PyObject *argv[%d] = {0}", maxargs + 1); @@ -2541,9 +2502,14 @@ public: if (!fastunpack) { Wrapper_add_local(f, "ii", "Py_ssize_t ii"); - if (maxargs - (add_self ? 1 : 0) > 0) - Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n"); - Append(f->code, "argc = args ? PyObject_Length(args) : 0;\n"); + + if (maxargs - (add_self ? 1 : 0) > 0) { + Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n"); + Append(f->code, "argc = PyObject_Length(args);\n"); + } else { + Append(f->code, "argc = args ? PyObject_Length(args) : 0;\n"); + } + if (add_self) Append(f->code, "argv[0] = self;\n"); Printf(f->code, "for (ii = 0; (ii < %d) && (ii < argc); ii++) {\n", add_self ? maxargs - 1 : maxargs); @@ -2553,7 +2519,7 @@ public: Append(f->code, "argc++;\n"); } else { String *iname = Getattr(n, "sym:name"); - Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args,\"%s\",0,%d,argv%s))) SWIG_fail;\n", iname, maxargs, add_self ? "+1" : ""); + Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", iname, maxargs, add_self ? "+1" : ""); if (add_self) Append(f->code, "argv[0] = self;\n"); else @@ -2566,8 +2532,8 @@ public: if (GetFlag(n, "feature:python:maybecall")) { Append(f->code, "fail:\n"); - Append(f->code, "Py_INCREF(Py_NotImplemented);\n"); - Append(f->code, "return Py_NotImplemented;\n"); + Append(f->code, " Py_INCREF(Py_NotImplemented);\n"); + Append(f->code, " return Py_NotImplemented;\n"); } else { Node *sibl = n; while (Getattr(sibl, "sym:previousSibling")) @@ -2579,7 +2545,7 @@ public: Delete(fulldecl); } while ((sibl = Getattr(sibl, "sym:nextSibling"))); Append(f->code, "fail:\n"); - Printf(f->code, "SWIG_SetErrorMsg(PyExc_NotImplementedError," + Printf(f->code, " SWIG_Python_RaiseOrModifyTypeError(" "\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); Printf(f->code, "return %s;\n", builtin_ctor ? "-1" : "0"); Delete(protoTypes); @@ -2596,6 +2562,7 @@ public: } DelWrapper(f); Delete(dispatch); + Delete(dispatch_code); Delete(tmp); Delete(wname); } @@ -2688,12 +2655,12 @@ public: builtin_self = false; else builtin_ctor = true; + Delete(mrename); } bool director_class = (getCurrentClass() && Swig_directorclass(getCurrentClass())); bool add_self = builtin_self && (!builtin_ctor || director_class); bool builtin_getter = (builtin && GetFlag(n, "memberget")); bool builtin_setter = (builtin && GetFlag(n, "memberset") && !builtin_getter); - bool over_varargs = false; char const *self_param = builtin ? "self" : "SWIGUNUSEDPARM(self)"; char const *wrap_return = builtin_ctor ? "int " : "PyObject *"; String *linkage = NewString("SWIGINTERN "); @@ -2742,9 +2709,10 @@ public: Append(wname, overname); } + const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : ""; if (!allow_kwargs || overname) { if (!varargs) { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); } else { Printv(f->def, linkage, wrap_return, wname, "__varargs__", "(PyObject *", self_param, ", PyObject *args, PyObject *varargs) {", NIL); } @@ -2761,53 +2729,33 @@ public: } if (!builtin || !in_class || tuple_arguments > 0) { if (!allow_kwargs) { - Append(parse_args, " if (!PyArg_ParseTuple(args,(char *)\""); + Append(parse_args, " if (!PyArg_ParseTuple(args, \""); } else { - Append(parse_args, " if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)\""); - Append(arglist, ",kwnames"); + Append(parse_args, " if (!PyArg_ParseTupleAndKeywords(args, kwargs, \""); + Append(arglist, ", kwnames"); } } - if (overname) { - String *over_varargs_attr = Getattr(n, "python:overvarargs"); - if (!over_varargs_attr) { - for (Node *sibling = n; sibling; sibling = Getattr(sibling, "sym:nextSibling")) { - if (emit_isvarargs(Getattr(sibling, "parms"))) { - over_varargs = true; - break; - } - } - over_varargs_attr = NewString(over_varargs ? "1" : "0"); - for (Node *sibling = n; sibling; sibling = Getattr(sibling, "sym:nextSibling")) - Setattr(sibling, "python:overvarargs", over_varargs_attr); - } - if (Strcmp(over_varargs_attr, "0") != 0) - over_varargs = true; - } + bool over_varargs = emit_isvarargs_function(n); - int funpack = modernargs && fastunpack && !varargs && !over_varargs && !allow_kwargs; + int funpack = fastunpack && !varargs && !over_varargs && !allow_kwargs; int noargs = funpack && (tuple_required == 0 && tuple_arguments == 0); int onearg = funpack && (tuple_required == 1 && tuple_arguments == 1); - if (builtin && funpack && !overname && !builtin_ctor && - !(GetFlag(n, "feature:compactdefaultargs") && (tuple_arguments > tuple_required || varargs))) { - String *argattr = NewStringf("%d", tuple_arguments); - Setattr(n, "python:argcount", argattr); - Delete(argattr); + if (builtin && funpack && !overname && !builtin_ctor) { + int compactdefargs = ParmList_is_compactdefargs(l); + if (!(compactdefargs && (tuple_arguments > tuple_required || varargs))) { + String *argattr = NewStringf("%d", tuple_arguments); + Setattr(n, "python:argcount", argattr); + Delete(argattr); + } } /* Generate code for argument marshalling */ if (funpack) { - if (overname) { - if (aliasobj0) { - Append(f->code, "#define obj0 (swig_obj[0])\n"); - } - } else if (num_arguments) { + if (num_arguments > 0 && !overname) { sprintf(source, "PyObject *swig_obj[%d]", num_arguments); Wrapper_add_localv(f, "swig_obj", source, NIL); - if (aliasobj0) { - Append(f->code, "#define obj0 (swig_obj[0])\n"); - } } } @@ -2852,7 +2800,7 @@ public: sprintf(source, "obj%d", builtin_ctor ? i + 1 : i); if (parse_from_tuple) { - Putc(',', arglist); + Printf(arglist, ", "); if (i == num_required) Putc('|', parse_args); /* Optional argument separator */ } @@ -2860,7 +2808,7 @@ public: /* Keyword argument handling */ if (allow_kwargs && parse_from_tuple) { String *name = makeParameterName(n, p, i + 1); - Printf(kwargs, "(char *) \"%s\",", name); + Printf(kwargs, " (char *)\"%s\", ", name); Delete(name); } @@ -2925,12 +2873,12 @@ public: /* finish argument marshalling */ Append(kwargs, " NULL }"); if (allow_kwargs) { - Printv(f->locals, " char * kwnames[] = ", kwargs, ";\n", NIL); + Printv(f->locals, " char * kwnames[] = ", kwargs, ";\n", NIL); } if (builtin && !funpack && in_class && tuple_arguments == 0) { Printf(parse_args, " if (args && PyTuple_Check(args) && PyTuple_GET_SIZE(args) > 0) SWIG_exception_fail(SWIG_TypeError, \"%s takes no arguments\");\n", iname); - } else if (use_parse || allow_kwargs || !modernargs) { + } else if (use_parse || allow_kwargs) { Printf(parse_args, ":%s\"", iname); Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); funpack = 0; @@ -2940,28 +2888,25 @@ public: Clear(f->def); if (overname) { if (noargs) { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", int nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); } else { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", int nobjs, PyObject **swig_obj) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); } Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments); } else { - if (noargs) { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args) {", NIL); - } else { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args) {", NIL); - } - if (onearg && !builtin_ctor) { + int is_tp_call = Equal(Getattr(n, "feature:python:slot"), "tp_call"); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); + if (onearg && !builtin_ctor && !is_tp_call) { Printf(parse_args, "if (!args) SWIG_fail;\n"); Append(parse_args, "swig_obj[0] = args;\n"); } else if (!noargs) { - Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args,\"%s\",%d,%d,swig_obj)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); + Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args, \"%s\", %d, %d, swig_obj)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); } else if (noargs) { - Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args,\"%s\",%d,%d,0)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); + Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args, \"%s\", %d, %d, 0)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); } } } else { - Printf(parse_args, "if(!PyArg_UnpackTuple(args,(char *)\"%s\",%d,%d", iname, num_fixed_arguments, tuple_arguments); + Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments); Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); } } @@ -3026,9 +2971,9 @@ public: } /* if the object is a director, and the method call originated from its - * underlying python object, resolve the call by going up the c++ - * inheritance chain. otherwise try to resolve the method in python. - * without this check an infinite loop is set up between the director and + * underlying python object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in python. + * without this check an infinite loop is set up between the director and * shadow class method calls. */ @@ -3122,7 +3067,7 @@ public: // base class pointers! /* New addition to unwrap director return values so that the original - * python object is returned instead. + * python object is returned instead. */ #if 1 int unwrap = 0; @@ -3204,21 +3149,18 @@ public: if (need_cleanup) { Printv(f->code, cleanup, NIL); } - if (builtin_ctor) + if (builtin_ctor) { Printv(f->code, " return -1;\n", NIL); - else - Printv(f->code, " return NULL;\n", NIL); - - - if (funpack) { - if (aliasobj0) { - Append(f->code, "#if defined(obj0)\n"); - Append(f->code, "#undef obj0\n"); - Append(f->code, "#endif\n"); + } else { + if (GetFlag(n, "feature:python:maybecall")) { + Append(f->code, " PyErr_Clear();\n"); + Append(f->code, " Py_INCREF(Py_NotImplemented);\n"); + Append(f->code, " return Py_NotImplemented;\n"); + } else { + Printv(f->code, " return NULL;\n", NIL); } } - Append(f->code, "}\n"); /* Substitute the cleanup code */ @@ -3244,9 +3186,10 @@ public: DelWrapper(f); f = NewWrapper(); if (funpack) { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", int nobjs, PyObject **swig_obj) {", NIL); + // Note: funpack is currently always false for varargs + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); } else { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); } Wrapper_add_local(f, "resultobj", builtin_ctor ? "int resultobj" : "PyObject *resultobj"); Wrapper_add_local(f, "varargs", "PyObject *varargs"); @@ -3309,6 +3252,10 @@ public: Delete(h); } Setattr(h, "getter", "SwigPyObject_get___dict__"); + if (!Getattr(h, "doc")) { + Setattr(n, "doc:high:name", Getattr(n, "name")); + Setattr(h, "doc", cdocstring(n, AUTODOC_VAR)); + } } if (builtin_getter) { @@ -3323,6 +3270,12 @@ public: } Setattr(h, "getter", wrapper_name); Delattr(n, "memberget"); + if (!Getattr(h, "doc")) { + Setattr(n, "doc:high:name", Getattr(n, "name")); + String *ds = cdocstring(n, AUTODOC_VAR); + Setattr(h, "doc", ds); + Delete(ds); + } } if (builtin_setter) { String *memname = Getattr(n, "membervariableHandler:sym:name"); @@ -3336,6 +3289,12 @@ public: } Setattr(h, "setter", wrapper_name); Delattr(n, "memberset"); + if (!Getattr(h, "doc")) { + Setattr(n, "doc:high:name", Getattr(n, "name")); + String *ds = cdocstring(n, AUTODOC_VAR); + Setattr(h, "doc", ds); + Delete(ds); + } } if (in_class && builtin) { @@ -3356,7 +3315,7 @@ public: closure_name = Copy(wrapper_name); } if (func_type) { - String *s = NewStringf("(%s) %s", func_type, closure_name); + String *s = NewStringf("%s", closure_name); Delete(closure_name); closure_name = s; } @@ -3413,7 +3372,17 @@ public: Python dictionary. */ if (!have_globals) { - Printf(f_init, "\t PyDict_SetItemString(md,(char *)\"%s\", SWIG_globals());\n", global_name); + Printf(f_init, "\t globals = SWIG_globals();\n"); + Printf(f_init, "\t if (!globals) {\n"); + Printf(f_init, " PyErr_SetString(PyExc_TypeError, \"Failure to create SWIG globals.\");\n"); + Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_init, "\t return NULL;\n"); + Printf(f_init, "#else\n"); + Printf(f_init, "\t return;\n"); + Printf(f_init, "#endif\n"); + Printf(f_init, "\t }\n"); + Printf(f_init, "\t PyDict_SetItemString(md, \"%s\", globals);\n", global_name); + Printf(f_init, "\t Py_DECREF(globals);\n"); if (builtin) Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", global_name); have_globals = 1; @@ -3501,9 +3470,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(globals, \"%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, \"%s\", PyObject_GetAttrString(globals, \"%s\"));\n", iname, iname); Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", iname); } Delete(vargetname); @@ -3529,7 +3498,7 @@ public: /* Note, that we need special handling for function pointers, as * SwigType_base(fptr) does not return the underlying pointer-to-function * type but the return-type of function. */ - if(!SwigType_isfunction(uqtype) && !SwigType_isfunctionpointer(uqtype)) { + if (!SwigType_isfunction(uqtype) && !SwigType_isfunctionpointer(uqtype)) { SwigType *basetype = SwigType_base(uqtype); result = SwigType_isclass(basetype) != 0; Delete(basetype); @@ -3595,15 +3564,7 @@ public: Printf(f_wrappers, "SWIGINTERN PyObject *%s_swigconstant(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", iname); Printf(f_wrappers, tab2 "PyObject *module;\n", tm); 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"); - } else { - 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 (!SWIG_Python_UnpackTuple(args, \"swigconstant\", 1, 1, &module)) return NULL;\n"); Printf(f_wrappers, tab2 "d = PyModule_GetDict(module);\n"); Printf(f_wrappers, tab2 "if (!d) return NULL;\n"); Printf(f_wrappers, tab2 "%s\n", tm); @@ -3612,7 +3573,7 @@ public: // Register the method in SwigMethods array String *cname = NewStringf("%s_swigconstant", iname); - add_method(cname, cname, 0); + add_method(cname, cname, 0, 0, 1, 1, 1); Delete(cname); } else { Printf(f_init, "%s\n", tm); @@ -3630,27 +3591,28 @@ public: } if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + String *f_s; if (!in_class) { - if(needs_swigconstant(n)) { - Printv(f_shadow, "\n",NIL); - Printv(f_shadow, module, ".", iname, "_swigconstant(",module,")\n", NIL); - } - Printv(f_shadow, iname, " = ", module, ".", iname, "\n", NIL); + f_s = f_shadow; } else { - if (!(Getattr(n, "feature:python:callback"))) { - if(needs_swigconstant(n)) { - Printv(f_shadow_stubs, "\n",NIL); - Printv(f_shadow_stubs, module, ".", iname, "_swigconstant(", module, ")\n", NIL); - } - Printv(f_shadow_stubs, iname, " = ", module, ".", iname, "\n", NIL); + f_s = Getattr(n, "feature:python:callback") ? NIL : f_shadow_stubs; + } + + if (f_s) { + if (needs_swigconstant(n)) { + Printv(f_s, "\n",NIL); + Printv(f_s, module, ".", iname, "_swigconstant(",module,")\n", NIL); } + Printv(f_s, iname, " = ", module, ".", iname, "\n", NIL); + if (have_docstring(n)) + Printv(f_s, docstring(n, AUTODOC_CONST, tab4), "\n", NIL); } } return SWIG_OK; } - /* ------------------------------------------------------------ + /* ------------------------------------------------------------ * nativeWrapper() * ------------------------------------------------------------ */ @@ -3685,7 +3647,7 @@ public: /* --------------------------------------------------------------- * classDirectorMethod() * - * Emit a virtual director method to pass a method call on to the + * Emit a virtual director method to pass a method call on to the * underlying Python object. * ** Moved down due to gcc-2.96 internal error ** * --------------------------------------------------------------- */ @@ -3722,7 +3684,7 @@ public: Wrapper *w = NewWrapper(); String *call; String *basetype = Getattr(parent, "classtype"); - String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + String *target = Swig_method_decl(0, decl, classname, parms, 0); call = Swig_csuperclass_call(0, basetype, superparms); Printf(w->def, "%s::%s: %s, Swig::Director(self) { \n", classname, target, call); Printf(w->def, " SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); @@ -3735,7 +3697,7 @@ public: /* constructor header */ { - String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + String *target = Swig_method_decl(0, decl, classname, parms, 1); Printf(f_directors_h, " %s;\n", target); Delete(target); } @@ -3857,7 +3819,7 @@ public: if (shadow) { if (builtin) { String *rname = SwigType_namestr(real_classname); - Printf(builtin_methods, " { \"__disown__\", (PyCFunction) Swig::Director::swig_pyobj_disown< %s >, METH_NOARGS, \"\" },\n", rname); + Printf(builtin_methods, " { \"__disown__\", Swig::Director::swig_pyobj_disown< %s >, METH_NOARGS, \"\" },\n", rname); Delete(rname); } else { String *symname = Getattr(n, "sym:name"); @@ -3869,7 +3831,7 @@ public: Printv(f_shadow, tab8, "self.this.disown()\n", NIL); #endif Printv(f_shadow, tab8, module, ".", mrename, "(self)\n", NIL); - Printv(f_shadow, tab8, "return weakref_proxy(self)\n", NIL); + Printv(f_shadow, tab8, "return weakref.proxy(self)\n", NIL); Delete(mrename); } } @@ -3937,7 +3899,7 @@ public: String *mname = SwigType_manglestr(rname); String *pmname = SwigType_manglestr(pname); String *templ = NewStringf("SwigPyBuiltin_%s", mname); - int funpack = modernargs && fastunpack; + int funpack = fastunpack; static String *tp_new = NewString("PyType_GenericNew"); Printv(f_init, " SwigPyBuiltin_SetMetaType(builtin_pytype, metatype);\n", NIL); @@ -4003,9 +3965,10 @@ public: const char *setter_closure = setter ? funpack ? "SwigPyBuiltin_FunpackSetterClosure" : "SwigPyBuiltin_SetterClosure" : "0"; 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, - setter_closure, name, memname, gspair); + String *doc = Getattr(mgetset, "doc"); + if (!doc) + doc = NewStringf("%s.%s", name, memname); + String *entry = NewStringf("{ (char *)\"%s\", %s, %s, (char *)\"%s\", &%s }", memname, getter_closure, setter_closure, doc, 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); @@ -4017,7 +3980,7 @@ public: Delete(gspair); Delete(entry); } - Printv(f, getset_def, " {NULL, NULL, NULL, NULL, NULL} /* Sentinel */\n", "};\n\n", NIL); + Printv(f, getset_def, " { NULL, NULL, NULL, NULL, NULL } /* Sentinel */\n", "};\n\n", NIL); // Rich compare function Hash *richcompare = Getattr(n, "python:richcompare"); @@ -4126,7 +4089,16 @@ public: Printv(f, "#else\n", NIL); 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"); + if (have_docstring(n)) { + String *ds = cdocstring(n, AUTODOC_CLASS); + String *tp_doc = NewString(""); + Printf(tp_doc, "\"%s\"", ds); + Delete(ds); + printSlot(f, tp_doc, "tp_doc"); + Delete(tp_doc); + } else { + 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, getSlot(n, "feature:python:tp_richcompare", richcompare_func), "tp_richcompare", "richcmpfunc"); @@ -4152,9 +4124,7 @@ public: 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); Printv(f, "#if PY_VERSION_HEX >= 0x03040000\n", NIL); printSlot(f, getSlot(n, "feature:python:tp_finalize"), "tp_finalize", "destructor"); Printv(f, "#endif\n", NIL); @@ -4162,9 +4132,7 @@ public: 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(n, "feature:python:tp_prev"), "tp_prev"); - Printv(f, "#endif\n", NIL); printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next"); Printv(f, "#endif\n", NIL); Printf(f, " },\n"); @@ -4230,9 +4198,7 @@ public: printSlot(f, getSlot(n, "feature:python:nb_divide"), "nb_true_divide", "binaryfunc"); printSlot(f, getSlot(n, "feature:python:nb_inplace_floor_divide"), "nb_inplace_floor_divide", "binaryfunc"); printSlot(f, getSlot(n, "feature:python:nb_inplace_divide"), "nb_inplace_true_divide", "binaryfunc"); - Printv(f, "#if PY_VERSION_HEX >= 0x02050000\n", NIL); printSlot(f, getSlot(n, "feature:python:nb_index"), "nb_index", "unaryfunc"); - Printv(f, "#endif\n", NIL); Printv(f, "#if PY_VERSION_HEX >= 0x03050000\n", NIL); printSlot(f, getSlot(n, "feature:python:nb_matrix_multiply"), "nb_matrix_multiply", "binaryfunc"); printSlot(f, getSlot(n, "feature:python:nb_inplace_matrix_multiply"), "nb_inplace_matrix_multiply", "binaryfunc"); @@ -4276,10 +4242,8 @@ public: printSlot(f, getSlot(n, "feature:python:bf_getsegcount"), "bf_getsegcount", "segcountproc"); printSlot(f, getSlot(n, "feature:python:bf_getcharbuffer"), "bf_getcharbuffer", "charbufferproc"); Printv(f, "#endif\n", NIL); - Printv(f, "#if PY_VERSION_HEX >= 0x02060000\n", NIL); printSlot(f, getSlot(n, "feature:python:bf_getbuffer"), "bf_getbuffer", "getbufferproc"); printSlot(f, getSlot(n, "feature:python:bf_releasebuffer"), "bf_releasebuffer", "releasebufferproc"); - Printv(f, "#endif\n", NIL); Printf(f, " },\n"); // PyObject *ht_name, *ht_slots, *ht_qualname; @@ -4349,8 +4313,6 @@ public: } virtual int classHandler(Node *n) { - int oldclassic = classic; - int oldmodern = modern; File *f_shadow_file = f_shadow; Node *base_node = NULL; @@ -4360,19 +4322,6 @@ public: have_constructor = 0; have_repr = 0; - if (GetFlag(n, "feature:classic")) { - classic = 1; - modern = 0; - } - if (GetFlag(n, "feature:modern")) { - classic = 0; - modern = 1; - } - if (GetFlag(n, "feature:exceptionclass")) { - classic = 1; - modern = 0; - } - class_name = Getattr(n, "sym:name"); real_classname = Getattr(n, "name"); @@ -4438,9 +4387,9 @@ public: if (builtin) { if (have_docstring(n)) { - String *str = cdocstring(n, AUTODOC_CLASS); - Setattr(n, "feature:python:tp_doc", str); - Delete(str); + String *ds = cdocstring(n, AUTODOC_CLASS); + Setattr(n, "feature:python:tp_doc", ds); + Delete(ds); } else { String *name = Getattr(n, "name"); String *rname = add_explicit_scope(SwigType_namestr(name)); @@ -4448,52 +4397,37 @@ public: Delete(rname); } } else { + if (!py3) { + if (GetFlag(n, "feature:python:nondynamic")) + Printv(f_shadow, "@_swig_add_metaclass(_SwigNonDynamicMeta)\n", NIL); + } Printv(f_shadow, "class ", class_name, NIL); if (Len(base_class)) { Printf(f_shadow, "(%s)", base_class); } else { - if (!classic) { - Printf(f_shadow, modern ? "(object)" : "(_object)"); - } if (GetFlag(n, "feature:exceptionclass")) { Printf(f_shadow, "(Exception)"); + } else { + Printf(f_shadow, "(object"); + Printf(f_shadow, py3 && GetFlag(n, "feature:python:nondynamic") ? ", metaclass=_SwigNonDynamicMeta" : "", ")"); + Printf(f_shadow, ")"); } } Printf(f_shadow, ":\n"); + + // write docstrings if requested if (have_docstring(n)) { String *str = docstring(n, AUTODOC_CLASS, tab4); if (str && Len(str)) Printv(f_shadow, tab4, str, "\n\n", NIL); } - if (!modern) { - Printv(f_shadow, tab4, "__swig_setmethods__ = {}\n", NIL); - if (Len(base_class)) { - Printv(f_shadow, tab4, "for _s in [", base_class, "]:\n", tab8, "__swig_setmethods__.update(getattr(_s, '__swig_setmethods__', {}))\n", NIL); - } - - if (!GetFlag(n, "feature:python:nondynamic")) { - Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr(self, ", class_name, ", name, value)\n", NIL); - } else { - Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr_nondynamic(self, ", class_name, ", name, value)\n", NIL); - } - - Printv(f_shadow, tab4, "__swig_getmethods__ = {}\n", NIL); - if (Len(base_class)) { - Printv(f_shadow, tab4, "for _s in [", base_class, "]:\n", tab8, "__swig_getmethods__.update(getattr(_s, '__swig_getmethods__', {}))\n", NIL); - } - - Printv(f_shadow, tab4, "__getattr__ = lambda self, name: _swig_getattr(self, ", class_name, ", name)\n", NIL); - } else { - Printv(f_shadow, tab4, "thisown = _swig_property(lambda x: x.this.own(), ", "lambda x, v: x.this.own(v), doc='The membership flag')\n", NIL); - /* Add static attribute */ - if (GetFlag(n, "feature:python:nondynamic")) { - Printv(f_shadow_file, - tab4, "__setattr__ = _swig_setattr_nondynamic_method(object.__setattr__)\n", - tab4, "class __metaclass__(type):\n", tab4, tab4, "__setattr__ = _swig_setattr_nondynamic_method(type.__setattr__)\n", NIL); - } + Printv(f_shadow, tab4, "thisown = property(lambda x: x.this.own(), ", "lambda x, v: x.this.own(v), doc=\"The membership flag\")\n", NIL); + /* Add static attribute */ + if (GetFlag(n, "feature:python:nondynamic")) { + Printv(f_shadow_file, tab4, "__setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n", NIL); } } } @@ -4544,20 +4478,12 @@ public: } else { Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); 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); - } else { - 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 (!SWIG_Python_UnpackTuple(args, \"swigregister\", 1, 1, &obj)) return NULL;\n", NIL); Printv(f_wrappers, " SWIG_TypeNewClientData(SWIGTYPE", SwigType_manglestr(ct), ", SWIG_NewClientData(obj));\n", " return SWIG_Py_Void();\n", "}\n\n", NIL); String *cname = NewStringf("%s_swigregister", class_name); - add_method(cname, cname, 0); + add_method(cname, cname, 0, 0, 1, 1, 1); Delete(cname); } Delete(smart); @@ -4567,7 +4493,7 @@ public: if (!builtin) Printv(f_shadow_file, "\n", tab4, "def __init__(self, *args, **kwargs):\n", tab8, "raise AttributeError(\"", "No constructor defined", (Getattr(n, "abstracts") ? " - class is abstract" : ""), "\")\n", NIL); - } else if (fastinit && !builtin) { + } else if (!builtin) { Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); Printv(f_wrappers, " return SWIG_Python_InitShadowInstance(args);\n", "}\n\n", NIL); @@ -4578,11 +4504,7 @@ public: if (!have_repr && !builtin) { /* Supply a repr method for this class */ String *rname = SwigType_namestr(real_classname); - if (new_repr) { - Printv(f_shadow_file, tab4, "__repr__ = _swig_repr\n", NIL); - } else { - Printv(f_shadow_file, tab4, "def __repr__(self):\n", tab8, "return \"<C ", rname, " instance at %p>\" % (self.this,)\n", NIL); - } + Printv(f_shadow_file, tab4, "__repr__ = _swig_repr\n", NIL); Delete(rname); } @@ -4594,35 +4516,12 @@ public: builtin_tp_init = 0; } - /* Now emit methods */ - if (!builtin) - Printv(f_shadow_file, f_shadow, NIL); - - /* Now the Ptr class */ - if (classptr && !builtin) { - Printv(f_shadow_file, "\nclass ", class_name, "Ptr(", class_name, "):\n", tab4, "def __init__(self, this):\n", NIL); - if (!modern) { - Printv(f_shadow_file, - tab8, "try:\n", tab8, tab4, "self.this.append(this)\n", - tab8, "except __builtin__.Exception:\n", tab8, tab4, "self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL); - } else { - Printv(f_shadow_file, - tab8, "try:\n", tab8, tab4, "self.this.append(this)\n", - tab8, "except __builtin__.Exception:\n", tab8, tab4, "self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL); - } - } - if (!builtin) { - if (fastproxy) { - List *shadow_list = Getattr(n, "shadow_methods"); - for (int i = 0; i < Len(shadow_list); ++i) { - String *symname = Getitem(shadow_list, i); - Printf(f_shadow_file, "%s.%s = new_instancemethod(%s.%s, None, %s)\n", class_name, symname, module, Swig_name_member(NSPACE_TODO, class_name, symname), - class_name); - } - } - Printf(f_shadow_file, "%s_swigregister = %s.%s_swigregister\n", class_name, module, class_name); - Printf(f_shadow_file, "%s_swigregister(%s)\n", class_name, class_name); + /* Now emit methods */ + Printv(f_shadow_file, f_shadow, NIL); + Printf(f_shadow_file, "\n"); + Printf(f_shadow_file, "# Register %s in %s:\n", class_name, module); + Printf(f_shadow_file, "%s.%s_swigregister(%s)\n", module, class_name, class_name); } shadow_indent = 0; @@ -4636,9 +4535,6 @@ public: Clear(builtin_methods); } - classic = oldclassic; - modern = oldmodern; - /* Restore shadow file back to original version */ Delete(f_shadow); f_shadow = f_shadow_file; @@ -4692,15 +4588,19 @@ public: String *wname = Swig_name_wrapper(fullname); Setattr(class_members, symname, n); int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2; - String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_FUNC) : NewString(""); + String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_METHOD) : NewString(""); if (check_kwargs(n)) { - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS|METH_KEYWORDS, (char *) \"%s\" },\n", symname, wname, ds); + // Cast via void(*)(void) to suppress GCC -Wcast-function-type + // warning. Python should always call the function correctly, but + // the Python C API requires us to store it in function pointer of a + // different type. + Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, METH_VARARGS|METH_KEYWORDS, \"%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\", %s, METH_NOARGS, \"%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\", %s, METH_O, \"%s\" },\n", symname, wname, ds); } else { - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS, (char *) \"%s\" },\n", symname, wname, ds); + Printf(builtin_methods, " { \"%s\", %s, METH_VARARGS, \"%s\" },\n", symname, wname, ds); } Delete(fullname); Delete(wname); @@ -4733,6 +4633,8 @@ public: if (!have_addtofunc(n)) { if (!fastproxy || olddefs) { Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL); Printv(f_shadow, tab8, "return ", funcCall(fullname, callParms), "\n", NIL); } } else { @@ -4754,13 +4656,8 @@ public: } } if (fproxy) { - List *shadow_list = Getattr(getCurrentClass(), "shadow_methods"); - if (!shadow_list) { - shadow_list = NewList(); - Setattr(getCurrentClass(), "shadow_methods", shadow_list); - Delete(shadow_list); - } - Append(shadow_list, symname); + Printf(f_shadow, tab4); + Printf(f_shadow, "%s = _swig_new_instance_method(%s.%s)\n", symname, module, Swig_name_member(NSPACE_TODO, class_name, symname)); } Delete(fullname); } @@ -4790,7 +4687,7 @@ public: String *fullname = Swig_name_member(NSPACE_TODO, class_name, symname); String *wname = Swig_name_wrapper(fullname); Setattr(class_members, symname, n); - int funpack = modernargs && fastunpack && !Getattr(n, "sym:overloaded"); + int funpack = fastunpack && !Getattr(n, "sym:overloaded"); String *pyflags = NewString("METH_STATIC|"); int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2; if (funpack && argcount == 0) @@ -4799,12 +4696,15 @@ public: Append(pyflags, "METH_O"); else Append(pyflags, "METH_VARARGS"); + // Cast via void(*)(void) to suppress GCC -Wcast-function-type warning. + // Python should always call the function correctly, but the Python C + // API requires us to store it in function pointer of a different type. 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)(void(*)(void))%s, %s, \"%s\" },\n", symname, wname, pyflags, ds); Delete(ds); } else { - Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, %s, \"\" },\n", symname, wname, pyflags); + Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"\" },\n", symname, wname, pyflags); } Delete(fullname); Delete(wname); @@ -4818,10 +4718,13 @@ public: } if (shadow) { - if (!Getattr(n, "feature:python:callback") && have_addtofunc(n)) { + String *staticfunc_name = NewString(fastproxy ? "_swig_new_static_method" : "staticmethod"); + bool fast = (fastproxy && !have_addtofunc(n)) || Getattr(n, "feature:callback"); + if (!fast || olddefs) { int kw = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; String *parms = make_pyParmList(n, false, false, kw); String *callParms = make_pyParmList(n, false, true, kw); + Printv(f_shadow, "\n", tab4, "@staticmethod", NIL); Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); if (have_docstring(n)) Printv(f_shadow, tab8, docstring(n, AUTODOC_STATICFUNC, tab8), "\n", NIL); @@ -4830,24 +4733,18 @@ public: if (have_pythonappend(n)) { Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL); Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); - Printv(f_shadow, tab8, "return val\n\n", NIL); + Printv(f_shadow, tab8, "return val\n", NIL); } else { - Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n\n", NIL); - } - Printv(f_shadow, tab4, symname, " = staticmethod(", symname, ")\n", NIL); - } else { - if (!classic) { - if (!modern) - Printv(f_shadow, tab4, "if _newclass:\n", tab4, NIL); - Printv(f_shadow, tab4, symname, " = staticmethod(", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), - ")\n", NIL); - } - if (classic || !modern) { - if (!classic) - Printv(f_shadow, tab4, "else:\n", tab4, NIL); - Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\n", NIL); + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL); } } + + // Below may result in a 2nd definition of the method when -olddefs is used. The Python interpreter will use the second definition as it overwrites the first. + if (fast) { + Printv(f_shadow, tab4, symname, " = ", staticfunc_name, "(", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), + ")\n", NIL); + } + Delete(staticfunc_name); } return SWIG_OK; } @@ -4861,7 +4758,7 @@ public: int oldshadow = shadow; int use_director = Swig_directorclass(n); - /* + /* * If we're wrapping the constructor of a C++ director class, prepend a new parameter * to receive the scripting language object (e.g. 'self') * @@ -4905,11 +4802,12 @@ public: Delete(cname); } + String *subfunc = Swig_name_construct(NSPACE_TODO, symname); if (!have_constructor && handled_as_init) { if (!builtin) { if (Getattr(n, "feature:shadow")) { String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), tab4, Getfile(n), Getline(n), "%feature(\"shadow\")"); - String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(NSPACE_TODO, symname)); + String *pyaction = NewStringf("%s.%s", module, subfunc); Replaceall(pycode, "$action", pyaction); Delete(pyaction); Printv(f_shadow, pycode, "\n", NIL); @@ -4923,7 +4821,7 @@ public: String *parms = make_pyParmList(n, true, false, allow_kwargs); /* Pass 'self' only if using director */ - String *callParms = make_pyParmList(n, false, true, allow_kwargs); + String *callParms = make_pyParmList(n, false, true, allow_kwargs, true); if (use_director) { Insert(callParms, 0, "_self, "); @@ -4939,13 +4837,7 @@ public: if (have_pythonprepend(n)) Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); Printv(f_shadow, pass_self, NIL); - if (fastinit) { - Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self, ", funcCall(Swig_name_construct(NSPACE_TODO, symname), callParms), ")\n", NIL); - } else { - Printv(f_shadow, - tab8, "this = ", funcCall(Swig_name_construct(NSPACE_TODO, symname), callParms), "\n", - tab8, "try:\n", tab8, tab4, "self.this.append(this)\n", tab8, "except __builtin__.Exception:\n", tab8, tab4, "self.this = this\n", NIL); - } + Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self, ", funcCall(subfunc, callParms), ")\n", NIL); if (have_pythonappend(n)) Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n\n", NIL); Delete(pass_self); @@ -4955,39 +4847,36 @@ public: } else { /* Hmmm. We seem to be creating a different constructor. We're just going to create a function for it. */ - if (Getattr(n, "feature:shadow")) { - String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), "", Getfile(n), Getline(n), "%feature(\"shadow\")"); - String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(NSPACE_TODO, symname)); - Replaceall(pycode, "$action", pyaction); - Delete(pyaction); - Printv(f_shadow_stubs, pycode, "\n", NIL); - Delete(pycode); - } else { - String *parms = make_pyParmList(n, false, false, allow_kwargs); - String *callParms = make_pyParmList(n, false, true, allow_kwargs); + if (!builtin) { + if (Getattr(n, "feature:shadow")) { + String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), "", Getfile(n), Getline(n), "%feature(\"shadow\")"); + String *pyaction = NewStringf("%s.%s", module, subfunc); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow_stubs, pycode, "\n", NIL); + Delete(pycode); + } else { + String *parms = make_pyParmList(n, false, false, allow_kwargs); + String *callParms = make_pyParmList(n, false, true, allow_kwargs); - Printv(f_shadow_stubs, "\ndef ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); - if (have_docstring(n)) - Printv(f_shadow_stubs, tab4, docstring(n, AUTODOC_CTOR, tab4), "\n", NIL); - if (have_pythonprepend(n)) - Printv(f_shadow_stubs, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); - String *subfunc = NULL; - /* - if (builtin) - subfunc = Copy(Getattr(getCurrentClass(), "sym:name")); - else - */ - subfunc = Swig_name_construct(NSPACE_TODO, symname); - Printv(f_shadow_stubs, tab4, "val = ", funcCall(subfunc, callParms), "\n", NIL); + Printv(f_shadow_stubs, "\ndef ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow_stubs, tab4, docstring(n, AUTODOC_CTOR, tab4), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow_stubs, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); + Printv(f_shadow_stubs, tab4, "val = ", funcCall(subfunc, callParms), "\n", NIL); #ifdef USE_THISOWN - Printv(f_shadow_stubs, tab4, "val.thisown = 1\n", NIL); + Printv(f_shadow_stubs, tab4, "val.thisown = 1\n", NIL); #endif - if (have_pythonappend(n)) - Printv(f_shadow_stubs, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); - Printv(f_shadow_stubs, tab4, "return val\n", NIL); - Delete(subfunc); + if (have_pythonappend(n)) + Printv(f_shadow_stubs, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); + Printv(f_shadow_stubs, tab4, "return val\n", NIL); + } + } else { + Printf(f_shadow_stubs, "%s = %s\n", symname, subfunc); } } + Delete(subfunc); } } return SWIG_OK; @@ -5027,9 +4916,6 @@ public: } else { Printv(f_shadow, tab4, "__swig_destroy__ = ", module, ".", Swig_name_destroy(NSPACE_TODO, symname), "\n", NIL); if (!have_pythonprepend(n) && !have_pythonappend(n)) { - if (proxydel) { - Printv(f_shadow, tab4, "__del__ = lambda self: None\n", NIL); - } return SWIG_OK; } Printv(f_shadow, tab4, "def __del__(self):\n", NIL); @@ -5070,20 +4956,12 @@ public: String *setname = Swig_name_set(NSPACE_TODO, mname); String *getname = Swig_name_get(NSPACE_TODO, mname); int assignable = is_assignable(n); - if (!modern) { - if (assignable) { - Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL); - } - Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL); - } - if (!classic) { - if (!modern) - Printv(f_shadow, tab4, "if _newclass:\n", tab4, NIL); - Printv(f_shadow, tab4, symname, " = _swig_property(", module, ".", getname, NIL); - if (assignable) - Printv(f_shadow, ", ", module, ".", setname, NIL); - Printv(f_shadow, ")\n", NIL); - } + Printv(f_shadow, tab4, symname, " = property(", module, ".", getname, NIL); + if (assignable) + Printv(f_shadow, ", ", module, ".", setname, NIL); + if (have_docstring(n)) + Printv(f_shadow, ", doc=", docstring(n, AUTODOC_VAR, tab4), NIL); + Printv(f_shadow, ")\n", NIL); Delete(mname); Delete(setname); Delete(getname); @@ -5129,13 +5007,13 @@ public: DelWrapper(f); int assignable = is_assignable(n); if (assignable) { - int funpack = modernargs && fastunpack; + int funpack = fastunpack; Wrapper *f = NewWrapper(); Printv(f->def, "SWIGINTERN PyObject *", wrapsetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); Wrapper_add_local(f, "res", "int res"); if (!funpack) { Wrapper_add_local(f, "value", "PyObject *value"); - Append(f->code, "if (!PyArg_ParseTuple(args,(char *)\"O:set\",&value)) return NULL;\n"); + Append(f->code, "if (!PyArg_ParseTuple(args, \"O:set\", &value)) return NULL;\n"); } Printf(f->code, "res = %s(%s);\n", varsetname, funpack ? "args" : "value"); Append(f->code, "return !res ? SWIG_Py_Void() : NULL;\n"); @@ -5144,18 +5022,12 @@ public: add_method(setname, wrapsetname, 0, 0, funpack, 1, 1); DelWrapper(f); } - if (!modern && !builtin) { - if (assignable) { - Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL); - } - Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL); - } - if (!classic && !builtin) { - if (!modern) - Printv(f_shadow, tab4, "if _newclass:\n", tab4, NIL); - Printv(f_shadow, tab4, symname, " = _swig_property(", module, ".", getname, NIL); + if (!builtin) { + Printv(f_shadow, tab4, symname, " = property(", module, ".", getname, NIL); if (assignable) Printv(f_shadow, ", ", module, ".", setname, NIL); + if (have_docstring(n)) + Printv(f_shadow, ", doc=", docstring(n, AUTODOC_VAR, tab4), NIL); Printv(f_shadow, ")\n", NIL); } String *getter = Getattr(n, "pybuiltin:getter"); @@ -5207,13 +5079,15 @@ public: Swig_restore(n); } else if (shadow) { Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab4, docstring(n, AUTODOC_CONST, tab4), "\n", NIL); } return SWIG_OK; } /* ------------------------------------------------------------ * insertDirective() - * + * * Hook for %insert directive. We're going to look for special %shadow inserts * as a special case so we can do indenting correctly * ------------------------------------------------------------ */ @@ -5229,9 +5103,11 @@ public: Delete(pycode); } } else if (!ImportMode && (Cmp(section, "pythonbegin") == 0)) { - String *pycode = indent_pythoncode(code, "", Getfile(n), Getline(n), "%pythonbegin or %insert(\"pythonbegin\") block"); - Printv(f_shadow_begin, pycode, NIL); - Delete(pycode); + if (shadow) { + String *pycode = indent_pythoncode(code, "", Getfile(n), Getline(n), "%pythonbegin or %insert(\"pythonbegin\") block"); + Printv(f_shadow_begin, pycode, NIL); + Delete(pycode); + } } else { Language::insertDirective(n); } @@ -5294,7 +5170,7 @@ public: /* --------------------------------------------------------------- * classDirectorMethod() * - * Emit a virtual director method to pass a method call on to the + * Emit a virtual director method to pass a method call on to the * underlying Python object. * * ** Moved it here due to internal error on gcc-2.96 ** @@ -5351,18 +5227,21 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { String *pclassname = NewStringf("SwigDirector_%s", classname); String *qualified_name = NewStringf("%s::%s", pclassname, name); SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); - target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + target = Swig_method_decl(rtype, decl, qualified_name, l, 0); Printf(w->def, "%s", target); Delete(qualified_name); Delete(target); /* header declaration */ - target = Swig_method_decl(rtype, decl, name, l, 0, 1); + target = Swig_method_decl(rtype, decl, name, l, 1); Printf(declaration, " virtual %s", target); Delete(target); // Get any exception classes in the throws typemap + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } ParmList *throw_parm_list = 0; - if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { Parm *p; int gencomma = 0; @@ -5392,12 +5271,20 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { Append(w->def, " {"); Append(declaration, ";\n"); - /* declare method return value + /* declare method return value * if the return value is a reference or const reference, a specialized typemap must * handle it, including declaration of c_result ($result). */ - if (!is_void) { - if (!(ignored_method && !pure_virtual)) { + if (!is_void && (!ignored_method || pure_virtual)) { + if (!SwigType_isclass(returntype)) { + if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { + String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); + Delete(construct_result); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } + } else { String *cres = SwigType_lstr(returntype, "c_result"); Printf(w->code, "%s;\n", cres); Delete(cres); @@ -5429,7 +5316,7 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { /* remove the wrapper 'w' since it was producing spurious temps */ Swig_typemap_attach_parms("in", l, 0); - Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("directorin", l, w); Swig_typemap_attach_parms("directorargout", l, w); Parm *p; @@ -5544,7 +5431,7 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { } else { Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); Printf(wrap_args, "%s = SWIG_InternalNewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); - //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", // source, nonconst, base); Printv(arglist, source, NIL); } @@ -5590,34 +5477,26 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { Append(w->code, "PyObject *method = swig_get_method(swig_method_index, swig_method_name);\n"); if (Len(parse_args) > 0) { - if (use_parse || !modernargs) { + if (use_parse) { Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunction(method, (char *)\"(%s)\" %s);\n", Swig_cresult_name(), parse_args, arglist); } else { Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunctionObjArgs(method %s, NULL);\n", Swig_cresult_name(), arglist); } } 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()); - } else { - Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunction(method, NULL, NULL);\n", Swig_cresult_name()); - } + 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()); } Append(w->code, "#else\n"); if (Len(parse_args) > 0) { - if (use_parse || !modernargs) { + if (use_parse) { Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n", Swig_cresult_name(), pyname, parse_args, arglist); } else { - Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar(\"%s\");\n", pyname); Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name %s, NULL);\n", Swig_cresult_name(), arglist); } } else { - if (!modernargs) { - Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethod(swig_get_self(), (char *) \"%s\", NULL);\n", Swig_cresult_name(), pyname); - } else { - Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); - Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n", Swig_cresult_name()); - } + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar(\"%s\");\n", pyname); + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n", Swig_cresult_name()); } Append(w->code, "#endif\n"); @@ -5646,7 +5525,7 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { /* * Python method may return a simple object, or a tuple. - * for in/out aruments, we have to extract the appropriate PyObjects from the tuple, + * for in/out arguments, we have to extract the appropriate PyObjects from the tuple, * then marshal everything back to C/C++ (return value and output arguments). * */ |