Browse Source

interrogate: nullptr handling, faster kwargs handling in some cases

rdb 8 years ago
parent
commit
a387fb9f35

+ 23 - 6
dtool/src/interrogate/functionRemap.cxx

@@ -869,8 +869,14 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       }
       }
 
 
       if (_args_type == InterfaceMaker::AT_varargs) {
       if (_args_type == InterfaceMaker::AT_varargs) {
-        // Of course methods named "make" can still take kwargs.
-        _args_type = InterfaceMaker::AT_keyword_args;
+        // Of course methods named "make" can still take kwargs, if they are
+        // named.
+        for (int i = first_param; i < _parameters.size(); ++i) {
+          if (_parameters[i]._has_name) {
+            _args_type = InterfaceMaker::AT_keyword_args;
+            break;
+          }
+        }
       }
       }
 
 
     } else if (fname == "operator /") {
     } else if (fname == "operator /") {
@@ -898,8 +904,13 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     } else {
     } else {
       if (_args_type == InterfaceMaker::AT_varargs) {
       if (_args_type == InterfaceMaker::AT_varargs) {
         // Every other method can take keyword arguments, if they take more
         // Every other method can take keyword arguments, if they take more
-        // than one argument.
-        _args_type |= InterfaceMaker::AT_keyword_args;
+        // than one argument, and the arguments are named.
+        for (int i = first_param; i < _parameters.size(); ++i) {
+          if (_parameters[i]._has_name) {
+            _args_type |= InterfaceMaker::AT_keyword_args;
+            break;
+          }
+        }
       }
       }
     }
     }
     break;
     break;
@@ -941,8 +952,14 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       _flags |= F_coerce_constructor;
       _flags |= F_coerce_constructor;
     }
     }
 
 
-    // Constructors always take varargs and keyword args.
-    _args_type = InterfaceMaker::AT_keyword_args;
+    // Constructors always take varargs, and possibly keyword args.
+    _args_type = InterfaceMaker::AT_varargs;
+    for (int i = first_param; i < _parameters.size(); ++i) {
+      if (_parameters[i]._has_name) {
+        _args_type = InterfaceMaker::AT_keyword_args;
+        break;
+      }
+    }
     break;
     break;
 
 
   default:
   default:

+ 204 - 68
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -3389,6 +3389,7 @@ write_function_for_name(ostream &out, Object *obj,
   FunctionRemap *remap = NULL;
   FunctionRemap *remap = NULL;
   int max_required_args = 0;
   int max_required_args = 0;
   bool all_nonconst = true;
   bool all_nonconst = true;
+  bool has_keywords = false;
 
 
   out << "/**\n * Python function wrapper for:\n";
   out << "/**\n * Python function wrapper for:\n";
   for (ri = remaps.begin(); ri != remaps.end(); ++ri) {
   for (ri = remaps.begin(); ri != remaps.end(); ++ri) {
@@ -3404,6 +3405,10 @@ write_function_for_name(ostream &out, Object *obj,
         all_nonconst = false;
         all_nonconst = false;
       }
       }
 
 
+      if (remap->_args_type == AT_keyword_args) {
+        has_keywords = true;
+      }
+
       max_required_args = max(max_num_args, max_required_args);
       max_required_args = max(max_num_args, max_required_args);
 
 
       for (int i = min_num_args; i <= max_num_args; ++i) {
       for (int i = min_num_args; i <= max_num_args; ++i) {
@@ -3450,6 +3455,19 @@ write_function_for_name(ostream &out, Object *obj,
     return;
     return;
   }
   }
 
 
+  if (args_type == AT_keyword_args && !has_keywords) {
+    // We don't actually take keyword arguments.  Make sure we didn't get any.
+    out << "  if (kwds != NULL && PyDict_Size(kwds) > 0) {\n";
+    out << "#ifdef NDEBUG\n";
+    error_raise_return(out, 4, return_flags, "TypeError", "function takes no keyword arguments");
+    out << "#else\n";
+    error_raise_return(out, 4, return_flags, "TypeError",
+      methodNameFromCppName(remap, "", false) + "() takes no keyword arguments");
+    out << "#endif\n";
+    out << "  }\n";
+    args_type = AT_varargs;
+  }
+
   if (args_type == AT_keyword_args || args_type == AT_varargs) {
   if (args_type == AT_keyword_args || args_type == AT_varargs) {
     max_required_args = collapse_default_remaps(map_sets, max_required_args);
     max_required_args = collapse_default_remaps(map_sets, max_required_args);
   }
   }
@@ -3461,6 +3479,7 @@ write_function_for_name(ostream &out, Object *obj,
                             args_type, return_flags);
                             args_type, return_flags);
 
 
   } else if (map_sets.size() > 1 && (args_type == AT_varargs || args_type == AT_keyword_args)) {
   } else if (map_sets.size() > 1 && (args_type == AT_varargs || args_type == AT_keyword_args)) {
+    // We have more than one remap.
     switch (args_type) {
     switch (args_type) {
     case AT_keyword_args:
     case AT_keyword_args:
       indent(out, 2) << "int parameter_count = (int)PyTuple_Size(args);\n";
       indent(out, 2) << "int parameter_count = (int)PyTuple_Size(args);\n";
@@ -3498,16 +3517,50 @@ write_function_for_name(ostream &out, Object *obj,
         indent(out, 2) << "case " << i << ":\n";
         indent(out, 2) << "case " << i << ":\n";
         num_args.insert(i + add_self);
         num_args.insert(i + add_self);
       }
       }
-      indent(out, 4) << "{\n";
       num_args.insert(max_args + add_self);
       num_args.insert(max_args + add_self);
 
 
-      if (min_args == 1 && max_args == 1 && args_type == AT_varargs) {
-        // Might as well, since we already checked the number of args.
-        indent(out, 6) << "  PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
+      bool strip_keyword_args = false;
+
+      // Check whether any remap actually takes keyword arguments.  If not,
+      // then we don't have to bother checking that for every remap.
+      if (args_type == AT_keyword_args && max_args > 0) {
+        strip_keyword_args = true;
+
+        std::set<FunctionRemap *>::iterator sii;
+        for (sii = mii->second.begin(); sii != mii->second.end(); ++sii) {
+          remap = (*sii);
+          int first_param = remap->_has_this ? 1 : 0;
+          for (int i = first_param; i < remap->_parameters.size(); ++i) {
+            if (remap->_parameters[i]._has_name) {
+              strip_keyword_args = false;
+              break;
+            }
+          }
+        }
+      }
+
+      if (strip_keyword_args) {
+        // None of the remaps take any keyword arguments, so let's check that
+        // we take none.  This saves some checks later on.
+        indent(out, 4) << "if (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0) {\n";
+        if (min_args == 1 && min_args == 1) {
+          indent(out, 4) << "  PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
+          write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
+                coercion_allowed, true, AT_single_arg, return_flags, true, !all_nonconst);
+        } else {
+          write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
+                coercion_allowed, true, AT_varargs, return_flags, true, !all_nonconst);
+        }
+      } else if (min_args == 1 && max_args == 1 && args_type == AT_varargs) {
+        // We already checked that the args tuple has only one argument, so
+        // we might as well extract that from the tuple now.
+        indent(out, 4) << "{\n";
+        indent(out, 4) << "  PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
 
 
         write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
         write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
                       coercion_allowed, true, AT_single_arg, return_flags, true, !all_nonconst);
                       coercion_allowed, true, AT_single_arg, return_flags, true, !all_nonconst);
       } else {
       } else {
+        indent(out, 4) << "{\n";
         write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
         write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
                       coercion_allowed, true, args_type, return_flags, true, !all_nonconst);
                       coercion_allowed, true, args_type, return_flags, true, !all_nonconst);
       }
       }
@@ -3574,14 +3627,14 @@ write_function_for_name(ostream &out, Object *obj,
     if (mii->first == 0 && args_type != AT_no_args) {
     if (mii->first == 0 && args_type != AT_no_args) {
       switch (args_type) {
       switch (args_type) {
       case AT_keyword_args:
       case AT_keyword_args:
-        out << "  if (PyTuple_Size(args) > 0 || (kwds != NULL && PyDict_Size(kwds) > 0)) {\n";
+        out << "  if (!Dtool_CheckNoArgs(args, kwds)) {\n";
         out << "    int parameter_count = (int)PyTuple_Size(args);\n";
         out << "    int parameter_count = (int)PyTuple_Size(args);\n";
         out << "    if (kwds != NULL) {\n";
         out << "    if (kwds != NULL) {\n";
         out << "      parameter_count += (int)PyDict_Size(kwds);\n";
         out << "      parameter_count += (int)PyDict_Size(kwds);\n";
         out << "    }\n";
         out << "    }\n";
         break;
         break;
       case AT_varargs:
       case AT_varargs:
-        out << "  if (PyTuple_Size(args) > 0) {\n";
+        out << "  if (!Dtool_CheckNoArgs(args)) {\n";
         out << "    const int parameter_count = (int)PyTuple_GET_SIZE(args);\n";
         out << "    const int parameter_count = (int)PyTuple_GET_SIZE(args);\n";
         break;
         break;
       case AT_single_arg:
       case AT_single_arg:
@@ -3607,14 +3660,14 @@ write_function_for_name(ostream &out, Object *obj,
     } else if (args_type == AT_keyword_args && max_required_args == 1 && mii->first == 1) {
     } else if (args_type == AT_keyword_args && max_required_args == 1 && mii->first == 1) {
       // Check this to be sure, as we handle the case of only 1 keyword arg in
       // Check this to be sure, as we handle the case of only 1 keyword arg in
       // write_function_forset (not using ParseTupleAndKeywords).
       // write_function_forset (not using ParseTupleAndKeywords).
-      out << "    int parameter_count = (int)PyTuple_Size(args);\n"
-             "    if (kwds != NULL) {\n"
-             "      parameter_count += (int)PyDict_Size(kwds);\n"
-             "    }\n"
+      out << "  int parameter_count = (int)PyTuple_Size(args);\n"
+             "  if (kwds != NULL) {\n"
+             "    parameter_count += (int)PyDict_Size(kwds);\n"
+             "  }\n"
              "  if (parameter_count != 1) {\n"
              "  if (parameter_count != 1) {\n"
              "#ifdef NDEBUG\n";
              "#ifdef NDEBUG\n";
       error_raise_return(out, 4, return_flags, "TypeError",
       error_raise_return(out, 4, return_flags, "TypeError",
-                         "function takes exactly 1 argument");
+                        "function takes exactly 1 argument");
       out << "#else\n";
       out << "#else\n";
       error_raise_return(out, 4, return_flags, "TypeError",
       error_raise_return(out, 4, return_flags, "TypeError",
         methodNameFromCppName(remap, "", false) + "() takes exactly 1 argument (%d given)",
         methodNameFromCppName(remap, "", false) + "() takes exactly 1 argument (%d given)",
@@ -4067,7 +4120,9 @@ int get_type_sort(CPPType *type) {
 // printf("    %s\n",type->get_local_name().c_str());
 // printf("    %s\n",type->get_local_name().c_str());
 
 
   // The highest numbered one will be checked first.
   // The highest numbered one will be checked first.
-  if (TypeManager::is_pointer_to_Py_buffer(type)) {
+  if (TypeManager::is_nullptr(type)) {
+    return 15;
+  } else if (TypeManager::is_pointer_to_Py_buffer(type)) {
     return 14;
     return 14;
   } else if (TypeManager::is_pointer_to_PyTypeObject(type)) {
   } else if (TypeManager::is_pointer_to_PyTypeObject(type)) {
     return 13;
     return 13;
@@ -4247,14 +4302,16 @@ write_function_forset(ostream &out,
       args_type == AT_keyword_args) {
       args_type == AT_keyword_args) {
     sii = remapsin.begin();
     sii = remapsin.begin();
     remap = (*sii);
     remap = (*sii);
-    first_param_name = remap->_parameters[(int)remap->_has_this]._name;
-    same_first_param = true;
+    if (remap->_parameters[(int)remap->_has_this]._has_name) {
+      first_param_name = remap->_parameters[(int)remap->_has_this]._name;
+      same_first_param = true;
 
 
-    for (++sii; sii != remapsin.end(); ++sii) {
-      remap = (*sii);
-      if (remap->_parameters[(int)remap->_has_this]._name != first_param_name) {
-        same_first_param = false;
-        break;
+      for (++sii; sii != remapsin.end(); ++sii) {
+        remap = (*sii);
+        if (remap->_parameters[(int)remap->_has_this]._name != first_param_name) {
+          same_first_param = false;
+          break;
+        }
       }
       }
     }
     }
   }
   }
@@ -4263,21 +4320,9 @@ write_function_forset(ostream &out,
     // Yes, they all have the same argument name (or there is only one remap).
     // Yes, they all have the same argument name (or there is only one remap).
     // Extract it from the dict so we don't have to call
     // Extract it from the dict so we don't have to call
     // ParseTupleAndKeywords.
     // ParseTupleAndKeywords.
-    indent(out, indent_level) << "PyObject *arg = NULL;\n";
-    indent(out, indent_level) << "if (PyTuple_GET_SIZE(args) == 1) {\n";
-    indent(out, indent_level) << "  arg = PyTuple_GET_ITEM(args, 0);\n";
-    indent(out, indent_level) << "} else if (kwds != NULL) {\n";
-    indent(out, indent_level) << "  arg = PyDict_GetItemString(kwds, \"" << first_param_name << "\");\n";
-    indent(out, indent_level) << "}\n";
-    if (report_errors) {
-      indent(out, indent_level) << "if (arg == (PyObject *)NULL) {\n";
-      error_raise_return(out, indent_level + 2, return_flags, "TypeError",
-        "Required argument '" + first_param_name + "' (pos 1) not found");
-      indent(out, indent_level) << "}\n";
-    } else {
-      indent(out, indent_level) << "if (arg != (PyObject *)NULL) {\n";
-      indent_level += 2;
-    }
+    indent(out, indent_level) << "PyObject *arg;\n";
+    indent(out, indent_level) << "if (Dtool_ExtractArg(&arg, args, kwds, \"" << first_param_name << "\")) {\n";
+    indent_level += 2;
     args_type = AT_single_arg;
     args_type = AT_single_arg;
   }
   }
 
 
@@ -4448,7 +4493,7 @@ write_function_forset(ostream &out,
   }
   }
 
 
   // Close the brace we opened earlier.
   // Close the brace we opened earlier.
-  if (same_first_param && !report_errors) {
+  if (same_first_param) {
     indent_level -= 2;
     indent_level -= 2;
     indent(out, indent_level) << "}\n";
     indent(out, indent_level) << "}\n";
   }
   }
@@ -4517,6 +4562,8 @@ write_function_instance(ostream &out, FunctionRemap *remap,
   string parameter_list;
   string parameter_list;
   string container;
   string container;
   string type_check;
   string type_check;
+  string param_name;
+  bool has_keywords = false;
   vector_string pexprs;
   vector_string pexprs;
   LineStream extra_convert;
   LineStream extra_convert;
   ostringstream extra_param_check;
   ostringstream extra_param_check;
@@ -4612,7 +4659,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     CPPType *orig_type = param->get_orig_type();
     CPPType *orig_type = param->get_orig_type();
     CPPType *type = param->get_new_type();
     CPPType *type = param->get_new_type();
     CPPExpression *default_value = param->get_default_value();
     CPPExpression *default_value = param->get_default_value();
-    string param_name = remap->get_parameter_name(pn);
+    param_name = remap->get_parameter_name(pn);
 
 
     if (!is_cpp_type_legal(orig_type)) {
     if (!is_cpp_type_legal(orig_type)) {
       // We can't wrap this.  We sometimes get here for default arguments.
       // We can't wrap this.  We sometimes get here for default arguments.
@@ -4667,7 +4714,14 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     }
     }
 
 
     string reported_name = remap->_parameters[pn]._name;
     string reported_name = remap->_parameters[pn]._name;
-    keyword_list += "\"" + reported_name + "\", ";
+    if (!keyword_list.empty()) {
+      keyword_list += ", \"" + reported_name + "\"";
+    } else {
+      keyword_list = "\"" + reported_name + "\"";
+    }
+    if (remap->_parameters[pn]._has_name) {
+      has_keywords = true;
+    }
 
 
     if (param->new_type_is_atomic_string()) {
     if (param->new_type_is_atomic_string()) {
 
 
@@ -4869,6 +4923,19 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       pexpr_string = "(PyObject_IsTrue(" + param_name + ") != 0)";
       pexpr_string = "(PyObject_IsTrue(" + param_name + ") != 0)";
       expected_params += "bool";
       expected_params += "bool";
 
 
+    } else if (TypeManager::is_nullptr(type)) {
+      if (args_type == AT_single_arg) {
+        type_check = "arg == Py_None";
+        param_name = "arg";
+      } else {
+        indent(out, indent_level) << "PyObject *" << param_name << default_expr << ";\n";
+        extra_param_check << " && " << param_name << " == Py_None";
+        format_specifiers += "O";
+        parameter_list += ", &" + param_name;
+      }
+      pexpr_string = "NULL";
+      expected_params += "NoneType";
+
     } else if (TypeManager::is_char(type)) {
     } else if (TypeManager::is_char(type)) {
       indent(out, indent_level) << "char " << param_name << default_expr << ";\n";
       indent(out, indent_level) << "char " << param_name << default_expr << ";\n";
 
 
@@ -4907,26 +4974,42 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       only_pyobjects = false;
       only_pyobjects = false;
 
 
     } else if (TypeManager::is_size(type)) {
     } else if (TypeManager::is_size(type)) {
-      // It certainly isn't the exact same thing as size_t, but Py_ssize_t
-      // should at least be the same size.  The problem with mapping this to
-      // unsigned int is that that doesn't work well on 64-bit systems, on
-      // which size_t is a 64-bit integer.
-      indent(out, indent_level) << "Py_ssize_t " << param_name << default_expr << ";\n";
-      format_specifiers += "n";
-      parameter_list += ", &" + param_name;
-      expected_params += "int";
-      only_pyobjects = false;
+      if (args_type == AT_single_arg) {
+        type_check = "PyLongOrInt_Check(arg)";
 
 
-      extra_convert
-        << "#ifndef NDEBUG\n"
-        << "if (" << param_name << " < 0) {\n";
+        extra_convert <<
+          "size_t arg_val = PyLongOrInt_AsSize_t(arg);\n"
+          "#ifndef NDEBUG\n"
+          "if (arg_val == (size_t)-1 && _PyErr_OCCURRED()) {\n";
+        error_return(extra_convert, 2, return_flags);
+        extra_convert <<
+          "}\n"
+          "#endif\n";
 
 
-      error_raise_return(extra_convert, 2, return_flags, "OverflowError",
-                         "can't convert negative value %zd to size_t",
-                         param_name);
-      extra_convert
-        << "}\n"
-        << "#endif\n";
+        pexpr_string = "arg_val";
+
+      } else {
+        // It certainly isn't the exact same thing as size_t, but Py_ssize_t
+        // should at least be the same size.  The problem with mapping this to
+        // unsigned int is that that doesn't work well on 64-bit systems, on
+        // which size_t is a 64-bit integer.
+        indent(out, indent_level) << "Py_ssize_t " << param_name << default_expr << ";\n";
+        format_specifiers += "n";
+        parameter_list += ", &" + param_name;
+
+        extra_convert
+          << "#ifndef NDEBUG\n"
+          << "if (" << param_name << " < 0) {\n";
+
+        error_raise_return(extra_convert, 2, return_flags, "OverflowError",
+                          "can't convert negative value %zd to size_t",
+                          param_name);
+        extra_convert
+          << "}\n"
+          << "#endif\n";
+      }
+      expected_params += "int";
+      only_pyobjects = false;
 
 
     } else if (TypeManager::is_longlong(type)) {
     } else if (TypeManager::is_longlong(type)) {
       // It's not trivial to do overflow checking for a long long, so we
       // It's not trivial to do overflow checking for a long long, so we
@@ -5555,15 +5638,60 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     switch (args_type) {
     switch (args_type) {
     case AT_keyword_args:
     case AT_keyword_args:
       // Wrapper takes a varargs tuple and a keyword args dict.
       // Wrapper takes a varargs tuple and a keyword args dict.
-      indent(out, indent_level)
-        << "static const char *keyword_list[] = {" << keyword_list << "NULL};\n";
-      indent(out, indent_level)
-        << "if (PyArg_ParseTupleAndKeywords(args, kwds, \""
-        << format_specifiers << ":" << method_name
-        << "\", (char **)keyword_list" << parameter_list << ")) {\n";
+      if (has_keywords) {
+        if (only_pyobjects && max_num_args == 1) {
+          // But we are only expecting one object arg, which is an easy common
+          // case we have implemented ourselves.
+          if (min_num_args == 1) {
+            indent(out, indent_level)
+              << "if (Dtool_ExtractArg(&" << param_name << ", args, kwds, " << keyword_list << ")) {\n";
+          } else {
+            indent(out, indent_level)
+              << "if (Dtool_ExtractOptionalArg(&" << param_name << ", args, kwds, " << keyword_list << ")) {\n";
+          }
+        } else {
+          // We have to use the more expensive PyArg_ParseTupleAndKeywords.
+          clear_error = true;
+          indent(out, indent_level)
+            << "static const char *keyword_list[] = {" << keyword_list << ", NULL};\n";
+          indent(out, indent_level)
+            << "if (PyArg_ParseTupleAndKeywords(args, kwds, \""
+            << format_specifiers << ":" << method_name
+            << "\", (char **)keyword_list" << parameter_list << ")) {\n";
+        }
+
+      } else if (only_pyobjects) {
+        // This function actually has no named parameters, so let's not take
+        // any keyword arguments.
+        if (max_num_args == 1) {
+          if (min_num_args == 1) {
+            indent(out, indent_level)
+              << "if (Dtool_ExtractArg(&" << param_name << ", args, kwds)) {\n";
+          } else {
+            indent(out, indent_level)
+              << "if (Dtool_ExtractOptionalArg(&" << param_name << ", args, kwds)) {\n";
+          }
+        } else if (max_num_args == 0) {
+          indent(out, indent_level)
+            << "if (Dtool_CheckNoArgs(args, kwds)) {\n";
+        } else {
+          clear_error = true;
+          indent(out, indent_level)
+            << "if ((kwds == NULL || PyDict_Size(kwds) == 0) && PyArg_UnpackTuple(args, \""
+            << methodNameFromCppName(remap, "", false)
+            << "\", " << min_num_args << ", " << max_num_args
+            << parameter_list << ")) {\n";
+        }
+
+      } else {
+        clear_error = true;
+        indent(out, indent_level)
+          << "if ((kwds == NULL || PyDict_Size(kwds) == 0) && PyArg_ParseTuple(args, \""
+          << format_specifiers << ":" << method_name
+          << "\"" << parameter_list << ")) {\n";
+      }
 
 
       ++open_scopes;
       ++open_scopes;
-      clear_error = true;
       indent_level += 2;
       indent_level += 2;
       break;
       break;
 
 
@@ -5572,20 +5700,28 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       if (only_pyobjects) {
       if (only_pyobjects) {
         // All parameters are PyObject*, so we can use the slightly more
         // All parameters are PyObject*, so we can use the slightly more
         // efficient PyArg_UnpackTuple function instead.
         // efficient PyArg_UnpackTuple function instead.
-        indent(out, indent_level)
-          << "if (PyArg_UnpackTuple(args, \""
-          << methodNameFromCppName(remap, "", false)
-          << "\", " << min_num_args << ", " << max_num_args
-          << parameter_list << ")) {\n";
+        if (min_num_args == 1 && max_num_args == 1) {
+          indent(out, indent_level)
+            << "if (PyTuple_GET_SIZE(args) == 1) {\n";
+          indent(out, indent_level + 2)
+            << param_name << " = PyTuple_GET_ITEM(args, 0);\n";
+        } else {
+          clear_error = true;
+          indent(out, indent_level)
+            << "if (PyArg_UnpackTuple(args, \""
+            << methodNameFromCppName(remap, "", false)
+            << "\", " << min_num_args << ", " << max_num_args
+            << parameter_list << ")) {\n";
+        }
 
 
       } else {
       } else {
+        clear_error = true;
         indent(out, indent_level)
         indent(out, indent_level)
           << "if (PyArg_ParseTuple(args, \""
           << "if (PyArg_ParseTuple(args, \""
           << format_specifiers << ":" << method_name
           << format_specifiers << ":" << method_name
           << "\"" << parameter_list << ")) {\n";
           << "\"" << parameter_list << ")) {\n";
       }
       }
       ++open_scopes;
       ++open_scopes;
-      clear_error = true;
       indent_level += 2;
       indent_level += 2;
       break;
       break;
 
 

+ 4 - 0
dtool/src/interrogate/interrogateBuilder.cxx

@@ -2346,6 +2346,10 @@ define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype) {
     itype._atomic_token = AT_void;
     itype._atomic_token = AT_void;
     break;
     break;
 
 
+  case CPPSimpleType::T_nullptr:
+    itype._atomic_token = AT_null;
+    break;
+
   default:
   default:
     nout << "Type \"" << *cpptype << "\" has invalid CPPSimpleType: "
     nout << "Type \"" << *cpptype << "\" has invalid CPPSimpleType: "
          << (int)cpptype->_type << "\n";
          << (int)cpptype->_type << "\n";

+ 21 - 0
dtool/src/interrogate/typeManager.cxx

@@ -364,6 +364,27 @@ is_const_ref_to_enum(CPPType *type) {
   }
   }
 }
 }
 
 
+/**
+ * Returns true if the indicated type is nullptr_t, possibly const or a
+ * typedef to it.
+ */
+bool TypeManager::
+is_nullptr(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_simple:
+    return type->as_simple_type()->_type == CPPSimpleType::T_nullptr;
+
+  case CPPDeclaration::ST_const:
+    return is_nullptr(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_typedef:
+    return is_nullptr(type->as_typedef_type()->_type);
+
+  default:
+    return false;
+  }
+}
+
 /**
 /**
  * Returns true if the indicated type is something that a scripting language
  * Returns true if the indicated type is something that a scripting language
  * can handle directly as a concrete, like an int or float, either const or
  * can handle directly as a concrete, like an int or float, either const or

+ 1 - 0
dtool/src/interrogate/typeManager.h

@@ -55,6 +55,7 @@ public:
   static bool is_enum(CPPType *type);
   static bool is_enum(CPPType *type);
   static bool is_const_enum(CPPType *type);
   static bool is_const_enum(CPPType *type);
   static bool is_const_ref_to_enum(CPPType *type);
   static bool is_const_ref_to_enum(CPPType *type);
+  static bool is_nullptr(CPPType *type);
   static bool is_simple(CPPType *type);
   static bool is_simple(CPPType *type);
   static bool is_const_simple(CPPType *type);
   static bool is_const_simple(CPPType *type);
   static bool is_const_ref_to_simple(CPPType *type);
   static bool is_const_ref_to_simple(CPPType *type);

+ 5 - 1
dtool/src/interrogatedb/interrogate_interface.h

@@ -82,7 +82,11 @@ enum AtomicToken {
   // string means whatever the native string representation is.
   // string means whatever the native string representation is.
   AT_string = 7,
   AT_string = 7,
 
 
-  AT_longlong = 8
+  AT_longlong = 8,
+
+  // This is not a type that C has, but C++ and many scripting languages do;
+  // it indicates a null value, or the absence of any value.
+  AT_null = 9,
 };
 };
 
 
 EXPCL_INTERROGATEDB void interrogate_add_search_directory(const char *dirname);
 EXPCL_INTERROGATEDB void interrogate_add_search_directory(const char *dirname);

+ 22 - 0
dtool/src/interrogatedb/py_panda.I

@@ -59,6 +59,23 @@ DTool_CreatePyInstanceTyped(T *obj, bool memory_rules) {
   return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, false, obj->get_type().get_index());
   return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, false, obj->get_type().get_index());
 }
 }
 
 
+/**
+ * Checks that the tuple is empty.
+ */
+ALWAYS_INLINE bool
+Dtool_CheckNoArgs(PyObject *args) {
+  return PyTuple_GET_SIZE(args) == 0;
+}
+
+/**
+ * Checks that the tuple is empty, and that the dict is empty or NULL.
+ */
+ALWAYS_INLINE bool
+Dtool_CheckNoArgs(PyObject *args, PyObject *kwds) {
+  return PyTuple_GET_SIZE(args) == 0 &&
+    (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0);
+}
+
 /**
 /**
  * The following functions wrap an arbitrary C++ value into a PyObject.
  * The following functions wrap an arbitrary C++ value into a PyObject.
  */
  */
@@ -196,6 +213,11 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value) {
   return PyUnicode_FromWideChar(&value, 1);
   return PyUnicode_FromWideChar(&value, 1);
 }
 }
 
 
+ALWAYS_INLINE PyObject *Dtool_WrapValue(nullptr_t) {
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
 ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value) {
 ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value) {
   return value;
   return value;
 }
 }

+ 165 - 8
dtool/src/interrogatedb/py_panda.cxx

@@ -31,6 +31,49 @@ static RuntimeTypeMap runtime_type_map;
 static RuntimeTypeSet runtime_type_set;
 static RuntimeTypeSet runtime_type_set;
 static NamedTypeMap named_type_map;
 static NamedTypeMap named_type_map;
 
 
+#if PY_MAJOR_VERSION < 3
+/**
+ * Given a long or int, returns a size_t, or raises an OverflowError if it is
+ * out of range.
+ */
+size_t PyLongOrInt_AsSize_t(PyObject *vv) {
+  if (PyInt_Check(vv)) {
+    long value = PyInt_AS_LONG(vv);
+    if (value < 0) {
+      PyErr_SetString(PyExc_OverflowError,
+                      "can't convert negative value to size_t");
+      return (size_t)-1;
+    }
+    return (size_t)value;
+  }
+
+  if (!PyLong_Check(vv)) {
+    PyErr_BadInternalCall();
+    return (size_t)-1;
+  }
+
+  size_t bytes;
+  int one = 1;
+  int res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes,
+                                SIZEOF_SIZE_T, (int)*(unsigned char*)&one, 0);
+
+  if (res < 0) {
+    return (size_t)res;
+  } else {
+    return bytes;
+  }
+}
+#endif
+
+#if PY_VERSION_HEX < 0x03060000
+INLINE static PyObject *_PyObject_CallNoArg(PyObject *func) {
+  PyObject *args = PyTuple_New(0);
+  PyObject *result = PyObject_Call(func, args, NULL);
+  Py_DECREF(args);
+  return result;
+}
+#endif
+
 /**
 /**
  * Given a valid (non-NULL) PyObject, does a simple check to see if it might
  * Given a valid (non-NULL) PyObject, does a simple check to see if it might
  * be an instance of a Panda type.  It does this using a signature that is
  * be an instance of a Panda type.  It does this using a signature that is
@@ -767,12 +810,16 @@ int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2) {
   if (func == NULL) {
   if (func == NULL) {
     PyErr_Clear();
     PyErr_Clear();
   } else {
   } else {
+#if PY_VERSION_HEX >= 0x03060000
+    PyObject *res = _PyObject_FastCall(func, &v2, 1);
+#else
     PyObject *res = NULL;
     PyObject *res = NULL;
     PyObject *args = PyTuple_Pack(1, v2);
     PyObject *args = PyTuple_Pack(1, v2);
     if (args != NULL) {
     if (args != NULL) {
       res = PyObject_Call(func, args, NULL);
       res = PyObject_Call(func, args, NULL);
       Py_DECREF(args);
       Py_DECREF(args);
     }
     }
+#endif
     Py_DECREF(func);
     Py_DECREF(func);
     PyErr_Clear(); // just in case the function threw an error
     PyErr_Clear(); // just in case the function threw an error
     // only use if the function returns an INT... hmm
     // only use if the function returns an INT... hmm
@@ -844,7 +891,13 @@ PyObject *DTOOL_PyObject_RichCompare(PyObject *v1, PyObject *v2, int op) {
  * make_copy() method.
  * make_copy() method.
  */
  */
 PyObject *copy_from_make_copy(PyObject *self, PyObject *noargs) {
 PyObject *copy_from_make_copy(PyObject *self, PyObject *noargs) {
-  return PyObject_CallMethod(self, (char *)"make_copy", (char *)"()");
+  PyObject *callable = PyObject_GetAttrString(self, "make_copy");
+  if (callable == NULL) {
+    return NULL;
+  }
+  PyObject *result = _PyObject_CallNoArg(callable);
+  Py_DECREF(callable);
+  return result;
 }
 }
 
 
 /**
 /**
@@ -852,13 +905,15 @@ PyObject *copy_from_make_copy(PyObject *self, PyObject *noargs) {
  * copy constructor.
  * copy constructor.
  */
  */
 PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) {
 PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) {
-  PyObject *this_class = PyObject_Type(self);
-  if (this_class == NULL) {
-    return NULL;
-  }
+  PyObject *callable = (PyObject *)Py_TYPE(self);
 
 
-  PyObject *result = PyObject_CallFunction(this_class, (char *)"(O)", self);
-  Py_DECREF(this_class);
+#if PY_VERSION_HEX >= 0x03060000
+  PyObject *result = _PyObject_FastCall(callable, &self, 1);
+#else
+  PyObject *args = PyTuple_Pack(1, self);
+  PyObject *result = PyObject_Call(callable, args, NULL);
+  Py_DECREF(args);
+#endif
   return result;
   return result;
 }
 }
 
 
@@ -868,7 +923,109 @@ PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) {
  * __copy__().
  * __copy__().
  */
  */
 PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
 PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
-  return PyObject_CallMethod(self, (char *)"__copy__", (char *)"()");
+  PyObject *callable = PyObject_GetAttrString(self, "__copy__");
+  if (callable == NULL) {
+    return NULL;
+  }
+  PyObject *result = _PyObject_CallNoArg(callable);
+  Py_DECREF(callable);
+  return result;
+}
+
+/**
+ * A more efficient version of PyArg_ParseTupleAndKeywords for the special
+ * case where there is only a single PyObject argument.
+ */
+bool Dtool_ExtractArg(PyObject **result, PyObject *args, PyObject *kwds,
+                      const char *keyword) {
+
+  if (PyTuple_GET_SIZE(args) == 1) {
+    if (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0) {
+      *result = PyTuple_GET_ITEM(args, 0);
+      return true;
+    }
+  } else if (PyTuple_GET_SIZE(args) == 0) {
+    PyObject *key;
+    Py_ssize_t ppos = 0;
+    if (kwds != NULL && ((PyDictObject *)kwds)->ma_used == 1 &&
+        PyDict_Next(kwds, &ppos, &key, result)) {
+      // We got the item, we just need to make sure that it had the right key.
+#if PY_VERSION_HEX >= 0x03050000
+      return PyUnicode_CheckExact(key) && _PyUnicode_EqualToASCIIString(key, keyword);
+#elif PY_MAJOR_VERSION >= 3
+      return PyUnicode_CheckExact(key) && PyUnicode_CompareWithASCIIString(key, keyword) == 0;
+#else
+      return PyString_CheckExact(key) && strcmp(PyString_AS_STRING(key), keyword) == 0;
+#endif
+    }
+  }
+
+  return false;
+}
+
+/**
+ * Variant of Dtool_ExtractArg that does not accept a keyword argument.
+ */
+bool Dtool_ExtractArg(PyObject **result, PyObject *args, PyObject *kwds) {
+  if (PyTuple_GET_SIZE(args) == 1 &&
+      (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0)) {
+    *result = PyTuple_GET_ITEM(args, 0);
+    return true;
+  }
+  return false;
+}
+
+/**
+ * A more efficient version of PyArg_ParseTupleAndKeywords for the special
+ * case where there is only a single optional PyObject argument.
+ *
+ * Returns true if valid (including if there were 0 items), false if there was
+ * an error, such as an invalid number of parameters.
+ */
+bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds,
+                              const char *keyword) {
+
+  if (PyTuple_GET_SIZE(args) == 1) {
+    if (kwds == NULL || ((PyDictObject *)kwds)->ma_used == 0) {
+      *result = PyTuple_GET_ITEM(args, 0);
+      return true;
+    }
+  } else if (PyTuple_GET_SIZE(args) == 0) {
+    if (kwds != NULL && ((PyDictObject *)kwds)->ma_used == 1) {
+      PyObject *key;
+      Py_ssize_t ppos = 0;
+      if (!PyDict_Next(kwds, &ppos, &key, result)) {
+        return true;
+      }
+
+      // We got the item, we just need to make sure that it had the right key.
+#if PY_VERSION_HEX >= 0x03050000
+      return PyUnicode_CheckExact(key) && _PyUnicode_EqualToASCIIString(key, keyword);
+#elif PY_MAJOR_VERSION >= 3
+      return PyUnicode_CheckExact(key) && PyUnicode_CompareWithASCIIString(key, keyword) == 0;
+#else
+      return PyString_CheckExact(key) && strcmp(PyString_AS_STRING(key), keyword) == 0;
+#endif
+    } else {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/**
+ * Variant of Dtool_ExtractOptionalArg that does not accept a keyword argument.
+ */
+bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds) {
+  if (kwds != NULL && ((PyDictObject *)kwds)->ma_used != 0) {
+    return false;
+  }
+  if (PyTuple_GET_SIZE(args) == 1) {
+    *result = PyTuple_GET_ITEM(args, 0);
+    return true;
+  }
+  return (PyTuple_GET_SIZE(args) == 0);
 }
 }
 
 
 /**
 /**

+ 19 - 0
dtool/src/interrogatedb/py_panda.h

@@ -107,11 +107,14 @@ inline PyObject* doPy_RETURN_FALSE()
 #define PyInt_Check PyLong_Check
 #define PyInt_Check PyLong_Check
 #define PyInt_AsLong PyLong_AsLong
 #define PyInt_AsLong PyLong_AsLong
 #define PyInt_AS_LONG PyLong_AS_LONG
 #define PyInt_AS_LONG PyLong_AS_LONG
+#define PyLongOrInt_AsSize_t PyLong_AsSize_t
 #else
 #else
 #define PyLongOrInt_Check(x) (PyInt_Check(x) || PyLong_Check(x))
 #define PyLongOrInt_Check(x) (PyInt_Check(x) || PyLong_Check(x))
 // PyInt_FromSize_t automatically picks the right type.
 // PyInt_FromSize_t automatically picks the right type.
 #define PyLongOrInt_AS_LONG PyInt_AsLong
 #define PyLongOrInt_AS_LONG PyInt_AsLong
 
 
+EXPCL_INTERROGATEDB size_t PyLongOrInt_AsSize_t(PyObject *);
+
 // For more portably defining hash functions.
 // For more portably defining hash functions.
 typedef long Py_hash_t;
 typedef long Py_hash_t;
 #endif
 #endif
@@ -469,6 +472,21 @@ struct Dtool_SequenceWrapper {
 
 
 EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SequenceWrapper_Type;
 EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SequenceWrapper_Type;
 
 
+/**
+ * These functions check whether the arguments passed to a function conform to
+ * certain expectations.
+ */
+ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args);
+ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args, PyObject *kwds);
+EXPCL_INTERROGATEDB bool Dtool_ExtractArg(PyObject **result, PyObject *args,
+                                          PyObject *kwds, const char *keyword);
+EXPCL_INTERROGATEDB bool Dtool_ExtractArg(PyObject **result, PyObject *args,
+                                          PyObject *kwds);
+EXPCL_INTERROGATEDB bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
+                                                  PyObject *kwds, const char *keyword);
+EXPCL_INTERROGATEDB bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
+                                                  PyObject *kwds);
+
 /**
 /**
  * These functions convert a C++ value into the corresponding Python object.
  * These functions convert a C++ value into the corresponding Python object.
  * This used to be generated by the code generator, but it seems more reliable
  * This used to be generated by the code generator, but it seems more reliable
@@ -491,6 +509,7 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::string *value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::wstring *value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::wstring *value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(char value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(char value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
+ALWAYS_INLINE PyObject *Dtool_WrapValue(nullptr_t);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::vector<unsigned char> &value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::vector<unsigned char> &value);
 
 

+ 0 - 2
dtool/src/parser-inc/stddef.h

@@ -23,7 +23,5 @@
 
 
 #define offsetof(type,member) ((size_t) &(((type*)0)->member))
 #define offsetof(type,member) ((size_t) &(((type*)0)->member))
 
 
-typedef decltype(nullptr) nullptr_t;
-
 #endif
 #endif
 
 

+ 1 - 5
dtool/src/parser-inc/stdtypedefs.h

@@ -41,11 +41,7 @@ inline namespace std {
 
 
 struct timeval;
 struct timeval;
 
 
-#ifdef __cplusplus
-#define NULL 0L
-#else
-#define NULL ((void *)0)
-#endif
+typedef decltype(nullptr) nullptr_t;
 
 
 // One day, we might extend interrogate to be able to parse this,
 // One day, we might extend interrogate to be able to parse this,
 // but we currently don't need it.
 // but we currently don't need it.

+ 17 - 1
dtool/src/pystub/pystub.cxx

@@ -32,6 +32,7 @@ extern "C" {
   EXPCL_PYSTUB int PyDict_GetItem(...);
   EXPCL_PYSTUB int PyDict_GetItem(...);
   EXPCL_PYSTUB int PyDict_GetItemString(...);
   EXPCL_PYSTUB int PyDict_GetItemString(...);
   EXPCL_PYSTUB int PyDict_New(...);
   EXPCL_PYSTUB int PyDict_New(...);
+  EXPCL_PYSTUB int PyDict_Next(...);
   EXPCL_PYSTUB int PyDict_SetItem(...);
   EXPCL_PYSTUB int PyDict_SetItem(...);
   EXPCL_PYSTUB int PyDict_SetItemString(...);
   EXPCL_PYSTUB int PyDict_SetItemString(...);
   EXPCL_PYSTUB int PyDict_Size(...);
   EXPCL_PYSTUB int PyDict_Size(...);
@@ -49,7 +50,6 @@ extern "C" {
   EXPCL_PYSTUB int PyErr_WarnEx(...);
   EXPCL_PYSTUB int PyErr_WarnEx(...);
   EXPCL_PYSTUB int PyEval_CallFunction(...);
   EXPCL_PYSTUB int PyEval_CallFunction(...);
   EXPCL_PYSTUB int PyEval_CallObjectWithKeywords(...);
   EXPCL_PYSTUB int PyEval_CallObjectWithKeywords(...);
-  EXPCL_PYSTUB int PyEval_InitThreads(...);
   EXPCL_PYSTUB int PyEval_RestoreThread(...);
   EXPCL_PYSTUB int PyEval_RestoreThread(...);
   EXPCL_PYSTUB int PyEval_SaveThread(...);
   EXPCL_PYSTUB int PyEval_SaveThread(...);
   EXPCL_PYSTUB int PyFloat_AsDouble(...);
   EXPCL_PYSTUB int PyFloat_AsDouble(...);
@@ -163,6 +163,7 @@ extern "C" {
   EXPCL_PYSTUB int PyUnicode_AsUTF8AndSize(...);
   EXPCL_PYSTUB int PyUnicode_AsUTF8AndSize(...);
   EXPCL_PYSTUB int PyUnicode_AsWideChar(...);
   EXPCL_PYSTUB int PyUnicode_AsWideChar(...);
   EXPCL_PYSTUB int PyUnicode_AsWideCharString(...);
   EXPCL_PYSTUB int PyUnicode_AsWideCharString(...);
+  EXPCL_PYSTUB int PyUnicode_CompareWithASCIIString(...);
   EXPCL_PYSTUB int PyUnicode_FromFormat(...);
   EXPCL_PYSTUB int PyUnicode_FromFormat(...);
   EXPCL_PYSTUB int PyUnicode_FromString(...);
   EXPCL_PYSTUB int PyUnicode_FromString(...);
   EXPCL_PYSTUB int PyUnicode_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicode_FromStringAndSize(...);
@@ -180,12 +181,16 @@ extern "C" {
   EXPCL_PYSTUB int _PyArg_ParseTuple_SizeT(...);
   EXPCL_PYSTUB int _PyArg_ParseTuple_SizeT(...);
   EXPCL_PYSTUB int _PyArg_ParseTupleAndKeywords_SizeT(...);
   EXPCL_PYSTUB int _PyArg_ParseTupleAndKeywords_SizeT(...);
   EXPCL_PYSTUB int _PyArg_Parse_SizeT(...);
   EXPCL_PYSTUB int _PyArg_Parse_SizeT(...);
+  EXPCL_PYSTUB int _PyErr_BadInternalCall(...);
+  EXPCL_PYSTUB int _PyLong_AsByteArray(...);
   EXPCL_PYSTUB int _PyObject_CallFunction_SizeT(...);
   EXPCL_PYSTUB int _PyObject_CallFunction_SizeT(...);
   EXPCL_PYSTUB int _PyObject_CallMethod_SizeT(...);
   EXPCL_PYSTUB int _PyObject_CallMethod_SizeT(...);
   EXPCL_PYSTUB int _PyObject_DebugFree(...);
   EXPCL_PYSTUB int _PyObject_DebugFree(...);
   EXPCL_PYSTUB int _PyObject_Del(...);
   EXPCL_PYSTUB int _PyObject_Del(...);
+  EXPCL_PYSTUB int _PyObject_FastCallDict(...);
   EXPCL_PYSTUB int _PyUnicode_AsString(...);
   EXPCL_PYSTUB int _PyUnicode_AsString(...);
   EXPCL_PYSTUB int _PyUnicode_AsStringAndSize(...);
   EXPCL_PYSTUB int _PyUnicode_AsStringAndSize(...);
+  EXPCL_PYSTUB int _PyUnicode_EqualToASCIIString(...);
   EXPCL_PYSTUB int _Py_AddToAllObjects(...);
   EXPCL_PYSTUB int _Py_AddToAllObjects(...);
   EXPCL_PYSTUB int _Py_BuildValue_SizeT(...);
   EXPCL_PYSTUB int _Py_BuildValue_SizeT(...);
   EXPCL_PYSTUB int _Py_Dealloc(...);
   EXPCL_PYSTUB int _Py_Dealloc(...);
@@ -198,6 +203,7 @@ extern "C" {
 
 
   EXPCL_PYSTUB void Py_Initialize();
   EXPCL_PYSTUB void Py_Initialize();
   EXPCL_PYSTUB int Py_IsInitialized();
   EXPCL_PYSTUB int Py_IsInitialized();
+  EXPCL_PYSTUB void PyEval_InitThreads();
 
 
   EXPCL_PYSTUB extern void *PyExc_AssertionError;
   EXPCL_PYSTUB extern void *PyExc_AssertionError;
   EXPCL_PYSTUB extern void *PyExc_AttributeError;
   EXPCL_PYSTUB extern void *PyExc_AttributeError;
@@ -208,6 +214,7 @@ extern "C" {
   EXPCL_PYSTUB extern void *PyExc_ImportError;
   EXPCL_PYSTUB extern void *PyExc_ImportError;
   EXPCL_PYSTUB extern void *PyExc_IndexError;
   EXPCL_PYSTUB extern void *PyExc_IndexError;
   EXPCL_PYSTUB extern void *PyExc_OSError;
   EXPCL_PYSTUB extern void *PyExc_OSError;
+  EXPCL_PYSTUB extern void *PyExc_OverflowError;
   EXPCL_PYSTUB extern void *PyExc_RuntimeError;
   EXPCL_PYSTUB extern void *PyExc_RuntimeError;
   EXPCL_PYSTUB extern void *PyExc_StandardError;
   EXPCL_PYSTUB extern void *PyExc_StandardError;
   EXPCL_PYSTUB extern void *PyExc_StopIteration;
   EXPCL_PYSTUB extern void *PyExc_StopIteration;
@@ -241,6 +248,7 @@ int PyDict_DelItemString(...) { return 0; }
 int PyDict_GetItem(...) { return 0; }
 int PyDict_GetItem(...) { return 0; }
 int PyDict_GetItemString(...) { return 0; }
 int PyDict_GetItemString(...) { return 0; }
 int PyDict_New(...) { return 0; };
 int PyDict_New(...) { return 0; };
+int PyDict_Next(...) { return 0; };
 int PyDict_SetItem(...) { return 0; };
 int PyDict_SetItem(...) { return 0; };
 int PyDict_SetItemString(...) { return 0; };
 int PyDict_SetItemString(...) { return 0; };
 int PyDict_Size(...){ return 0; }
 int PyDict_Size(...){ return 0; }
@@ -372,6 +380,7 @@ int PyUnicode_AsUTF8(...) { return 0; }
 int PyUnicode_AsUTF8AndSize(...) { return 0; }
 int PyUnicode_AsUTF8AndSize(...) { return 0; }
 int PyUnicode_AsWideChar(...) { return 0; }
 int PyUnicode_AsWideChar(...) { return 0; }
 int PyUnicode_AsWideCharString(...) { return 0; }
 int PyUnicode_AsWideCharString(...) { return 0; }
+int PyUnicode_CompareWithASCIIString(...) { return 0; }
 int PyUnicode_FromFormat(...) { return 0; }
 int PyUnicode_FromFormat(...) { return 0; }
 int PyUnicode_FromString(...) { return 0; }
 int PyUnicode_FromString(...) { return 0; }
 int PyUnicode_FromStringAndSize(...) { return 0; }
 int PyUnicode_FromStringAndSize(...) { return 0; }
@@ -389,12 +398,16 @@ int Py_InitModule4TraceRefs_64(...) { return 0; };
 int _PyArg_ParseTuple_SizeT(...) { return 0; };
 int _PyArg_ParseTuple_SizeT(...) { return 0; };
 int _PyArg_ParseTupleAndKeywords_SizeT(...) { return 0; };
 int _PyArg_ParseTupleAndKeywords_SizeT(...) { return 0; };
 int _PyArg_Parse_SizeT(...) { return 0; };
 int _PyArg_Parse_SizeT(...) { return 0; };
+int _PyErr_BadInternalCall(...) { return 0; };
+int _PyLong_AsByteArray(...) { return 0; };
 int _PyObject_CallFunction_SizeT(...) { return 0; };
 int _PyObject_CallFunction_SizeT(...) { return 0; };
 int _PyObject_CallMethod_SizeT(...) { return 0; };
 int _PyObject_CallMethod_SizeT(...) { return 0; };
 int _PyObject_DebugFree(...) { return 0; };
 int _PyObject_DebugFree(...) { return 0; };
 int _PyObject_Del(...) { return 0; };
 int _PyObject_Del(...) { return 0; };
+int _PyObject_FastCallDict(...) { return 0; };
 int _PyUnicode_AsString(...) { return 0; };
 int _PyUnicode_AsString(...) { return 0; };
 int _PyUnicode_AsStringAndSize(...) { return 0; };
 int _PyUnicode_AsStringAndSize(...) { return 0; };
+int _PyUnicode_EqualToASCIIString(...) { return 0; };
 int _Py_AddToAllObjects(...) { return 0; };
 int _Py_AddToAllObjects(...) { return 0; };
 int _Py_BuildValue_SizeT(...) { return 0; };
 int _Py_BuildValue_SizeT(...) { return 0; };
 int _Py_Dealloc(...) { return 0; };
 int _Py_Dealloc(...) { return 0; };
@@ -411,6 +424,8 @@ void Py_Initialize() {
 int Py_IsInitialized() {
 int Py_IsInitialized() {
   return 0;
   return 0;
 }
 }
+void PyEval_InitThreads() {
+}
 
 
 
 
 void *PyExc_AssertionError = (void *)NULL;
 void *PyExc_AssertionError = (void *)NULL;
@@ -422,6 +437,7 @@ void *PyExc_FutureWarning = (void *)NULL;
 void *PyExc_ImportError = (void *)NULL;
 void *PyExc_ImportError = (void *)NULL;
 void *PyExc_IndexError = (void *)NULL;
 void *PyExc_IndexError = (void *)NULL;
 void *PyExc_OSError = (void *)NULL;
 void *PyExc_OSError = (void *)NULL;
+void *PyExc_OverflowError = (void *)NULL;
 void *PyExc_RuntimeError = (void *)NULL;
 void *PyExc_RuntimeError = (void *)NULL;
 void *PyExc_StandardError = (void *)NULL;
 void *PyExc_StandardError = (void *)NULL;
 void *PyExc_StopIteration = (void *)NULL;
 void *PyExc_StopIteration = (void *)NULL;