diff options
Diffstat (limited to 'Source/Modules/python.cxx')
-rw-r--r-- | Source/Modules/python.cxx | 661 |
1 files changed, 384 insertions, 277 deletions
diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index ea31af029..905a0263a 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -4,7 +4,7 @@ * 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 * included with the SWIG source code as distributed by the SWIG developers - * and at http://www.swig.org/legal.html. + * and at https://www.swig.org/legal.html. * * python.cxx * @@ -12,13 +12,12 @@ * ----------------------------------------------------------------------------- */ #include "swigmod.h" -#include <limits.h> #include "cparse.h" +#include <limits.h> #include <ctype.h> #include <errno.h> -#include "pydoc.h" - #include <stdint.h> +#include "pydoc.h" #define PYSHADOW_MEMBER 0x2 #define WARN_PYTHON_MULTIPLE_INH 405 @@ -69,12 +68,12 @@ static int no_header_file = 0; static int max_bases = 0; static int builtin_bases_needed = 0; -static int py3 = 0; - /* C++ Support + Shadow Classes */ -static int have_constructor; -static int have_repr; +static int have_constructor = 0; +static int have_repr = 0; +static bool have_builtin_static_member_method_callback = false; +static bool have_fast_proxy_static_member_method_callback = false; static String *real_classname; /* Thread Support */ @@ -91,8 +90,10 @@ static int castmode = 0; static int extranative = 0; static int nortti = 0; static int relativeimport = 0; +static int flat_static_method = 0; /* flags for the make_autodoc function */ +namespace { enum autodoc_t { AUTODOC_CLASS, AUTODOC_CTOR, @@ -103,7 +104,7 @@ enum autodoc_t { AUTODOC_CONST, AUTODOC_VAR }; - +} static const char *usage1 = "\ Python Options (available with -python)\n\ @@ -115,6 +116,7 @@ Python Options (available with -python)\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\ + -flatstaticmethod - Generate additional flattened Python methods for C++ static 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"; @@ -126,7 +128,6 @@ static const char *usage3 = "\ -nortti - Disable the use of the native C++ RTTI with directors\n\ -nothreads - Disable thread support for the entire interface\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\ @@ -219,7 +220,7 @@ public: " $director_new \n", "} else {\n", " SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing abstract class or protected constructor\"); \n", " SWIG_fail;\n", "}\n", NIL); director_multiple_inheritance = 1; - director_language = 1; + directorLanguage(); } ~PYTHON() { @@ -313,7 +314,6 @@ public: } else { Swig_arg_error(); } - /* end added */ } else if (strcmp(argv[i], "-globals") == 0) { if (argv[i + 1]) { global_name = NewString(argv[i + 1]); @@ -371,6 +371,9 @@ public: } else if (strcmp(argv[i], "-extranative") == 0) { extranative = 1; Swig_mark_arg(i); + } else if (strcmp(argv[i], "-flatstaticmethod") == 0) { + flat_static_method = 1; + Swig_mark_arg(i); } else if (strcmp(argv[i], "-noh") == 0) { no_header_file = 1; Swig_mark_arg(i); @@ -389,10 +392,6 @@ public: fputs(usage1, stdout); fputs(usage2, stdout); fputs(usage3, stdout); - } else if (strcmp(argv[i], "-py3") == 0) { - py3 = 1; - Preprocessor_define("SWIGPYTHON_PY3", 0); - Swig_mark_arg(i); } else if (strcmp(argv[i], "-builtin") == 0) { builtin = 1; Preprocessor_define("SWIGPYTHON_BUILTIN", 0); @@ -408,7 +407,10 @@ public: 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]); + Printf(stderr, "Deprecated command line option: %s. Ignored, this option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-py3") == 0) { + Printf(stderr, "Deprecated command line option: %s. Ignored, this option is no longer supported.\n", argv[i]); Swig_mark_arg(i); } else if (strcmp(argv[i], "-aliasobj0") == 0 || strcmp(argv[i], "-buildnone") == 0 || @@ -436,14 +438,23 @@ public: 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]); + Printf(stderr, "Deprecated command line option: %s. This option is no longer available.\n", argv[i]); Swig_mark_arg(i); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } } } + if (builtin && !shadow) { + Printf(stderr, "Incompatible options -builtin and -noproxy specified.\n"); + Exit(EXIT_FAILURE); + } + + if (fastproxy) { + Preprocessor_define("SWIGPYTHON_FASTPROXY", 0); + } + if (doxygen) doxygenTranslator = new PyDocConverter(doxygen_translator_flags); @@ -496,22 +507,22 @@ public: } if (Getattr(options, "nocastmode")) { Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nocastmode"); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } if (Getattr(options, "extranative")) { extranative = 1; } if (Getattr(options, "noextranative")) { Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "noextranative"); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } if (Getattr(options, "outputtuple")) { Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "outputtuple"); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } if (Getattr(options, "nooutputtuple")) { Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nooutputtuple"); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } mod_docstring = Getattr(options, "docstring"); package = Getattr(options, "package"); @@ -530,7 +541,7 @@ public: f_begin = NewFile(outfile, "w", SWIG_output_files()); if (!f_begin) { FileErrorDisplay(outfile); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } f_runtime = NewString(""); f_init = NewString(""); @@ -549,12 +560,12 @@ public: f_builtins = NewString(""); } - if (directorsEnabled()) { + if (Swig_directors_enabled()) { if (!no_header_file) { f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); if (!f_runtime_h) { FileErrorDisplay(outfile_h); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } } else { f_runtime_h = f_runtime; @@ -576,9 +587,9 @@ public: Swig_banner(f_begin); - Printf(f_runtime, "\n\n#ifndef SWIGPYTHON\n#define SWIGPYTHON\n#endif\n\n"); + Swig_obligatory_macros(f_runtime, "PYTHON"); - if (directorsEnabled()) { + if (Swig_directors_enabled()) { Printf(f_runtime, "#define SWIG_DIRECTORS\n"); } @@ -611,6 +622,10 @@ public: Printf(f_runtime, "#define SWIGPYTHON_BUILTIN\n"); } + if (fastproxy) { + Printf(f_runtime, "#define SWIGPYTHON_FASTPROXY\n"); + } + Printf(f_runtime, "\n"); Printf(f_header, "#ifdef SWIG_TypeQuery\n"); @@ -623,7 +638,7 @@ public: module = Copy(Getattr(n, "name")); mainmodule = Getattr(n, "name"); - if (directorsEnabled()) { + if (Swig_directors_enabled()) { Swig_banner(f_directors_h); Printf(f_directors_h, "\n"); Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module); @@ -655,7 +670,7 @@ public: Insert(module, 0, "_"); if ((f_shadow_py = NewFile(filen, "w", SWIG_output_files())) == 0) { FileErrorDisplay(filen); - SWIG_exit(EXIT_FAILURE); + Exit(EXIT_FAILURE); } Delete(filen); filen = NULL; @@ -696,9 +711,11 @@ public: 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 (!builtin) { + /* 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 (!builtin && fastproxy) { Printf(f_shadow, "\n"); @@ -706,58 +723,54 @@ public: 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 name in (\"this\", \"thisown\"):\n", - tab4, tab4, tab4, "set(self, name, value)\n", -#else - 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, "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()) { - Printv(f_shadow, "import weakref\n\n", NIL); + if (!builtin) { + 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", + tab4, tab4, "if name == \"this\":\n", + tab4, tab4, tab4, "set(self, name, value)\n", + tab4, tab4, "elif name == \"thisown\":\n", + tab4, tab4, tab4, "self.this.own(value)\n", + 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 (Swig_directors_enabled()) + Printv(f_shadow, "import weakref\n\n", NIL); } } // Include some information in the code @@ -792,7 +805,7 @@ public: /* emit code */ Language::top(n); - if (directorsEnabled()) { + if (Swig_directors_enabled()) { // Insert director runtime into the f_runtime file (make it occur before %header section) Swig_insert_file("director_common.swg", f_runtime); Swig_insert_file("director.swg", f_runtime); @@ -804,7 +817,8 @@ public: 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 ((fastproxy && !builtin) || have_fast_proxy_static_member_method_callback) + Printf(f_wrappers, "%s\n", methods_proxydocs); if (builtin) { Dump(f_builtins, f_wrappers); @@ -814,6 +828,10 @@ public: Append(const_code, "{0, 0, 0, 0.0, 0, 0}};\n"); Printf(f_wrappers, "%s\n", const_code); + + if (have_fast_proxy_static_member_method_callback) + Printf(f_init, " SWIG_Python_FixMethods(SwigMethods_proxydocs, swig_const_table, swig_types, swig_type_initial);\n\n"); + initialize_threads(f_init); Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); @@ -846,8 +864,6 @@ public: 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); @@ -859,8 +875,10 @@ public: Printv(f_shadow_py, default_import_code, NIL); } - Printv(f_shadow_py, "\n", f_shadow, "\n", NIL); - Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); + if (Len(f_shadow) > 0) + Printv(f_shadow_py, "\n", f_shadow, "\n", NIL); + if (Len(f_shadow_stubs) > 0) + Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); Delete(f_shadow_py); } @@ -868,7 +886,7 @@ public: Dump(f_runtime, f_begin); Dump(f_header, f_begin); - if (directorsEnabled()) { + if (Swig_directors_enabled()) { Dump(f_directors_h, f_runtime_h); Printf(f_runtime_h, "\n"); Printf(f_runtime_h, "#endif\n"); @@ -905,15 +923,15 @@ public: * as a replacement of new.instancemethod in Python 3. * ------------------------------------------------------------ */ int add_pyinstancemethod_new() { - String *name = NewString("SWIG_PyInstanceMethod_New"); - String *line = NewString(""); - Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); - Append(methods, line); - if (fastproxy) { + if (!builtin && fastproxy) { + String *name = NewString("SWIG_PyInstanceMethod_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); } - Delete(line); - Delete(name); return 0; } @@ -923,7 +941,7 @@ public: * generated for static methods when using -fastproxy * ------------------------------------------------------------ */ int add_pystaticmethod_new() { - if (fastproxy) { + if (!builtin && fastproxy) { String *name = NewString("SWIG_PyStaticMethod_New"); String *line = NewString(""); Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); @@ -1473,19 +1491,28 @@ public: /* ------------------------------------------------------------ * build_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. + * Build the full docstring: + * Use the docstring if there is one present otherwise + * use the Doxygen comment if there is one present. + * Ignore autodoc if there is a Doxygen comment, otherwise + * create the autodoc string and append to any docstring. * * Return new string to be deleted by caller (never NIL but * may be empty if there is no docstring). * ------------------------------------------------------------ */ String *build_combined_docstring(Node *n, autodoc_t ad_type, const String *indent = "", bool low_level = false) { + bool add_autodoc = true; String *docstr = Getattr(n, "feature:docstring"); - if (docstr && Len(docstr)) { - docstr = Copy(docstr); + if (docstr) { + // Simplify the code below by just ignoring empty docstrings. + if (!Len(docstr)) + docstr = NULL; + else + docstr = Copy(docstr); + } + + if (docstr) { char *t = Char(docstr); if (*t == '{') { Delitem(docstr, 0); @@ -1493,26 +1520,10 @@ public: } } - 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 (!docstr || !Len(docstr)) { - if (doxygen) { + if (!docstr) { + if (doxygen && doxygenTranslator->hasDocumentation(n)) { docstr = Getattr(n, "python:docstring"); - if (!docstr && doxygenTranslator->hasDocumentation(n)) { + if (!docstr) { docstr = doxygenTranslator->getDocumentation(n, 0); // Avoid rebuilding it again the next time: notice that we can't do @@ -1528,7 +1539,24 @@ public: // the cached object! docstr = Copy(docstr); } + add_autodoc = false; + } + } + + if (add_autodoc && Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) { + String *autodoc = make_autodoc(n, ad_type, low_level); + if (autodoc && Len(autodoc) > 0) { + if (docstr) { + Append(autodoc, "\n"); + Append(autodoc, docstr); + } + + String *tmp = autodoc; + autodoc = docstr; + docstr = tmp; } + + Delete(autodoc); } if (!docstr) @@ -1564,7 +1592,8 @@ public: 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)) + const int len = Len(docstr); + if (!len) return docstr; // Notice that all comments are created as raw strings (prefix "r"), @@ -1577,9 +1606,32 @@ public: // escape '\x'. '\' may additionally appear in verbatim or htmlonly sections // of doxygen doc, Latex expressions, ... String *doc = NewString(""); - Append(doc, "r\"\"\""); + + // Determine which kind of quotes to use as delimiters: for single line + // strings we can avoid problems with having a quote as the last character + // of the docstring by using different kind of quotes as delimiters. For + // multi-line strings this problem doesn't arise, as we always have a new + // line or spaces at the end of it, but it still does no harm to do it for + // them too. + // + // Note: we use double quotes by default, i.e. if there is no reason to + // prefer using single ones, for consistency with the older SWIG versions. + const bool useSingleQuotes = (Char(docstr))[len - 1] == '"'; + + Append(doc, useSingleQuotes ? "r'''" : "r\"\"\""); + + // We also need to avoid having triple quotes of whichever type we use, as + // this would break Python doc string syntax too. Unfortunately there is no + // way to have triple quotes inside of raw-triple-quoted string, so we have + // to break the string in parts and rely on concatenation of the adjacent + // string literals. + if (useSingleQuotes) + Replaceall(docstr, "'''", "''' \"'''\" '''"); + else + Replaceall(docstr, "\"\"\"", "\"\"\" '\"\"\"' \"\"\""); + Append(doc, docstr); - Append(doc, "\"\"\""); + Append(doc, useSingleQuotes ? "'''" : "\"\"\""); Delete(docstr); return doc; @@ -1846,16 +1898,20 @@ public: String *str = Getattr(n, "feature:docstring"); if (!str || Len(str) == 0) { if (builtin) { - String *name = Getattr(n, "name"); - String *rname = add_explicit_scope(SwigType_namestr(name)); + SwigType *name = Getattr(n, "name"); + SwigType *sname = add_explicit_scope(name); + String *rname = SwigType_namestr(sname); Printf(doc, "%s", rname); + Delete(sname); Delete(rname); } else { + String *classname_str = SwigType_namestr(real_classname); if (CPlusPlus) { - Printf(doc, "Proxy of C++ %s class.", SwigType_namestr(real_classname)); + Printf(doc, "Proxy of C++ %s class.", classname_str); } else { - Printf(doc, "Proxy of C %s struct.", SwigType_namestr(real_classname)); + Printf(doc, "Proxy of C %s struct.", classname_str); } + Delete(classname_str); } } } @@ -2219,7 +2275,7 @@ public: return parms; } - bool funcanno = py3 ? true : false; + bool funcanno = Equal(Getattr(n, "feature:python:annotations"), "c") ? true : false; String *params = NewString(""); String *_params = make_autodocParmList(n, false, ((in_class || has_self_for_count)? 2 : 1), is_calling, funcanno); @@ -2335,8 +2391,25 @@ public: if (ret) ret = SwigType_str(ret, 0); } - return (ret && py3) ? NewStringf(" -> \"%s\"", ret) - : NewString(""); + bool funcanno = Equal(Getattr(n, "feature:python:annotations"), "c") ? true : false; + return (ret && funcanno) ? NewStringf(" -> \"%s\"", ret) : NewString(""); + } + + /* ------------------------------------------------------------ + * variableAnnotation() + * + * Helper function for constructing a variable annotation + * ------------------------------------------------------------ */ + + String *variableAnnotation(Node *n) { + String *type = Getattr(n, "type"); + if (type) + type = SwigType_str(type, 0); + bool anno = Equal(Getattr(n, "feature:python:annotations"), "c") ? true : false; + anno = GetFlag(n, "feature:python:annotations:novar") ? false : anno; + String *annotation = (type && anno) ? NewStringf(": \"%s\"", type) : NewString(""); + Delete(type); + return annotation; } /* ------------------------------------------------------------ @@ -2441,6 +2514,7 @@ public: Printf(methods, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); if (fastproxy) { Printf(methods_proxydocs, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + have_fast_proxy_static_member_method_callback = true; } } else { Append(methods, "NULL"); @@ -2458,7 +2532,7 @@ public: /* ------------------------------------------------------------ * dispatchFunction() * ------------------------------------------------------------ */ - void dispatchFunction(Node *n, String *linkage, int funpack = 0, bool builtin_self = false, bool builtin_ctor = false, bool director_class = false) { + void dispatchFunction(Node *n, String *linkage, int funpack = 0, bool builtin_self = false, bool builtin_ctor = false, bool director_class = false, bool use_static_method = false) { /* Last node in overloaded chain */ bool add_self = builtin_self && (!builtin_ctor || director_class); @@ -2493,9 +2567,14 @@ public: String *symname = Getattr(n, "sym:name"); String *wname = Swig_name_wrapper(symname); - const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : ""; + const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : ""; Printv(f->def, linkage, builtin_ctor ? "int " : "PyObject *", wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); + if (builtin) { + /* Avoid warning if the self parameter is not used. */ + Append(f->code, "(void)self;\n"); + } + Wrapper_add_local(f, "argc", "Py_ssize_t argc"); Printf(tmp, "PyObject *argv[%d] = {0}", maxargs + 1); Wrapper_add_local(f, "argv", tmp); @@ -2503,6 +2582,9 @@ public: if (!fastunpack) { Wrapper_add_local(f, "ii", "Py_ssize_t ii"); + if (builtin_ctor) + Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname); + 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"); @@ -2518,8 +2600,9 @@ public: if (add_self) 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" : ""); + if (builtin_ctor) + Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname); + Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", symname, maxargs, add_self ? "+1" : ""); if (add_self) Append(f->code, "argv[0] = self;\n"); else @@ -2553,11 +2636,11 @@ public: Printv(f->code, "}\n", NIL); Wrapper_print(f, f_wrappers); Node *p = Getattr(n, "sym:previousSibling"); - if (!builtin_self) + if (!builtin_self && (use_static_method || !builtin)) add_method(symname, wname, 0, p); /* Create a shadow for this function (if enabled and not in a member function) */ - if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER) && use_static_method) { emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, symname, 0); } DelWrapper(f); @@ -2635,6 +2718,7 @@ public: int constructor = (!Cmp(nodeType, "constructor")); int destructor = (!Cmp(nodeType, "destructor")); String *storage = Getattr(n, "storage"); + int isfriend = Strstr(storage, "friend") != NULL; /* Only the first constructor is handled as init method. Others constructor can be emitted via %rename */ int handled_as_init = 0; @@ -2661,7 +2745,6 @@ public: 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); - char const *self_param = builtin ? "self" : "SWIGUNUSEDPARM(self)"; char const *wrap_return = builtin_ctor ? "int " : "PyObject *"; String *linkage = NewString("SWIGINTERN "); String *wrapper_name = Swig_name_wrapper(iname); @@ -2700,8 +2783,12 @@ public: --tuple_required; } num_fixed_arguments = tuple_required; + + // builtin handles/checks kwargs by default except in constructor wrappers so we need to explicitly handle them in the C constructor wrapper + // The check below is for zero arguments. Sometimes (eg directors) self is the first argument for a method with zero arguments. if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self"))) - allow_kwargs = 0; + if (!builtin_ctor) + allow_kwargs = 0; varargs = emit_isvarargs(l); String *wname = Copy(wrapper_name); @@ -2709,12 +2796,12 @@ public: Append(wname, overname); } - const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : ""; + const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : ""; if (!allow_kwargs || overname) { if (!varargs) { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); } else { - Printv(f->def, linkage, wrap_return, wname, "__varargs__", "(PyObject *", self_param, ", PyObject *args, PyObject *varargs) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "__varargs__", "(PyObject *self, PyObject *args, PyObject *varargs", builtin_kwargs, ") {", NIL); } if (allow_kwargs) { Swig_warning(WARN_LANG_OVERLOAD_KEYWORD, input_file, line_number, "Can't use keyword arguments with overloaded functions (%s).\n", Swig_name_decl(n)); @@ -2725,9 +2812,15 @@ public: Swig_warning(WARN_LANG_VARARGS_KEYWORD, input_file, line_number, "Can't wrap varargs with keyword arguments enabled\n"); varargs = 0; } - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args, PyObject *kwargs) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args, PyObject *kwargs) {", NIL); + } + + if (!builtin) { + /* Avoid warning if the self parameter is not used. */ + Append(f->code, "(void)self;\n"); } - if (!builtin || !in_class || tuple_arguments > 0) { + + if (!builtin || !in_class || tuple_arguments > 0 || builtin_ctor) { if (!allow_kwargs) { Append(parse_args, " if (!PyArg_ParseTuple(args, \""); } else { @@ -2753,7 +2846,7 @@ public: /* Generate code for argument marshalling */ if (funpack) { - if (num_arguments > 0 && !overname) { + if (num_arguments > (builtin_self && !constructor ? 1 : 0) && !overname) { sprintf(source, "PyObject *swig_obj[%d]", num_arguments); Wrapper_add_localv(f, "swig_obj", source, NIL); } @@ -2823,8 +2916,6 @@ public: } else { Replaceall(tm, "$self", "obj0"); } - Replaceall(tm, "$source", source); - Replaceall(tm, "$target", ln); Replaceall(tm, "$input", source); Setattr(p, "emit:input", source); /* Save the location of the object */ @@ -2876,26 +2967,27 @@ public: 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) { + if (use_parse || allow_kwargs) { Printf(parse_args, ":%s\"", iname); Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); funpack = 0; } else { Clear(parse_args); + if (funpack) { Clear(f->def); if (overname) { if (noargs) { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, Py_ssize_t nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); } else { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); } Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments); } else { 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); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); + if (builtin_ctor) + Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname); if (onearg && !builtin_ctor && !is_tp_call) { Printf(parse_args, "if (!args) SWIG_fail;\n"); Append(parse_args, "swig_obj[0] = args;\n"); @@ -2906,8 +2998,14 @@ public: } } } else { - Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments); - Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); + if (builtin_ctor) + Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname); + if (builtin && 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 { + Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments); + Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); + } } } @@ -2925,7 +3023,6 @@ public: /* Insert constraint checking code */ for (p = l; p;) { if ((tm = Getattr(p, "tmap:check"))) { - Replaceall(tm, "$target", Getattr(p, "lname")); Printv(f->code, tm, "\n", NIL); p = Getattr(p, "tmap:check:next"); } else { @@ -2947,7 +3044,6 @@ public: } } if (tm && (Len(tm) != 0)) { - Replaceall(tm, "$source", Getattr(p, "lname")); Printv(cleanup, tm, "\n", NIL); } p = Getattr(p, "tmap:freearg:next"); @@ -2959,8 +3055,6 @@ public: /* Insert argument output code */ for (p = l; p;) { if ((tm = Getattr(p, "tmap:argout"))) { - Replaceall(tm, "$source", Getattr(p, "lname")); - Replaceall(tm, "$target", "resultobj"); Replaceall(tm, "$arg", Getattr(p, "emit:input")); Replaceall(tm, "$input", Getattr(p, "emit:input")); Printv(outarg, tm, "\n", NIL); @@ -3049,8 +3143,6 @@ public: } else { Replaceall(tm, "$self", "obj0"); } - Replaceall(tm, "$source", Swig_cresult_name()); - Replaceall(tm, "$target", "resultobj"); Replaceall(tm, "$result", "resultobj"); if (builtin_ctor) { Replaceall(tm, "$owner", "SWIG_BUILTIN_INIT"); @@ -3063,27 +3155,9 @@ public: Replaceall(tm, "$owner", "0"); } } - // FIXME: this will not try to unwrap directors returned as non-director - // base class pointers! - /* New addition to unwrap director return values so that the original - * python object is returned instead. - */ -#if 1 - int unwrap = 0; - String *decl = Getattr(n, "decl"); - int is_pointer = SwigType_ispointer_return(decl); - int is_reference = SwigType_isreference_return(decl); - if (is_pointer || is_reference) { - String *type = Getattr(n, "type"); - //Node *classNode = Swig_methodclass(n); - //Node *module = Getattr(classNode, "module"); - Node *module = Getattr(parent, "module"); - Node *target = Swig_directormap(module, type); - if (target) - unwrap = 1; - } - if (unwrap) { + // Unwrap return values that are director classes so that the original Python object is returned instead. + if (!constructor && Swig_director_can_unwrap(n)) { Wrapper_add_local(f, "director", "Swig::Director *director = 0"); Printf(f->code, "director = SWIG_DIRECTOR_CAST(%s);\n", Swig_cresult_name()); Append(f->code, "if (director) {\n"); @@ -3095,9 +3169,7 @@ public: } else { Printf(f->code, "%s\n", tm); } -#else - Printf(f->code, "%s\n", tm); -#endif + Delete(tm); } else { Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); @@ -3116,7 +3188,6 @@ public: /* Look to see if there is any newfree cleanup code */ if (GetFlag(n, "feature:new")) { if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { - Replaceall(tm, "$source", Swig_cresult_name()); Printf(f->code, "%s\n", tm); Delete(tm); } @@ -3124,7 +3195,6 @@ public: /* See if there is any return cleanup code */ if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { - Replaceall(tm, "$source", Swig_cresult_name()); Printf(f->code, "%s\n", tm); Delete(tm); } @@ -3153,6 +3223,9 @@ public: Printv(f->code, " return -1;\n", NIL); } else { if (GetFlag(n, "feature:python:maybecall")) { + Append(f->code, " if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) {\n"); + Append(f->code, " return NULL;\n"); + Append(f->code, " }\n"); Append(f->code, " PyErr_Clear();\n"); Append(f->code, " Py_INCREF(Py_NotImplemented);\n"); Append(f->code, " return Py_NotImplemented;\n"); @@ -3187,9 +3260,9 @@ public: f = NewWrapper(); if (funpack) { // 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); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); } else { - Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); } Wrapper_add_local(f, "resultobj", builtin_ctor ? "int resultobj" : "PyObject *resultobj"); Wrapper_add_local(f, "varargs", "PyObject *varargs"); @@ -3207,10 +3280,10 @@ public: Printf(f->code, " Py_XINCREF(swig_obj[i + %d]);\n", num_fixed_arguments); Printf(f->code, "}\n"); } else { - Printf(f->code, "newargs = PyTuple_GetSlice(args,0,%d);\n", num_fixed_arguments); - Printf(f->code, "varargs = PyTuple_GetSlice(args,%d,PyTuple_Size(args));\n", num_fixed_arguments); + Printf(f->code, "newargs = PyTuple_GetSlice(args, 0, %d);\n", num_fixed_arguments); + Printf(f->code, "varargs = PyTuple_GetSlice(args, %d, PyTuple_Size(args));\n", num_fixed_arguments); } - Printf(f->code, "resultobj = %s__varargs__(%s,newargs,varargs);\n", wname, builtin ? "self" : "NULL"); + Printf(f->code, "resultobj = %s__varargs__(%s, newargs, varargs%s);\n", wname, builtin ? "self" : "NULL", strlen(builtin_kwargs) == 0 ? "" : ", kwargs"); Append(f->code, "Py_XDECREF(newargs);\n"); Append(f->code, "Py_XDECREF(varargs);\n"); Append(f->code, "return resultobj;\n"); @@ -3218,18 +3291,20 @@ public: Wrapper_print(f, f_wrappers); } + bool use_static_method = flat_static_method || !Swig_storage_isstatic_custom(n, "staticmemberfunctionHandler:storage"); /* Now register the function with the interpreter. */ if (!Getattr(n, "sym:overloaded")) { - if (!builtin_self) + if (!builtin_self && (use_static_method || !builtin)) add_method(iname, wname, allow_kwargs, n, funpack, num_required, num_arguments); /* Create a shadow for this function (if enabled and not in a member function) */ - if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER) && use_static_method) { emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, iname, allow_kwargs); } + } else { if (!Getattr(n, "sym:nextSibling")) { - dispatchFunction(n, linkage, funpack, builtin_self, builtin_ctor, director_class); + dispatchFunction(n, linkage, funpack, builtin_self, builtin_ctor, director_class, use_static_method); } } @@ -3300,7 +3375,7 @@ public: if (in_class && builtin) { /* Handle operator overloads for builtin types */ String *slot = Getattr(n, "feature:python:slot"); - if (slot) { + if (slot && !isfriend) { String *func_type = Getattr(n, "feature:python:slot:functype"); String *closure_decl = getClosure(func_type, wrapper_name, overname ? 0 : funpack); String *feature_name = NewStringf("feature:python:%s", slot); @@ -3382,15 +3457,14 @@ public: 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; - if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER)) { Printf(f_shadow_stubs, "%s = %s.%s\n", global_name, module, global_name); } } - int assignable = is_assignable(n); + int assignable = !is_immutable(n); if (!builtin && shadow && !assignable && !in_class) Printf(f_shadow_stubs, "%s = %s.%s\n", iname, global_name, iname); @@ -3410,8 +3484,6 @@ public: } Printf(setf->def, "SWIGINTERN int %s(PyObject *_val) {", varsetname); if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { - Replaceall(tm, "$source", "_val"); - Replaceall(tm, "$target", name); Replaceall(tm, "$input", "_val"); if (Getattr(n, "tmap:varin:implicitconv")) { Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); @@ -3452,8 +3524,6 @@ public: Append(getf->code, " (void)self;\n"); } if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { - Replaceall(tm, "$source", name); - Replaceall(tm, "$target", "pyobj"); Replaceall(tm, "$result", "pyobj"); addfail = emit_action_code(n, getf->code, tm); Delete(tm); @@ -3533,8 +3603,6 @@ public: } if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { - Replaceall(tm, "$source", value); - Replaceall(tm, "$target", name); Replaceall(tm, "$value", value); Printf(const_code, "%s,\n", tm); Delete(tm); @@ -3549,10 +3617,8 @@ public: } if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { - Replaceall(tm, "$source", value); - Replaceall(tm, "$target", name); Replaceall(tm, "$value", value); - if (needs_swigconstant(n) && !builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER)) && (!in_class || !Getattr(n, "feature:python:callback"))) { + if (needs_swigconstant(n) && !builtin && shadow && !(shadow & PYSHADOW_MEMBER) && (!in_class || !Getattr(n, "feature:python:callback"))) { // Generate `*_swigconstant()` method which registers the new constant. // // *_swigconstant methods are required for constants of class type. @@ -3562,7 +3628,7 @@ public: // class type (the SWIG_init() is called before shadow classes are // defined and registered). 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 *module;\n"); Printf(f_wrappers, tab2 "PyObject *d;\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"); @@ -3590,7 +3656,7 @@ public: return SWIG_NOWRAP; } - if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER)) { String *f_s; if (!in_class) { f_s = f_shadow; @@ -3825,11 +3891,7 @@ public: String *symname = Getattr(n, "sym:name"); String *mrename = Swig_name_disown(NSPACE_TODO, symname); //Getattr(n, "name")); Printv(f_shadow, tab4, "def __disown__(self):\n", NIL); -#ifdef USE_THISOWN - Printv(f_shadow, tab8, "self.thisown = 0\n", NIL); -#else 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); Delete(mrename); @@ -3868,40 +3930,45 @@ public: * classHandler() * ------------------------------------------------------------ */ - String *add_explicit_scope(String *s) { + SwigType *add_explicit_scope(SwigType *s) { if (!Strstr(s, "::")) { - String *ss = NewStringf("::%s", s); - Delete(s); - s = ss; + return NewStringf("::%s", s); } - return s; + return Copy(s); } void builtin_pre_decl(Node *n) { - String *name = Getattr(n, "name"); - String *rname = add_explicit_scope(SwigType_namestr(name)); - String *mname = SwigType_manglestr(rname); + SwigType *name = Getattr(n, "name"); + SwigType *sname = add_explicit_scope(name); + String *rname = SwigType_namestr(sname); + String *mname = SwigType_manglestr(sname); Printf(f_init, "\n/* type '%s' */\n", rname); Printf(f_init, " builtin_pytype = (PyTypeObject *)&SwigPyBuiltin_%s_type;\n", mname); Printf(f_init, " builtin_pytype->tp_dict = d = PyDict_New();\n"); + Delete(sname); Delete(rname); Delete(mname); } void builtin_post_decl(File *f, Node *n) { - String *name = Getattr(n, "name"); - String *pname = Copy(name); + SwigType *name = Getattr(n, "name"); + SwigType *pname = Copy(name); SwigType_add_pointer(pname); String *symname = Getattr(n, "sym:name"); - String *rname = add_explicit_scope(SwigType_namestr(name)); - String *mname = SwigType_manglestr(rname); + SwigType *sname = add_explicit_scope(name); + String *rname = SwigType_namestr(sname); + String *mname = SwigType_manglestr(sname); String *pmname = SwigType_manglestr(pname); String *templ = NewStringf("SwigPyBuiltin_%s", mname); int funpack = fastunpack; static String *tp_new = NewString("PyType_GenericNew"); + if (have_builtin_static_member_method_callback) { + Printf(f_init, " SWIG_Python_FixMethods(SwigPyBuiltin_%s_methods, swig_const_table, swig_types, swig_type_initial);\n", mname); + } + Printv(f_init, " SwigPyBuiltin_SetMetaType(builtin_pytype, metatype);\n", NIL); // We can’t statically initialize a structure member with a function defined in another C module @@ -3972,7 +4039,7 @@ public: if (GetFlag(mgetset, "static")) { Printf(f, "static PyGetSetDef %s_def = %s;\n", gspair, entry); Printf(f_init, "static_getset = SwigPyStaticVar_new_getset(metatype, &%s_def);\n", gspair); - Printf(f_init, "PyDict_SetItemString(d, static_getset->d_getset->name, (PyObject *) static_getset);\n", memname); + Printf(f_init, "PyDict_SetItemString(d, static_getset->d_getset->name, (PyObject *) static_getset);\n"); Printf(f_init, "Py_DECREF(static_getset);\n"); } else { Printf(getset_def, " %s,\n", entry); @@ -3995,15 +4062,17 @@ public: Printf(f, " PyTuple_SET_ITEM(tuple, 0, other);\n"); Printf(f, " Py_XINCREF(other);\n"); } - Iterator rich_iter = First(richcompare); + List *richcompare_list = SortedKeys(richcompare, 0); + Iterator rich_iter = First(richcompare_list); if (rich_iter.item) { Printf(f, " switch (op) {\n"); for (; rich_iter.item; rich_iter = Next(rich_iter)) - Printf(f, " case %s : result = %s(self, %s); break;\n", rich_iter.key, rich_iter.item, funpack ? "other" : "tuple"); + Printf(f, " case %s : result = %s(self, %s); break;\n", rich_iter.item, Getattr(richcompare, rich_iter.item), funpack ? "other" : "tuple"); Printv(f, " default : break;\n", NIL); Printf(f, " }\n"); } - Printv(f, " if (!result) {\n", NIL); + Delete(richcompare_list); + Printv(f, " if (!result && !PyErr_Occurred()) {\n", NIL); Printv(f, " if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) {\n", NIL); Printv(f, " result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op);\n", NIL); Printv(f, " } else {\n", NIL); @@ -4066,7 +4135,11 @@ public: printSlot(f, getSlot(n, "feature:python:tp_basicsize", tp_basicsize), "tp_basicsize"); printSlot(f, getSlot(n, "feature:python:tp_itemsize"), "tp_itemsize"); printSlot(f, getSlot(n, "feature:python:tp_dealloc", tp_dealloc_bad), "tp_dealloc", "destructor"); + Printv(f, "#if PY_VERSION_HEX < 0x030800b4\n", NIL); printSlot(f, getSlot(n, "feature:python:tp_print"), "tp_print", "printfunc"); + Printv(f, "#else\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_vectorcall_offset"), "tp_vectorcall_offset", "Py_ssize_t"); + Printv(f, "#endif\n", NIL); printSlot(f, getSlot(n, "feature:python:tp_getattr"), "tp_getattr", "getattrfunc"); printSlot(f, getSlot(n, "feature:python:tp_setattr"), "tp_setattr", "setattrfunc"); Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); @@ -4128,6 +4201,16 @@ public: 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); + Printv(f, "#if PY_VERSION_HEX >= 0x03080000\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_vectorcall"), "tp_vectorcall", "vectorcallfunc"); + Printv(f, "#endif\n", NIL); + Printv(f, "#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)\n", NIL); + printSlot(f, getSlot(), "tp_print"); + Printv(f, "#endif\n", NIL); + Printv(f, "#if PY_VERSION_HEX >= 0x030c0000\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_watched"), "tp_watched", "char"); + Printv(f, "#endif\n", NIL); + Printv(f, "#ifdef COUNT_ALLOCS\n", NIL); 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"); @@ -4143,6 +4226,9 @@ public: printSlot(f, getSlot(n, "feature:python:am_await"), "am_await", "unaryfunc"); printSlot(f, getSlot(n, "feature:python:am_aiter"), "am_aiter", "unaryfunc"); printSlot(f, getSlot(n, "feature:python:am_anext"), "am_anext", "unaryfunc"); + Printv(f, "# if PY_VERSION_HEX >= 0x030a0000\n", NIL); + printSlot(f, getSlot(n, "feature:python:am_send"), "am_send", "sendfunc"); + Printv(f, "# endif\n", NIL); Printf(f, " },\n"); Printv(f, "#endif\n", NIL); @@ -4255,18 +4341,38 @@ public: // struct _dictkeysobject *ht_cached_keys; printSlot(f, getSlot(n, "feature:python:ht_cached_keys"), "ht_cached_keys"); Printv(f, "#endif\n", NIL); + + // PyObject *ht_module; + Printv(f, "#if PY_VERSION_HEX >= 0x03090000\n", NIL); + printSlot(f, getSlot(n, "feature:python:ht_module"), "ht_module", "PyObject *"); + Printv(f, "#endif\n", NIL); + + // char *_ht_tpname; + Printv(f, "#if PY_VERSION_HEX >= 0x030b0000\n", NIL); + printSlot(f, getSlot(n, "feature:python:_ht_tpname"), "_ht_tpname", "char *"); + + // struct _specialization_cache _spec_cache; + Printf(f, " {\n"); + printSlot(f, getSlot(n, "feature:python:getitem"), "getitem", "PyObject *"); + Printv(f, "#if PY_VERSION_HEX >= 0x030c0000\n", NIL); + printSlot(f, getSlot(n, "feature:python:getitem_version"), "getitem_version", "uint32_t"); + Printv(f, "#endif\n", NIL); + Printf(f, " }\n"); + Printv(f, "#endif\n", NIL); Printf(f, "};\n\n"); String *clientdata = NewString(""); Printf(clientdata, "&%s_clientdata", templ); SwigType_remember_mangleddata(pmname, clientdata); - SwigType *smart = Swig_cparse_smartptr(n); + SwigType *smart = Getattr(n, "smart"); if (smart) { - SwigType_add_pointer(smart); - String *smart_pmname = SwigType_manglestr(smart); + SwigType *psmart = Copy(smart); + SwigType_add_pointer(psmart); + String *smart_pmname = SwigType_manglestr(psmart); SwigType_remember_mangleddata(smart_pmname, clientdata); Delete(smart_pmname); + Delete(psmart); } String *clientdata_klass = NewString("0"); @@ -4291,10 +4397,10 @@ public: Printv(f_init, " d = md;\n", NIL); Delete(clientdata); - Delete(smart); + Delete(sname); Delete(rname); - Delete(pname); Delete(mname); + Delete(pname); Delete(pmname); Delete(templ); Delete(tp_flags); @@ -4321,6 +4427,7 @@ public: /* Create new strings for building up a wrapper function */ have_constructor = 0; have_repr = 0; + have_builtin_static_member_method_callback = false; class_name = Getattr(n, "sym:name"); real_classname = Getattr(n, "name"); @@ -4378,10 +4485,9 @@ public: /* dealing with abstract base class */ String *abcs = Getattr(n, "feature:python:abc"); - if (py3 && abcs) { - if (Len(base_class)) { + if (abcs) { + if (Len(base_class) > 0) Printv(base_class, ", ", NIL); - } Printv(base_class, abcs, NIL); } @@ -4391,16 +4497,16 @@ public: Setattr(n, "feature:python:tp_doc", ds); Delete(ds); } else { - String *name = Getattr(n, "name"); - String *rname = add_explicit_scope(SwigType_namestr(name)); + SwigType *name = Getattr(n, "name"); + SwigType *sname = add_explicit_scope(name); + String *rname = SwigType_namestr(sname); Setattr(n, "feature:python:tp_doc", rname); + Delete(sname); Delete(rname); } } else { - if (!py3) { - if (GetFlag(n, "feature:python:nondynamic")) - Printv(f_shadow, "@_swig_add_metaclass(_SwigNonDynamicMeta)\n", NIL); - } + 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)) { @@ -4410,7 +4516,11 @@ public: Printf(f_shadow, "(Exception)"); } else { Printf(f_shadow, "(object"); - Printf(f_shadow, py3 && GetFlag(n, "feature:python:nondynamic") ? ", metaclass=_SwigNonDynamicMeta" : "", ")"); + /* Replace @_swig_add_metaclass above with below when support for python 2.7 is dropped + if (GetFlag(n, "feature:python:nondynamic")) { + Printf(f_shadow, ", metaclass=_SwigNonDynamicMeta"); + } + */ Printf(f_shadow, ")"); } } @@ -4464,7 +4574,7 @@ public: if (shadow) { /* Generate a class registration function */ // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) - SwigType *smart = Swig_cparse_smartptr(n); + SwigType *smart = Getattr(n, "smart"); SwigType *ct = Copy(smart ? smart : real_classname); SwigType_add_pointer(ct); SwigType *realct = Copy(real_classname); @@ -4486,7 +4596,6 @@ public: add_method(cname, cname, 0, 0, 1, 1, 1); Delete(cname); } - Delete(smart); Delete(ct); Delete(realct); if (!have_constructor) { @@ -4525,7 +4634,8 @@ public: } shadow_indent = 0; - Printf(f_shadow_file, "%s\n", f_shadow_stubs); + if (Len(f_shadow_stubs) > 0) + Printf(f_shadow_file, "%s\n", f_shadow_stubs); Clear(f_shadow_stubs); } @@ -4681,6 +4791,7 @@ public: Swig_restore(n); } + int kw = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; if (builtin && in_class) { if ((GetFlagAttr(n, "feature:extend") || checkAttribute(n, "access", "public")) && !Getattr(class_members, symname)) { @@ -4695,7 +4806,7 @@ public: else if (funpack && argcount == 1) Append(pyflags, "METH_O"); else - Append(pyflags, "METH_VARARGS"); + Append(pyflags, kw ? "METH_VARARGS|METH_KEYWORDS" : "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. @@ -4703,6 +4814,11 @@ public: String *ds = cdocstring(n, AUTODOC_STATICFUNC); Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"%s\" },\n", symname, wname, pyflags, ds); Delete(ds); + } else if (Getattr(n, "feature:callback")) { + String *ds = NewStringf("swig_ptr: %s", Getattr(n, "feature:callback:name")); + Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"%s\" },\n", symname, wname, pyflags, ds); + Delete(ds); + have_builtin_static_member_method_callback = true; } else { Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"\" },\n", symname, wname, pyflags); } @@ -4721,7 +4837,6 @@ public: 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); @@ -4818,6 +4933,7 @@ public: String *classname = Swig_class_name(parent); String *rclassname = Swig_class_name(getCurrentClass()); assert(rclassname); + (void)rclassname; String *parms = make_pyParmList(n, true, false, allow_kwargs); /* Pass 'self' only if using director */ @@ -4865,9 +4981,6 @@ public: 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); -#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); @@ -4923,12 +5036,6 @@ public: Printv(f_shadow, tab8, docstring(n, AUTODOC_DTOR, tab8), "\n", NIL); if (have_pythonprepend(n)) Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); -#ifdef USE_THISOWN - Printv(f_shadow, tab8, "try:\n", NIL); - Printv(f_shadow, tab8, tab4, "if self.thisown:", module, ".", Swig_name_destroy(NSPACE_TODO, symname), "(self)\n", NIL); - Printv(f_shadow, tab8, "except __builtin__.Exception: pass\n", NIL); -#else -#endif if (have_pythonappend(n)) Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); Printv(f_shadow, tab8, "pass\n", NIL); @@ -4955,13 +5062,18 @@ public: String *mname = Swig_name_member(NSPACE_TODO, class_name, symname); String *setname = Swig_name_set(NSPACE_TODO, mname); String *getname = Swig_name_get(NSPACE_TODO, mname); - int assignable = is_assignable(n); - Printv(f_shadow, tab4, symname, " = property(", module, ".", getname, NIL); + int assignable = !is_immutable(n); + String *variable_annotation = variableAnnotation(n); + Printv(f_shadow, tab4, symname, variable_annotation, " = 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); + if (have_docstring(n)) { + String *s = docstring(n, AUTODOC_VAR, tab4); + if (Len(s)) + Printv(f_shadow, ", doc=", s, NIL); + } Printv(f_shadow, ")\n", NIL); + Delete(variable_annotation); Delete(mname); Delete(setname); Delete(getname); @@ -5005,7 +5117,7 @@ public: add_method(getname, wrapgetname, 0); Wrapper_print(f, f_wrappers); DelWrapper(f); - int assignable = is_assignable(n); + int assignable = !is_immutable(n); if (assignable) { int funpack = fastunpack; Wrapper *f = NewWrapper(); @@ -5026,8 +5138,11 @@ public: 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); + if (have_docstring(n)) { + String *s = docstring(n, AUTODOC_VAR, tab4); + if (Len(s)) + Printv(f_shadow, ", doc=", s, NIL); + } Printv(f_shadow, ")\n", NIL); } String *getter = Getattr(n, "pybuiltin:getter"); @@ -5336,14 +5451,6 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { continue; } - /* old style? caused segfaults without the p!=0 check - in the for() condition, and seems dangerous in the - while loop as well. - while (Getattr(p, "tmap:ignore")) { - p = Getattr(p, "tmap:ignore:next"); - } - */ - if (Getattr(p, "tmap:directorargout") != 0) outputs++; |