|
|
@@ -18,19 +18,26 @@
|
|
|
#ifdef HAVE_PYTHON
|
|
|
|
|
|
PyMemberDef standard_type_members[] = {
|
|
|
- {(char *)"this", T_ULONG, offsetof(Dtool_PyInstDef,_ptr_to_object),READONLY, (char *)"C++ 'this' pointer, if any"},
|
|
|
-// {(char *)"this_ownership", T_INT, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
|
|
|
-// {(char *)"this_const", T_INT, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"},
|
|
|
+ {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"},
|
|
|
+ {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
|
|
|
+ {(char *)"this_const", T_BOOL, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"},
|
|
|
// {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature), READONLY, (char *)"A type check signature"},
|
|
|
{(char *)"this_metatype", T_OBJECT, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"},
|
|
|
{NULL} /* Sentinel */
|
|
|
};
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////////
|
|
|
-/// Simple Recognition Functions..
|
|
|
-////////////////////////////////////////////////////////////////////////
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: DtoolCanThisBeAPandaInstance
|
|
|
+// Description: 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
|
|
|
+// encoded on each instance.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
bool DtoolCanThisBeAPandaInstance(PyObject *self) {
|
|
|
// simple sanity check for the class type..size.. will stop basic foobars..
|
|
|
+ // It is arguably better to use something like this:
|
|
|
+ // PyType_IsSubtype(Py_TYPE(self), &Dtool_DTOOL_SUPER_BASE._PyType)
|
|
|
+ // ...but probably not as fast.
|
|
|
if (Py_TYPE(self)->tp_basicsize >= (int)sizeof(Dtool_PyInstDef)) {
|
|
|
Dtool_PyInstDef *pyself = (Dtool_PyInstDef *) self;
|
|
|
if (pyself->_signature == PY_PANDA_SIGNATURE) {
|
|
|
@@ -56,101 +63,51 @@ void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *c
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: attempt_coercion
|
|
|
-// Description: A helper function for DTOOL_Call_GetPointerThisClass,
|
|
|
-// below. This attempts to coerce the given object to
|
|
|
-// the indicated Panda object, by creating a temporary
|
|
|
-// instance of the required Panda object. If
|
|
|
-// successful, returns the "this" pointer of the
|
|
|
-// temporary object; otherwise, returns NULL.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-static void *
|
|
|
-attempt_coercion(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
|
- PyObject **coerced) {
|
|
|
- // The supplied parameter is not the required type.
|
|
|
- if (coerced != NULL) {
|
|
|
- // Attempt coercion: try to create a temporary instance of the
|
|
|
- // required class using the supplied parameter.
|
|
|
- // Because we want to use the special InitNoCoerce constructor
|
|
|
- // here instead of the regular constructor (we don't want to risk
|
|
|
- // recursive coercion on the nested type we're creating), we have
|
|
|
- // to call the constructor with a few more steps.
|
|
|
- PyObject *obj = NULL;
|
|
|
- if (classdef->_PyType.tp_new != NULL) {
|
|
|
- obj = classdef->_PyType.tp_new(&classdef->_PyType, self, NULL);
|
|
|
- assert(obj != NULL);
|
|
|
-
|
|
|
- if (PyTuple_Check(self)) {
|
|
|
- // A tuple was passed, which we assume are the constructor arguments.
|
|
|
- if (classdef->_Dtool_InitNoCoerce(obj, self) != 0) {
|
|
|
- Py_DECREF(obj);
|
|
|
- obj = NULL;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // We need to pack the value into an args tuple.
|
|
|
- PyObject *args = PyTuple_Pack(1, self);
|
|
|
- if (classdef->_Dtool_InitNoCoerce(obj, args) != 0) {
|
|
|
- Py_DECREF(obj);
|
|
|
- obj = NULL;
|
|
|
- }
|
|
|
- Py_DECREF(args);
|
|
|
- }
|
|
|
- }
|
|
|
- if (obj == NULL) {
|
|
|
- // That didn't work; try to call a static "make" method instead.
|
|
|
- // Presently, we don't bother filtering this for coercion,
|
|
|
- // because none of our classes suffer from a recursion danger
|
|
|
- // here. Maybe one day we will need to also construct a
|
|
|
- // makeNoCoerce wrapper?
|
|
|
- PyObject *make = PyObject_GetAttrString((PyObject *)classdef, "make");
|
|
|
- if (make != NULL) {
|
|
|
- PyErr_Clear();
|
|
|
- if (PyTuple_Check(self)) {
|
|
|
- obj = PyObject_CallObject(make, self);
|
|
|
- } else {
|
|
|
- obj = PyObject_CallFunctionObjArgs(make, self, NULL);
|
|
|
- }
|
|
|
- Py_DECREF(make);
|
|
|
- }
|
|
|
- }
|
|
|
- if (obj != NULL) {
|
|
|
- // Well, whaddaya know? The supplied parameter(s) suited
|
|
|
- // the object's constructor. Now we have a temporary object
|
|
|
- // that we can pass to the function.
|
|
|
- Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)obj)->_My_Type;
|
|
|
- void *result = my_type->_Dtool_UpcastInterface(obj, classdef);
|
|
|
- if (result != NULL) {
|
|
|
- // Successfully coerced. Store the newly-allocated
|
|
|
- // pointer, so the caller can release the coerced object
|
|
|
- // at his leisure. We store it in a list, so that other
|
|
|
- // parameters can accumulate there too.
|
|
|
- if ((*coerced) == NULL) {
|
|
|
- (*coerced) = PyList_New(0);
|
|
|
- }
|
|
|
- PyList_Append(*coerced, obj);
|
|
|
- Py_DECREF(obj);
|
|
|
- return result;
|
|
|
- }
|
|
|
- // Some problem getting the C++ pointer from our created
|
|
|
- // temporary object. Weird.
|
|
|
- Py_DECREF(obj);
|
|
|
- }
|
|
|
-
|
|
|
- // Clear the error returned by the coercion constructor. It's not
|
|
|
- // the error message we want to report.
|
|
|
- PyErr_Clear();
|
|
|
+// Function: Dtool_Call_ExtractThisPointer
|
|
|
+// Description: This is a support function for the Python bindings:
|
|
|
+// it extracts the underlying C++ pointer of the given
|
|
|
+// type for a given Python object. If it was of the
|
|
|
+// wrong type, raises an AttributeError.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer) {
|
|
|
+ if (self == NULL || !DtoolCanThisBeAPandaInstance(self)) {
|
|
|
+ Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
|
|
|
+ return false;
|
|
|
}
|
|
|
- return NULL;
|
|
|
+
|
|
|
+ *answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, &classdef);
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
-// Temporary function to preserve backward compatibility.
|
|
|
-void *
|
|
|
-DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
|
- int param, const string &function_name, bool const_ok,
|
|
|
- PyObject **coerced) {
|
|
|
- return DTOOL_Call_GetPointerThisClass(self, classdef,
|
|
|
- param, function_name, const_ok,
|
|
|
- coerced, true);
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_Call_ExtractThisPointer_NonConst
|
|
|
+// Description: The same thing as Dtool_Call_ExtractThisPointer,
|
|
|
+// except that it performs the additional check that
|
|
|
+// the pointer is a non-const pointer. This is called
|
|
|
+// by function wrappers for functions of which all
|
|
|
+// overloads are non-const, and saves a bit of code.
|
|
|
+//
|
|
|
+// The extra method_name argument is used in formatting
|
|
|
+// the error message.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
|
|
|
+ void **answer, const char *method_name) {
|
|
|
+
|
|
|
+ if (self == NULL || !DtoolCanThisBeAPandaInstance(self)) {
|
|
|
+ Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (((Dtool_PyInstDef *)self)->_is_const) {
|
|
|
+ // All overloads of this function are non-const.
|
|
|
+ PyErr_Format(PyExc_TypeError,
|
|
|
+ "Cannot call %s() on a const object.",
|
|
|
+ method_name);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ *answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, &classdef);
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -176,18 +133,6 @@ DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
|
// declared non-const, and can therefore be called with
|
|
|
// only a non-const "this" pointer.
|
|
|
//
|
|
|
-// If coerced is non-NULL, parameter coercion will be
|
|
|
-// attempted. This means the supplied parameter may not
|
|
|
-// exactly match the required type, but will satisfy the
|
|
|
-// require type's constructor; and we will create
|
|
|
-// temporary object(s) of the required type instead. In
|
|
|
-// this case, coerced is a pointer to a PyList that will
|
|
|
-// be filled with these temporary objects. If coerced
|
|
|
-// is a pointer to a NULL PyObject, a new PyList will be
|
|
|
-// created on the first successful coercion. If coerced
|
|
|
-// itself is NULL, parameter coercion will not be
|
|
|
-// attempted.
|
|
|
-//
|
|
|
// The return value is the C++ pointer that was
|
|
|
// extracted, or NULL if there was a problem (in which
|
|
|
// case the Python exception state will have been set).
|
|
|
@@ -195,103 +140,36 @@ DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
|
void *
|
|
|
DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
|
int param, const string &function_name, bool const_ok,
|
|
|
- PyObject **coerced, bool report_errors) {
|
|
|
- if (PyErr_Occurred()) {
|
|
|
+ bool report_errors) {
|
|
|
+ //if (PyErr_Occurred()) {
|
|
|
+ // return NULL;
|
|
|
+ //}
|
|
|
+ if (self == NULL) {
|
|
|
+ if (report_errors) {
|
|
|
+ return Dtool_Raise_TypeError("self is NULL");
|
|
|
+ }
|
|
|
return NULL;
|
|
|
}
|
|
|
- if (self != NULL) {
|
|
|
- if (DtoolCanThisBeAPandaInstance(self)) {
|
|
|
- Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)self)->_My_Type;
|
|
|
- void *result = my_type->_Dtool_UpcastInterface(self, classdef);
|
|
|
- if (result != NULL) {
|
|
|
- if (const_ok || !((Dtool_PyInstDef *)self)->_is_const) {
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- if (report_errors) {
|
|
|
- ostringstream str;
|
|
|
- str << function_name << "() argument " << param << " may not be const";
|
|
|
- string msg = str.str();
|
|
|
- PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
|
- }
|
|
|
-
|
|
|
- } else {
|
|
|
- if (report_errors) {
|
|
|
- ostringstream str;
|
|
|
- str << function_name << "() argument " << param << " must be ";
|
|
|
-
|
|
|
- PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
|
|
|
- if (fname != (PyObject *)NULL) {
|
|
|
-#if PY_MAJOR_VERSION >= 3
|
|
|
- str << PyUnicode_AsUTF8(fname);
|
|
|
-#else
|
|
|
- str << PyString_AsString(fname);
|
|
|
-#endif
|
|
|
- Py_DECREF(fname);
|
|
|
- } else {
|
|
|
- str << classdef->_name;
|
|
|
- }
|
|
|
-
|
|
|
- PyObject *tname = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
|
|
|
- if (tname != (PyObject *)NULL) {
|
|
|
-#if PY_MAJOR_VERSION >= 3
|
|
|
- str << ", not " << PyUnicode_AsUTF8(tname);
|
|
|
-#else
|
|
|
- str << ", not " << PyString_AsString(tname);
|
|
|
-#endif
|
|
|
- Py_DECREF(tname);
|
|
|
- } else {
|
|
|
- str << ", not " << my_type->_name;
|
|
|
- }
|
|
|
|
|
|
- string msg = str.str();
|
|
|
- PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
|
- }
|
|
|
- }
|
|
|
+ if (DtoolCanThisBeAPandaInstance(self)) {
|
|
|
+ void *result = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, classdef);
|
|
|
|
|
|
- } else {
|
|
|
- // The parameter was not a Panda type. Can we coerce it to the
|
|
|
- // appropriate type, by creating a temporary object?
|
|
|
- void *result = attempt_coercion(self, classdef, coerced);
|
|
|
- if (result != NULL) {
|
|
|
+ if (result != NULL) {
|
|
|
+ if (const_ok || !((Dtool_PyInstDef *)self)->_is_const) {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- // Coercion failed.
|
|
|
if (report_errors) {
|
|
|
- ostringstream str;
|
|
|
- str << function_name << "() argument " << param << " must be ";
|
|
|
-
|
|
|
- PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
|
|
|
- if (fname != (PyObject *)NULL) {
|
|
|
-#if PY_MAJOR_VERSION >= 3
|
|
|
- str << PyUnicode_AsUTF8(fname);
|
|
|
-#else
|
|
|
- str << PyString_AsString(fname);
|
|
|
-#endif
|
|
|
- Py_DECREF(fname);
|
|
|
- } else {
|
|
|
- str << classdef->_name;
|
|
|
- }
|
|
|
-
|
|
|
- PyObject *tname = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
|
|
|
- if (tname != (PyObject *)NULL) {
|
|
|
-#if PY_MAJOR_VERSION >= 3
|
|
|
- str << ", not " << PyUnicode_AsUTF8(tname);
|
|
|
-#else
|
|
|
- str << ", not " << PyString_AsString(tname);
|
|
|
-#endif
|
|
|
- Py_DECREF(tname);
|
|
|
- }
|
|
|
-
|
|
|
- string msg = str.str();
|
|
|
- PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
|
+ return PyErr_Format(PyExc_TypeError,
|
|
|
+ "%s() argument %d may not be const",
|
|
|
+ function_name.c_str(), param);
|
|
|
}
|
|
|
+ return NULL;
|
|
|
}
|
|
|
- } else {
|
|
|
- if (report_errors) {
|
|
|
- PyErr_SetString(PyExc_TypeError, "self is NULL");
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (report_errors) {
|
|
|
+ return Dtool_Raise_ArgTypeError(self, param, function_name.c_str(), classdef->_PyType.tp_name);
|
|
|
}
|
|
|
|
|
|
return NULL;
|
|
|
@@ -304,31 +182,175 @@ void *DTOOL_Call_GetPointerThis(PyObject *self) {
|
|
|
return pyself->_ptr_to_object;
|
|
|
}
|
|
|
}
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+#ifndef NDEBUG
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_CheckErrorOccurred
|
|
|
+// Description: This is similar to a PyErr_Occurred() check, except
|
|
|
+// that it also checks Notify to see if an assertion
|
|
|
+// has occurred. If that is the case, then it raises
|
|
|
+// an AssertionError.
|
|
|
+//
|
|
|
+// Returns true if there is an active exception, false
|
|
|
+// otherwise.
|
|
|
+//
|
|
|
+// In the NDEBUG case, this is simply a #define to
|
|
|
+// _PyErr_OCCURRED() (which is an undocumented inline
|
|
|
+// version of PyErr_Occurred()).
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool Dtool_CheckErrorOccurred() {
|
|
|
+ if (_PyErr_OCCURRED()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (Notify::ptr()->has_assert_failed()) {
|
|
|
+ Dtool_Raise_AssertionError();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+#endif // NDEBUG
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_Raise_AssertionError
|
|
|
+// Description: Raises an AssertionError containing the last thrown
|
|
|
+// assert message, and clears the assertion flag.
|
|
|
+// Returns NULL.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+PyObject *Dtool_Raise_AssertionError() {
|
|
|
+ Notify *notify = Notify::ptr();
|
|
|
+#if PY_MAJOR_VERSION >= 3
|
|
|
+ PyObject *message = PyUnicode_FromString(notify->get_assert_error_message().c_str());
|
|
|
+#else
|
|
|
+ PyObject *message = PyString_FromString(notify->get_assert_error_message().c_str());
|
|
|
+#endif
|
|
|
+ Py_INCREF(PyExc_AssertionError);
|
|
|
+ PyErr_Restore(PyExc_AssertionError, message, (PyObject *)NULL);
|
|
|
+ notify->clear_assert_failed();
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_Raise_TypeError
|
|
|
+// Description: Raises a TypeError with the given message, and
|
|
|
+// returns NULL.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+PyObject *Dtool_Raise_TypeError(const char *message) {
|
|
|
+ // PyErr_Restore is what PyErr_SetString would have ended up calling
|
|
|
+ // eventually anyway, so we might as well just get to the point.
|
|
|
+ Py_INCREF(PyExc_TypeError);
|
|
|
+#if PY_MAJOR_VERSION >= 3
|
|
|
+ PyErr_Restore(PyExc_TypeError, PyUnicode_FromString(message), (PyObject *)NULL);
|
|
|
+#else
|
|
|
+ PyErr_Restore(PyExc_TypeError, PyString_FromString(message), (PyObject *)NULL);
|
|
|
+#endif
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_Raise_ArgTypeError
|
|
|
+// Description: Raises a TypeError of the form:
|
|
|
+// function_name() argument n must be type, not type
|
|
|
+// for a given object passed to a function.
|
|
|
+//
|
|
|
+// Always returns NULL so that it can be conveniently
|
|
|
+// used as a return expression for wrapper functions
|
|
|
+// that return a PyObject pointer.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name) {
|
|
|
+#if PY_MAJOR_VERSION >= 3
|
|
|
+ PyObject *message = PyUnicode_FromFormat(
|
|
|
+#else
|
|
|
+ PyObject *message = PyString_FromFormat(
|
|
|
+#endif
|
|
|
+ "%s() argument %d must be %s, not %s",
|
|
|
+ function_name, param, type_name,
|
|
|
+ Py_TYPE(obj)->tp_name);
|
|
|
+
|
|
|
+ Py_INCREF(PyExc_TypeError);
|
|
|
+ PyErr_Restore(PyExc_TypeError, message, (PyObject *)NULL);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_Raise_BadArgumentsError
|
|
|
+// Description: Raises a TypeError of the form:
|
|
|
+// Arguments must match:
|
|
|
+// <list of overloads>
|
|
|
+//
|
|
|
+// However, in release builds, this instead is defined
|
|
|
+// to a function that just prints out a generic
|
|
|
+// message, to help reduce the amount of strings in
|
|
|
+// the compiled library.
|
|
|
+//
|
|
|
+// Always returns NULL so that it can be conveniently
|
|
|
+// used as a return expression for wrapper functions
|
|
|
+// that return a PyObject pointer.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+PyObject *_Dtool_Raise_BadArgumentsError() {
|
|
|
+ return Dtool_Raise_TypeError("arguments do not match any function overload");
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_Return_None
|
|
|
+// Description: Convenience method that checks for exceptions, and
|
|
|
+// if one occurred, returns NULL, otherwise Py_None.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+PyObject *_Dtool_Return_None() {
|
|
|
+ if (_PyErr_OCCURRED()) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+#ifndef NDEBUG
|
|
|
+ if (Notify::ptr()->has_assert_failed()) {
|
|
|
+ return Dtool_Raise_AssertionError();
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ Py_INCREF(Py_None);
|
|
|
+ return Py_None;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Dtool_Return_Bool
|
|
|
+// Description: Convenience method that checks for exceptions, and
|
|
|
+// if one occurred, returns NULL, otherwise the given
|
|
|
+// boolean value as a PyObject *.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+PyObject *Dtool_Return_Bool(bool value) {
|
|
|
+ if (_PyErr_OCCURRED()) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+#ifndef NDEBUG
|
|
|
+ if (Notify::ptr()->has_assert_failed()) {
|
|
|
+ return Dtool_Raise_AssertionError();
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ PyObject *result = (value ? Py_True : Py_False);
|
|
|
+ Py_INCREF(result);
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
// Function : DTool_CreatePyInstanceTyped
|
|
|
//
|
|
|
// this function relies on the behavior of typed objects in the panda system.
|
|
|
//
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
-PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject & known_class_type, bool memory_rules, bool is_const, int RunTimeType) {
|
|
|
- if (local_this_in == NULL) {
|
|
|
- // Let's not be stupid..
|
|
|
- PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this'");
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int type_index) {
|
|
|
+ // We can't do the NULL check here like in DTool_CreatePyInstance, since
|
|
|
+ // the caller will have to get the type index to pass to this function
|
|
|
+ // to begin with. That code probably would have crashed by now if it was
|
|
|
+ // really NULL for whatever reason.
|
|
|
+ nassertr(local_this_in != NULL, NULL);
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
// IF the class is possibly a run time typed object
|
|
|
/////////////////////////////////////////////////////
|
|
|
- if (RunTimeType > 0) {
|
|
|
+ if (type_index > 0) {
|
|
|
/////////////////////////////////////////////////////
|
|
|
// get best fit class...
|
|
|
/////////////////////////////////////////////////////
|
|
|
- Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(RunTimeType);
|
|
|
+ Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(type_index);
|
|
|
if (target_class != NULL) {
|
|
|
/////////////////////////////////////////////////////
|
|
|
// cast to the type...
|
|
|
@@ -343,7 +365,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
|
|
|
self->_ptr_to_object = new_local_this;
|
|
|
self->_memory_rules = memory_rules;
|
|
|
self->_is_const = is_const;
|
|
|
- self->_signature = PY_PANDA_SIGNATURE;
|
|
|
+ //self->_signature = PY_PANDA_SIGNATURE;
|
|
|
self->_My_Type = target_class;
|
|
|
return (PyObject *)self;
|
|
|
}
|
|
|
@@ -360,7 +382,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
|
|
|
self->_ptr_to_object = local_this_in;
|
|
|
self->_memory_rules = memory_rules;
|
|
|
self->_is_const = is_const;
|
|
|
- self->_signature = PY_PANDA_SIGNATURE;
|
|
|
+ //self->_signature = PY_PANDA_SIGNATURE;
|
|
|
self->_My_Type = &known_class_type;
|
|
|
}
|
|
|
return (PyObject *)self;
|
|
|
@@ -372,8 +394,10 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const) {
|
|
|
if (local_this == NULL) {
|
|
|
- PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this'");
|
|
|
- return NULL;
|
|
|
+ // This is actually a very common case, so let's allow this, but return
|
|
|
+ // Py_None consistently. This eliminates code in the wrappers.
|
|
|
+ Py_INCREF(Py_None);
|
|
|
+ return Py_None;
|
|
|
}
|
|
|
|
|
|
Dtool_PyTypedObject *classdef = &in_classdef;
|
|
|
@@ -425,7 +449,7 @@ void
|
|
|
RegisterRuntimeClass(Dtool_PyTypedObject *otype, int class_id) {
|
|
|
if (class_id == 0) {
|
|
|
interrogatedb_cat.warning()
|
|
|
- << "Class " << otype->_name
|
|
|
+ << "Class " << otype->_PyType.tp_name
|
|
|
<< " has a zero TypeHandle value; check that init_type() is called.\n";
|
|
|
|
|
|
} else if (class_id > 0) {
|
|
|
@@ -436,13 +460,14 @@ RegisterRuntimeClass(Dtool_PyTypedObject *otype, int class_id) {
|
|
|
// There was already an entry in the dictionary for class_id.
|
|
|
Dtool_PyTypedObject *other_type = (*result.first).second;
|
|
|
interrogatedb_cat.warning()
|
|
|
- << "Classes " << otype->_name << " and " << other_type->_name
|
|
|
+ << "Classes " << otype->_PyType.tp_name
|
|
|
+ << " and " << other_type->_PyType.tp_name
|
|
|
<< " share the same TypeHandle value (" << class_id
|
|
|
<< "); check class definitions.\n";
|
|
|
|
|
|
} else {
|
|
|
GetRunTimeTypeList().insert(class_id);
|
|
|
- otype->_Dtool_IsRunTimeCapable = true;
|
|
|
+ otype->_type = TypeRegistry::ptr()->find_type_by_id(class_id);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -495,11 +520,10 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
|
|
|
|
|
|
if (module == NULL) {
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
|
- PyErr_SetString(PyExc_TypeError, "PyModule_Create returned NULL");
|
|
|
+ return Dtool_Raise_TypeError("PyModule_Create returned NULL");
|
|
|
#else
|
|
|
- PyErr_SetString(PyExc_TypeError, "Py_InitModule returned NULL");
|
|
|
+ return Dtool_Raise_TypeError("Py_InitModule returned NULL");
|
|
|
#endif
|
|
|
- return NULL;
|
|
|
}
|
|
|
|
|
|
// the constant inits... enums, classes ...
|
|
|
@@ -508,7 +532,6 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
|
|
|
}
|
|
|
|
|
|
PyModule_AddIntConstant(module, "Dtool_PyNativeInterface", 1);
|
|
|
-
|
|
|
return module;
|
|
|
}
|
|
|
|
|
|
@@ -523,20 +546,26 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
|
|
|
PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args) {
|
|
|
PyObject *from_in = NULL;
|
|
|
PyObject *to_in = NULL;
|
|
|
- if (PyArg_ParseTuple(args, "OO", &to_in, &from_in)) {
|
|
|
+ if (PyArg_UnpackTuple(args, "Dtool_BorrowThisReference", 2, 2, &to_in, &from_in)) {
|
|
|
|
|
|
if (DtoolCanThisBeAPandaInstance(from_in) && DtoolCanThisBeAPandaInstance(to_in)) {
|
|
|
- Dtool_PyInstDef * from = (Dtool_PyInstDef *) from_in;
|
|
|
- Dtool_PyInstDef * to = (Dtool_PyInstDef *) to_in;
|
|
|
+ Dtool_PyInstDef *from = (Dtool_PyInstDef *) from_in;
|
|
|
+ Dtool_PyInstDef *to = (Dtool_PyInstDef *) to_in;
|
|
|
+
|
|
|
+ //if (PyObject_TypeCheck(to_in, Py_TYPE(from_in))) {
|
|
|
if (from->_My_Type == to->_My_Type) {
|
|
|
to->_memory_rules = false;
|
|
|
to->_is_const = from->_is_const;
|
|
|
to->_ptr_to_object = from->_ptr_to_object;
|
|
|
- return Py_BuildValue("");
|
|
|
+
|
|
|
+ Py_INCREF(Py_None);
|
|
|
+ return Py_None;
|
|
|
}
|
|
|
- PyErr_SetString(PyExc_TypeError, "Must Be Same Type??");
|
|
|
+
|
|
|
+ return PyErr_Format(PyExc_TypeError, "types %s and %s do not match",
|
|
|
+ Py_TYPE(from)->tp_name, Py_TYPE(to)->tp_name);
|
|
|
} else {
|
|
|
- PyErr_SetString(PyExc_TypeError, "One of these does not appear to be DTOOL Instance ??");
|
|
|
+ return Dtool_Raise_TypeError("One of these does not appear to be DTOOL Instance ??");
|
|
|
}
|
|
|
}
|
|
|
return (PyObject *) NULL;
|
|
|
@@ -551,16 +580,17 @@ PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args) {
|
|
|
PyObject *key;
|
|
|
if (PyArg_ParseTuple(args, "OSO", &self, &key, &subject)) {
|
|
|
PyObject *dict = ((PyTypeObject *)self)->tp_dict;
|
|
|
- if (dict == NULL && !PyDict_Check(dict)) {
|
|
|
- PyErr_SetString(PyExc_TypeError, "No dictionary On Object");
|
|
|
+ if (dict == NULL || !PyDict_Check(dict)) {
|
|
|
+ return Dtool_Raise_TypeError("No dictionary On Object");
|
|
|
} else {
|
|
|
- PyDict_SetItem(dict,key,subject);
|
|
|
+ PyDict_SetItem(dict, key, subject);
|
|
|
}
|
|
|
}
|
|
|
if (PyErr_Occurred()) {
|
|
|
return (PyObject *)NULL;
|
|
|
}
|
|
|
- return Py_BuildValue("");
|
|
|
+ Py_INCREF(Py_None);
|
|
|
+ return Py_None;
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
@@ -725,7 +755,7 @@ PyObject *make_list_for_item(PyObject *self, const char *num_name,
|
|
|
Py_DECREF(list);
|
|
|
return NULL;
|
|
|
}
|
|
|
- PyList_SetItem(list, i, element);
|
|
|
+ PyList_SET_ITEM(list, i, element);
|
|
|
}
|
|
|
return list;
|
|
|
}
|
|
|
@@ -772,18 +802,15 @@ PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
|
|
|
// either a regular integer or a long integer, according
|
|
|
// to whether the indicated value will fit.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
+#if PY_MAJOR_VERSION < 3
|
|
|
EXPCL_DTOOLCONFIG PyObject *
|
|
|
PyLongOrInt_FromUnsignedLong(unsigned long value) {
|
|
|
-#if PY_MAJOR_VERSION >= 3
|
|
|
- // Python 3 only has longs.
|
|
|
- return PyLong_FromUnsignedLong(value);
|
|
|
-#else
|
|
|
if ((long)value < 0) {
|
|
|
return PyLong_FromUnsignedLong(value);
|
|
|
} else {
|
|
|
return PyInt_FromLong((long)value);
|
|
|
}
|
|
|
-#endif
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
#endif // HAVE_PYTHON
|