diff --git a/.travis.yml b/.travis.yml index 7d8a3003b6..36e4749240 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ addons: - python-dev - python3-dev - zlib1g-dev + - fakeroot script: $PYTHONV makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT $FLAGS --threads 4 && LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV makepanda/test_imports.py notifications: irc: diff --git a/direct/src/actor/Actor.py b/direct/src/actor/Actor.py index 5a64c1fe2a..8a7ef093b0 100644 --- a/direct/src/actor/Actor.py +++ b/direct/src/actor/Actor.py @@ -897,7 +897,7 @@ class Actor(DirectObject, NodePath): return ((toFrame+1)-fromFrame) / animControl.getFrameRate() def getNumFrames(self, animName=None, partName=None): - lodName = next(iter(self.__animControlDict)) + #lodName = next(iter(self.__animControlDict)) controls = self.getAnimControls(animName, partName) if len(controls) == 0: return None diff --git a/dtool/src/interrogate/functionRemap.cxx b/dtool/src/interrogate/functionRemap.cxx index d58cdf8b88..5b04209c48 100644 --- a/dtool/src/interrogate/functionRemap.cxx +++ b/dtool/src/interrogate/functionRemap.cxx @@ -772,16 +772,14 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak first_param = 1; } - if (_has_this || _type == T_constructor) { - if (_parameters.size() > (size_t)first_param && _parameters[first_param]._name == "self" && - TypeManager::is_pointer_to_PyObject(_parameters[first_param]._remap->get_orig_type())) { - // Here's a special case. If the first parameter of a nonstatic method - // is a PyObject * called "self", then we will automatically fill it in - // from the this pointer, and remove it from the generated parameter - // list. - _parameters.erase(_parameters.begin() + first_param); - _flags |= F_explicit_self; - } + if (_parameters.size() > (size_t)first_param && _parameters[first_param]._name == "self" && + TypeManager::is_pointer_to_PyObject(_parameters[first_param]._remap->get_orig_type())) { + // Here's a special case. If the first parameter of a nonstatic method + // is a PyObject * called "self", then we will automatically fill it in + // from the this pointer, and remove it from the generated parameter + // list. + _parameters.erase(_parameters.begin() + first_param); + _flags |= F_explicit_self; } if ((int)_parameters.size() == first_param) { diff --git a/dtool/src/interrogate/interfaceMaker.cxx b/dtool/src/interrogate/interfaceMaker.cxx index 527f983f8a..5c2e589e3c 100644 --- a/dtool/src/interrogate/interfaceMaker.cxx +++ b/dtool/src/interrogate/interfaceMaker.cxx @@ -616,7 +616,7 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) { // If *any* of the variants of this function has a "this" pointer, // the entire set of functions is deemed to have a "this" pointer. - if (remap->_has_this) { + if (remap->_has_this || (remap->_flags & FunctionRemap::F_explicit_self) != 0) { func->_has_this = true; } diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 4042136bab..7b9aa8487a 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -478,6 +478,11 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap, def._wrapper_type = WT_mapping_setitem; return true; } + if (remap->_flags & FunctionRemap::F_size) { + def._answer_location = "mp_length"; + def._wrapper_type = WT_sequence_size; + return true; + } } if (obj->_protocol_types & Object::PT_iter) { @@ -707,7 +712,10 @@ write_python_instance(ostream &out, int indent_level, const string &return_expr, string class_name = itype.get_scoped_name(); - if (IsPandaTypedObject(itype._cpptype->as_struct_type())) { + // We don't handle final classes via DTool_CreatePyInstanceTyped since we + // know it can't be of a subclass type, so we don't need to do the downcast. + CPPStructType *struct_type = itype._cpptype->as_struct_type(); + if (IsPandaTypedObject(struct_type) && !struct_type->is_final()) { // We can't let DTool_CreatePyInstanceTyped do the NULL check since we // will be grabbing the type index (which would obviously crash when // called on a NULL pointer), so we do it here. @@ -2100,10 +2108,10 @@ write_module_class(ostream &out, Object *obj) { for (ri = def._remaps.begin(); ri != def._remaps.end(); ++ri) { FunctionRemap *remap = (*ri); - if (remap->_flags & FunctionRemap::F_setitem_int) { + if (remap->_flags & FunctionRemap::F_setitem) { setitem_remaps.insert(remap); - } else if (remap->_flags & FunctionRemap::F_delitem_int) { + } else if (remap->_flags & FunctionRemap::F_delitem) { delitem_remaps.insert(remap); } } @@ -2137,14 +2145,21 @@ write_module_class(ostream &out, Object *obj) { out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; out << "//////////////////\n"; out << "static int " << def._wrapper_name << "(PyObject *self) {\n"; - out << " " << cClassName << " *local_this = NULL;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; + // Find the remap. There should be only one. FunctionRemap *remap = *def._remaps.begin(); + const char *container = ""; + + if (remap->_has_this) { + out << " " << cClassName << " *local_this = NULL;\n"; + out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; + out << " return -1;\n"; + out << " }\n\n"; + container = "local_this"; + } + vector_string params; - out << " return (int) " << remap->call_function(out, 4, false, "local_this", params) << ";\n"; + out << " return (int) " << remap->call_function(out, 4, false, container, params) << ";\n"; out << "}\n\n"; } break; @@ -2374,23 +2389,25 @@ write_module_class(ostream &out, Object *obj) { out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; out << "//////////////////\n"; out << "static int " << def._wrapper_name << "(PyObject *self, visitproc visit, void *arg) {\n"; - out << " " << cClassName << " *local_this = NULL;\n"; - out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **) &local_this);\n"; - out << " if (local_this == NULL) {\n"; - out << " return 0;\n"; - out << " }\n\n"; // Find the remap. There should be only one. FunctionRemap *remap = *def._remaps.begin(); + const char *container = ""; - vector_string params(1); - if (remap->_flags & FunctionRemap::F_explicit_self) { - params.push_back("self"); + if (remap->_has_this) { + out << " " << cClassName << " *local_this = NULL;\n"; + out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **) &local_this);\n"; + out << " if (local_this == NULL) {\n"; + out << " return 0;\n"; + out << " }\n\n"; + container = "local_this"; } + + vector_string params((int)remap->_has_this); params.push_back("visit"); params.push_back("arg"); - out << " return " << remap->call_function(out, 2, false, "local_this", params) << ";\n"; + out << " return " << remap->call_function(out, 2, false, container, params) << ";\n"; out << "}\n\n"; } break; @@ -2857,11 +2874,9 @@ write_module_class(ostream &out, Object *obj) { } // getattrofunc tp_getattro; - write_function_slot(out, 4, slots, "tp_getattro", - "PyObject_GenericGetAttr"); + write_function_slot(out, 4, slots, "tp_getattro"); // setattrofunc tp_setattro; - write_function_slot(out, 4, slots, "tp_setattro", - "PyObject_GenericSetAttr"); + write_function_slot(out, 4, slots, "tp_setattro"); // PyBufferProcs *tp_as_buffer; if (has_parent_class || has_local_getbuffer) { @@ -4180,7 +4195,7 @@ int get_type_sort(CPPType *type) { return 7; } else if (TypeManager::is_longlong(type)) { return 6; - } else if (TypeManager::is_integer(type)) { + } else if (TypeManager::is_integer(type) && !TypeManager::is_bool(type)) { return 5; } else if (TypeManager::is_double(type)) { return 4; @@ -4973,7 +4988,7 @@ write_function_instance(ostream &out, FunctionRemap *remap, format_specifiers += "O"; parameter_list += ", &" + param_name; } - pexpr_string = "NULL"; + pexpr_string = "nullptr"; expected_params += "NoneType"; } else if (TypeManager::is_char(type)) { @@ -5800,7 +5815,8 @@ write_function_instance(ostream &out, FunctionRemap *remap, indent_level += 2; } - if (!remap->_has_this && (remap->_flags & FunctionRemap::F_explicit_self) != 0) { + if (is_constructor && !remap->_has_this && + (remap->_flags & FunctionRemap::F_explicit_self) != 0) { // If we'll be passing "self" to the constructor, we need to pre- // initialize it here. Unfortunately, we can't pre-load the "this" // pointer, but the constructor itself can do this. diff --git a/dtool/src/interrogate/interrogateBuilder.cxx b/dtool/src/interrogate/interrogateBuilder.cxx index a36b370942..349e9c46ad 100644 --- a/dtool/src/interrogate/interrogateBuilder.cxx +++ b/dtool/src/interrogate/interrogateBuilder.cxx @@ -1850,12 +1850,24 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP continue; } + const CPPParameterList::Parameters ¶ms = ftype->_parameters->_parameters; + + size_t expected_num_args = (size_t)is_seq; + size_t index_arg = 0; + + if (!params.empty() && params[0]->get_simple_name() == "self" && + TypeManager::is_pointer_to_PyObject(params[0]->_type)) { + // Taking a PyObject *self argument. + expected_num_args += 1; + index_arg += 1; + } + // The getter must either take no arguments, or all defaults. - if (ftype->_parameters->_parameters.size() == (size_t)is_seq || - (ftype->_parameters->_parameters.size() > (size_t)is_seq && - ftype->_parameters->_parameters[(size_t)is_seq]->_initializer != NULL)) { + if (params.size() == expected_num_args || + (params.size() > expected_num_args && + params[expected_num_args]->_initializer != NULL)) { // If this is a sequence getter, it must take an index argument. - if (is_seq && !TypeManager::is_integer(ftype->_parameters->_parameters[0]->_type)) { + if (is_seq && !TypeManager::is_integer(params[index_arg]->_type)) { continue; } @@ -2428,6 +2440,10 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype, break; } + if (cpptype->is_final()) { + itype._flags |= InterrogateType::F_final; + } + if (cpptype->_file.is_c_file()) { // This type declaration appears in a .C file. We can only export types // defined in a .h file. diff --git a/dtool/src/interrogatedb/interrogateType.I b/dtool/src/interrogatedb/interrogateType.I index b5527bbd23..840fdb18f3 100644 --- a/dtool/src/interrogatedb/interrogateType.I +++ b/dtool/src/interrogatedb/interrogateType.I @@ -289,6 +289,14 @@ is_union() const { return (_flags & F_union) != 0; } +/** + * + */ +INLINE bool InterrogateType:: +is_final() const { + return (_flags & F_final) != 0; +} + /** * */ diff --git a/dtool/src/interrogatedb/interrogateType.h b/dtool/src/interrogatedb/interrogateType.h index 151e10b5f5..176efb4fb9 100644 --- a/dtool/src/interrogatedb/interrogateType.h +++ b/dtool/src/interrogatedb/interrogateType.h @@ -75,6 +75,7 @@ public: INLINE bool is_struct() const; INLINE bool is_class() const; INLINE bool is_union() const; + INLINE bool is_final() const; INLINE bool is_fully_defined() const; INLINE bool is_unpublished() const; @@ -139,6 +140,7 @@ private: F_typedef = 0x200000, F_array = 0x400000, F_scoped_enum = 0x800000, + F_final =0x1000000, }; public: diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index 7b920979ef..1156b6dfef 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -17,6 +17,8 @@ #ifdef HAVE_PYTHON +PyTupleObject Dtool_EmptyTuple; + PyMemberDef standard_type_members[] = { {(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"}, @@ -65,15 +67,6 @@ size_t PyLongOrInt_AsSize_t(PyObject *vv) { } #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 * be an instance of a Panda type. It does this using a signature that is @@ -625,6 +618,9 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) { return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)"); } + // Initialize the "empty tuple". + (void)PyObject_INIT_VAR((PyObject *)&Dtool_EmptyTuple, &PyTuple_Type, 0); + // Initialize the base class of everything. Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(NULL); } diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index 05a787de9f..9df9fad4af 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -138,6 +138,12 @@ typedef long Py_hash_t; #define FMTCHAR_BYTES "s" #endif +extern EXPCL_INTERROGATEDB PyTupleObject Dtool_EmptyTuple; + +#ifndef _PyObject_CallNoArg +#define _PyObject_CallNoArg(func) PyObject_Call((func), (PyObject *)&Dtool_EmptyTuple, NULL) +#endif + using namespace std; // this is tempory .. untill this is glued better into the panda build system diff --git a/dtool/src/pystub/pystub.cxx b/dtool/src/pystub/pystub.cxx index c97cea7476..935b3a47b6 100644 --- a/dtool/src/pystub/pystub.cxx +++ b/dtool/src/pystub/pystub.cxx @@ -142,7 +142,6 @@ extern "C" { EXPCL_PYSTUB int PyTuple_New(...); EXPCL_PYSTUB int PyTuple_Pack(...); EXPCL_PYSTUB int PyTuple_Size(...); - EXPCL_PYSTUB int PyTuple_Type(...); EXPCL_PYSTUB int PyType_GenericAlloc(...); EXPCL_PYSTUB int PyType_IsSubtype(...); EXPCL_PYSTUB int PyType_Ready(...); @@ -224,6 +223,7 @@ extern "C" { EXPCL_PYSTUB extern void *PyExc_SystemExit; EXPCL_PYSTUB extern void *PyExc_TypeError; EXPCL_PYSTUB extern void *PyExc_ValueError; + EXPCL_PYSTUB extern void *PyTuple_Type; EXPCL_PYSTUB extern void *PyType_Type; EXPCL_PYSTUB extern void *_PyThreadState_Current; EXPCL_PYSTUB extern void *_Py_FalseStruct; @@ -363,7 +363,6 @@ int PyTuple_GetItem(...) { return 0; } int PyTuple_New(...) { return 0; } int PyTuple_Pack(...) { return 0; } int PyTuple_Size(...) { return 0; }; -int PyTuple_Type(...) { return 0; }; int PyType_GenericAlloc(...) { return 0; }; int PyType_IsSubtype(...) { return 0; } int PyType_Ready(...) { return 0; }; @@ -451,6 +450,7 @@ void *PyExc_StopIteration = (void *)NULL; void *PyExc_SystemExit = (void *)NULL; void *PyExc_TypeError = (void *)NULL; void *PyExc_ValueError = (void *)NULL; +void *PyTuple_Type = (void *)NULL; void *PyType_Type = (void *)NULL; void *_PyThreadState_Current = (void *)NULL; void *_Py_FalseStruct = (void *)NULL; diff --git a/makepanda/test_imports.py b/makepanda/test_imports.py index b5ab5c1977..290ec03e13 100644 --- a/makepanda/test_imports.py +++ b/makepanda/test_imports.py @@ -7,13 +7,19 @@ import os, importlib import direct.showbase.VerboseImport +import imp import panda3d dir = os.path.dirname(panda3d.__file__) -for basename in os.listdir(dir): - module, ext = os.path.splitext(basename) +extensions = set() +for suffix in imp.get_suffixes(): + extensions.add(suffix[0]) - if ext in ('.pyd', '.so'): +for basename in os.listdir(dir): + module = basename.split('.', 1)[0] + ext = basename[len(module):] + + if ext in extensions: importlib.import_module('panda3d.%s' % (module)) diff --git a/panda/src/express/datagramSink.h b/panda/src/express/datagramSink.h index 0c1b74449c..c72cf7595d 100644 --- a/panda/src/express/datagramSink.h +++ b/panda/src/express/datagramSink.h @@ -40,6 +40,10 @@ PUBLISHED: virtual const Filename &get_filename(); virtual const FileReference *get_file(); virtual streampos get_file_pos(); + + MAKE_PROPERTY(filename, get_filename); + MAKE_PROPERTY(file, get_file); + MAKE_PROPERTY(file_pos, get_file_pos); }; #include "datagramSink.I" diff --git a/panda/src/putil/datagramOutputFile.h b/panda/src/putil/datagramOutputFile.h index d2013c75ee..bd2007219a 100644 --- a/panda/src/putil/datagramOutputFile.h +++ b/panda/src/putil/datagramOutputFile.h @@ -28,14 +28,13 @@ * header followed by a number of datagrams. */ class EXPCL_PANDA_PUTIL DatagramOutputFile : public DatagramSink { -public: +PUBLISHED: INLINE DatagramOutputFile(); INLINE ~DatagramOutputFile(); bool open(const FileReference *file); INLINE bool open(const Filename &filename); bool open(ostream &out, const Filename &filename = Filename()); - INLINE ostream &get_stream(); void close(); @@ -46,10 +45,16 @@ public: virtual bool is_error(); virtual void flush(); +public: virtual const Filename &get_filename(); virtual const FileReference *get_file(); virtual streampos get_file_pos(); + INLINE ostream &get_stream(); + +PUBLISHED: + MAKE_PROPERTY(stream, get_stream); + private: bool _wrote_first_datagram; bool _error; diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index 1ccede6968..054581e1fd 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -1440,15 +1440,12 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { break; case WM_SIZE: + // Actually, since we don't return in WM_WINDOWPOSCHANGED, WM_SIZE won't + // end up being called at all. This is more efficient according to MSDN. if (windisplay_cat.is_debug()) { windisplay_cat.debug() << "WM_SIZE: " << hwnd << ", " << wparam << "\n"; } - - // Resist calling handle_reshape before the window has opened. - if (_hWnd != NULL) { - handle_reshape(); - } break; case WM_EXITSIZEMOVE: @@ -1456,8 +1453,15 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { break; case WM_WINDOWPOSCHANGED: + if (windisplay_cat.is_debug()) { + windisplay_cat.debug() + << "WM_WINDOWPOSCHANGED: " << hwnd << ", " << wparam << "\n"; + } + if (_hWnd != NULL) { + handle_reshape(); + } adjust_z_order(); - break; + return 0; case WM_PAINT: // In response to WM_PAINT, we check to see if there are any update