diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..a55a3def2d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{py,pyw}] +indent_style = space +indent_size = 4 + +[*.{h,c,cxx,cpp,I}] +indent_style = space +indent_size = 2 + +[{CMakeLists.txt,*.cmake}] +indent_style = space +indent_size = 2 + +[*.bat] +end_of_line = crlf diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 0000000000..b4bba76898 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,16 @@ +coverage: + status: + project: + default: + threshold: 0.1 + patch: + default: + threshold: 0.1 +codecov: + require_ci_to_pass: true + notify: + after_n_builds: 2 + wait_for_ci: true +comment: + require_changes: true + after_n_builds: 2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e264cc7ed..e709f364bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,6 +109,7 @@ jobs: libeigen3-dev libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev libopenal-dev libpng-dev libssl-dev libvorbis-dev libx11-dev libxcursor-dev libxrandr-dev nvidia-cg-toolkit zlib1g-dev + python3-setuptools # Workaround for CMake 3.12 finding this first: @@ -180,37 +181,6 @@ jobs: run: cmake --build . --config ${{ matrix.config }} --parallel 4 # END A - - name: Setup Python (Python 2.7) - if: contains(matrix.python, 'YES') - uses: actions/setup-python@v1 - with: - python-version: 2.7 - - name: Configure (Python 2.7) - if: contains(matrix.python, 'YES') - working-directory: build - shell: bash - run: > - cmake -DWANT_PYTHON_VERSION=2.7 - -DPython_FIND_REGISTRY=NEVER -DPython_ROOT=$pythonLocation . - - name: Build (Python 2.7) - if: contains(matrix.python, 'YES') - # BEGIN A - working-directory: build - run: cmake --build . --config ${{ matrix.config }} --parallel 4 - # END A - - name: Test (Python 2.7) - # BEGIN B - if: contains(matrix.python, 'YES') - working-directory: build - shell: bash - env: - PYTHONPATH: ${{ matrix.config }} - run: | - PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') - $PYTHON_EXECUTABLE -m pip install pytest - $PYTHON_EXECUTABLE -m pytest ../tests - # END B - - name: Setup Python (Python 3.5) if: contains(matrix.python, 'YES') uses: actions/setup-python@v1 @@ -353,7 +323,7 @@ jobs: llvm-profdata merge pid-*.profraw -o coverage.profdata llvm-cov show $(grep -Rl LLVM_PROFILE_FILE . | sed 's/^/-object /') -instr-profile=coverage.profdata > coverage.txt - bash <(curl -s https://codecov.io/bash) + bash <(curl -s https://codecov.io/bash) -y ../.github/codecov.yml makepanda: strategy: @@ -365,6 +335,7 @@ jobs: - name: Install dependencies (Ubuntu) if: matrix.os == 'ubuntu-16.04' run: | + sudo apt-get update sudo apt-get install build-essential bison flex libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev libopenal-dev libpng-dev libssl-dev libvorbis-dev libx11-dev libxcursor-dev libxrandr-dev nvidia-cg-toolkit zlib1g-dev - name: Get thirdparty packages (Windows) if: runner.os == 'Windows' @@ -406,18 +377,6 @@ jobs: run: | python -m pip install pytest PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - - name: Set up Python 2.7 - uses: actions/setup-python@v1 - with: - python-version: 2.7 - - name: Build Python 2.7 - run: | - python makepanda/makepanda.py --no-copy-python --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir=$pythonLocation/include --python-libdir=$pythonLocation/lib --verbose --threads=4 - - name: Test Python 2.7 - shell: bash - run: | - python -m pip install pytest - PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Make installer run: | python makepanda/makepackage.py --verbose --lzma diff --git a/.travis.yml b/.travis.yml index ee9b09d37e..910892bd97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,9 @@ matrix: - compiler: clang env: PYTHONV=python3 FLAGS=--installer - compiler: clang - env: PYTHONV=python2.7 FLAGS=--override=STDFLOAT_DOUBLE=1 + env: PYTHONV=python3 FLAGS=--override=STDFLOAT_DOUBLE=1 - compiler: gcc - env: PYTHONV=python2.7 FLAGS=--optimize=4 + env: PYTHONV=python3 FLAGS=--optimize=4 before_install: - export CC=gcc-4.7 - export CXX=g++-4.7 diff --git a/CMakeLists.txt b/CMakeLists.txt index f5f03be4d3..9870660adc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,6 @@ endif() if(IS_MULTICONFIG) message(STATUS "Using multi-configuration generator") - set(CMAKE_CONFIGURATION_TYPES ${_configs}) else() # Set the default CMAKE_BUILD_TYPE before calling project(). if(NOT CMAKE_BUILD_TYPE) @@ -80,6 +79,7 @@ include(GNUInstallDirs) # Defines CMAKE_INSTALL_ variables # Include global modules needed for configure scripts include(PackageConfig) # Defines package_option +include(PerConfigOption) # Defines per_config_option # Configure Panda3D include(dtool/CompilerFlags.cmake) diff --git a/README.md b/README.md index 41c29411d3..4168167184 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ python makepanda/makepanda.py --everything --installer ``` You may target a specific minimum macOS version using the --osxtarget flag -followed by the release number, eg. 10.7 or 10.9. +followed by the release number, eg. 10.9 or 10.14. If the build was successful, makepanda will have generated a .dmg file in the source directory containing the installer. Simply open it and run the @@ -164,11 +164,11 @@ pkg install pkgconf bison png jpeg-turbo tiff freetype2 harfbuzz eigen squish op ``` You will also need to choose which version of Python you want to use. -Install the appropriate package for it (such as `python2` or `python36`) and +Install the appropriate package for it (such as `python37` or `python38`) and run the makepanda script with your chosen Python version: ```bash -python3.6 makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-gles2 +python3.7 makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-gles2 ``` If successful, this will produce a .pkg file in the root of the source diff --git a/cmake/macros/PerConfigOption.cmake b/cmake/macros/PerConfigOption.cmake new file mode 100644 index 0000000000..44be908384 --- /dev/null +++ b/cmake/macros/PerConfigOption.cmake @@ -0,0 +1,50 @@ +# Filename: PerConfigOption.cmake +# +# This contains a convenience function for defining per-config options. +# In single-config generators, it will set the option based on the defined +# CMAKE_BUILD_TYPE. In multi-config generators, it will create separate +# options, one per config. +# +# Function: per_config_option +# Usage: +# option(name "help string" [Config1] [Config2] [...ConfigN]) +# +# Example: +# per_config_option(DO_DEBUGGING "Enables debugging." Debug Standard) + +set(_PER_CONFIG_OPTIONS CACHE INTERNAL "Internal variable") + +function(per_config_option name help) + set(_configs ${ARGN}) + + # In single-config generatotrs, we simply create one config. + if(NOT IS_MULTICONFIG) + list(FIND _configs "${CMAKE_BUILD_TYPE}" _index) + if(${_index} GREATER -1) + option("${name}" "${help}" ON) + else() + option("${name}" "${help}" OFF) + endif() + + elseif(DEFINED "${name}") + # It's been explicitly defined, so that makes it not a multi-configuration + # variable anymore. + option("${name}" "${help}") + return() + + else() + foreach(_config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER "${_config}" _config_upper) + list(FIND _configs "${_config}" _index) + if(${_index} GREATER -1) + option("${name}_${_config_upper}" "${help}" ON) + else() + option("${name}_${_config_upper}" "${help}" OFF) + endif() + endforeach() + + endif() + + list(APPEND _PER_CONFIG_OPTIONS "${name}") + set(_PER_CONFIG_OPTIONS "${_PER_CONFIG_OPTIONS}" CACHE INTERNAL "Internal variable") +endfunction(per_config_option) diff --git a/cmake/templates/METADATA.in b/cmake/templates/METADATA.in new file mode 100644 index 0000000000..8d0cd6cc84 --- /dev/null +++ b/cmake/templates/METADATA.in @@ -0,0 +1,7 @@ +Metadata-Version: 2.0 +Name: Panda3D +Version: ${PROJECT_VERSION} +License: BSD +Home-page: https://www.panda3d.org/ +Author: Panda3D Team +Author-email: etc-panda3d@lists.andrew.cmu.edu diff --git a/direct/src/cluster/ClusterMsgs.py b/direct/src/cluster/ClusterMsgs.py index ba166f7c09..7de69420b9 100644 --- a/direct/src/cluster/ClusterMsgs.py +++ b/direct/src/cluster/ClusterMsgs.py @@ -31,18 +31,16 @@ CLUSTER_DAEMON_PORT = 8001 CLUSTER_SERVER_PORT = 1970 # Precede command string with ! to tell server to execute command string -# NOTE: Had to stick with the import __builtin__ scheme, at startup, -# __builtins__ is a module, not a dictionary, like it is inside of a module # Note, this startup string obviates the need to set any cluster related # config variables in the client Configrc files SERVER_STARTUP_STRING = ( '!bash ppython -c ' + - '"import __builtin__; ' + - '__builtin__.clusterMode = \'server\';' + - '__builtin__.clusterServerPort = %s;' + - '__builtin__.clusterSyncFlag = %d;' + - '__builtin__.clusterDaemonClient = \'%s\';' + - '__builtin__.clusterDaemonPort = %d;' + '"import builtins; ' + + 'builtins.clusterMode = \'server\';' + + 'builtins.clusterServerPort = %s;' + + 'builtins.clusterSyncFlag = %d;' + + 'builtins.clusterDaemonClient = \'%s\';' + + 'builtins.clusterDaemonPort = %d;' 'from direct.directbase.DirectStart import *; run()"') class ClusterMsgHandler: diff --git a/direct/src/dcparser/dcClass.cxx b/direct/src/dcparser/dcClass.cxx index f1d6955981..e6a5fce230 100644 --- a/direct/src/dcparser/dcClass.cxx +++ b/direct/src/dcparser/dcClass.cxx @@ -85,9 +85,7 @@ DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) : */ DCClass:: ~DCClass() { - if (_constructor != nullptr) { - delete _constructor; - } + delete _constructor; Fields::iterator fi; for (fi = _fields.begin(); fi != _fields.end(); ++fi) { diff --git a/direct/src/dcparser/dcClass_ext.cxx b/direct/src/dcparser/dcClass_ext.cxx index 4e9ffb9aa9..a37749b04a 100644 --- a/direct/src/dcparser/dcClass_ext.cxx +++ b/direct/src/dcparser/dcClass_ext.cxx @@ -540,11 +540,7 @@ client_format_generate_CMU(PyObject *distobj, DOID_TYPE do_id, for (int i = 0; i < num_optional_fields; i++) { PyObject *py_field_name = PySequence_GetItem(optional_fields, i); -#if PY_MAJOR_VERSION >= 3 std::string field_name = PyUnicode_AsUTF8(py_field_name); -#else - std::string field_name = PyString_AsString(py_field_name); -#endif Py_XDECREF(py_field_name); DCField *field = _this->get_field_by_name(field_name); @@ -621,11 +617,7 @@ ai_format_generate(PyObject *distobj, DOID_TYPE do_id, for (int i = 0; i < num_optional_fields; ++i) { PyObject *py_field_name = PySequence_GetItem(optional_fields, i); -#if PY_MAJOR_VERSION >= 3 std::string field_name = PyUnicode_AsUTF8(py_field_name); -#else - std::string field_name = PyString_AsString(py_field_name); -#endif Py_XDECREF(py_field_name); DCField *field = _this->get_field_by_name(field_name); diff --git a/direct/src/dcparser/dcField_ext.cxx b/direct/src/dcparser/dcField_ext.cxx index 3d229b2906..e2c1167811 100644 --- a/direct/src/dcparser/dcField_ext.cxx +++ b/direct/src/dcparser/dcField_ext.cxx @@ -266,22 +266,14 @@ get_pystr(PyObject *value) { PyObject *str = PyObject_Str(value); if (str != nullptr) { -#if PY_MAJOR_VERSION >= 3 std::string result = PyUnicode_AsUTF8(str); -#else - std::string result = PyString_AsString(str); -#endif Py_DECREF(str); return result; } PyObject *repr = PyObject_Repr(value); if (repr != nullptr) { -#if PY_MAJOR_VERSION >= 3 std::string result = PyUnicode_AsUTF8(repr); -#else - std::string result = PyString_AsString(repr); -#endif Py_DECREF(repr); return result; } @@ -289,11 +281,7 @@ get_pystr(PyObject *value) { if (value->ob_type != nullptr) { PyObject *typestr = PyObject_Str((PyObject *)(value->ob_type)); if (typestr != nullptr) { -#if PY_MAJOR_VERSION >= 3 std::string result = PyUnicode_AsUTF8(typestr); -#else - std::string result = PyString_AsString(typestr); -#endif Py_DECREF(typestr); return result; } diff --git a/direct/src/dcparser/dcPacker.I b/direct/src/dcparser/dcPacker.I index 6b6ef79ee5..c9212b3302 100644 --- a/direct/src/dcparser/dcPacker.I +++ b/direct/src/dcparser/dcPacker.I @@ -1124,7 +1124,9 @@ operator new(size_t size) { */ INLINE void DCPacker::StackElement:: operator delete(void *ptr) { - StackElement *obj = (StackElement *)ptr; - obj->_next = _deleted_chain; - _deleted_chain = obj; + if (ptr != nullptr) { + StackElement *obj = (StackElement *)ptr; + obj->_next = _deleted_chain; + _deleted_chain = obj; + } } diff --git a/direct/src/dcparser/dcPackerCatalog.cxx b/direct/src/dcparser/dcPackerCatalog.cxx index 594c7b6742..86966aed1c 100644 --- a/direct/src/dcparser/dcPackerCatalog.cxx +++ b/direct/src/dcparser/dcPackerCatalog.cxx @@ -44,9 +44,7 @@ DCPackerCatalog(const DCPackerCatalog ©) : */ DCPackerCatalog:: ~DCPackerCatalog() { - if (_live_catalog != nullptr) { - delete _live_catalog; - } + delete _live_catalog; SwitchCatalogs::iterator si; for (si = _switch_catalogs.begin(); si != _switch_catalogs.end(); ++si) { diff --git a/direct/src/dcparser/dcPackerInterface.cxx b/direct/src/dcparser/dcPackerInterface.cxx index db51d2712c..54784391c4 100644 --- a/direct/src/dcparser/dcPackerInterface.cxx +++ b/direct/src/dcparser/dcPackerInterface.cxx @@ -60,9 +60,7 @@ DCPackerInterface(const DCPackerInterface ©) : */ DCPackerInterface:: ~DCPackerInterface() { - if (_catalog != nullptr) { - delete _catalog; - } + delete _catalog; } /** diff --git a/direct/src/dcparser/dcPacker_ext.cxx b/direct/src/dcparser/dcPacker_ext.cxx index 8e7eb1ec5f..0b1770b819 100644 --- a/direct/src/dcparser/dcPacker_ext.cxx +++ b/direct/src/dcparser/dcPacker_ext.cxx @@ -40,12 +40,6 @@ pack_object(PyObject *object) { _this->pack_int64(PyLong_AsLongLong(object)); return; } -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(object)) { - _this->pack_int64(PyInt_AsLong(object)); - return; - } -#endif break; case PT_uint64: @@ -53,14 +47,6 @@ pack_object(PyObject *object) { _this->pack_uint64(PyLong_AsUnsignedLongLong(object)); return; } -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(object)) { - PyObject *obj1 = PyNumber_Long(object); - _this->pack_int(PyLong_AsUnsignedLongLong(obj1)); - Py_DECREF(obj1); - return; - } -#endif break; case PT_int: @@ -68,12 +54,6 @@ pack_object(PyObject *object) { _this->pack_int(PyLong_AsLong(object)); return; } -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(object)) { - _this->pack_int(PyInt_AsLong(object)); - return; - } -#endif break; case PT_uint: @@ -81,14 +61,6 @@ pack_object(PyObject *object) { _this->pack_uint(PyLong_AsUnsignedLong(object)); return; } -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(object)) { - PyObject *obj1 = PyNumber_Long(object); - _this->pack_uint(PyLong_AsUnsignedLong(obj1)); - Py_DECREF(obj1); - return; - } -#endif break; default: @@ -97,15 +69,10 @@ pack_object(PyObject *object) { if (PyLong_Check(object)) { _this->pack_int(PyLong_AsLong(object)); -#if PY_MAJOR_VERSION < 3 - } else if (PyInt_Check(object)) { - _this->pack_int(PyInt_AS_LONG(object)); -#endif } else if (PyFloat_Check(object)) { _this->pack_double(PyFloat_AS_DOUBLE(object)); } else if (PyLong_Check(object)) { _this->pack_int64(PyLong_AsLongLong(object)); -#if PY_MAJOR_VERSION >= 3 } else if (PyUnicode_Check(object)) { const char *buffer; Py_ssize_t length; @@ -120,15 +87,6 @@ pack_object(PyObject *object) { if (buffer) { _this->pack_blob(vector_uchar(buffer, buffer + length)); } -#else - } else if (PyString_Check(object) || PyUnicode_Check(object)) { - char *buffer; - Py_ssize_t length; - PyString_AsStringAndSize(object, &buffer, &length); - if (buffer) { - _this->pack_string(std::string(buffer, length)); - } -#endif } else { // For some reason, PySequence_Check() is incorrectly reporting that a // class instance is a sequence, even if it doesn't provide __len__, so we @@ -230,26 +188,14 @@ unpack_object() { case PT_int: { int value = _this->unpack_int(); -#if PY_MAJOR_VERSION >= 3 object = PyLong_FromLong(value); -#else - object = PyInt_FromLong(value); -#endif } break; case PT_uint: { unsigned int value = _this->unpack_uint(); -#if PY_MAJOR_VERSION >= 3 object = PyLong_FromLong(value); -#else - if (value & 0x80000000) { - object = PyLong_FromUnsignedLong(value); - } else { - object = PyInt_FromLong(value); - } -#endif } break; @@ -268,25 +214,18 @@ unpack_object() { break; case PT_blob: -#if PY_MAJOR_VERSION >= 3 { std::string str; _this->unpack_string(str); object = PyBytes_FromStringAndSize(str.data(), str.size()); } break; -#endif - // On Python 2, fall through to below. case PT_string: { std::string str; _this->unpack_string(str); -#if PY_MAJOR_VERSION >= 3 object = PyUnicode_FromStringAndSize(str.data(), str.size()); -#else - object = PyString_FromStringAndSize(str.data(), str.size()); -#endif } break; diff --git a/direct/src/dcparser/dcSwitch.cxx b/direct/src/dcparser/dcSwitch.cxx index 041533efbe..dba5dacad0 100644 --- a/direct/src/dcparser/dcSwitch.cxx +++ b/direct/src/dcparser/dcSwitch.cxx @@ -42,21 +42,15 @@ DCSwitch:: nassertv(_key_parameter != nullptr); delete _key_parameter; - Cases::iterator ci; - for (ci = _cases.begin(); ci != _cases.end(); ++ci) { - SwitchCase *dcase = (*ci); + for (SwitchCase *dcase : _cases) { delete dcase; } - CaseFields::iterator fi; - for (fi = _case_fields.begin(); fi != _case_fields.end(); ++fi) { - SwitchFields *fields = (*fi); + for (SwitchFields *fields : _case_fields) { delete fields; } - Fields::iterator ni; - for (ni = _nested_fields.begin(); ni != _nested_fields.end(); ++ni) { - DCField *field = (*ni); + for (DCField *field : _nested_fields) { delete field; } } diff --git a/direct/src/directscripts/extract_docs.py b/direct/src/directscripts/extract_docs.py index 50a775d108..68f3671193 100644 --- a/direct/src/directscripts/extract_docs.py +++ b/direct/src/directscripts/extract_docs.py @@ -9,7 +9,7 @@ from __future__ import print_function __all__ = [] -import os, sys +import os from distutils import sysconfig import panda3d, pandac from panda3d.interrogatedb import * @@ -309,13 +309,8 @@ if __name__ == "__main__": processModule(handle, "core") # Determine the suffix for the extension modules. - if sys.version_info >= (3, 0): - import _imp - ext_suffix = _imp.extension_suffixes()[0] - elif sys.platform == "win32": - ext_suffix = ".pyd" - else: - ext_suffix = ".so" + import _imp + ext_suffix = _imp.extension_suffixes()[0] for lib in os.listdir(os.path.dirname(panda3d.__file__)): if lib.endswith(ext_suffix) and not lib.startswith('core.'): diff --git a/direct/src/directtools/DirectSession.py b/direct/src/directtools/DirectSession.py index 367b753064..8d4d2391f5 100644 --- a/direct/src/directtools/DirectSession.py +++ b/direct/src/directtools/DirectSession.py @@ -1,5 +1,4 @@ import math -import sys from panda3d.core import * from .DirectUtil import * @@ -942,10 +941,7 @@ class DirectSession(DirectObject): def getAndSetName(self, nodePath): """ Prompt user for new node path name """ - if sys.version_info >= (3, 0): - from tkinter.simpledialog import askstring - else: - from tkSimpleDialog import askstring + from tkinter.simpledialog import askstring newName = askstring('Node Path: ' + nodePath.getName(), 'Enter new name:') if newName: diff --git a/direct/src/dist/FreezeTool.py b/direct/src/dist/FreezeTool.py index f7b2ea9b91..f448913bd9 100644 --- a/direct/src/dist/FreezeTool.py +++ b/direct/src/dist/FreezeTool.py @@ -36,21 +36,15 @@ isDebugBuild = (python.lower().endswith('_d')) # NB. if encodings are removed, be sure to remove them from the shortcut in # deploy-stub.c. startupModules = [ - 'imp', 'encodings', 'encodings.*', + 'imp', 'encodings', 'encodings.*', 'io', 'marshal', 'importlib.machinery', + 'importlib.util', ] -if sys.version_info >= (3, 0): - # Modules specific to Python 3 - startupModules += ['io', 'marshal', 'importlib.machinery', 'importlib.util'] -else: - # Modules specific to Python 2 - startupModules += [] # These are some special init functions for some built-in Python modules that # deviate from the standard naming convention. A value of None means that a # dummy entry should be written to the inittab. builtinInitFuncs = { 'builtins': None, - '__builtin__': None, 'sys': None, 'exceptions': None, '_warnings': '_PyWarnings_Init', @@ -76,6 +70,7 @@ hiddenImports = { 'datetime': ['_strptime'], 'keyring.backends': ['keyring.backends.*'], 'matplotlib.font_manager': ['encodings.mac_roman'], + 'matplotlib.backends._backend_tk': ['tkinter'], 'direct.particles': ['direct.particles.ParticleManagerGlobal'], 'numpy.core._multiarray_umath': [ 'numpy.core._internal', @@ -84,12 +79,6 @@ hiddenImports = { ], } -if sys.version_info >= (3,): - hiddenImports['matplotlib.backends._backend_tk'] = ['tkinter'] -else: - hiddenImports['matplotlib.backends._backend_tk'] = ['Tkinter'] - - # These are overrides for specific modules. overrideModules = { # Used by the warnings module, among others, to get line numbers. Since @@ -1311,11 +1300,7 @@ class Freezer: def __addPyc(self, multifile, filename, code, compressionLevel): if code: - data = imp.get_magic() + b'\0\0\0\0' - - if sys.version_info >= (3, 0): - data += b'\0\0\0\0' - + data = imp.get_magic() + b'\0\0\0\0\0\0\0\0' data += marshal.dumps(code) stream = StringStream(data) @@ -1672,10 +1657,7 @@ class Freezer: # initmodule or PyInit_module function. modname = mod.split('.')[-1] libfile = modname + '.lib' - if sys.version_info >= (3, 0): - symbolName = 'PyInit_' + modname - else: - symbolName = 'init' + modname + symbolName = 'PyInit_' + modname os.system('lib /nologo /def /export:%s /name:%s.pyd /out:%s' % (symbolName, modname, libfile)) extraLink.append(libfile) cleanFiles += [libfile, modname + '.exp'] @@ -1779,10 +1761,7 @@ class Freezer: code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(sys.path[0], "%s%s"))' % (moduleName, moduleName, moduleName, modext) else: code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(os.path.dirname(sys.executable), "%s%s"))' % (moduleName, moduleName, moduleName, modext) - if sys.version_info >= (3, 2): - code = compile(code, moduleName, 'exec', optimize=2) - else: - code = compile(code, moduleName, 'exec') + code = compile(code, moduleName, 'exec', optimize=2) code = marshal.dumps(code) moduleList.append((moduleName, len(pool), len(code))) pool += code @@ -2274,7 +2253,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder): except KeyError: return None - if sys.version_info >= (3, 0) and 'b' not in mode: + if 'b' not in mode: return io.TextIOWrapper(fp, encoding='utf8') return fp @@ -2359,27 +2338,14 @@ class PandaModuleFinder(modulefinder.ModuleFinder): raise co = marshal.loads(memoryview(data)[16:]) - elif sys.version_info >= (3, 4): + else: try: - if sys.version_info >= (3, 5): - marshal_data = importlib._bootstrap_external._validate_bytecode_header(fp.read()) - else: - marshal_data = importlib._bootstrap._validate_bytecode_header(fp.read()) + marshal_data = importlib._bootstrap_external._validate_bytecode_header(fp.read()) except ImportError as exc: self.msgout(2, "raise ImportError: " + str(exc), pathname) raise co = marshal.loads(marshal_data) - else: - if fp.read(4) != imp.get_magic(): - self.msgout(2, "raise ImportError: Bad magic number", pathname) - raise ImportError("Bad magic number in %s" % pathname) - - fp.read(4) - if sys.version_info >= (3, 3): - fp.read(4) - - co = marshal.load(fp) else: co = None @@ -2489,7 +2455,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder): # If we found folders on the path with this module name without an # __init__.py file, we should consider this a namespace package. - if ns_dirs and sys.version_info >= (3, 3): + if ns_dirs: return (None, ns_dirs, ('', '', _PKG_NAMESPACE_DIRECTORY)) raise ImportError(name) diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index 1b70a70268..42997c63f4 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -30,10 +30,6 @@ from .icon import Icon import panda3d.core as p3d -if 'basestring' not in globals(): - basestring = str - - if sys.version_info < (3, 0): # Python 3 defines these subtypes of IOError, but Python 2 doesn't. FileNotFoundError = IOError @@ -48,7 +44,7 @@ if sys.version_info < (3, 0): def _parse_list(input): - if isinstance(input, basestring): + if isinstance(input, str): input = input.strip().replace(',', '\n') if input: return [item.strip() for item in input.split('\n') if item.strip()] @@ -123,45 +119,7 @@ PACKAGE_LIB_DIRS = { 'scipy': ['scipy/extra-dll'], } -# site.py for Python 2. -SITE_PY2 = u""" -import sys - -sys.frozen = True - -# Override __import__ to set __file__ for frozen modules. -prev_import = __import__ -def __import__(*args, **kwargs): - mod = prev_import(*args, **kwargs) - if mod: - mod.__file__ = sys.executable - return mod - -# Add our custom __import__ version to the global scope, as well as a builtin -# definition for __file__ so that it is available in the module itself. -import __builtin__ -__builtin__.__import__ = __import__ -__builtin__.__file__ = sys.executable -del __builtin__ - -# Set the TCL_LIBRARY directory to the location of the Tcl/Tk/Tix files. -import os -tcl_dir = os.path.join(os.path.dirname(sys.executable), 'tcl') -if os.path.isdir(tcl_dir): - for dir in os.listdir(tcl_dir): - sub_dir = os.path.join(tcl_dir, dir) - if os.path.isdir(sub_dir): - if dir.startswith('tcl'): - os.environ['TCL_LIBRARY'] = sub_dir - if dir.startswith('tk'): - os.environ['TK_LIBRARY'] = sub_dir - if dir.startswith('tix'): - os.environ['TIX_LIBRARY'] = sub_dir -del os -""" - -# site.py for Python 3. -SITE_PY3 = u""" +SITE_PY = u""" import sys from _frozen_importlib import _imp, FrozenImporter @@ -209,8 +167,6 @@ if os.path.isdir(tcl_dir): del os """ -SITE_PY = SITE_PY3 if sys.version_info >= (3,) else SITE_PY2 - class build_apps(setuptools.Command): description = 'build Panda3D applications' @@ -407,10 +363,6 @@ class build_apps(setuptools.Command): if sys.version_info < (3, 8): abi_tag += 'm' - # For these distributions, we need to append 'u' on Linux - if abi_tag in ('cp26m', 'cp27m', 'cp32m') and not platform.startswith('win') and not platform.startswith('macosx'): - abi_tag += 'u' - whldir = os.path.join(whlcache, '_'.join((platform, abi_tag))) os.makedirs(whldir, exist_ok=True) @@ -571,15 +523,19 @@ class build_apps(setuptools.Command): libdir = os.path.dirname(dtool_fn.to_os_specific()) etcdir = os.path.join(libdir, '..', 'etc') - for fn in os.listdir(etcdir): + etcfiles = os.listdir(etcdir) + etcfiles.sort(reverse=True) + for fn in etcfiles: if fn.lower().endswith('.prc'): with open(os.path.join(etcdir, fn)) as f: prcstring += f.read() else: etcfiles = [i for i in p3dwhl.namelist() if i.endswith('.prc')] + etcfiles.sort(reverse=True) for fn in etcfiles: with p3dwhl.open(fn) as f: prcstring += f.read().decode('utf8') + user_prcstring = self.extra_prc_data for fn in self.extra_prc_files: with open(fn) as f: @@ -598,12 +554,33 @@ class build_apps(setuptools.Command): for ln in prcstr.split('\n'): ln = ln.strip() useline = True + if ln.startswith('#') or not ln: continue - if 'model-cache-dir' in ln: - ln = ln.replace('/panda3d', '/{}'.format(self.distribution.get_name())) + + words = ln.split(None, 1) + if not words: + continue + var = words[0] + value = words[1] if len(words) > 1 else '' + + # Strip comment after value. + c = value.find(' #') + if c > 0: + value = value[:c].rstrip() + + if var == 'model-cache-dir' and value: + value = value.replace('/panda3d', '/{}'.format(self.distribution.get_name())) + + if var == 'audio-library-name': + # We have the default set to p3fmod_audio on macOS in 1.10, + # but this can be unexpected as other platforms use OpenAL + # by default. Switch it up if FMOD is not included. + if value not in self.plugins and value == 'p3fmod_audio' and 'p3openal_audio' in self.plugins: + self.warn("Missing audio plugin p3fmod_audio referenced in PRC data, replacing with p3openal_audio") + for plugin in check_plugins: - if plugin in ln and plugin not in self.plugins: + if plugin in value and plugin not in self.plugins: useline = False if warn_on_missing_plugin: self.warn( @@ -611,7 +588,10 @@ class build_apps(setuptools.Command): ) break if useline: - out.append(ln) + if value: + out.append(var + ' ' + value) + else: + out.append(var) return out prcexport = parse_prc(prcstring, 0) + parse_prc(user_prcstring, 1) @@ -778,11 +758,10 @@ class build_apps(setuptools.Command): basename = module.rsplit('.', 1)[0] + '.' + basename # Remove python version string - if sys.version_info >= (3, 0): - parts = basename.split('.') - if len(parts) >= 3 and '-' in parts[-2]: - parts = parts[:-2] + parts[-1:] - basename = '.'.join(parts) + parts = basename.split('.') + if len(parts) >= 3 and '-' in parts[-2]: + parts = parts[:-2] + parts[-1:] + basename = '.'.join(parts) else: # Builtin module, but might not be builtin in wheel libs, so double check if module in whl_modules: @@ -801,9 +780,8 @@ class build_apps(setuptools.Command): #TODO: get this to work on non-Windows platforms. if sys.platform == "win32" and platform.startswith('win'): tcl_dir = os.path.join(sys.prefix, 'tcl') - tkinter_name = 'tkinter' if sys.version_info >= (3, 0) else 'Tkinter' - if os.path.isdir(tcl_dir) and tkinter_name in freezer_modules: + if os.path.isdir(tcl_dir) and 'tkinter' in freezer_modules: self.announce('Copying Tcl files', distutils.log.INFO) os.makedirs(os.path.join(builddir, 'tcl')) diff --git a/direct/src/dist/pefile.py b/direct/src/dist/pefile.py index 548c09e1b7..aa09c40667 100755 --- a/direct/src/dist/pefile.py +++ b/direct/src/dist/pefile.py @@ -10,11 +10,7 @@ from collections import namedtuple from array import array import time from io import BytesIO -import sys -if sys.version_info >= (3, 0): - unicode = str - unichr = chr # Define some internally used structures. RVASize = namedtuple('RVASize', ('addr', 'size')) @@ -38,7 +34,7 @@ def _unpack_wstring(mem, offs=0): name = "" for i in range(name_len): offs += 2 - name += unichr(*unpack('= (3, 0): - from pickle import dumps, loads -else: - from cPickle import dumps, loads +from pickle import dumps, loads class NetMessenger(Messenger): diff --git a/direct/src/distributed/ServerRepository.py b/direct/src/distributed/ServerRepository.py index 966d22923b..ac0f2c6856 100644 --- a/direct/src/distributed/ServerRepository.py +++ b/direct/src/distributed/ServerRepository.py @@ -628,7 +628,7 @@ class ServerRepository: del self.clientsByConnection[client.connection] del self.clientsByDoIdBase[client.doIdBase] - id = client.doIdBase / self.doIdRange + id = client.doIdBase // self.doIdRange self.idAllocator.free(id) self.qcr.removeConnection(client.connection) @@ -689,7 +689,7 @@ class ServerRepository: def clientHardDisconnectTask(self, task): """ client did not tell us he was leaving but we lost connection to him, so we need to update our data and tell others """ - for client in self.clientsByConnection.values(): + for client in list(self.clientsByConnection.values()): if not self.qcr.isConnectionOk(client.connection): self.handleClientDisconnect(client) return Task.cont diff --git a/direct/src/distributed/cConnectionRepository.cxx b/direct/src/distributed/cConnectionRepository.cxx index 59617330f5..5df82cd619 100644 --- a/direct/src/distributed/cConnectionRepository.cxx +++ b/direct/src/distributed/cConnectionRepository.cxx @@ -411,19 +411,12 @@ send_datagram(const Datagram &dg) { if (!result && _bdc.IsConnected()) { #ifdef HAVE_PYTHON std::ostringstream s; - -#if PY_VERSION_HEX >= 0x03030000 - PyObject *exc_type = PyExc_ConnectionError; -#else - PyObject *exc_type = PyExc_OSError; -#endif - s << endl << "Error sending message: " << endl; dg.dump_hex(s); s << "Message data: " << dg.get_data() << endl; string message = s.str(); - PyErr_SetString(exc_type, message.c_str()); + PyErr_SetString(PyExc_ConnectionError, message.c_str()); #endif } return result; @@ -922,22 +915,14 @@ describe_message(std::ostream &out, const string &prefix, if (_python_repository != nullptr) { PyObject *msgId = PyLong_FromLong(msg_type); nassertv(msgId != nullptr); -#if PY_MAJOR_VERSION >= 3 PyObject *methodName = PyUnicode_FromString("_getMsgName"); -#else - PyObject *methodName = PyString_FromString("_getMsgName"); -#endif nassertv(methodName != nullptr); PyObject *result = PyObject_CallMethodObjArgs(_python_repository, methodName, msgId, nullptr); nassertv(result != nullptr); -#if PY_MAJOR_VERSION >= 3 msgName += string(PyUnicode_AsUTF8(result)); -#else - msgName += string(PyString_AsString(result)); -#endif Py_DECREF(methodName); Py_DECREF(msgId); diff --git a/direct/src/doc/howto.adjust b/direct/src/doc/howto.adjust index cf6925ad2f..5d4027e177 100644 --- a/direct/src/doc/howto.adjust +++ b/direct/src/doc/howto.adjust @@ -52,10 +52,7 @@ of the slider to change settings. Click on: You can pack multiple sliders into a single panel: -if sys.version_info >= (3, 0): - from tkinter import * -else: - from Tkinter import * +from tkinter import * def func1(x): print '1:', x diff --git a/direct/src/extensions_native/extension_native_helpers.py b/direct/src/extensions_native/extension_native_helpers.py index e9648e7440..2a302f415e 100644 --- a/direct/src/extensions_native/extension_native_helpers.py +++ b/direct/src/extensions_native/extension_native_helpers.py @@ -1,17 +1,13 @@ __all__ = ["Dtool_ObjectToDict", "Dtool_funcToMethod"] -import sys def Dtool_ObjectToDict(cls, name, obj): cls.DtoolClassDict[name] = obj + def Dtool_funcToMethod(func, cls, method_name=None): """Adds func to class so it is an accessible method; use method_name to specify the name to be used for calling the method. The new method is accessible to any instance immediately.""" - if sys.version_info < (3, 0): - func.im_class = cls - func.im_func = func - func.im_self = None func.__func__ = func func.__self__ = None if not method_name: diff --git a/direct/src/gui/DirectEntry.py b/direct/src/gui/DirectEntry.py index d870bf0c7e..1c20141a14 100644 --- a/direct/src/gui/DirectEntry.py +++ b/direct/src/gui/DirectEntry.py @@ -12,7 +12,6 @@ from direct.showbase import ShowBaseGlobal from . import DirectGuiGlobals as DGG from .DirectFrame import * from .OnscreenText import OnscreenText -import sys # import this to make sure it gets pulled into the publish import encodings.utf_8 from direct.showbase.DirectObject import DirectObject @@ -274,16 +273,9 @@ class DirectEntry(DirectFrame): does not change the current cursor position. Also see enterText(). """ - if sys.version_info >= (3, 0): - assert not isinstance(text, bytes) - self.unicodeText = True - self.guiItem.setWtext(text) - else: - self.unicodeText = isinstance(text, unicode) - if self.unicodeText: - self.guiItem.setWtext(text) - else: - self.guiItem.setText(text) + assert not isinstance(text, bytes) + self.unicodeText = True + self.guiItem.setWtext(text) def get(self, plain = False): """ Returns the text currently showing in the typable region. diff --git a/direct/src/gui/DirectFrame.py b/direct/src/gui/DirectFrame.py index cf66bd6a47..96b782a666 100644 --- a/direct/src/gui/DirectFrame.py +++ b/direct/src/gui/DirectFrame.py @@ -24,12 +24,6 @@ from .DirectGuiBase import * from .OnscreenImage import OnscreenImage from .OnscreenGeom import OnscreenGeom from .OnscreenText import OnscreenText -import sys - -if sys.version_info >= (3, 0): - stringType = str -else: - stringType = basestring class DirectFrame(DirectGuiWidget): @@ -105,7 +99,7 @@ class DirectFrame(DirectGuiWidget): self["text"] = text text = self["text"] - if text is None or isinstance(text, stringType): + if text is None or isinstance(text, str): text_list = (text,) * self['numStates'] else: text_list = text @@ -126,7 +120,7 @@ class DirectFrame(DirectGuiWidget): geom = self["geom"] if geom is None or \ isinstance(geom, NodePath) or \ - isinstance(geom, stringType): + isinstance(geom, str): geom_list = (geom,) * self['numStates'] else: geom_list = geom @@ -147,11 +141,11 @@ class DirectFrame(DirectGuiWidget): if image is None or \ isinstance(image, NodePath) or \ isinstance(image, Texture) or \ - isinstance(image, stringType) or \ + isinstance(image, str) or \ isinstance(image, Filename) or \ (len(image) == 2 and \ - isinstance(image[0], stringType) and \ - isinstance(image[1], stringType)): + isinstance(image[0], str) and \ + isinstance(image[1], str)): image_list = (image,) * self['numStates'] else: image_list = image diff --git a/direct/src/gui/DirectGuiBase.py b/direct/src/gui/DirectGuiBase.py index fecfea608a..21c2b3acd5 100644 --- a/direct/src/gui/DirectGuiBase.py +++ b/direct/src/gui/DirectGuiBase.py @@ -97,12 +97,6 @@ from .OnscreenImage import * from direct.directtools.DirectUtil import ROUND_TO from direct.showbase import DirectObject from direct.task import Task -import sys - -if sys.version_info >= (3, 0): - stringType = str -else: - stringType = basestring guiObjectCollector = PStatCollector("Client::GuiObjects") @@ -960,7 +954,7 @@ class DirectGuiWidget(DirectGuiBase, NodePath): # Convert None, and string arguments if relief == None: relief = PGFrameStyle.TNone - elif isinstance(relief, stringType): + elif isinstance(relief, str): # Convert string to frame style int relief = DGG.FrameStyleDict[relief] # Set style @@ -1001,14 +995,14 @@ class DirectGuiWidget(DirectGuiBase, NodePath): textures = self['frameTexture'] if textures == None or \ isinstance(textures, Texture) or \ - isinstance(textures, stringType): + isinstance(textures, str): textures = (textures,) * self['numStates'] for i in range(self['numStates']): if i >= len(textures): texture = textures[-1] else: texture = textures[i] - if isinstance(texture, stringType): + if isinstance(texture, str): texture = loader.loadTexture(texture) if texture: self.frameStyle[i].setTexture(texture) diff --git a/direct/src/gui/DirectScrolledList.py b/direct/src/gui/DirectScrolledList.py index 6cb39675b6..ffe43ab3e7 100644 --- a/direct/src/gui/DirectScrolledList.py +++ b/direct/src/gui/DirectScrolledList.py @@ -13,12 +13,6 @@ from direct.directnotify import DirectNotifyGlobal from direct.task.Task import Task from .DirectFrame import * from .DirectButton import * -import sys - -if sys.version_info >= (3,0): - stringType = str -else: - stringType = basestring class DirectScrolledListItem(DirectButton): @@ -71,7 +65,7 @@ class DirectScrolledList(DirectFrame): # so we can modify it without mangling the user's list if 'items' in kw: for item in kw['items']: - if not isinstance(item, stringType): + if not isinstance(item, str): break else: # we get here if every item in 'items' is a string @@ -116,7 +110,7 @@ class DirectScrolledList(DirectFrame): DirectFrame, (self,), ) for item in self["items"]: - if not isinstance(item, stringType): + if not isinstance(item, str): item.reparentTo(self.itemFrame) self.initialiseoptions(DirectScrolledList) @@ -134,7 +128,7 @@ class DirectScrolledList(DirectFrame): else: self.maxHeight = 0.0 for item in self["items"]: - if not isinstance(item, stringType): + if not isinstance(item, str): self.maxHeight = max(self.maxHeight, item.getHeight()) def setScrollSpeed(self): @@ -182,7 +176,7 @@ class DirectScrolledList(DirectFrame): if len(self["items"]) == 0: return 0 - if isinstance(self["items"][0], stringType): + if isinstance(self["items"][0], str): self.notify.warning("getItemIndexForItemID: cant find itemID for non-class list items!") return 0 @@ -248,7 +242,7 @@ class DirectScrolledList(DirectFrame): # Hide them all for item in self["items"]: - if not isinstance(item, stringType): + if not isinstance(item, str): item.hide() # Then show the ones in range, and stack their positions @@ -258,7 +252,7 @@ class DirectScrolledList(DirectFrame): #print "stacking buttontext[", i,"]", self["items"][i]["text"] # If the item is a 'str', then it has not been created (scrolled list is 'as needed') # Therefore, use the the function given to make it or just make it a frame - if isinstance(item, stringType): + if isinstance(item, str): if self['itemMakeFunction']: # If there is a function to create the item item = self['itemMakeFunction'](item, i, self['itemMakeExtraArgs']) @@ -290,7 +284,7 @@ class DirectScrolledList(DirectFrame): # Therefore, use the the function given to make it or # just make it a frame #print "Making " + str(item) - if isinstance(item, stringType): + if isinstance(item, str): if self['itemMakeFunction']: # If there is a function to create the item item = self['itemMakeFunction'](item, i, self['itemMakeExtraArgs']) @@ -355,16 +349,16 @@ class DirectScrolledList(DirectFrame): Add this string and extraArg to the list """ assert self.notify.debugStateCall(self) - if not isinstance(item, stringType): + if not isinstance(item, str): # cant add attribs to non-classes (like strings & ints) item.itemID = self.nextItemID self.nextItemID += 1 self['items'].append(item) - if not isinstance(item, stringType): + if not isinstance(item, str): item.reparentTo(self.itemFrame) if refresh: self.refresh() - if not isinstance(item, stringType): + if not isinstance(item, str): return item.itemID # to pass to scrollToItemID def removeItem(self, item, refresh=1): @@ -379,7 +373,7 @@ class DirectScrolledList(DirectFrame): if hasattr(self, "currentSelected") and self.currentSelected is item: del self.currentSelected self["items"].remove(item) - if not isinstance(item, stringType): + if not isinstance(item, str): item.reparentTo(ShowBaseGlobal.hidden) self.refresh() return 1 @@ -397,7 +391,7 @@ class DirectScrolledList(DirectFrame): if (hasattr(item, 'destroy') and hasattr(item.destroy, '__call__')): item.destroy() self["items"].remove(item) - if not isinstance(item, stringType): + if not isinstance(item, str): item.reparentTo(ShowBaseGlobal.hidden) self.refresh() return 1 @@ -419,7 +413,7 @@ class DirectScrolledList(DirectFrame): if hasattr(self, "currentSelected") and self.currentSelected is item: del self.currentSelected self["items"].remove(item) - if not isinstance(item, stringType): + if not isinstance(item, str): #RAU possible leak here, let's try to do the right thing #item.reparentTo(ShowBaseGlobal.hidden) item.removeNode() @@ -444,7 +438,7 @@ class DirectScrolledList(DirectFrame): if (hasattr(item, 'destroy') and hasattr(item.destroy, '__call__')): item.destroy() self["items"].remove(item) - if not isinstance(item, stringType): + if not isinstance(item, str): #RAU possible leak here, let's try to do the right thing #item.reparentTo(ShowBaseGlobal.hidden) item.removeNode() @@ -469,7 +463,7 @@ class DirectScrolledList(DirectFrame): def getSelectedText(self): assert self.notify.debugStateCall(self) - if isinstance(self['items'][self.index], stringType): + if isinstance(self['items'][self.index], str): return self['items'][self.index] else: return self['items'][self.index]['text'] diff --git a/direct/src/gui/DirectWaitBar.py b/direct/src/gui/DirectWaitBar.py index 55785152cf..ae089ecf3e 100644 --- a/direct/src/gui/DirectWaitBar.py +++ b/direct/src/gui/DirectWaitBar.py @@ -9,12 +9,6 @@ __all__ = ['DirectWaitBar'] from panda3d.core import * from . import DirectGuiGlobals as DGG from .DirectFrame import * -import sys - -if sys.version_info >= (3, 0): - stringType = str -else: - stringType = basestring """ import DirectWaitBar @@ -102,7 +96,7 @@ class DirectWaitBar(DirectFrame): """Updates the bar texture, which you can set using bar['barTexture'].""" # this must be a single texture (or a string). texture = self['barTexture'] - if isinstance(texture, stringType): + if isinstance(texture, str): texture = loader.loadTexture(texture) if texture: self.barStyle.setTexture(texture) diff --git a/direct/src/gui/OnscreenGeom.py b/direct/src/gui/OnscreenGeom.py index e1a35a77d1..ac4f93a418 100644 --- a/direct/src/gui/OnscreenGeom.py +++ b/direct/src/gui/OnscreenGeom.py @@ -4,12 +4,7 @@ __all__ = ['OnscreenGeom'] from panda3d.core import * from direct.showbase.DirectObject import DirectObject -import sys -if sys.version_info >= (3, 0): - stringType = str -else: - stringType = basestring class OnscreenGeom(DirectObject, NodePath): def __init__(self, geom = None, @@ -98,7 +93,7 @@ class OnscreenGeom(DirectObject, NodePath): # Assign geometry if isinstance(geom, NodePath): self.assign(geom.copyTo(parent, sort)) - elif isinstance(geom, stringType): + elif isinstance(geom, str): self.assign(loader.loadModel(geom)) self.reparentTo(parent, sort) diff --git a/direct/src/gui/OnscreenImage.py b/direct/src/gui/OnscreenImage.py index 3d8a9b0633..e5a3944178 100644 --- a/direct/src/gui/OnscreenImage.py +++ b/direct/src/gui/OnscreenImage.py @@ -8,12 +8,6 @@ __all__ = ['OnscreenImage'] from panda3d.core import * from direct.showbase.DirectObject import DirectObject -import sys - -if sys.version_info >= (3, 0): - stringType = str -else: - stringType = basestring class OnscreenImage(DirectObject, NodePath): @@ -106,8 +100,7 @@ class OnscreenImage(DirectObject, NodePath): # Assign geometry if isinstance(image, NodePath): self.assign(image.copyTo(parent, sort)) - elif isinstance(image, stringType) or \ - isinstance(image, Texture): + elif isinstance(image, str) or isinstance(image, Texture): if isinstance(image, Texture): # It's a Texture tex = image diff --git a/direct/src/gui/OnscreenText.py b/direct/src/gui/OnscreenText.py index 4491c918e9..c26e7033b7 100644 --- a/direct/src/gui/OnscreenText.py +++ b/direct/src/gui/OnscreenText.py @@ -8,7 +8,6 @@ __all__ = ['OnscreenText', 'Plain', 'ScreenTitle', 'ScreenPrompt', 'NameConfirm' from panda3d.core import * from . import DirectGuiGlobals as DGG -import sys ## These are the styles of text we might commonly see. They set the ## overall appearance of the text according to one of a number of @@ -281,34 +280,15 @@ class OnscreenText(NodePath): self.textNode.clearText() def setText(self, text): - if sys.version_info >= (3, 0): - assert not isinstance(text, bytes) - self.unicodeText = True - else: - self.unicodeText = isinstance(text, unicode) - - if self.unicodeText: - self.textNode.setWtext(text) - else: - self.textNode.setText(text) + assert not isinstance(text, bytes) + self.textNode.setWtext(text) def appendText(self, text): - if sys.version_info >= (3, 0): - assert not isinstance(text, bytes) - self.unicodeText = True - else: - self.unicodeText = isinstance(text, unicode) - - if self.unicodeText: - self.textNode.appendWtext(text) - else: - self.textNode.appendText(text) + assert not isinstance(text, bytes) + self.textNode.appendWtext(text) def getText(self): - if self.unicodeText: - return self.textNode.getWtext() - else: - return self.textNode.getText() + return self.textNode.getWtext() text = property(getText, setText) diff --git a/direct/src/interval/Interval.py b/direct/src/interval/Interval.py index 02a5f4bc00..135cbb9d5d 100644 --- a/direct/src/interval/Interval.py +++ b/direct/src/interval/Interval.py @@ -454,12 +454,9 @@ class Interval(DirectObject): """ # Don't use a regular import, to prevent ModuleFinder from picking # it up as a dependency when building a .p3d package. - import importlib, sys + import importlib EntryScale = importlib.import_module('direct.tkwidgets.EntryScale') - if sys.version_info >= (3, 0): - tkinter = importlib.import_module('tkinter') - else: - tkinter = importlib.import_module('Tkinter') + tkinter = importlib.import_module('tkinter') if tl == None: tl = tkinter.Toplevel() diff --git a/direct/src/particles/ParticleEffect.py b/direct/src/particles/ParticleEffect.py index 2705ae39fd..9d33fb3150 100644 --- a/direct/src/particles/ParticleEffect.py +++ b/direct/src/particles/ParticleEffect.py @@ -7,12 +7,6 @@ from . import Particles from . import ForceGroup from direct.directnotify import DirectNotifyGlobal -import sys - - -if sys.version_info < (3, 0): - FileNotFoundError = IOError - class ParticleEffect(NodePath): diff --git a/direct/src/showbase/ContainerLeakDetector.py b/direct/src/showbase/ContainerLeakDetector.py index abfe5cf99e..48c3e810a1 100755 --- a/direct/src/showbase/ContainerLeakDetector.py +++ b/direct/src/showbase/ContainerLeakDetector.py @@ -3,27 +3,14 @@ from direct.showbase.PythonUtil import makeFlywheelGen from direct.showbase.PythonUtil import itype, serialNum, safeRepr, fastRepr from direct.showbase.Job import Job import types, weakref, random, sys +import builtins -if sys.version_info >= (3, 0): - import builtins as __builtin__ - - intTypes = (int,) - deadEndTypes = (bool, types.BuiltinFunctionType, - types.BuiltinMethodType, complex, - float, int, - type(None), type(NotImplemented), - type, types.CodeType, types.FunctionType, - bytes, str, tuple) -else: - import __builtin__ - - intTypes = (int, long) - deadEndTypes = (types.BooleanType, types.BuiltinFunctionType, - types.BuiltinMethodType, types.ComplexType, - types.FloatType, types.IntType, types.LongType, - types.NoneType, types.NotImplementedType, - types.TypeType, types.CodeType, types.FunctionType, - types.StringType, types.UnicodeType, types.TupleType) +deadEndTypes = (bool, types.BuiltinFunctionType, + types.BuiltinMethodType, complex, + float, int, + type(None), type(NotImplemented), + type, types.CodeType, types.FunctionType, + bytes, str, tuple) def _createContainerLeak(): @@ -136,7 +123,7 @@ class Indirection: def dereferenceDictKey(self, parentDict): # look ourselves up in parentDict key = self._getNonWeakDictKey() - # objects in __builtin__ will have parentDict==None + # objects in builtins will have parentDict==None if parentDict is None: return key return parentDict[key] @@ -185,7 +172,7 @@ class ObjectRef: # make sure we're not storing a reference to the actual object, # that could cause a memory leak - assert type(objId) in intTypes + assert type(objId) is int # prevent cycles (i.e. base.loader.base.loader) assert not self.goesThrough(objId=objId) @@ -206,7 +193,7 @@ class ObjectRef: def goesThroughGen(self, obj=None, objId=None): if obj is None: - assert type(objId) in intTypes + assert type(objId) is int else: objId = id(obj) o = None @@ -253,9 +240,9 @@ class ObjectRef: # eval('curObj.foo.bar.someDict') evalStr = 'curObj%s' % evalStr else: - # this eval is not based off of curObj, use the global__builtin__ namespace - # put __builtin__ at the start if it's not already there - bis = '__builtin__' + # this eval is not based off of curObj, use the globalbuiltins namespace + # put builtins at the start if it's not already there + bis = 'builtins' if evalStr[:len(bis)] != bis: evalStr = '%s.%s' % (bis, evalStr) try: @@ -369,17 +356,17 @@ class FindContainers(Job): ContainerLeakDetector.addPrivateObj(self.__dict__) # set up the base containers, the ones that hold most objects - ref = ObjectRef(Indirection(evalStr='__builtin__.__dict__'), id(__builtin__.__dict__)) - self._id2baseStartRef[id(__builtin__.__dict__)] = ref + ref = ObjectRef(Indirection(evalStr='builtins.__dict__'), id(builtins.__dict__)) + self._id2baseStartRef[id(builtins.__dict__)] = ref # container for objects that want to make sure they are found by # the object exploration algorithm, including objects that exist # just to measure things such as C++ memory usage, scene graph size, # framerate, etc. See LeakDetectors.py - if not hasattr(__builtin__, "leakDetectors"): - __builtin__.leakDetectors = {} + if not hasattr(builtins, "leakDetectors"): + builtins.leakDetectors = {} ref = ObjectRef(Indirection(evalStr='leakDetectors'), id(leakDetectors)) self._id2baseStartRef[id(leakDetectors)] = ref - for i in self._addContainerGen(__builtin__.__dict__, ref): + for i in self._addContainerGen(builtins.__dict__, ref): pass try: base @@ -457,7 +444,7 @@ class FindContainers(Job): objId = id(obj) if objId in self._id2discoveredStartRef: existingRef = self._id2discoveredStartRef[objId] - if type(existingRef) not in intTypes: + if type(existingRef) is not int: if (existingRef.getNumIndirections() >= ref.getNumIndirections()): # the ref that we already have is more concise than the new ref @@ -522,11 +509,11 @@ class FindContainers(Job): startRefWorkingList.refGen = fw if curObjRef is None: # this ref set is empty, choose another - # the base set should never be empty (__builtin__ etc.) + # the base set should never be empty (builtins etc.) continue # do we need to go look up the object in _id2ref? sometimes we do that # to avoid storing multiple redundant refs to a single item - if type(curObjRef) in intTypes: + if type(curObjRef) is int: startId = curObjRef curObjRef = None try: @@ -605,7 +592,7 @@ class FindContainers(Job): # don't yield, container might lose this element pass if not goesThrough: - if curObj is __builtin__.__dict__: + if curObj is builtins.__dict__: objRef = ObjectRef(Indirection(evalStr='%s' % key), id(curObj[key])) else: diff --git a/direct/src/showbase/GarbageReport.py b/direct/src/showbase/GarbageReport.py index 7d268bf450..73e1210a99 100755 --- a/direct/src/showbase/GarbageReport.py +++ b/direct/src/showbase/GarbageReport.py @@ -8,12 +8,9 @@ from direct.showbase.PythonUtil import AlphabetCounter from direct.showbase.Job import Job import gc import types -import sys GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num' -if sys.version_info >= (3, 0): - xrange = range class FakeObject: pass @@ -23,7 +20,7 @@ class FakeDelObject: pass def _createGarbage(num=1): - for i in xrange(num): + for i in range(num): a = FakeObject() b = FakeObject() a.other = b @@ -84,7 +81,7 @@ class GarbageReport(Job): self.numGarbageInstances = len(garbageInstances) # grab the ids of the garbage instances (objects with __del__) self.garbageInstanceIds = set() - for i in xrange(len(garbageInstances)): + for i in range(len(garbageInstances)): self.garbageInstanceIds.add(id(garbageInstances[i])) if not (i % 20): yield None @@ -144,7 +141,7 @@ class GarbageReport(Job): self.cycleIds = set() # make the id->index table to speed up the next steps - for i in xrange(self.numGarbage): + for i in range(self.numGarbage): self._id2index[id(self.garbage[i])] = i if not (i % 20): yield None @@ -153,7 +150,7 @@ class GarbageReport(Job): if self._args.fullReport and (self.numGarbage != 0): if self._args.verbose: self.notify.info('getting referrers...') - for i in xrange(self.numGarbage): + for i in range(self.numGarbage): yield None for result in self._getReferrers(self.garbage[i]): yield None @@ -165,7 +162,7 @@ class GarbageReport(Job): if self.numGarbage > 0: if self._args.verbose: self.notify.info('getting referents...') - for i in xrange(self.numGarbage): + for i in range(self.numGarbage): yield None for result in self._getReferents(self.garbage[i]): yield None @@ -173,7 +170,7 @@ class GarbageReport(Job): self.referentsByNumber[i] = byNum self.referentsByReference[i] = byRef - for i in xrange(self.numGarbage): + for i in range(self.numGarbage): if hasattr(self.garbage[i], '_garbageInfo') and callable(self.garbage[i]._garbageInfo): try: info = self.garbage[i]._garbageInfo() @@ -189,7 +186,7 @@ class GarbageReport(Job): if self._args.findCycles and self.numGarbage > 0: if self._args.verbose: self.notify.info('calculating cycles...') - for i in xrange(self.numGarbage): + for i in range(self.numGarbage): yield None for newCycles in self._getCycles(i, self.uniqueCycleSets): yield None @@ -219,7 +216,7 @@ class GarbageReport(Job): startIndex -= 1 endIndex -= 1 - for index in xrange(startIndex, endIndex): + for index in range(startIndex, endIndex): if numToSkip: numToSkip -= 1 continue @@ -259,7 +256,7 @@ class GarbageReport(Job): # get object being referenced by container nextObj = objs[index+1] cycleBySyntax += brackets[0] - for index in xrange(len(obj)): + for index in range(len(obj)): if obj[index] is nextObj: index = str(index) break @@ -313,7 +310,7 @@ class GarbageReport(Job): digits = digits format = '%0' + '%s' % digits + 'i:%s \t%s' - for i in xrange(numGarbage): + for i in range(numGarbage): yield None idx = garbageIndices[i] if self._args.safeMode: @@ -329,7 +326,7 @@ class GarbageReport(Job): # also log the types of the objects s.append('===== Garbage Item Types %s=====' % abbrev) - for i in xrange(numGarbage): + for i in range(numGarbage): yield None idx = garbageIndices[i] objStr = str(deeptype(self.garbage[idx])) @@ -342,21 +339,21 @@ class GarbageReport(Job): if self._args.findCycles: s.append('===== Garbage Cycles (Garbage Item Numbers) =====') ac = AlphabetCounter() - for i in xrange(self.numCycles): + for i in range(self.numCycles): yield None s.append('%s:%s' % (ac.next(), self.cycles[i])) if self._args.findCycles: s.append('===== Garbage Cycles (Python Syntax) =====') ac = AlphabetCounter() - for i in xrange(len(self.cyclesBySyntax)): + for i in range(len(self.cyclesBySyntax)): yield None s.append('%s:%s' % (ac.next(), self.cyclesBySyntax[i])) if len(self._id2garbageInfo): s.append('===== Garbage Custom Info =====') ac = AlphabetCounter() - for i in xrange(len(self.cyclesBySyntax)): + for i in range(len(self.cyclesBySyntax)): yield None counter = ac.next() _id = id(self.garbage[i]) @@ -366,19 +363,19 @@ class GarbageReport(Job): if self._args.fullReport: format = '%0' + '%s' % digits + 'i:%s' s.append('===== Referrers By Number (what is referring to garbage item?) =====') - for i in xrange(numGarbage): + for i in range(numGarbage): yield None s.append(format % (i, self.referrersByNumber[i])) s.append('===== Referents By Number (what is garbage item referring to?) =====') - for i in xrange(numGarbage): + for i in range(numGarbage): yield None s.append(format % (i, self.referentsByNumber[i])) s.append('===== Referrers (what is referring to garbage item?) =====') - for i in xrange(numGarbage): + for i in range(numGarbage): yield None s.append(format % (i, self.referrersByReference[i])) s.append('===== Referents (what is garbage item referring to?) =====') - for i in xrange(numGarbage): + for i in range(numGarbage): yield None s.append(format % (i, self.referentsByReference[i])) @@ -386,7 +383,7 @@ class GarbageReport(Job): if self._args.log: self.printingBegin() - for i in xrange(len(self._report)): + for i in range(len(self._report)): if self.numGarbage > 0: yield None self.notify.info(self._report[i]) @@ -450,7 +447,7 @@ class GarbageReport(Job): yield None # look to see if each referrer is another garbage item byNum = [] - for i in xrange(len(byRef)): + for i in range(len(byRef)): if not (i % 20): yield None referrer = byRef[i] @@ -467,7 +464,7 @@ class GarbageReport(Job): yield None # look to see if each referent is another garbage item byNum = [] - for i in xrange(len(byRef)): + for i in range(len(byRef)): if not (i % 20): yield None referent = byRef[i] @@ -484,7 +481,7 @@ class GarbageReport(Job): return cycle min = 1<<30 minIndex = None - for i in xrange(len(cycle)): + for i in range(len(cycle)): elem = cycle[i] if elem < min: min = elem @@ -517,7 +514,7 @@ class GarbageReport(Job): else: print('restart: %s root=%s cur=%s resume=%s' % ( candidateCycle, rootId, curId, resumeIndex)) - for index in xrange(resumeIndex, len(self.referentsByNumber[curId])): + for index in range(resumeIndex, len(self.referentsByNumber[curId])): yield None refId = self.referentsByNumber[curId][index] if self.notify.getDebug(): diff --git a/direct/src/showbase/LeakDetectors.py b/direct/src/showbase/LeakDetectors.py index b2a17b5617..1cec5bf74d 100755 --- a/direct/src/showbase/LeakDetectors.py +++ b/direct/src/showbase/LeakDetectors.py @@ -5,12 +5,8 @@ ContainerLeakDetector. from panda3d.core import * from direct.showbase.DirectObject import DirectObject from direct.showbase.Job import Job -import gc, sys - -if sys.version_info >= (3, 0): - import builtins -else: - import __builtin__ as builtins +import gc +import builtins class LeakDetector: diff --git a/direct/src/showbase/MessengerLeakDetector.py b/direct/src/showbase/MessengerLeakDetector.py index 08cbe0778f..187c0d51ac 100755 --- a/direct/src/showbase/MessengerLeakDetector.py +++ b/direct/src/showbase/MessengerLeakDetector.py @@ -1,12 +1,8 @@ from direct.directnotify.DirectNotifyGlobal import directNotify from direct.showbase.DirectObject import DirectObject from direct.showbase.Job import Job -import gc, sys - -if sys.version_info >= (3, 0): - import builtins -else: - import __builtin__ as builtins +import gc +import builtins class MessengerLeakObject(DirectObject): diff --git a/direct/src/showbase/ObjectReport.py b/direct/src/showbase/ObjectReport.py index a0fcce7168..4ee511a597 100755 --- a/direct/src/showbase/ObjectReport.py +++ b/direct/src/showbase/ObjectReport.py @@ -16,11 +16,8 @@ from direct.showbase import DirectObject, ObjectPool, GarbageReport from direct.showbase.PythonUtil import makeList, Sync import gc import sys +import builtins -if sys.version_info >= (3, 0): - import builtins -else: - import __builtin__ as builtins class ExclusiveObjectPool(DirectObject.DirectObject): # ObjectPool specialization that excludes particular objects diff --git a/direct/src/showbase/ProfileSession.py b/direct/src/showbase/ProfileSession.py index 3470f0dc9e..80862d09b3 100755 --- a/direct/src/showbase/ProfileSession.py +++ b/direct/src/showbase/ProfileSession.py @@ -6,12 +6,7 @@ from direct.showbase.PythonUtil import ( _getProfileResultFileInfo, _setProfileResultsFileInfo) import profile import pstats -import sys - -if sys.version_info >= (3, 0): - import builtins -else: - import __builtin__ as builtins +import builtins class PercentStats(pstats.Stats): diff --git a/direct/src/showbase/PythonUtil.py b/direct/src/showbase/PythonUtil.py index 4c9afa634b..8605a3f891 100644 --- a/direct/src/showbase/PythonUtil.py +++ b/direct/src/showbase/PythonUtil.py @@ -37,17 +37,13 @@ import os import sys import random import time +import builtins +import importlib __report_indent = 3 from panda3d.core import ConfigVariableBool -if sys.version_info >= (3, 0): - import builtins - xrange = range -else: - import __builtin__ as builtins - """ # with one integer positional arg, this uses about 4/5 of the memory of the Functor class below @@ -59,41 +55,6 @@ def Functor(function, *args, **kArgs): return functor """ -try: - import importlib -except ImportError: - # Backward compatibility for Python 2.6. - def _resolve_name(name, package, level): - if not hasattr(package, 'rindex'): - raise ValueError("'package' not set to a string") - dot = len(package) - for x in xrange(level, 1, -1): - try: - dot = package.rindex('.', 0, dot) - except ValueError: - raise ValueError("attempted relative import beyond top-level " - "package") - return "%s.%s" % (package[:dot], name) - - def import_module(name, package=None): - if name.startswith('.'): - if not package: - raise TypeError("relative imports require the 'package' argument") - level = 0 - for character in name: - if character != '.': - break - level += 1 - name = _resolve_name(name[level:], package, level) - __import__(name) - return sys.modules[name] - - imp = import_module('imp') - importlib = imp.new_module("importlib") - importlib._resolve_name = _resolve_name - importlib.import_module = import_module - sys.modules['importlib'] = importlib - class Functor: def __init__(self, function, *args, **kargs): @@ -506,7 +467,7 @@ def replace(list, old, new, all=0): return 1 else: numReplaced = 0 - for i in xrange(len(list)): + for i in range(len(list)): if list[i] == old: numReplaced += 1 list[i] = new @@ -1659,16 +1620,13 @@ def itype(obj): # version of type that gives more complete information about instance types global dtoolSuperBase t = type(obj) - if sys.version_info < (3, 0) and t is types.InstanceType: - return ">" % (obj.__class__) - else: - # C++ object instances appear to be types via type() - # check if this is a C++ object - if dtoolSuperBase is None: - _getDtoolSuperBase() - if isinstance(obj, dtoolSuperBase): - return "" % (obj.__class__) - return t + # C++ object instances appear to be types via type() + # check if this is a C++ object + if dtoolSuperBase is None: + _getDtoolSuperBase() + if isinstance(obj, dtoolSuperBase): + return "" % (obj.__class__) + return t def deeptype(obj, maxLen=100, _visitedIds=None): if _visitedIds is None: @@ -1728,7 +1686,7 @@ def getNumberedTypedString(items, maxLen=5000, numPrefix=''): first = True s = '' snip = '' - for i in xrange(len(items)): + for i in range(len(items)): if not first: s += '\n' first = False @@ -1759,7 +1717,7 @@ def getNumberedTypedSortedString(items, maxLen=5000, numPrefix=''): first = True s = '' strs.sort() - for i in xrange(len(strs)): + for i in range(len(strs)): if not first: s += '\n' first = False @@ -1777,7 +1735,7 @@ def printNumberedTyped(items, maxLen=5000): n //= 10 digits = digits format = '%0' + '%s' % digits + 'i:%s \t%s' - for i in xrange(len(items)): + for i in range(len(items)): objStr = fastRepr(items[i]) if len(objStr) > maxLen: snip = '' @@ -1792,7 +1750,7 @@ def printNumberedTypesGen(items, maxLen=5000): n //= 10 digits = digits format = '%0' + '%s' % digits + 'i:%s' - for i in xrange(len(items)): + for i in range(len(items)): print(format % (i, itype(items[i]))) yield None @@ -2287,14 +2245,14 @@ def makeFlywheelGen(objects, countList=None, countFunc=None, scale=None): countList.append(countFunc(object)) if scale is not None: # scale the counts if we've got a scale factor - for i in xrange(len(countList)): + for i in range(len(countList)): yield None if countList[i] > 0: countList[i] = max(1, int(countList[i] * scale)) # create a dict for the flywheel to use during its iteration to efficiently select # the objects for the sequence index2objectAndCount = {} - for i in xrange(len(countList)): + for i in range(len(countList)): yield None index2objectAndCount[i] = [objects[i], countList[i]] # create the flywheel generator @@ -2540,7 +2498,7 @@ if __debug__ and __name__ == '__main__': def testAlphabetCounter(): tempList = [] ac = AlphabetCounter() - for i in xrange(26*3): + for i in range(26*3): tempList.append(ac.next()) assert tempList == [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ', @@ -2551,7 +2509,7 @@ if __debug__ and __name__ == '__main__': num += 26 # AAZ num += 1 # ABA num += 2 # ABC - for i in xrange(num): + for i in range(num): x = ac.next() assert x == 'ABC' testAlphabetCounter() diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 85a28c9f71..aab1887e1b 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -46,10 +46,7 @@ from direct.extensions_native import NodePath_extensions # This needs to be available early for DirectGUI imports import sys -if sys.version_info >= (3, 0): - import builtins -else: - import __builtin__ as builtins +import builtins builtins.config = DConfig from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify diff --git a/direct/src/showbase/ShowBaseGlobal.py b/direct/src/showbase/ShowBaseGlobal.py index c6e451851f..6f39b2dab7 100644 --- a/direct/src/showbase/ShowBaseGlobal.py +++ b/direct/src/showbase/ShowBaseGlobal.py @@ -72,13 +72,8 @@ def inspect(anObject): return Inspector.inspect(anObject) -import sys -if sys.version_info >= (3, 0): - import builtins -else: - import __builtin__ as builtins +import builtins builtins.inspect = inspect -del sys # this also appears in AIBaseGlobal if (not __debug__) and __dev__: diff --git a/direct/src/showbase/TkGlobal.py b/direct/src/showbase/TkGlobal.py index 512bdb3583..8d4f4e3ae1 100644 --- a/direct/src/showbase/TkGlobal.py +++ b/direct/src/showbase/TkGlobal.py @@ -1,11 +1,8 @@ """ This module is now vestigial. """ import sys, Pmw +from tkinter import * -if sys.version_info >= (3, 0): - from tkinter import * -else: - from Tkinter import * # This is required by the ihooks.py module used by Squeeze (used by # pandaSqueezer.py) so that Pmw initializes properly diff --git a/direct/src/showbase/VFSImporter.py b/direct/src/showbase/VFSImporter.py index b59965ae3c..463281e391 100644 --- a/direct/src/showbase/VFSImporter.py +++ b/direct/src/showbase/VFSImporter.py @@ -230,10 +230,7 @@ class VFSLoader: #print >>sys.stderr, "importing frozen %s" % (fullname) module = imp.load_module(fullname, None, fullname, ('', '', imp.PY_FROZEN)) - - # Workaround for bug in Python 2. - if getattr(module, '__path__', None) == fullname: - module.__path__ = [] + module.__path__ = [] return module def _read_code(self): @@ -288,13 +285,8 @@ class VFSLoader: if data[:4] != imp.get_magic(): raise ValueError("Bad magic number in %s" % (vfile)) - if sys.version_info >= (3, 0): - t = int.from_bytes(data[4:8], 'little') - data = data[12:] - else: - t = ord(data[4]) + (ord(data[5]) << 8) + \ - (ord(data[6]) << 16) + (ord(data[7]) << 24) - data = data[8:] + t = int.from_bytes(data[4:8], 'little') + data = data[12:] if not timestamp or t == timestamp: return marshal.loads(data) @@ -320,14 +312,8 @@ class VFSLoader: pass else: f.write(imp.get_magic()) - if sys.version_info >= (3, 0): - f.write((self.timestamp & 0xffffffff).to_bytes(4, 'little')) - f.write(b'\0\0\0\0') - else: - f.write(chr(self.timestamp & 0xff) + - chr((self.timestamp >> 8) & 0xff) + - chr((self.timestamp >> 16) & 0xff) + - chr((self.timestamp >> 24) & 0xff)) + f.write((self.timestamp & 0xffffffff).to_bytes(4, 'little')) + f.write(b'\0\0\0\0') f.write(marshal.dumps(code)) f.close() diff --git a/direct/src/stdpy/file.py b/direct/src/stdpy/file.py index 49896c2109..48b25420fb 100644 --- a/direct/src/stdpy/file.py +++ b/direct/src/stdpy/file.py @@ -11,7 +11,6 @@ __all__ = [ ] from panda3d import core -import sys import os import io import encodings @@ -19,19 +18,6 @@ from posixpath import join _vfs = core.VirtualFileSystem.getGlobalPtr() -if sys.version_info < (3, 0): - # Python 3 defines these subtypes of IOError, but Python 2 doesn't. - FileNotFoundError = IOError - IsADirectoryError = IOError - FileExistsError = IOError - PermissionError = IOError - - unicodeType = unicode - strType = str -else: - unicodeType = str - strType = () - def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True): """This function emulates the built-in Python open() function, additionally @@ -39,12 +25,9 @@ def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, arguments as Python's built-in open() function. """ - if sys.version_info >= (3, 0): - # Python 3 is much stricter than Python 2, which lets - # unknown flags fall through. - for ch in mode: - if ch not in 'rwxabt+U': - raise ValueError("invalid mode: '%s'" % (mode)) + for ch in mode: + if ch not in 'rwxabt+U': + raise ValueError("invalid mode: '%s'" % (mode)) creating = 'x' in mode writing = 'w' in mode @@ -81,21 +64,16 @@ def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, # We can also "open" a VirtualFile object for reading. vfile = file filename = vfile.getFilename() - elif isinstance(file, unicodeType): + elif isinstance(file, str): # If a raw string is given, assume it's an os-specific # filename. filename = core.Filename.fromOsSpecificW(file) - elif isinstance(file, strType): - filename = core.Filename.fromOsSpecific(file) else: # It's either a Filename object or an os.PathLike. # If a Filename is given, make a writable copy anyway. filename = core.Filename(file) - if binary or sys.version_info >= (3, 0): - filename.setBinary() - else: - filename.setText() + filename.setBinary() if not vfile: vfile = _vfs.getFile(filename) @@ -156,10 +134,6 @@ def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, if binary: return raw - # If we're in Python 2, we don't decode unicode strings by default. - if not encoding and sys.version_info < (3, 0): - return raw - line_buffering = False if buffering == 1: line_buffering = True @@ -172,12 +146,6 @@ def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, return wrapper -if sys.version_info < (3, 0): - # Python 2 had an alias for open() called file(). - __all__.append('file') - file = open - - class StreamIOWrapper(io.IOBase): """ This is a file-like object that wraps around a C++ istream and/or ostream object. It only deals with binary data; to work with text I/O, @@ -197,13 +165,7 @@ class StreamIOWrapper(io.IOBase): if isinstance(stream, core.Ostream): self.__writer = core.StreamWriter(stream, False) self.__lastWrite = True - if sys.version_info >= (3, 0): - # In Python 3, we use appendData, which only accepts bytes. - self.__write = self.__writer.appendData - else: - # In Python 2.7, we also accept unicode objects, which are - # implicitly converted to C++ strings. - self.__write = self.__writer.write + self.__write = self.__writer.appendData def __repr__(self): s = "= (3, 0) and isinstance(pathname, bytes): + if isinstance(pathname, bytes): newpath = bytearray(drive) for c in pathname: if c == 42 or c == 63 or c == 91: diff --git a/direct/src/stdpy/pickle.py b/direct/src/stdpy/pickle.py index fefdeae9ff..03ef1969d0 100644 --- a/direct/src/stdpy/pickle.py +++ b/direct/src/stdpy/pickle.py @@ -23,11 +23,8 @@ support extensions of this nature. """ import sys from panda3d.core import BamWriter, BamReader +from copyreg import dispatch_table -if sys.version_info >= (3, 0): - from copyreg import dispatch_table -else: - from copy_reg import dispatch_table # A funny replacement for "import pickle" so we don't get confused # with the local pickle.py. diff --git a/direct/src/stdpy/thread.py b/direct/src/stdpy/thread.py index 29844b32e2..31d4586c26 100644 --- a/direct/src/stdpy/thread.py +++ b/direct/src/stdpy/thread.py @@ -31,12 +31,8 @@ consider_yield = core.Thread.consider_yield forceYield = force_yield considerYield = consider_yield +error = RuntimeError -if sys.version_info >= (3, 3): - error = RuntimeError -else: - class error(Exception): - pass class LockType: """ Implements a mutex lock. Instead of directly subclassing diff --git a/direct/src/task/Task.py b/direct/src/task/Task.py index d96f3f44e8..f8d9156f4c 100644 --- a/direct/src/task/Task.py +++ b/direct/src/task/Task.py @@ -17,19 +17,16 @@ from direct.showbase.MessengerGlobal import messenger import types import random import importlib -import sys try: - if sys.version_info >= (3, 0): - import _signal as signal - else: - import signal + import _signal as signal except ImportError: signal = None from panda3d.core import * from direct.extensions_native import HTTPChannel_extensions + def print_exc_plus(): """ Print the usual traceback information, followed by a listing of all the diff --git a/direct/src/tkpanels/AnimPanel.py b/direct/src/tkpanels/AnimPanel.py index 12bc1feefd..27b7f23cfe 100644 --- a/direct/src/tkpanels/AnimPanel.py +++ b/direct/src/tkpanels/AnimPanel.py @@ -9,16 +9,11 @@ __all__ = ['AnimPanel', 'ActorControl'] # Import Tkinter, Pmw, and the floater code from this directory tree. from direct.tkwidgets.AppShell import * from direct.showbase.TkGlobal import * -import Pmw, sys, os +import Pmw, os from direct.task import Task from panda3d.core import Filename, getModelPath - -if sys.version_info >= (3, 0): - from tkinter.simpledialog import askfloat - from tkinter.filedialog import askopenfilename -else: - from tkSimpleDialog import askfloat - from tkFileDialog import askopenfilename +from tkinter.simpledialog import askfloat +from tkinter.filedialog import askopenfilename FRAMES = 0 diff --git a/direct/src/tkpanels/FSMInspector.py b/direct/src/tkpanels/FSMInspector.py index 42ab82a37d..418bcfb0f6 100644 --- a/direct/src/tkpanels/FSMInspector.py +++ b/direct/src/tkpanels/FSMInspector.py @@ -106,12 +106,8 @@ __all__ = ['FSMInspector', 'StateInspector'] from direct.tkwidgets.AppShell import * from direct.showbase.TkGlobal import * -import Pmw, math, operator, sys - -if sys.version_info >= (3, 0): - from tkinter.simpledialog import askstring -else: - from tkSimpleDialog import askstring +import Pmw, math, operator +from tkinter.simpledialog import askstring DELTA = (5.0 / 360.) * 2.0 * math.pi diff --git a/direct/src/tkpanels/MopathRecorder.py b/direct/src/tkpanels/MopathRecorder.py index 1cf65cd0aa..2690556f3b 100644 --- a/direct/src/tkpanels/MopathRecorder.py +++ b/direct/src/tkpanels/MopathRecorder.py @@ -12,17 +12,13 @@ from direct.directtools.DirectGlobals import * from direct.directtools.DirectUtil import * from direct.directtools.DirectGeometry import * from direct.directtools.DirectSelection import * -import Pmw, os, sys +import Pmw, os from direct.tkwidgets import Dial from direct.tkwidgets import Floater from direct.tkwidgets import Slider from direct.tkwidgets import EntryScale from direct.tkwidgets import VectorWidgets - -if sys.version_info >= (3, 0): - from tkinter.filedialog import * -else: - from tkFileDialog import * +from tkinter.filedialog import * PRF_UTILITIES = [ diff --git a/direct/src/tkpanels/ParticlePanel.py b/direct/src/tkpanels/ParticlePanel.py index d82677b5e5..bd8e35abed 100644 --- a/direct/src/tkpanels/ParticlePanel.py +++ b/direct/src/tkpanels/ParticlePanel.py @@ -13,15 +13,9 @@ from direct.tkpanels import Placer from direct.particles import ForceGroup from direct.particles import Particles from direct.particles import ParticleEffect -import Pmw, os, sys - -if sys.version_info >= (3, 0): - from tkinter.filedialog import * - from tkinter.simpledialog import askstring -else: - from tkFileDialog import * - from tkSimpleDialog import askstring - +import Pmw, os +from tkinter.filedialog import * +from tkinter.simpledialog import askstring from panda3d.core import * from panda3d.physics import * from panda3d.direct import getParticlePath diff --git a/direct/src/tkpanels/TaskManagerPanel.py b/direct/src/tkpanels/TaskManagerPanel.py index 1283044b59..c333f5a6d4 100644 --- a/direct/src/tkpanels/TaskManagerPanel.py +++ b/direct/src/tkpanels/TaskManagerPanel.py @@ -4,14 +4,9 @@ __all__ = ['TaskManagerPanel', 'TaskManagerWidget'] from direct.tkwidgets.AppShell import * from direct.showbase.DirectObject import DirectObject -import Pmw, sys - -if sys.version_info >= (3, 0): - from tkinter import * - from tkinter.messagebox import askokcancel -else: - from Tkinter import * - from tkMessageBox import askokcancel +import Pmw +from tkinter import * +from tkinter.messagebox import askokcancel class TaskManagerPanel(AppShell): diff --git a/direct/src/tkwidgets/AppShell.py b/direct/src/tkwidgets/AppShell.py index 6c5d930976..34e933b859 100644 --- a/direct/src/tkwidgets/AppShell.py +++ b/direct/src/tkwidgets/AppShell.py @@ -16,11 +16,7 @@ from . import Slider from . import EntryScale from . import VectorWidgets from . import ProgressBar - -if sys.version_info >= (3, 0): - from tkinter.filedialog import * -else: - from tkFileDialog import * +from tkinter.filedialog import * """ diff --git a/direct/src/tkwidgets/EntryScale.py b/direct/src/tkwidgets/EntryScale.py index c9685fcf6c..30d981fffa 100644 --- a/direct/src/tkwidgets/EntryScale.py +++ b/direct/src/tkwidgets/EntryScale.py @@ -5,14 +5,9 @@ EntryScale Class: Scale with a label, and a linked and validated entry __all__ = ['EntryScale', 'EntryScaleGroup'] from direct.showbase.TkGlobal import * -import Pmw, sys - -if sys.version_info >= (3, 0): - from tkinter.simpledialog import * - from tkinter.colorchooser import askcolor -else: - from tkSimpleDialog import * - from tkColorChooser import askcolor +import Pmw +from tkinter.simpledialog import * +from tkinter.colorchooser import askcolor """ Change Min/Max buttons to labels, add highlight binding diff --git a/direct/src/tkwidgets/Tree.py b/direct/src/tkwidgets/Tree.py index 5674888c77..9de192ca0c 100644 --- a/direct/src/tkwidgets/Tree.py +++ b/direct/src/tkwidgets/Tree.py @@ -24,10 +24,6 @@ from direct.showbase.TkGlobal import * from panda3d.core import * -if sys.version_info < (3, 0): - FileNotFoundError = IOError - - class TreeNode: def __init__(self, canvas, parent, item, menuList = []): diff --git a/direct/src/tkwidgets/Valuator.py b/direct/src/tkwidgets/Valuator.py index 4bc57c7896..6115a4e198 100644 --- a/direct/src/tkwidgets/Valuator.py +++ b/direct/src/tkwidgets/Valuator.py @@ -8,12 +8,7 @@ from . import WidgetPropertiesDialog import Pmw from direct.directtools.DirectUtil import getTkColorString from panda3d.core import Vec4 -import sys - -if sys.version_info >= (3, 0): - from tkinter.colorchooser import askcolor -else: - from tkColorChooser import askcolor +from tkinter.colorchooser import askcolor VALUATOR_MINI = 'mini' VALUATOR_FULL = 'full' diff --git a/direct/src/tkwidgets/VectorWidgets.py b/direct/src/tkwidgets/VectorWidgets.py index 1edfa951dd..ef3963aa1a 100644 --- a/direct/src/tkwidgets/VectorWidgets.py +++ b/direct/src/tkwidgets/VectorWidgets.py @@ -5,12 +5,7 @@ __all__ = ['VectorEntry', 'Vector2Entry', 'Vector3Entry', 'Vector4Entry', 'Color from direct.showbase.TkGlobal import * from . import Valuator import Pmw -import sys - -if sys.version_info >= (3, 0): - from tkinter.colorchooser import askcolor -else: - from tkColorChooser import askcolor +from tkinter.colorchooser import askcolor class VectorEntry(Pmw.MegaWidget): diff --git a/direct/src/tkwidgets/WidgetPropertiesDialog.py b/direct/src/tkwidgets/WidgetPropertiesDialog.py index 584e45620c..97d186b51f 100644 --- a/direct/src/tkwidgets/WidgetPropertiesDialog.py +++ b/direct/src/tkwidgets/WidgetPropertiesDialog.py @@ -3,7 +3,7 @@ __all__ = ['WidgetPropertiesDialog'] from direct.showbase.TkGlobal import * -import Pmw, sys +import Pmw """ TODO: @@ -31,12 +31,8 @@ class WidgetPropertiesDialog(Toplevel): self.propertyList.sort() # Use default parent if none specified if not parent: - if sys.version_info >= (3, 0): - import tkinter - parent = tkinter._default_root - else: - import Tkinter - parent = Tkinter._default_root + import tkinter + parent = tkinter._default_root # Create toplevel window Toplevel.__init__(self, parent) self.transient(parent) diff --git a/direct/src/wxwidgets/WxPandaShell.py b/direct/src/wxwidgets/WxPandaShell.py index d6a1793684..4835f28e2b 100755 --- a/direct/src/wxwidgets/WxPandaShell.py +++ b/direct/src/wxwidgets/WxPandaShell.py @@ -3,13 +3,9 @@ from wx.lib.agw import fourwaysplitter as FWS from panda3d.core import * from direct.showbase.ShowBase import * +from direct.showbase import ShowBaseGlobal from direct.directtools.DirectGlobals import * -try: - base -except NameError: - base = ShowBase(False, windowType = 'none') - from .WxAppShell import * from .ViewPort import * @@ -19,6 +15,7 @@ ID_FRONT_VIEW = 403 ID_LEFT_VIEW = 404 ID_PERSP_VIEW = 405 + class WxPandaShell(WxAppShell): """ Class for Panda3D LevelEditor """ frameWidth = 800 @@ -37,6 +34,10 @@ class WxPandaShell(WxAppShell): } def __init__(self, fStartDirect = False): + base = getattr(ShowBaseGlobal, 'base', None) + if not base: + base = ShowBase(False, windowType='none') + fDirect = (base.config.GetBool('want-directtools', 0) or (base.config.GetString("cluster-mode", '') != '')) @@ -237,5 +238,3 @@ class WxPandaShell(WxAppShell): self.currentView = self.perspView return self.currentView - - diff --git a/dtool/Config.cmake b/dtool/Config.cmake index 1b04a19936..95c8b844d4 100644 --- a/dtool/Config.cmake +++ b/dtool/Config.cmake @@ -22,7 +22,16 @@ if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") set(IS_FREEBSD 1) endif() -set(PER_CONFIG_OPTIONS) +# Define the type of build we are setting up. + +set(_configs Standard Release RelWithDebInfo Debug MinSizeRel) +if(DEFINED CMAKE_CXX_FLAGS_COVERAGE) + list(APPEND _configs Coverage) +endif() + +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES ${_configs}) +endif() # Are we building with static or dynamic linking? option(BUILD_SHARED_LIBS @@ -134,7 +143,7 @@ identified by PRC_ENCRYPTED_PATTERNS.") # that case, config will execute the file if it appears to be # executable; otherwise, it will simply read it. -set(PRC_EXECUTABLE_PATTERNS "" CACHE STRING +set(PRC_EXECUTABLE_PATTERNS "" CACHE STRING "The filename(s) to search for, and execute, in the above paths. Normally this is empty.") @@ -193,10 +202,9 @@ set(PRC_INC_TRUST_LEVEL "0" CACHE STRING # Similarly, the descriptions are normally saved only in a # development build, not in a release build. Set this value true to # explicitly save them anyway. -#XXX only for release-release builds -option(PRC_SAVE_DESCRIPTIONS +per_config_option(PRC_SAVE_DESCRIPTIONS "Define if you want to save the descriptions for ConfigVariables." - ON) + Debug Standard) mark_as_advanced(DEFAULT_PRC_DIR PRC_DIR_ENVVARS PRC_PATH_ENVVARS PRC_PATTERNS PRC_ENCRYPTED_PATTERNS PRC_ENCRYPTION_KEY @@ -243,49 +251,46 @@ debugging information." OFF) mark_as_advanced(INTERROGATE_OPTIONS) # -# The following options have to do with the memory allocation system -# that will be used by Panda3D. +# The following options have to do with optional debugging features. # -option(DO_MEMORY_USAGE +per_config_option(DO_MEMORY_USAGE "Do you want to compile in support for tracking memory usage? This enables you to define the variable 'track-memory-usage' at runtime to help track memory leaks, and also report total memory usage on PStats. There is some small overhead for having this ability -available, even if it is unused." OFF) -list(APPEND PER_CONFIG_OPTIONS DO_MEMORY_USAGE) -set(DO_MEMORY_USAGE_Debug ON CACHE BOOL "") +available, even if it is unused." Debug Standard) -option(SIMULATE_NETWORK_DELAY +per_config_option(DO_COLLISION_RECORDING + "Do you want to enable debugging features for the collision system?" + Debug Standard) + +per_config_option(DO_PSTATS + "Enable support for performance profiling using PStats?" + Debug Standard) + +per_config_option(DO_DCAST + "Add safe typecast checking? This adds significant overhead." + Debug Standard) + +per_config_option(SIMULATE_NETWORK_DELAY "This option compiles in support for simulating network delay via the min-lag and max-lag prc variables. It adds a tiny bit of overhead even when it is not activated, so it is typically enabled -only in a development build." OFF) -list(APPEND PER_CONFIG_OPTIONS SIMULATE_NETWORK_DELAY) -set(SIMULATE_NETWORK_DELAY_Debug ON CACHE BOOL "") +only in a development build." + Debug) -option(SUPPORT_IMMEDIATE_MODE - "This option compiles in support for immediate-mode OpenGL -rendering. Since this is normally useful only for researching -buggy drivers, and since there is a tiny bit of per-primitive -overhead to have this option available even if it is unused, it is -by default enabled only in a development build. This has no effect -on DirectX rendering." OFF) -list(APPEND PER_CONFIG_OPTIONS SUPPORT_IMMEDIATE_MODE) -set(SUPPORT_IMMEDIATE_MODE_Debug ON CACHE BOOL "") - -option(NOTIFY_DEBUG +per_config_option(NOTIFY_DEBUG "Do you want to include the 'debug' and 'spam' Notify messages? Normally, these are stripped out when we build for release, but sometimes it's -useful to keep them around. Turn this setting on to achieve that." OFF) -list(APPEND PER_CONFIG_OPTIONS NOTIFY_DEBUG) -set(NOTIFY_DEBUG_Debug ON CACHE BOOL "") -set(NOTIFY_DEBUG_Standard ON CACHE BOOL "") +useful to keep them around. Turn this setting on to achieve that." + Debug Standard) -option(SUPPORT_FIXED_FUNCTION - "This option compiles in support for the fixed-function OpenGL -pipeline. It is only really useful to turn this off if you are targeting -an OpenGL ES 2 system." ON) +mark_as_advanced(SIMULATE_NETWORK_DELAY DO_MEMORY_USAGE DO_DCAST) + +# +# The following options have to do with the memory allocation system. +# option(USE_MEMORY_DLMALLOC "This is an optional alternative memory-allocation scheme @@ -313,8 +318,7 @@ calls to malloc() and free() for frequently-created and -deleted objects. There's usually no reason to set this false, unless you suspect a bug in Panda's memory management code." ON) -mark_as_advanced(DO_MEMORY_USAGE SIMULATE_NETWORK_DELAY - SUPPORT_IMMEDIATE_MODE USE_MEMORY_DLMALLOC USE_MEMORY_PTMALLOC2 +mark_as_advanced(USE_MEMORY_DLMALLOC USE_MEMORY_PTMALLOC2 MEMORY_HOOK_DO_ALIGN USE_DELETED_CHAIN) @@ -368,11 +372,11 @@ mark_as_advanced(ANDROID_NDK_HOME ANDROID_ABI ANDROID_STL # By default, we'll assume the user only wants to run with Debug # python if he has to--that is, on Windows when building a debug build. -set(USE_DEBUG_PYTHON OFF) if(WIN32) - set(USE_DEBUG_PYTHON_Debug ON) + per_config_option(USE_DEBUG_PYTHON "" Debug) +else() + option(USE_DEBUG_PYTHON "" OFF) endif() -list(APPEND PER_CONFIG_OPTIONS USE_DEBUG_PYTHON) cmake_dependent_option(HAVE_VIDEO4LINUX "Set this to enable webcam support on Linux." ON @@ -394,15 +398,27 @@ version and below, which may reduce runtime portability to other systems, but it will avoid issues with getting extension function pointers.") +option(SUPPORT_FIXED_FUNCTION + "This option compiles in support for the fixed-function OpenGL pipeline. +It is only really useful to turn this off to save space if you are building +an application that only needs to use an OpenGL 3.2+ context and only uses +custom GLSL shaders." ON) + +option(SUPPORT_IMMEDIATE_MODE + "This option compiles in support for immediate-mode OpenGL +rendering. Since this is normally useful only for researching +buggy drivers, and since there is a tiny bit of per-primitive +overhead to have this option available even if it is unused, it is +by default enabled only in a development build. This has no effect +on DirectX rendering." OFF) + +mark_as_advanced(SUPPORT_FIXED_FUNCTION) # Should build tinydisplay? #option(HAVE_TINYDISPLAY # "Builds TinyDisplay, a light software renderer based on TinyGL, #that is built into Panda. TinyDisplay is not as full-featured as Mesa #but is many times faster." ON) -#option(HAVE_TINYDISPLAY_MinSizeRel "" OFF) -#list(APPEND PER_CONFIG_OPTIONS HAVE_TINYDISPLAY) - # Is SDL installed, and where? set(Threads_FIND_QUIETLY TRUE) # Fix for builtin FindSDL @@ -466,9 +482,6 @@ build (such as, for instance, for the iPhone)." ON) option(HAVE_AUDIO "Do you want to build the audio interface?" ON) -option(DO_PSTATS - "Enable the pstats client?" ON) - option(USE_PANDAFILESTREAM "Enable the PandaFileStream implementation of pfstream etc.?" ON) @@ -481,16 +494,12 @@ option(HAVE_IMG "Enable support for loading IMG images." ON) option(HAVE_SOFTIMAGE_PIC "Enable support for loading SOFTIMAGE PIC images." ON) option(HAVE_BMP "Enable support for loading BMP images." ON) option(HAVE_PNM "Enable support for loading PNM images." ON) - -foreach(adv_image_format - HAVE_SGI_RGB HAVE_TGA HAVE_IMG HAVE_SOFTIMAGE_PIC HAVE_BMP HAVE_PNM) - - option(${adv_image_format}_MinSizeRel "" OFF) - list(APPEND PER_CONFIG_OPTIONS ${adv_image_format}) - - mark_as_advanced(${adv_image_format} ${adv_image_format}_MinSizeRel) - -endforeach(adv_image_format) +option(HAVE_SGI_RGB "" ON) +option(HAVE_TGA "" ON) +option(HAVE_IMG "" ON) +option(HAVE_SOFTIMAGE_PIC "" ON) +option(HAVE_BMP "" ON) +option(HAVE_PNM "" ON) # How to invoke bison and flex. Panda takes advantage of some # bison/flex features, and therefore specifically requires bison and @@ -528,9 +537,9 @@ slightly slow down Panda for the single CPU case." IMPORTED_AS Threads::Threads) # Configure debug threads -option(DEBUG_THREADS "If on, enables debugging of thread and sync operations (i.e. mutexes, deadlocks)" OFF) -list(APPEND PER_CONFIG_OPTIONS DEBUG_THREADS) -set(DEBUG_THREADS_Debug ON CACHE BOOL "") +option(DEBUG_THREADS + "If on, enables debugging of thread and sync operations (i.e. mutexes, +deadlocks). Very slow, disabled by default." OFF) option(SIMPLE_THREADS "If on, compile with simulated threads. Threads, by default, use @@ -540,7 +549,6 @@ On the other hand, compiling in this full OS-provided support can impose some substantial runtime overhead, making the application run slower on a single-CPU machine. This settings avoid the overhead, but still gain some of the basic functionality of threads." OFF) -list(APPEND PER_CONFIG_OPTIONS SIMPLE_THREADS) option(OS_SIMPLE_THREADS "If on, OS threading constructs will be used to perform context switches. @@ -549,7 +557,6 @@ normal SIMPLE_THREADS optimizations still apply, and the normal SIMPLE_THREADS scheduler is used to switch between threads (instead of the OS scheduler). This may be more portable and more reliable, but it is a hybrid between user-space threads and os-provided threads." ON) -list(APPEND PER_CONFIG_OPTIONS OS_SIMPLE_THREADS) ### Configure pipelining ### option(DO_PIPELINING "If on, compile with pipelined rendering." ON) @@ -559,8 +566,6 @@ option(COMPILE_IN_DEFAULT_FONT "If on, compiles in a default font, so that every TextNode will always have a font available without requiring the user to specify one. When turned off, the generated library will save a few kilobytes." ON) -list(APPEND PER_CONFIG_OPTIONS COMPILE_IN_DEFAULT_FONT) -set(COMPILE_IN_DEFAULT_FONT_MinSizeRel OFF CACHE BOOL "") option(STDFLOAT_DOUBLE "Define this true to compile a special version of Panda to use a diff --git a/dtool/LocalSetup.cmake b/dtool/LocalSetup.cmake index eed31b0e84..627fe4c3c9 100644 --- a/dtool/LocalSetup.cmake +++ b/dtool/LocalSetup.cmake @@ -186,11 +186,14 @@ message("") # Generate dtool_config.h if(IS_MULTICONFIG) foreach(config ${CMAKE_CONFIGURATION_TYPES}) - foreach(option ${PER_CONFIG_OPTIONS}) + string(TOUPPER "${config}" config_upper) + foreach(option ${_PER_CONFIG_OPTIONS}) # Check for the presence of a config-specific option, and override what's # in the cache if there is. - if(DEFINED ${option}_${config}) - set(${option} ${${option}_${config}}) + if(DEFINED "${option}_${config_upper}") + set(${option} ${${option}_${config_upper}}) + else() + message(FATAL_ERROR "${option}_${config_upper} is not defined") endif() endforeach(option) @@ -199,7 +202,7 @@ if(IS_MULTICONFIG) # unset() does not unset CACHE variables by default, just normal variables. # By doing this we're reverting back to what was in the cache. - foreach(option ${PER_CONFIG_OPTIONS}) + foreach(option ${_PER_CONFIG_OPTIONS}) unset(${option}) endforeach(option) endforeach(config) diff --git a/dtool/Package.cmake b/dtool/Package.cmake index fbf014390c..057965957f 100644 --- a/dtool/Package.cmake +++ b/dtool/Package.cmake @@ -369,7 +369,7 @@ package_option(TIFF "Enable support for loading .tif images.") package_status(TIFF "libtiff") # OpenEXR -find_package(OpenEXR QUIET) +find_package(OpenEXR QUIET MODULE) package_option(OpenEXR "Enable support for loading .exr images.") diff --git a/dtool/PandaVersion.cmake b/dtool/PandaVersion.cmake index 2ca0a3e6e5..4ea2ef6688 100644 --- a/dtool/PandaVersion.cmake +++ b/dtool/PandaVersion.cmake @@ -24,37 +24,7 @@ particular license. Some packages don't have a listed license because they are almost always required/used, or because they are only used in plugins that can be easily removed (eg. directx, ffmpeg, fmod, ...).") -set(PANDA_PACKAGE_VERSION CACHE STRING - "This string is used to describe the Panda3D \"package\" associated -with this current build of Panda. It should increment with major -and minor version changes, but not sequence (or \"bugfix\") changes. -It should be unique for each unique distributor. The default is -the empty string, which means this build does not precisely match -any distributable Panda3D packages. If you are making a Panda3D -build which you will be using to produce a distributable Panda3D -package, you should set this string appropriately.") - -set(P3D_PLUGIN_VERSION "1.0.4" CACHE STRING - "We also define a version for the Panda3D plugin/runtime, -i.e. nppanda3d.dll, p3dactivex.ocx, and panda3d.exe. This is an -independent version number from PANDA_VERSION or -PANDA_PACKAGE_VERSION, because it is anticipated that this plugin -code, once settled, will need to be updated much less frequently -than Panda itself.") - -set(P3D_COREAPI_VERSION "${P3D_PLUGIN_VERSION}.1" CACHE STRING - "Finally, there's a separate version number for the Core API. At -first, we didn't believe we needed a Core API version number, but -in this belief we were naive. This version number is a little less -strict in its format requirements than P3D_PLUGIN_VERSION, above, -and it doesn't necessarily consist of a specific number of -integers, but by convention it will consist of four integers, with -the first three matching the plugin version, and the fourth integer -being incremented with each new Core API revision.") - -mark_as_advanced(PANDA_VERSION PANDA_OFFICIAL_VERSION - PANDA_PACKAGE_VERSION P3D_PLUGIN_VERSION P3D_COREAPI_VERSION - PANDA_DIST_USE_LICENSES) +mark_as_advanced(PANDA_VERSION PANDA_OFFICIAL_VERSION PANDA_DIST_USE_LICENSES) # The version gets a "c" at the end if it's not an official one. if(PANDA_OFFICIAL_VERSION) @@ -82,22 +52,3 @@ if(GIT_EXECUTABLE) OUTPUT_VARIABLE PANDA_GIT_COMMIT_STR ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) endif() - -# Separate the plugin version into its three components. -string(REPLACE "." ";" P3D_PLUGIN_VERSION_LIST "${P3D_PLUGIN_VERSION}") -list(GET P3D_PLUGIN_VERSION_LIST 0 P3D_PLUGIN_MAJOR_VERSION) -list(GET P3D_PLUGIN_VERSION_LIST 1 P3D_PLUGIN_MINOR_VERSION) -list(GET P3D_PLUGIN_VERSION_LIST 2 P3D_PLUGIN_SEQUENCE_VERSION) - -set(P3D_PLUGIN_VERSION_STR "${P3D_PLUGIN_VERSION}${VERSION_SUFFIX}") - -# The plugin version as dot-delimited integer quad, according to MS -# conventions for DLL version numbers. -if(PANDA_OFFICIAL_VERSION) - set(P3D_PLUGIN_DLL_DOT_VERSION "${P3D_PLUGIN_VERSION}.1000") -else() - set(P3D_PLUGIN_DLL_DOT_VERSION "${P3D_PLUGIN_VERSION}.0") -endif() - -# The same thing as a comma-delimited quad. -string(REPLACE "." "," P3D_PLUGIN_DLL_COMMA_VERSION "${P3D_PLUGIN_DLL_DOT_VERSION}") diff --git a/dtool/src/cppparser/cppManifest.cxx b/dtool/src/cppparser/cppManifest.cxx index 2fc85783a7..fb3a19554d 100644 --- a/dtool/src/cppparser/cppManifest.cxx +++ b/dtool/src/cppparser/cppManifest.cxx @@ -127,9 +127,7 @@ CPPManifest(const string ¯o, const string &definition) : */ CPPManifest:: ~CPPManifest() { - if (_expr != nullptr) { - delete _expr; - } + delete _expr; } /** diff --git a/dtool/src/dtoolbase/deletedChain.h b/dtool/src/dtoolbase/deletedChain.h index 1915223450..a72bc85f96 100644 --- a/dtool/src/dtoolbase/deletedChain.h +++ b/dtool/src/dtoolbase/deletedChain.h @@ -85,7 +85,9 @@ public: return ptr; \ } \ inline void operator delete(void *ptr) { \ - StaticDeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \ + if (ptr != nullptr) { \ + StaticDeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \ + } \ } \ inline void operator delete(void *, void *) { \ } \ @@ -104,7 +106,9 @@ public: return ptr; \ } \ inline void operator delete(void *ptr) { \ - _deleted_chain.deallocate((Type *)ptr, get_type_handle(Type)); \ + if (ptr != nullptr) { \ + _deleted_chain.deallocate((Type *)ptr, get_type_handle(Type)); \ + } \ } \ inline void operator delete(void *, void *) { \ } \ diff --git a/dtool/src/dtoolbase/memoryBase.h b/dtool/src/dtoolbase/memoryBase.h index d1d9f00ca5..b82e9d1cc0 100644 --- a/dtool/src/dtoolbase/memoryBase.h +++ b/dtool/src/dtoolbase/memoryBase.h @@ -32,7 +32,9 @@ return ptr; \ } \ inline void operator delete(void *ptr) { \ - PANDA_FREE_SINGLE(ptr); \ + if (ptr != nullptr) { \ + PANDA_FREE_SINGLE(ptr); \ + } \ } \ inline void operator delete(void *, void *) { \ } \ @@ -44,7 +46,9 @@ return ptr; \ } \ inline void operator delete[](void *ptr) { \ - PANDA_FREE_ARRAY(ptr); \ + if (ptr != nullptr) { \ + PANDA_FREE_ARRAY(ptr); \ + } \ } \ inline void operator delete[](void *, void *) { \ } diff --git a/dtool/src/dtoolbase/pandaVersion.h.in b/dtool/src/dtoolbase/pandaVersion.h.in index ecaed20cd7..4854ae47df 100644 --- a/dtool/src/dtoolbase/pandaVersion.h.in +++ b/dtool/src/dtoolbase/pandaVersion.h.in @@ -61,13 +61,3 @@ /* This is a string indicating who has provided this distribution. */ #define PANDA_DISTRIBUTOR "@PANDA_DISTRIBUTOR@" - -/* The string indicating the version number of the associated Panda3D - distributable package, or empty string if there is no associated - package. */ -#define PANDA_PACKAGE_VERSION_STR "@PANDA_PACKAGE_VERSION@" - -/* The string indicating the URL from which the associated Panda3D - distributable package may be downloaded, or empty string if there - is no associated package. */ -#define PANDA_PACKAGE_HOST_URL "@PANDA_PACKAGE_HOST_URL@" diff --git a/dtool/src/dtoolutil/executionEnvironment.cxx b/dtool/src/dtoolutil/executionEnvironment.cxx index 7d57614e08..b018365cfb 100644 --- a/dtool/src/dtoolutil/executionEnvironment.cxx +++ b/dtool/src/dtoolutil/executionEnvironment.cxx @@ -805,21 +805,25 @@ read_args() { #elif defined(IS_FREEBSD) // In FreeBSD, we can use sysctl to determine the command-line arguments. - size_t bufsize = 4096; - char buffer[4096]; + size_t bufsize = 0; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0}; mib[3] = getpid(); - if (sysctl(mib, 4, (void*) buffer, &bufsize, nullptr, 0) == -1) { + if (sysctl(mib, 4, nullptr, &bufsize, nullptr, 0) == -1) { perror("sysctl"); } else { - if (_binary_name.empty()) { - _binary_name = buffer; - } - size_t idx = strlen(buffer) + 1; - while (idx < bufsize) { - _args.push_back((char*)(buffer + idx)); - size_t newidx = strlen(buffer + idx); - idx += newidx + 1; + char *buffer = (char *)alloca(bufsize); + if (sysctl(mib, 4, buffer, &bufsize, nullptr, 0) == -1) { + perror("sysctl"); + } else { + if (_binary_name.empty()) { + _binary_name = buffer; + } + size_t idx = strlen(buffer) + 1; + while (idx < bufsize) { + _args.push_back((char*)(buffer + idx)); + size_t newidx = strlen(buffer + idx); + idx += newidx + 1; + } } } diff --git a/dtool/src/dtoolutil/filename_ext.cxx b/dtool/src/dtoolutil/filename_ext.cxx index e60bf83a90..58b96f74bc 100644 --- a/dtool/src/dtoolutil/filename_ext.cxx +++ b/dtool/src/dtoolutil/filename_ext.cxx @@ -34,18 +34,9 @@ __init__(PyObject *path) { if (PyUnicode_CheckExact(path)) { wchar_t *data; -#if PY_VERSION_HEX >= 0x03020000 data = PyUnicode_AsWideCharString(path, &length); -#else - length = PyUnicode_GET_SIZE(path); - data = (wchar_t *)alloca(sizeof(wchar_t) * (length + 1)); - PyUnicode_AsWideChar((PyUnicodeObject *)path, data, length); -#endif (*_this) = wstring(data, length); - -#if PY_VERSION_HEX >= 0x03020000 PyMem_Free(data); -#endif return; } @@ -81,13 +72,7 @@ __init__(PyObject *path) { if (PyObject_HasAttrString(path, "_format_parsed_parts")) { path_str = PyObject_Str(path); } else { -#if PY_VERSION_HEX >= 0x03040000 PyErr_Format(PyExc_TypeError, "expected str, bytes, Path or Filename object, not %s", Py_TYPE(path)->tp_name); -#elif PY_MAJOR_VERSION >= 3 - PyErr_Format(PyExc_TypeError, "expected str, bytes or Filename object, not %s", Py_TYPE(path)->tp_name); -#else - PyErr_Format(PyExc_TypeError, "expected str or unicode object, not %s", Py_TYPE(path)->tp_name); -#endif return; } #endif @@ -98,18 +83,9 @@ __init__(PyObject *path) { if (PyUnicode_CheckExact(path_str)) { wchar_t *data; -#if PY_VERSION_HEX >= 0x03020000 data = PyUnicode_AsWideCharString(path_str, &length); -#else - length = PyUnicode_GET_SIZE(path_str); - data = (wchar_t *)alloca(sizeof(wchar_t) * (length + 1)); - PyUnicode_AsWideChar((PyUnicodeObject *)path_str, data, length); -#endif (*_this) = Filename::from_os_specific_w(wstring(data, length)); - -#if PY_VERSION_HEX >= 0x03020000 PyMem_Free(data); -#endif } else if (PyBytes_CheckExact(path_str)) { char *data; @@ -117,11 +93,7 @@ __init__(PyObject *path) { (*_this) = Filename::from_os_specific(string(data, length)); } else { -#if PY_MAJOR_VERSION >= 3 PyErr_Format(PyExc_TypeError, "expected str or bytes object, not %s", Py_TYPE(path_str)->tp_name); -#else - PyErr_Format(PyExc_TypeError, "expected str or unicode object, not %s", Py_TYPE(path_str)->tp_name); -#endif } Py_DECREF(path_str); } @@ -150,25 +122,10 @@ __reduce__(PyObject *self) const { */ PyObject *Extension:: __repr__() const { -#if PY_MAJOR_VERSION >= 3 - // Python 3 case: return a unicode object. wstring filename = _this->get_fullpath_w(); PyObject *str = PyUnicode_FromWideChar(filename.data(), (Py_ssize_t)filename.size()); -#if PY_VERSION_HEX >= 0x03040000 PyObject *result = PyUnicode_FromFormat("Filename(%R)", str); -#else - static PyObject *format = PyUnicode_FromString("Filename(%r)"); - PyObject *result = PyUnicode_Format(format, str); -#endif - -#else - // Python 2 case: return a regular string. - string filename = _this->get_fullpath(); - PyObject *str = PyString_FromStringAndSize(filename.data(), (Py_ssize_t)filename.size()); - static PyObject *format = PyString_FromString("Filename(%r)"); - PyObject *result = PyString_Format(format, str); -#endif Py_DECREF(str); return result; @@ -199,12 +156,8 @@ scan_directory() const { PyObject *result = PyList_New(contents.size()); for (size_t i = 0; i < contents.size(); ++i) { const string &filename = contents[i]; -#if PY_MAJOR_VERSION >= 3 // This function expects UTF-8. PyObject *str = PyUnicode_FromStringAndSize(filename.data(), filename.size()); -#else - PyObject *str = PyString_FromStringAndSize(filename.data(), filename.size()); -#endif PyList_SET_ITEM(result, i, str); } diff --git a/dtool/src/dtoolutil/iostream_ext.cxx b/dtool/src/dtoolutil/iostream_ext.cxx index 09cfaff6d7..352927b0d6 100644 --- a/dtool/src/dtoolutil/iostream_ext.cxx +++ b/dtool/src/dtoolutil/iostream_ext.cxx @@ -49,11 +49,7 @@ read(Py_ssize_t size) { #endif } -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize(buffer, read_bytes); -#else - return PyString_FromStringAndSize(buffer, read_bytes); -#endif } /** @@ -92,11 +88,7 @@ read1(Py_ssize_t size) { Py_BLOCK_THREADS #endif -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize(buffer, read_bytes); -#else - return PyString_FromStringAndSize(buffer, read_bytes); -#endif } /** @@ -128,11 +120,7 @@ readall() { Py_BLOCK_THREADS #endif -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)result.data(), result.size()); -#else - return PyString_FromStringAndSize((char *)result.data(), result.size()); -#endif } /** @@ -195,11 +183,7 @@ readline(Py_ssize_t size) { Py_BLOCK_THREADS #endif -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize(line.data(), line.size()); -#else - return PyString_FromStringAndSize(line.data(), line.size()); -#endif } /** diff --git a/dtool/src/dtoolutil/pandaSystem.cxx b/dtool/src/dtoolutil/pandaSystem.cxx index 79a8e5206b..62185a8307 100644 --- a/dtool/src/dtoolutil/pandaSystem.cxx +++ b/dtool/src/dtoolutil/pandaSystem.cxx @@ -31,11 +31,6 @@ PandaSystem() : { _system_names_dirty = false; - // These are settable via Config.prc, but only in development (!NDEBUG) - // mode, and only if they are not already defined. - _package_version_string = ""; - _package_host_url = ""; - #ifdef STDFLOAT_DOUBLE add_system("stdfloat-double"); #endif @@ -86,75 +81,6 @@ get_version_string() { return PANDA_VERSION_STR; } -/** - * Returns the version of the Panda3D distributable package that provides this - * build of Panda. - * - * When the currently-executing version of Panda was loaded from a - * distributable package, such as via the browser plugin, then this string - * will be nonempty and will contain the corresponding version string. You - * can build applications that use this particular version of Panda by - * requesting it in the pdef file, using "panda3d", this version string, and - * the download host provided by get_package_host_url(). - * - * If this string is empty, then the currently-executing Panda was built - * independently, and is not part of a distributable package. - * - * @deprecated Runtime/plugin environment has been removed, this now always - * returns an empty string. - */ -string PandaSystem:: -get_package_version_string() { -#ifdef NDEBUG - return ""; -#else - return get_global_ptr()->_package_version_string; -#endif -} - -/** - * Returns the URL of the download server that provides the Panda3D - * distributable package currently running. This can be used, along with the - * get_package_version_string(), to uniquely identify the running version of - * Panda among distributable Panda versions. - * - * See get_package_version_string() for more information. - * - * This string is set explicitly at compilation time. Normally, it should be - * set to a nonempty string only when building a Panda3D package for - * distribution. - * - * @deprecated Runtime/plugin environment has been removed, this now always - * returns an empty string. - */ -string PandaSystem:: -get_package_host_url() { -#ifdef NDEBUG - return ""; -#else - return get_global_ptr()->_package_host_url; -#endif -} - -/** - * Returns the current version of Panda's Core API, expressed as a string of - * dot-delimited integers. There are usually four integers in this version, - * but this is not guaranteed. - * - * The Core API is used during the runtime (plugin) environment only. This - * may be the empty string if the current version of Panda is not built to - * provide a particular Core API, which will be the normal case in a - * development SDK. However, you should not use this method to determine - * whether you are running in a runtime environment or not. - * - * @deprecated Runtime/plugin environment has been removed, this now always - * returns an empty string. - */ -string PandaSystem:: -get_p3d_coreapi_version_string() { - return ""; -} - /** * Returns the major version number of the current version of Panda. This is * the first number of the dotted triple returned by get_version_string(). It @@ -465,33 +391,3 @@ reset_system_names() { _system_names_dirty = false; } - -/** - * Loads the value returned by get_package_version_string(). This is intended - * to be called by ConfigPageManager to preload the value from the panda- - * package-version config variable, for developer's convenience. This has no - * effect if the PANDA_PACKAGE_VERSION_STR configure variable is defined at - * compilation time. This also has no effect in NDEBUG mode. - */ -void PandaSystem:: -set_package_version_string(const string &package_version_string) { - _package_version_string = ""; - if (_package_version_string.empty()) { - _package_version_string = package_version_string; - } -} - -/** - * Loads the value returned by get_package_host_url(). This is intended to be - * called by ConfigPageManager to preload the value from the panda-package- - * host-url config variable, for developer's convenience. This has no effect - * if the PANDA_PACKAGE_HOST_URL configure variable is defined at compilation - * time. This also has no effect in NDEBUG mode. - */ -void PandaSystem:: -set_package_host_url(const string &package_host_url) { - _package_host_url = ""; - if (_package_host_url.empty()) { - _package_host_url = package_host_url; - } -} diff --git a/dtool/src/dtoolutil/pandaSystem.h b/dtool/src/dtoolutil/pandaSystem.h index 712b61e834..640338edbc 100644 --- a/dtool/src/dtoolutil/pandaSystem.h +++ b/dtool/src/dtoolutil/pandaSystem.h @@ -30,9 +30,6 @@ protected: PUBLISHED: static std::string get_version_string(); - static std::string get_package_version_string(); - static std::string get_package_host_url(); - static std::string get_p3d_coreapi_version_string(); static int get_major_version(); static int get_minor_version(); @@ -85,9 +82,6 @@ PUBLISHED: private: void reset_system_names(); - void set_package_version_string(const std::string &package_version_string); - void set_package_host_url(const std::string &package_host_url); - typedef pmap SystemTags; typedef pmap Systems; typedef pvector SystemNames; @@ -96,9 +90,6 @@ private: SystemNames _system_names; bool _system_names_dirty; - std::string _package_version_string; - std::string _package_host_url; - static PandaSystem *_global_ptr; public: diff --git a/dtool/src/dtoolutil/textEncoder_ext.cxx b/dtool/src/dtoolutil/textEncoder_ext.cxx index 1947e6c749..4774286c5b 100644 --- a/dtool/src/dtoolutil/textEncoder_ext.cxx +++ b/dtool/src/dtoolutil/textEncoder_ext.cxx @@ -22,26 +22,11 @@ void Extension:: set_text(PyObject *text) { if (PyUnicode_Check(text)) { -#if PY_VERSION_HEX >= 0x03030000 Py_ssize_t len; const char *str = PyUnicode_AsUTF8AndSize(text, &len); _this->set_text(std::string(str, len), TextEncoder::E_utf8); -#else - Py_ssize_t len = PyUnicode_GET_SIZE(text); - wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1)); - PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len); - _this->set_wtext(std::wstring(str, len)); -#endif } else { -#if PY_MAJOR_VERSION >= 3 Dtool_Raise_TypeError("expected string"); -#else - char *str; - Py_ssize_t len; - if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) { - _this->set_text(std::string(str, len)); - } -#endif } } @@ -63,13 +48,8 @@ set_text(PyObject *text, TextEncoder::Encoding encoding) { */ PyObject *Extension:: get_text() const { -#if PY_MAJOR_VERSION >= 3 std::wstring text = _this->get_wtext(); return PyUnicode_FromWideChar(text.data(), (Py_ssize_t)text.size()); -#else - std::string text = _this->get_text(); - return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); -#endif } /** @@ -78,11 +58,7 @@ get_text() const { PyObject *Extension:: get_text(TextEncoder::Encoding encoding) const { std::string text = _this->get_text(encoding); -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); -#else - return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); -#endif } /** @@ -91,7 +67,6 @@ get_text(TextEncoder::Encoding encoding) const { void Extension:: append_text(PyObject *text) { if (PyUnicode_Check(text)) { -#if PY_VERSION_HEX >= 0x03030000 Py_ssize_t len; const char *str = PyUnicode_AsUTF8AndSize(text, &len); std::string text_str(str, len); @@ -100,22 +75,8 @@ append_text(PyObject *text) { } else { _this->append_wtext(TextEncoder::decode_text(text_str, TextEncoder::E_utf8)); } -#else - Py_ssize_t len = PyUnicode_GET_SIZE(text); - wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1)); - PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len); - _this->append_wtext(std::wstring(str, len)); -#endif } else { -#if PY_MAJOR_VERSION >= 3 Dtool_Raise_TypeError("expected string"); -#else - char *str; - Py_ssize_t len; - if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) { - _this->append_text(std::string(str, len)); - } -#endif } } @@ -125,11 +86,7 @@ append_text(PyObject *text) { PyObject *Extension:: encode_wchar(char32_t ch, TextEncoder::Encoding encoding) { std::string value = TextEncoder::encode_wchar(ch, encoding); -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); -#else - return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); -#endif } /** @@ -139,11 +96,7 @@ encode_wchar(char32_t ch, TextEncoder::Encoding encoding) { PyObject *Extension:: encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) { std::string value = TextEncoder::encode_wtext(wtext, encoding); -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); -#else - return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); -#endif } /** diff --git a/dtool/src/prc/configPageManager.cxx b/dtool/src/prc/configPageManager.cxx index 27afc3c395..c6672deddf 100644 --- a/dtool/src/prc/configPageManager.cxx +++ b/dtool/src/prc/configPageManager.cxx @@ -722,27 +722,6 @@ void ConfigPageManager:: config_initialized() { Notify::config_initialized(); -#ifndef NDEBUG - ConfigVariableString panda_package_version - ("panda-package-version", "local_dev", - PRC_DESC("This can be used to specify the value returned by " - "PandaSystem::get_package_version_str(), in development mode only, " - "and only if another value has not already been compiled in. This " - "is intended for developer convenience, to masquerade a development " - "build of Panda as a different runtime version. Use with caution.")); - ConfigVariableString panda_package_host_url - ("panda-package-host-url", "", - PRC_DESC("This can be used to specify the value returned by " - "PandaSystem::get_package_host_url(), in development mode only, " - "and only if another value has not already been compiled in. This " - "is intended for developer convenience, to masquerade a development " - "build of Panda as a different runtime version. Use with caution.")); - - PandaSystem *panda_sys = PandaSystem::get_global_ptr(); - panda_sys->set_package_version_string(panda_package_version); - panda_sys->set_package_host_url(panda_package_host_url); -#endif // NDEBUG - // Also set up some other low-level things. ConfigVariableEnum text_encoding ("text-encoding", TextEncoder::E_utf8, diff --git a/dtool/src/prc/streamReader_ext.cxx b/dtool/src/prc/streamReader_ext.cxx index 9fc12dc51f..767e5890eb 100644 --- a/dtool/src/prc/streamReader_ext.cxx +++ b/dtool/src/prc/streamReader_ext.cxx @@ -60,11 +60,7 @@ readline() { ch = in->get(); } -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize(line.data(), line.size()); -#else - return PyString_FromStringAndSize(line.data(), line.size()); -#endif } /** @@ -80,11 +76,7 @@ readlines() { PyObject *py_line = readline(); -#if PY_MAJOR_VERSION >= 3 while (PyBytes_GET_SIZE(py_line) > 0) { -#else - while (PyString_GET_SIZE(py_line) > 0) { -#endif PyList_Append(lst, py_line); Py_DECREF(py_line); diff --git a/dtool/src/prc/streamWriter.I b/dtool/src/prc/streamWriter.I index 1f12c1517e..0a5594357c 100644 --- a/dtool/src/prc/streamWriter.I +++ b/dtool/src/prc/streamWriter.I @@ -16,9 +16,6 @@ */ INLINE StreamWriter:: StreamWriter(std::ostream &out) : -#ifdef HAVE_PYTHON - softspace(0), -#endif _out(&out), _owns_stream(false) { @@ -29,9 +26,6 @@ StreamWriter(std::ostream &out) : */ INLINE StreamWriter:: StreamWriter(std::ostream *out, bool owns_stream) : -#ifdef HAVE_PYTHON - softspace(0), -#endif _out(out), _owns_stream(owns_stream) { @@ -42,9 +36,6 @@ StreamWriter(std::ostream *out, bool owns_stream) : */ INLINE StreamWriter:: StreamWriter(const StreamWriter ©) : -#ifdef HAVE_PYTHON - softspace(0), -#endif _out(copy._out), _owns_stream(false) { @@ -55,9 +46,6 @@ StreamWriter(const StreamWriter ©) : */ INLINE StreamWriter:: StreamWriter(StreamWriter &&from) noexcept : -#ifdef HAVE_PYTHON - softspace(0), -#endif _out(from._out), _owns_stream(from._owns_stream) { diff --git a/dtool/src/prc/streamWriter.h b/dtool/src/prc/streamWriter.h index 8072e8aa40..522fa45050 100644 --- a/dtool/src/prc/streamWriter.h +++ b/dtool/src/prc/streamWriter.h @@ -83,12 +83,6 @@ public: private: std::ostream *_out; bool _owns_stream; - -#ifdef HAVE_PYTHON -PUBLISHED: - // Python 2 needs this for printing to work correctly. - int softspace; -#endif }; #include "streamWriter.I" diff --git a/makepanda/installer.nsi b/makepanda/installer.nsi index 3ad99e7875..468dd091ff 100644 --- a/makepanda/installer.nsi +++ b/makepanda/installer.nsi @@ -14,7 +14,7 @@ ; ; BUILT - location of panda install tree. ; SOURCE - location of the panda source-tree if available, OR location of panda install tree. -; INCLUDE_PYVER - version of Python that Panda was built with (eg. "2.7", "3.5-32") +; INCLUDE_PYVER - version of Python that Panda was built with (eg. "3.8", "3.7-32") ; REGVIEW - either 32 or 64, depending on the build architecture. ; @@ -367,7 +367,6 @@ SectionGroup "Python modules" SecGroupPython File /r "${BUILT}\panda3d\*.py" SectionEnd - !insertmacro PyBindingSection 2.7 .pyd !if "${REGVIEW}" == "32" !insertmacro PyBindingSection 3.5-32 .cp35-win32.pyd !insertmacro PyBindingSection 3.6-32 .cp36-win32.pyd @@ -479,7 +478,6 @@ Function .onInit SetRegView ${REGVIEW} !endif - ; We never check for 2.7; it is always disabled in Auto mode !if "${REGVIEW}" == "32" !insertmacro MaybeEnablePyBindingSection 3.5-32 !insertmacro MaybeEnablePyBindingSection 3.6-32 @@ -872,7 +870,6 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${SecTools} $(DESC_SecTools) !insertmacro MUI_DESCRIPTION_TEXT ${SecGroupPython} $(DESC_SecGroupPython) !insertmacro MUI_DESCRIPTION_TEXT ${SecPyShared} $(DESC_SecPyShared) - !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings2.7} $(DESC_SecPyBindings2.7) !if "${REGVIEW}" == "32" !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.5-32} $(DESC_SecPyBindings3.5-32) !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.6-32} $(DESC_SecPyBindings3.6-32) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index c725317d1e..ec6fa85d99 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -209,8 +209,7 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, python_versions=[], **kwargs): outputdir = GetOutputDir() - # We pack Python 2 and Python 3, if we built with support for it. - python2_ver = None + # We pack the default Python 3 version that ships with Ubuntu. python3_ver = None install_python_versions = [] @@ -218,12 +217,9 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, oscmd('python3 -V > "%s/tmp/python3_version.txt"' % (outputdir)) sys_python3_ver = '.'.join(ReadFile(outputdir + "/tmp/python3_version.txt").strip().split(' ')[1].split('.')[:2]) - # Check that we built with support for these. + # Check that we built with support for it. for version_info in python_versions: - if version_info["version"] == "2.7": - python2_ver = "2.7" - install_python_versions.append(version_info) - elif version_info["version"] == sys_python3_ver: + if version_info["version"] == sys_python3_ver: python3_ver = sys_python3_ver install_python_versions.append(version_info) @@ -301,18 +297,9 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, recommends = ReadFile("targetroot/debian/substvars_rec").replace("shlibs:Depends=", "").strip() provides = "panda3d" - if python2_ver or python3_ver: - recommends += ", python-pmw" - - if python2_ver: - depends += ", python%s" % (python2_ver) - recommends += ", python-wxversion" - recommends += ", python-tk (>= %s)" % (python2_ver) - provides += ", python2-panda3d" - if python3_ver: depends += ", python%s" % (python3_ver) - recommends += ", python3-tk (>= %s)" % (python3_ver) + recommends += ", python-pmw, python3-tk (>= %s)" % (python3_ver) provides += ", python3-panda3d" if not PkgSkip("NVIDIACG"): @@ -654,11 +641,7 @@ def MakeInstallerOSX(version, python_versions=[], installdir=None, **kwargs): for version_info in python_versions: pyver = version_info["version"] - if pyver in ("2.7", "3.4"): - # Don't install these EOL versions of Python by default. - cond = "false" - else: - cond = "isPythonVersionInstalled('%s')" % (pyver) + cond = "isPythonVersionInstalled('%s')" % (pyver) dist.write(' \n' % (pyver, cond, pyver, pyver)) dist.write(' \n' % (pyver)) dist.write(' \n') diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 7c2d0f959a..b34cecd011 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -7,14 +7,16 @@ # panda3d. # ######################################################################## + +import sys +if sys.version_info < (3, 5): + print("This version of Python is not supported, use version 3.5 or higher.") + exit(1) + try: - import sys, os, platform, time, stat, re, getopt, threading, signal, shutil - if sys.platform == "darwin" or sys.version_info >= (2, 6): - import plistlib - if sys.version_info >= (3, 0): - import queue - else: - import Queue as queue + import os, platform, time, stat, re, getopt, threading, signal, shutil + import plistlib + import queue except KeyboardInterrupt: raise except: @@ -484,15 +486,13 @@ SdkAutoDisableMax() SdkAutoDisableSpeedTree() if not PkgSkip("PYTHON") and SDK["PYTHONVERSION"] == "python2.7": - warn_prefix = "%sWARNING:%s " % (GetColor("red"), GetColor()) - print("==========================================================================") - print(warn_prefix + "Python 2.7 has reached EOL as of January 1, 2020 and is no longer") - print(warn_prefix + "maintained. Panda3D will soon cease to work with this version.") - print(warn_prefix + "Please upgrade to Python 3 now.") - print("==========================================================================") + pref = "%sERROR:%s " % (GetColor("red"), GetColor()) + print("========================================================================") + print(pref + "Python 2.7 has reached EOL as of January 1, 2020 and is no longer") + print(pref + "supported. Please upgrade to Python 3.5 or later.") + print("========================================================================") sys.stdout.flush() - # Give the user some time to contemplate their sins - time.sleep(6.0) + sys.exit(1) ######################################################################## ## @@ -1969,8 +1969,7 @@ def FreezePy(target, inputs, opts): assert len(inputs) > 0 cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"].replace('\\', '/')) + " " - if sys.version_info >= (2, 6): - cmdstr += "-B " + cmdstr += "-B " cmdstr += os.path.join(GetOutputDir(), "direct", "dist", "pfreeze.py") @@ -2584,12 +2583,8 @@ p3d_init = """"Python bindings for the Panda3D libraries" __version__ = '%s' if __debug__: - import sys - if sys.version_info < (3, 0): - sys.stderr.write("WARNING: Python 2.7 has reached EOL as of January 1, 2020.\\n") - sys.stderr.write("To suppress this warning, upgrade to Python 3.\\n") - sys.stderr.flush() - del sys + if 1 / 2 == 0: + raise ImportError("Python 2 is not supported.") """ % (WHLVERSION) if GetTarget() == 'windows': @@ -6034,9 +6029,7 @@ finally: # Run the test suite. if RUNTESTS: cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"].replace('\\', '/')) - if sys.version_info >= (2, 6): - cmdstr += " -B" - cmdstr += " -m pytest tests" + cmdstr += " -B -m pytest tests" if GetVerbose(): cmdstr += " --verbose" oscmd(cmdstr) diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index bfc9b85a3c..ae0ee8d360 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -8,15 +8,9 @@ import sys,os,time,stat,string,re,getopt,fnmatch,threading,signal,shutil,platform,glob,getpass,signal import subprocess from distutils import sysconfig - -if sys.version_info >= (3, 0): - import pickle - import _thread as thread - import configparser -else: - import cPickle as pickle - import thread - import ConfigParser as configparser +import pickle +import _thread as thread +import configparser SUFFIX_INC = [".cxx",".cpp",".c",".h",".I",".yxx",".lxx",".mm",".rc",".r"] SUFFIX_DLL = [".dll",".dlo",".dle",".dli",".dlm",".mll",".exe",".pyd",".ocx"] @@ -49,10 +43,7 @@ if sys.platform == 'darwin': # On OSX, platform.architecture reports '64bit' even if it is # currently running in 32-bit mode. But sys.maxint is a reliable # indicator. - if sys.version_info >= (3, 0): - host_64 = (sys.maxsize > 0x100000000) - else: - host_64 = (sys.maxint > 0x100000000) + host_64 = (sys.maxsize > 0x100000000) else: # On Windows (and Linux?) sys.maxint reports 0x7fffffff even on a # 64-bit build. So we stick with platform.architecture in that @@ -215,10 +206,7 @@ def GetColor(color = None): else: token = curses.tparm(curses.tigetstr("sgr0")) - if sys.version_info >= (3, 0): - return token.decode('ascii') - else: - return token + return token.decode('ascii') def ColorText(color, text, reset=True): if reset is True: @@ -1000,10 +988,7 @@ def JavaCalcDependencies(srcfile, clspath): if sys.platform == "win32": # Note: not supported on cygwin. - if sys.version_info >= (3, 0): - import winreg - else: - import _winreg as winreg + import winreg def TryRegistryKey(path): try: @@ -1148,10 +1133,7 @@ def WriteFile(wfile, data, newline=None): data = data.replace('\n', newline) try: - if sys.version_info >= (3, 0): - dsthandle = open(wfile, "w", newline='') - else: - dsthandle = open(wfile, "w") + dsthandle = open(wfile, "w", newline='') dsthandle.write(data) dsthandle.close() except: @@ -2057,10 +2039,7 @@ def SdkLocatePython(prefer_thirdparty_python=False): if GetTarget() == 'windows': sdkdir = GetThirdpartyBase() + "/win-python" - - if sys.version_info >= (3, 0): - # Python 3 build... - sdkdir += "%d.%d" % sys.version_info[:2] + sdkdir += "%d.%d" % sys.version_info[:2] if GetOptimize() <= 2: sdkdir += "-dbg" @@ -3239,15 +3218,8 @@ def SetOrigExt(x, v): ORIG_EXT[x] = v def GetExtensionSuffix(): - if sys.version_info >= (3, 0): - import _imp - return _imp.extension_suffixes()[0] - - target = GetTarget() - if target == 'windows': - return '.pyd' - else: - return '.so' + import _imp + return _imp.extension_suffixes()[0] def GetPythonABI(): soabi = sysconfig.get_config_var('SOABI') @@ -3267,11 +3239,6 @@ def GetPythonABI(): if malloc_flag is None or malloc_flag: soabi += 'm' - if sys.version_info < (3, 3): - usize = sysconfig.get_config_var('Py_UNICODE_SIZE') - if (usize is None and sys.maxunicode == 0x10ffff) or usize == 4: - soabi += 'u' - return soabi def CalcLocation(fn, ipath): @@ -3406,12 +3373,14 @@ def UpdatePythonVersionInfoFile(new_info): json_data = [] # Prune the list by removing the entries that conflict with our build, - # plus the entries that no longer exist + # plus the entries that no longer exist, and the EOL Python versions for version_info in json_data[:]: core_pyd = os.path.join(GetOutputDir(), "panda3d", "core" + version_info["ext_suffix"]) if version_info["ext_suffix"] == new_info["ext_suffix"] or \ version_info["soabi"] == new_info["soabi"] or \ - not os.path.isfile(core_pyd): + not os.path.isfile(core_pyd) or \ + version_info["version"].split(".", 1)[0] == "2" or \ + version_info["version"] in ("3.0", "3.1", "3.2", "3.3", "3.4"): json_data.remove(version_info) if not PkgSkip("PYTHON"): @@ -3428,10 +3397,17 @@ def ReadPythonVersionInfoFile(): json_file = os.path.join(GetOutputDir(), "tmp", "python_versions.json") if os.path.isfile(json_file): try: - return json.load(open(json_file, 'r')) + json_data = json.load(open(json_file, 'r')) except: pass + # Don't include unsupported versions of Python. + for version_info in json_data[:]: + if version_info["version"] in ("2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4"): + json_data.remove(version_info) + + return json_data + return [] diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index 04475fc0bb..5755742b9b 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -20,12 +20,11 @@ from base64 import urlsafe_b64encode def get_abi_tag(): - if sys.version_info >= (3, 0): - soabi = get_config_var('SOABI') - if soabi and soabi.startswith('cpython-'): - return 'cp' + soabi.split('-')[1] - elif soabi: - return soabi.replace('.', '_').replace('-', '_') + soabi = get_config_var('SOABI') + if soabi and soabi.startswith('cpython-'): + return 'cp' + soabi.split('-')[1] + elif soabi: + return soabi.replace('.', '_').replace('-', '_') soabi = 'cp%d%d' % (sys.version_info[:2]) @@ -40,11 +39,6 @@ def get_abi_tag(): if malloc_flag is None or malloc_flag: soabi += 'm' - if sys.version_info < (3, 3): - usize = get_config_var('Py_UNICODE_SIZE') - if (usize is None and sys.maxunicode == 0x10ffff) or usize == 4: - soabi += 'u' - return soabi @@ -424,6 +418,15 @@ class WheelFile(object): continue new_dep = os.path.join(deps_path, os.path.relpath(target_dep, os.path.dirname(target_path))) + elif '@rpath' in dep: + # Unlike makepanda, CMake uses @rpath instead of + # @loader_path. This means we can just search for the + # dependencies like normal. + dep_path = dep.replace('@rpath', '.') + target_dep = os.path.dirname(target_path) + '/' + os.path.basename(dep) + self.consider_add_dependency(target_dep, dep_path) + continue + elif dep.startswith('/Library/Frameworks/Python.framework/'): # Add this dependency if it's in the Python directory. target_dep = os.path.dirname(target_path) + '/' + os.path.basename(dep) @@ -528,6 +531,9 @@ def makewheel(version, output_dir, platform=None): if not LocateBinary("patchelf"): raise Exception("patchelf is required when building a Linux wheel.") + if sys.version_info < (3, 5): + raise Exception("Python 3.5 is required to produce a wheel.") + if platform is None: # Determine the platform from the build. platform_dat = os.path.join(output_dir, 'tmp', 'platform.dat') @@ -616,12 +622,8 @@ __version__ = '{0}' if '27' in ABI_TAG: p3d_init += """ if __debug__: - import sys - if sys.version_info < (3, 0): - sys.stderr.write("WARNING: Python 2.7 will reach EOL after December 31, 2019.\\n") - sys.stderr.write("To suppress this warning, upgrade to Python 3.\\n") - sys.stderr.flush() - del sys + if 1 / 2 == 0: + raise ImportError(\"Python 2 is not supported.\") """ whl.write_file_data('panda3d/__init__.py', p3d_init) diff --git a/makepanda/selfdestruct.py b/makepanda/selfdestruct.py index 67d0303c20..512c383919 100755 --- a/makepanda/selfdestruct.py +++ b/makepanda/selfdestruct.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import os import re diff --git a/panda/CMakeLists.txt b/panda/CMakeLists.txt index 93e9eb3aa1..83a796c82d 100644 --- a/panda/CMakeLists.txt +++ b/panda/CMakeLists.txt @@ -118,14 +118,8 @@ if(INTERROGATE_PYTHON_INTERFACE) __version__ = '${PROJECT_VERSION}' if __debug__: - import sys - if sys.version_info < (3, 0): - sys.stderr.write('''\\ -WARNING: Python 2.7 has reached EOL as of January 1, 2020. -To suppress this warning, upgrade to Python 3. -''') - sys.stdout.flush() - del sys + if 1 / 2 == 0: + raise ImportError(\"Python 2 is not supported.\") ${win32_init}") @@ -151,6 +145,16 @@ from .interrogatedb import * file(WRITE "${PROJECT_BINARY_DIR}/panda3d/dtoolconfig.py" ${dtoolconfig_file}) endif() + # Also generate a panda3d.dist-info directory. + set(entry_points_file "[distutils.commands] +build_apps = direct.dist.commands:build_apps +bdist_apps = direct.dist.commands:bdist_apps +") + + configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/METADATA.in" + "${PROJECT_BINARY_DIR}/panda3d.dist-info/METADATA") + file(WRITE "${PROJECT_BINARY_DIR}/panda3d.dist-info/entry_points.txt" ${entry_points_file}) + if(HAVE_BULLET) add_python_module(panda3d.bullet p3bullet IMPORT panda3d.core COMPONENT BulletPython) diff --git a/panda/src/android/python_main.cxx b/panda/src/android/python_main.cxx index 0e4059c61c..fafb4b37cb 100644 --- a/panda/src/android/python_main.cxx +++ b/panda/src/android/python_main.cxx @@ -18,9 +18,7 @@ #undef _POSIX_C_SOURCE #undef _XOPEN_SOURCE #include -#if PY_MAJOR_VERSION >= 3 #include -#endif #include diff --git a/panda/src/android/site.py b/panda/src/android/site.py index fd3909ede8..7c8d22e207 100644 --- a/panda/src/android/site.py +++ b/panda/src/android/site.py @@ -4,10 +4,7 @@ import os from importlib.abc import Loader, MetaPathFinder from importlib.machinery import ModuleSpec -if sys.version_info >= (3, 5): - from importlib import _bootstrap_external -else: - from importlib import _bootstrap as _bootstrap_external +from importlib import _bootstrap_external sys.platform = "android" diff --git a/panda/src/collide/collisionPolygon.cxx b/panda/src/collide/collisionPolygon.cxx index 6f3d3e39f2..2a1dae80da 100644 --- a/panda/src/collide/collisionPolygon.cxx +++ b/panda/src/collide/collisionPolygon.cxx @@ -484,6 +484,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { } LPoint2 p = to_2d(from_center - dist * get_normal()); + LPoint2 edge_p; PN_stdfloat edge_dist = 0.0f; const ClipPlaneAttrib *cpa = entry.get_into_clip_planes(); @@ -492,7 +493,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { Points new_points; if (apply_clip_plane(new_points, cpa, entry.get_into_node_path().get_net_transform())) { // All points are behind the clip plane; just do the default test. - edge_dist = dist_to_polygon(p, _points); + edge_dist = dist_to_polygon(p, edge_p, _points); } else if (new_points.empty()) { // The polygon is completely clipped. @@ -500,12 +501,12 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { } else { // Test against the clipped polygon. - edge_dist = dist_to_polygon(p, new_points); + edge_dist = dist_to_polygon(p, edge_p, new_points); } } else { // No clip plane is in effect. Do the default test. - edge_dist = dist_to_polygon(p, _points); + edge_dist = dist_to_polygon(p, edge_p, _points); } // Now we have edge_dist, which is the distance from the sphere center to @@ -527,8 +528,8 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { max_dist = csqrt(max_dist_2); } - if (dist > max_dist) { - // There's no intersection: the sphere is hanging off the edge. + if (dist > max_dist || -dist > max_dist) { + // There's no intersection: the sphere is hanging above or under the edge. return nullptr; } @@ -548,9 +549,21 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { into_depth = max_dist - orig_dist; } + if (edge_dist >= 0.0f) { + // If colliding with an edge, we take the point on the edge. + LMatrix4 to_3d_mat; + rederive_to_3d_mat(to_3d_mat); + + LPoint3 surface_point = to_3d(edge_p, to_3d_mat); + new_entry->set_surface_point(surface_point); + new_entry->set_interior_point(surface_point - normal * into_depth); + } else { + // Otherwise, we use the projection of the center onto the polygon. + new_entry->set_surface_point(from_center - normal * dist); + new_entry->set_interior_point(from_center - normal * (dist + into_depth)); + } + new_entry->set_surface_normal(normal); - new_entry->set_surface_point(from_center - normal * dist); - new_entry->set_interior_point(from_center - normal * (dist + into_depth)); new_entry->set_contact_pos(contact_point); new_entry->set_contact_normal(get_normal()); new_entry->set_t(actual_t); @@ -1330,9 +1343,12 @@ point_is_inside(const LPoint2 &p, const CollisionPolygon::Points &points) const * Returns the linear distance from the 2-d point to the nearest part of the * polygon defined by the points vector. The result is negative if the point * is within the polygon. + * + * If the point is not within the polygon, the closest point to the edge is + * returned in the edge_p argument. */ PN_stdfloat CollisionPolygon:: -dist_to_polygon(const LPoint2 &p, const CollisionPolygon::Points &points) const { +dist_to_polygon(const LPoint2 &p, LPoint2 &edge_p, const CollisionPolygon::Points &points) const { // We know that that the polygon is convex and is defined with the points in // counterclockwise order. Therefore, we simply compare the signed distance @@ -1344,6 +1360,7 @@ dist_to_polygon(const LPoint2 &p, const CollisionPolygon::Points &points) const bool got_dist = false; PN_stdfloat best_dist = -1.0f; + size_t best_i; size_t num_points = points.size(); for (size_t i = 0; i < num_points - 1; ++i) { @@ -1353,6 +1370,7 @@ dist_to_polygon(const LPoint2 &p, const CollisionPolygon::Points &points) const if (!got_dist || d < best_dist) { best_dist = d; got_dist = true; + best_i = i; } } } @@ -1363,6 +1381,24 @@ dist_to_polygon(const LPoint2 &p, const CollisionPolygon::Points &points) const if (!got_dist || d < best_dist) { best_dist = d; got_dist = true; + best_i = num_points - 1; + } + } + + if (got_dist) { + // Project the point onto the best line, so that we can confine it to the + // line segment. + LPoint2 best_p = points[best_i]._p; + LPoint2 next_p = points[(best_i + 1) % points.size()]._p; + LVector2 segment = next_p - best_p; + PN_stdfloat t = (p - best_p).dot(segment) / segment.length_squared(); + if (t <= 0.0f) { + edge_p = best_p; + } else if (t >= 1.0f) { + edge_p = next_p; + } else { + LVector2 v(points[best_i]._v[1], -points[best_i]._v[0]); + edge_p = p - v * best_dist; } } diff --git a/panda/src/collide/collisionPolygon.h b/panda/src/collide/collisionPolygon.h index 9782d6cf01..e657b3d623 100644 --- a/panda/src/collide/collisionPolygon.h +++ b/panda/src/collide/collisionPolygon.h @@ -32,12 +32,12 @@ PUBLISHED: const LVecBase3 &c); INLINE CollisionPolygon(const LVecBase3 &a, const LVecBase3 &b, const LVecBase3 &c, const LVecBase3 &d); - INLINE CollisionPolygon(const LPoint3 *begin, const LPoint3 *end); private: INLINE CollisionPolygon(); public: + INLINE CollisionPolygon(const LPoint3 *begin, const LPoint3 *end); CollisionPolygon(const CollisionPolygon ©); virtual CollisionSolid *make_copy(); @@ -124,7 +124,7 @@ private: const Points &points) const; bool point_is_inside(const LPoint2 &p, const Points &points) const; - PN_stdfloat dist_to_polygon(const LPoint2 &p, const Points &points) const; + PN_stdfloat dist_to_polygon(const LPoint2 &p, LPoint2 &edge_p, const Points &points) const; void project(const LVector3 &axis, PN_stdfloat ¢er, PN_stdfloat &extent) const; void setup_points(const LPoint3 *begin, const LPoint3 *end); diff --git a/panda/src/display/graphicsWindow_ext.cxx b/panda/src/display/graphicsWindow_ext.cxx index ac06b3565a..7dbc05c8b2 100644 --- a/panda/src/display/graphicsWindow_ext.cxx +++ b/panda/src/display/graphicsWindow_ext.cxx @@ -37,11 +37,6 @@ remove_python_event_handler(PyObject* name){ if (PyObject_RichCompareBool(pgwp->get_name(), name, Py_EQ) == 1) { toRemove.push_back(pgwp); } -#if PY_MAJOR_VERSION < 3 - else if (PyObject_Compare(pgwp->get_name(), name) == 0) { - toRemove.push_back(pgwp); - } -#endif } std::list::iterator iter2; for (iter2 = toRemove.begin(); iter2 != toRemove.end(); ++iter2) { diff --git a/panda/src/display/windowProperties_ext.cxx b/panda/src/display/windowProperties_ext.cxx index 5c8a711415..9d04e1a24e 100644 --- a/panda/src/display/windowProperties_ext.cxx +++ b/panda/src/display/windowProperties_ext.cxx @@ -66,11 +66,7 @@ __init__(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *key_repr = PyObject_Repr(key); PyErr_Format(PyExc_TypeError, "%.100s is an invalid keyword argument for WindowProperties()", -#if PY_MAJOR_VERSION >= 3 PyUnicode_AsUTF8(key_repr) -#else - PyString_AsString(key_repr) -#endif ); Py_DECREF(key_repr); return; diff --git a/panda/src/downloader/bioStreamPtr.cxx b/panda/src/downloader/bioStreamPtr.cxx index 6444703b16..d7454da760 100644 --- a/panda/src/downloader/bioStreamPtr.cxx +++ b/panda/src/downloader/bioStreamPtr.cxx @@ -20,10 +20,8 @@ */ BioStreamPtr:: ~BioStreamPtr() { - if (_stream != nullptr) { - delete _stream; - _stream = nullptr; - } + delete _stream; + _stream = nullptr; } #endif // HAVE_OPENSSL diff --git a/panda/src/downloader/multiplexStream.I b/panda/src/downloader/multiplexStream.I index aff3d4a064..e360df6922 100644 --- a/panda/src/downloader/multiplexStream.I +++ b/panda/src/downloader/multiplexStream.I @@ -37,7 +37,7 @@ add_ostream(std::ostream *out, bool delete_later) { INLINE bool MultiplexStream:: add_stdio_file(FILE *fout, bool close_when_done) { _msb.add_output(MultiplexStreamBuf::BT_line, - MultiplexStreamBuf::OT_ostream, + MultiplexStreamBuf::OT_stdio, nullptr, fout, close_when_done); return true; } diff --git a/panda/src/egg/eggTransform.I b/panda/src/egg/eggTransform.I index e6bccb6819..2896fc0d93 100644 --- a/panda/src/egg/eggTransform.I +++ b/panda/src/egg/eggTransform.I @@ -93,18 +93,10 @@ operator = (const EggTransform::Component ©) { */ INLINE EggTransform::Component:: ~Component() { - if (_vec2 != nullptr) { - delete _vec2; - } - if (_vec3 != nullptr) { - delete _vec3; - } - if (_mat3 != nullptr) { - delete _mat3; - } - if (_mat4 != nullptr) { - delete _mat4; - } + delete _vec2; + delete _vec3; + delete _mat3; + delete _mat4; } /** diff --git a/panda/src/event/asyncFuture_ext.cxx b/panda/src/event/asyncFuture_ext.cxx index c4cc4b5302..f47abdf7db 100644 --- a/panda/src/event/asyncFuture_ext.cxx +++ b/panda/src/event/asyncFuture_ext.cxx @@ -117,22 +117,7 @@ static PyObject *get_done_result(const AsyncFuture *future) { } } else { // If the future was cancelled, we should raise an exception. - static PyObject *exc_type = nullptr; - if (exc_type == nullptr) { - // Get the CancelledError that asyncio uses, too. - PyObject *module = PyImport_ImportModule("concurrent.futures._base"); - if (module != nullptr) { - exc_type = PyObject_GetAttrString(module, "CancelledError"); - Py_DECREF(module); - } - // If we can't get that, we should pretend and make our own. - if (exc_type == nullptr) { - exc_type = PyErr_NewExceptionWithDoc((char*)"concurrent.futures._base.CancelledError", - (char*)"The Future was cancelled.", - nullptr, nullptr); - } - } - PyErr_SetNone(exc_type); + PyErr_SetNone(Extension::get_cancelled_error_type()); return nullptr; } } @@ -211,16 +196,26 @@ result(PyObject *timeout) const { static PyObject *exc_type = nullptr; if (exc_type == nullptr) { // Get the TimeoutError that asyncio uses, too. +#if PY_VERSION_HEX >= 0x03080000 + PyObject *module = PyImport_ImportModule("asyncio.exceptions"); +#else PyObject *module = PyImport_ImportModule("concurrent.futures._base"); +#endif if (module != nullptr) { exc_type = PyObject_GetAttrString(module, "TimeoutError"); Py_DECREF(module); } // If we can't get that, we should pretend and make our own. if (exc_type == nullptr) { +#if PY_VERSION_HEX >= 0x03080000 + exc_type = PyErr_NewExceptionWithDoc((char*)"asyncio.exceptions.TimeoutError", + (char*)"The operation exceeded the given deadline.", + nullptr, nullptr); +#else exc_type = PyErr_NewExceptionWithDoc((char*)"concurrent.futures._base.TimeoutError", (char*)"The operation exceeded the given deadline.", nullptr, nullptr); +#endif } } PyErr_SetNone(exc_type); @@ -285,13 +280,11 @@ gather(PyObject *args) { futures.push_back(fut); continue; } -#if PY_VERSION_HEX >= 0x03050000 } else if (PyCoro_CheckExact(item)) { // We allow passing in a coroutine instead of a future. This causes it // to be scheduled as a task. futures.push_back(new PythonTask(item)); continue; -#endif } return Dtool_Raise_ArgTypeError(item, i, "gather", "coroutine, task or future"); } @@ -305,4 +298,37 @@ gather(PyObject *args) { } } +/** + * Returns a borrowed reference to the CancelledError exception type. + */ +PyObject *Extension:: +get_cancelled_error_type() { + static PyObject *exc_type = nullptr; + if (exc_type == nullptr) { + // Get the CancelledError that asyncio uses, too. +#if PY_VERSION_HEX >= 0x03080000 + PyObject *module = PyImport_ImportModule("asyncio.exceptions"); +#else + PyObject *module = PyImport_ImportModule("concurrent.futures._base"); +#endif + if (module != nullptr) { + exc_type = PyObject_GetAttrString(module, "CancelledError"); + Py_DECREF(module); + } + // If we can't get that, we should pretend and make our own. + if (exc_type == nullptr) { +#if PY_VERSION_HEX >= 0x03080000 + exc_type = PyErr_NewExceptionWithDoc((char *)"asyncio.exceptions.CancelledError", + (char *)"The Future or Task was cancelled.", + PyExc_BaseException, nullptr); +#else + exc_type = PyErr_NewExceptionWithDoc((char *)"concurrent.futures._base.CancelledError", + (char *)"The Future was cancelled.", + nullptr, nullptr); +#endif + } + } + return exc_type; +} + #endif diff --git a/panda/src/event/asyncFuture_ext.h b/panda/src/event/asyncFuture_ext.h index 94f0b3d60b..eb8c688710 100644 --- a/panda/src/event/asyncFuture_ext.h +++ b/panda/src/event/asyncFuture_ext.h @@ -34,6 +34,8 @@ public: PyObject *add_done_callback(PyObject *self, PyObject *fn); static PyObject *gather(PyObject *args); + + static PyObject *get_cancelled_error_type(); }; #endif // HAVE_PYTHON diff --git a/panda/src/event/asyncTask.cxx b/panda/src/event/asyncTask.cxx index e00b4f46e3..f1d9141e95 100644 --- a/panda/src/event/asyncTask.cxx +++ b/panda/src/event/asyncTask.cxx @@ -68,6 +68,9 @@ AsyncTask:: * Removes the task from its active manager, if any, and makes the state * S_inactive (or possible S_servicing_removed). This is a no-op if the state * is already S_inactive. + * + * If the task is a coroutine that is currently awaiting a future, this will + * fail, but see also cancel(). */ bool AsyncTask:: remove() { @@ -457,7 +460,8 @@ unlock_and_do_task() { } /** - * Cancels this task. This is equivalent to remove(). + * Cancels this task. This is equivalent to remove(), except for coroutines, + * for which it will throw an exception into any currently pending await. */ bool AsyncTask:: cancel() { diff --git a/panda/src/event/asyncTask.h b/panda/src/event/asyncTask.h index 5a7a2cd805..82e6a4ed34 100644 --- a/panda/src/event/asyncTask.h +++ b/panda/src/event/asyncTask.h @@ -124,7 +124,7 @@ protected: void jump_to_task_chain(AsyncTaskManager *manager); DoneStatus unlock_and_do_task(); - virtual bool cancel() final; + virtual bool cancel(); virtual bool is_task() const final {return true;} virtual bool is_runnable(); diff --git a/panda/src/event/asyncTaskChain.h b/panda/src/event/asyncTaskChain.h index 6de098b6ed..3f288c9770 100644 --- a/panda/src/event/asyncTaskChain.h +++ b/panda/src/event/asyncTaskChain.h @@ -218,6 +218,7 @@ private: friend class AsyncTask; friend class AsyncTaskManager; friend class AsyncTaskSortWakeTime; + friend class PythonTask; }; INLINE std::ostream &operator << (std::ostream &out, const AsyncTaskChain &chain) { diff --git a/panda/src/event/pythonTask.cxx b/panda/src/event/pythonTask.cxx index 86c05b33d7..8430d3d59d 100644 --- a/panda/src/event/pythonTask.cxx +++ b/panda/src/event/pythonTask.cxx @@ -20,6 +20,7 @@ #include "pythonThread.h" #include "asyncTaskManager.h" +#include "asyncFuture_ext.h" TypeHandle PythonTask::_type_handle; @@ -52,12 +53,10 @@ PythonTask(PyObject *func_or_coro, const std::string &name) : if (func_or_coro == Py_None || PyCallable_Check(func_or_coro)) { _function = func_or_coro; Py_INCREF(_function); -#if PY_VERSION_HEX >= 0x03050000 } else if (PyCoro_CheckExact(func_or_coro)) { // We also allow passing in a coroutine, because why not. _generator = func_or_coro; Py_INCREF(_generator); -#endif } else if (PyGen_CheckExact(func_or_coro)) { // Something emulating a coroutine. _generator = func_or_coro; @@ -283,11 +282,7 @@ exception() const { */ int PythonTask:: __setattr__(PyObject *self, PyObject *attr, PyObject *v) { -#if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(attr)) { -#else - if (!PyString_Check(attr)) { -#endif PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", attr->ob_type->tp_name); @@ -307,13 +302,8 @@ __setattr__(PyObject *self, PyObject *attr, PyObject *v) { PyObject *str = PyObject_Repr(v); task_cat.debug() << *this << ": task." -#if PY_MAJOR_VERSION >= 3 << PyUnicode_AsUTF8(attr) << " = " << PyUnicode_AsUTF8(str) << "\n"; -#else - << PyString_AsString(attr) << " = " - << PyString_AsString(str) << "\n"; -#endif Py_DECREF(str); } @@ -340,15 +330,9 @@ __delattr__(PyObject *self, PyObject *attr) { if (PyDict_DelItem(__dict__, attr) == -1) { // PyDict_DelItem does not raise an exception. -#if PY_MAJOR_VERSION < 3 - PyErr_Format(PyExc_AttributeError, - "'PythonTask' object has no attribute '%.400s'", - PyString_AS_STRING(attr)); -#else PyErr_Format(PyExc_AttributeError, "'PythonTask' object has no attribute '%U'", attr); -#endif return -1; } @@ -408,6 +392,51 @@ __clear__() { return 0; } +/** + * Cancels this task. This is equivalent to remove(), except for coroutines, + * for which it will throw an exception into any currently pending await. + */ +bool PythonTask:: +cancel() { + AsyncTaskManager *manager = _manager; + if (manager != nullptr) { + nassertr(_chain->_manager == manager, false); + if (task_cat.is_debug()) { + task_cat.debug() + << "Cancelling " << *this << "\n"; + } + + MutexHolder holder(manager->_lock); + if (_state == S_awaiting) { + // Reactivate it so that it can receive a CancelledException. + _must_cancel = true; + _state = AsyncTask::S_active; + _chain->_active.push_back(this); + --_chain->_num_awaiting_tasks; + return true; + } + else if (_future_done != nullptr) { + // We are polling, waiting for a non-Panda future to be done. + Py_DECREF(_future_done); + _future_done = nullptr; + _must_cancel = true; + return true; + } + else if (_chain->do_remove(this, true)) { + return true; + } + else { + if (task_cat.is_debug()) { + task_cat.debug() + << " (unable to cancel " << *this << ")\n"; + } + return false; + } + } + + return false; +} + /** * Override this function to return true if the task can be successfully * executed, false if it cannot. Mainly intended as a sanity check when @@ -475,23 +504,15 @@ do_python_task() { // The function has yielded a generator. We will call into that // henceforth, instead of calling the function from the top again. if (task_cat.is_debug()) { -#if PY_MAJOR_VERSION >= 3 PyObject *str = PyObject_ASCII(_function); task_cat.debug() << PyUnicode_AsUTF8(str) << " in " << *this << " yielded a generator.\n"; -#else - PyObject *str = PyObject_Repr(_function); - task_cat.debug() - << PyString_AsString(str) << " in " << *this - << " yielded a generator.\n"; -#endif Py_DECREF(str); } _generator = result; result = nullptr; -#if PY_VERSION_HEX >= 0x03050000 } else if (result != nullptr && Py_TYPE(result)->tp_as_async != nullptr) { // The function yielded a coroutine, or something of the sort. if (task_cat.is_debug()) { @@ -513,17 +534,26 @@ do_python_task() { Py_DECREF(result); } result = nullptr; -#endif } } if (_generator != nullptr) { - // We are calling a generator. Use "send" rather than PyIter_Next since - // we need to be able to read the value from a StopIteration exception. - PyObject *func = PyObject_GetAttrString(_generator, "send"); - nassertr(func != nullptr, DS_interrupt); - result = PyObject_CallFunctionObjArgs(func, Py_None, nullptr); - Py_DECREF(func); + if (!_must_cancel) { + // We are calling a generator. Use "send" rather than PyIter_Next since + // we need to be able to read the value from a StopIteration exception. + PyObject *func = PyObject_GetAttrString(_generator, "send"); + nassertr(func != nullptr, DS_interrupt); + result = PyObject_CallFunctionObjArgs(func, Py_None, nullptr); + Py_DECREF(func); + } else { + // Throw a CancelledError into the generator. + _must_cancel = false; + PyObject *exc = _PyObject_CallNoArg(Extension::get_cancelled_error_type()); + PyObject *func = PyObject_GetAttrString(_generator, "throw"); + result = PyObject_CallFunctionObjArgs(func, exc, nullptr); + Py_DECREF(func); + Py_DECREF(exc); + } if (result == nullptr) { // An error happened. If StopIteration, that indicates the task has @@ -532,15 +562,15 @@ do_python_task() { Py_DECREF(_generator); _generator = nullptr; -#if PY_VERSION_HEX >= 0x03030000 if (_PyGen_FetchStopIterationValue(&result) == 0) { -#else - if (PyErr_ExceptionMatches(PyExc_StopIteration)) { - result = Py_None; - Py_INCREF(result); -#endif PyErr_Clear(); + if (_must_cancel) { + // Task was cancelled right before finishing. Make sure it is not + // getting rerun or marked as successfully completed. + _state = S_servicing_removed; + } + // If we passed a coroutine into the task, eg. something like: // taskMgr.add(my_async_function()) // then we cannot rerun the task, so the return value is always @@ -556,6 +586,18 @@ do_python_task() { _exc_value = result; return DS_done; } + + } else if (PyErr_ExceptionMatches(Extension::get_cancelled_error_type())) { + // Someone cancelled the coroutine, and it did not bother to handle it, + // so we should consider it cancelled. + if (task_cat.is_debug()) { + task_cat.debug() + << *this << " was cancelled and did not catch CancelledError.\n"; + } + _state = S_servicing_removed; + PyErr_Clear(); + return DS_done; + } else if (_function == nullptr) { // We got an exception. If this is a scheduled coroutine, we will // keep it and instead throw it into whatever 'awaits' this task. @@ -635,14 +677,12 @@ do_python_task() { << "future.done is not callable\n"; return DS_interrupt; } -#if PY_MAJOR_VERSION >= 3 if (task_cat.is_debug()) { PyObject *str = PyObject_ASCII(result); task_cat.debug() << *this << " is now polling " << PyUnicode_AsUTF8(str) << ".done()\n"; Py_DECREF(str); } -#endif Py_DECREF(result); return DS_cont; } @@ -671,13 +711,8 @@ do_python_task() { return DS_done; } -#if PY_MAJOR_VERSION >= 3 if (PyLong_Check(result)) { long retval = PyLong_AS_LONG(result); -#else - if (PyInt_Check(result)) { - long retval = PyInt_AS_LONG(result); -#endif switch (retval) { case DS_again: @@ -710,11 +745,7 @@ do_python_task() { PyMethodDef *meth = nullptr; if (PyCFunction_Check(result)) { meth = ((PyCFunctionObject *)result)->m_ml; -#if PY_MAJOR_VERSION >= 3 } else if (Py_TYPE(result) == &PyMethodDescr_Type) { -#else - } else if (strcmp(Py_TYPE(result)->tp_name, "method_descriptor") == 0) { -#endif meth = ((PyMethodDescrObject *)result)->d_method; } @@ -724,21 +755,12 @@ do_python_task() { } std::ostringstream strm; -#if PY_MAJOR_VERSION >= 3 PyObject *str = PyObject_ASCII(result); if (str == nullptr) { str = PyUnicode_FromString(""); } strm << *this << " returned " << PyUnicode_AsUTF8(str); -#else - PyObject *str = PyObject_Repr(result); - if (str == nullptr) { - str = PyString_FromString(""); - } - strm - << *this << " returned " << PyString_AsString(str); -#endif Py_DECREF(str); Py_DECREF(result); std::string message = strm.str(); @@ -776,6 +798,12 @@ void PythonTask:: upon_death(AsyncTaskManager *manager, bool clean_exit) { AsyncTask::upon_death(manager, clean_exit); + // If we were polling something when we were removed, get rid of it. + if (_future_done != nullptr) { + Py_DECREF(_future_done); + _future_done = nullptr; + } + if (_upon_death != Py_None) { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) // Use PyGILState to protect this asynchronous call. diff --git a/panda/src/event/pythonTask.h b/panda/src/event/pythonTask.h index 0861827f94..7af6598ab1 100644 --- a/panda/src/event/pythonTask.h +++ b/panda/src/event/pythonTask.h @@ -90,6 +90,8 @@ PUBLISHED: PyObject *__dict__; protected: + virtual bool cancel(); + virtual bool is_runnable(); virtual DoneStatus do_task(); DoneStatus do_python_task(); @@ -119,6 +121,7 @@ private: bool _ignore_return; bool _registered_to_owner; mutable bool _retrieved_exception; + bool _must_cancel = false; friend class Extension; diff --git a/panda/src/express/datagram_ext.I b/panda/src/express/datagram_ext.I index 9c997e64f6..284d9b2bf3 100644 --- a/panda/src/express/datagram_ext.I +++ b/panda/src/express/datagram_ext.I @@ -18,12 +18,7 @@ INLINE PyObject *Extension:: get_message() const { const char *data = (const char *)_this->get_data(); size_t size = _this->get_length(); - -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)data, size); -#else - return PyString_FromStringAndSize((char *)data, size); -#endif } /** diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index f7055d2467..8179a76fa5 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -337,7 +337,7 @@ close() { if (!_read->unref()) { delete _read; } - } else if (_write != nullptr) { + } else { delete _write; } } diff --git a/panda/src/express/pointerToArray_ext.I b/panda/src/express/pointerToArray_ext.I index 5bcd1b77e9..9d259df11b 100644 --- a/panda/src/express/pointerToArray_ext.I +++ b/panda/src/express/pointerToArray_ext.I @@ -80,11 +80,7 @@ INLINE void set_matrix_view(Py_buffer &view, int flags, int length, int size, bo template INLINE void Extension >:: __init__(PyObject *self, PyObject *source) { -#if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(source)) { -#else - if (PyString_CheckExact(source)) { -#endif // It's a byte sequence, or any object that exports the buffer protocol. this->set_data(source); return; @@ -158,11 +154,7 @@ __setitem__(size_t n, const Element &value) { template INLINE PyObject *Extension >:: get_data() const { -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size()); -#else - return PyString_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size()); -#endif } /** @@ -175,7 +167,6 @@ get_data() const { template INLINE void Extension >:: set_data(PyObject *data) { -#if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(data)) { // User passed a buffer object. Py_buffer view; @@ -208,33 +199,6 @@ set_data(PyObject *data) { PyBuffer_Release(&view); return; } -#endif - - // In Python 2, there was also an older buffer protocol, supported by eg. - // str and array objects. -#if PY_MAJOR_VERSION < 3 - // The old, deprecated buffer interface, as used by eg. the array module. - const void *buffer; - Py_ssize_t buffer_len; - if (!PyUnicode_CheckExact(data) && - PyObject_AsReadBuffer(data, &buffer, &buffer_len) == 0) { - if (buffer_len % sizeof(Element) != 0) { - PyErr_Format(PyExc_ValueError, - "byte buffer is not a multiple of %zu bytes", - sizeof(Element)); - return; - } - - if (buffer_len > 0) { - this->_this->resize(buffer_len / sizeof(Element)); - memcpy(this->_this->p(), buffer, buffer_len); - } else { - this->_this->clear(); - } - - return; - } -#endif Dtool_Raise_TypeError("PointerToArray.set_data() requires a buffer object"); } @@ -252,11 +216,7 @@ get_subdata(size_t n, size_t count) const { n = std::min(n, this->_this->size()); count = std::max(count, n); count = std::min(count, this->_this->size() - n); -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count); -#else - return PyString_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count); -#endif } /** @@ -277,11 +237,7 @@ __getitem__(size_t n) const { template INLINE PyObject *Extension >:: get_data() const { -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size()); -#else - return PyString_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size()); -#endif } /** @@ -297,11 +253,7 @@ get_subdata(size_t n, size_t count) const { n = std::min(n, this->_this->size()); count = std::max(count, n); count = std::min(count, this->_this->size() - n); -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count); -#else - return PyString_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count); -#endif } /** @@ -311,7 +263,6 @@ get_subdata(size_t n, size_t count) const { template INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) { -#if PY_VERSION_HEX >= 0x02060000 const char *format = get_format_code(Element); if (format == nullptr) { // Not supported. @@ -350,9 +301,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -362,7 +310,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) { -#if PY_VERSION_HEX >= 0x02060000 if (self != nullptr) { Py_INCREF(self); } @@ -376,9 +323,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -388,7 +332,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) { -#if PY_VERSION_HEX >= 0x02060000 if (self != nullptr) { Py_INCREF(self); } @@ -402,9 +345,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -414,7 +354,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) { -#if PY_VERSION_HEX >= 0x02060000 if (self != nullptr) { Py_INCREF(self); } @@ -428,9 +367,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -440,7 +376,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) { -#if PY_VERSION_HEX >= 0x02060000 if (self != nullptr) { Py_INCREF(self); } @@ -454,9 +389,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -465,14 +397,12 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { template INLINE void Extension >:: __releasebuffer__(PyObject *self, Py_buffer *view) const { -#if PY_VERSION_HEX >= 0x02060000 // Note: PyBuffer_Release automatically decrements view->obj. if (view->internal != nullptr) { // Oh, right, let's not forget to unref this. unref_delete((const PointerToArray *)view->internal); view->internal = nullptr; } -#endif } /** @@ -482,7 +412,6 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const { template INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { -#if PY_VERSION_HEX >= 0x02060000 if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable."); @@ -527,9 +456,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -538,7 +464,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { -#if PY_VERSION_HEX >= 0x02060000 if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable."); @@ -557,9 +482,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -568,7 +490,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { -#if PY_VERSION_HEX >= 0x02060000 if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable."); @@ -587,9 +508,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -598,7 +516,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { -#if PY_VERSION_HEX >= 0x02060000 if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable."); @@ -617,9 +534,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -628,7 +542,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { template<> INLINE int Extension >:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { -#if PY_VERSION_HEX >= 0x02060000 if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable."); @@ -647,9 +560,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { view->internal = (void*) this->_this; return 0; -#else - return -1; -#endif } /** @@ -658,12 +568,10 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { template INLINE void Extension >:: __releasebuffer__(PyObject *self, Py_buffer *view) const { -#if PY_VERSION_HEX >= 0x02060000 // Note: PyBuffer_Release automatically decrements obj->view. if (view->internal != nullptr) { // Oh, right, let's not forget to unref this. unref_delete((const PointerToArray *)view->internal); view->internal = nullptr; } -#endif } diff --git a/panda/src/express/ramfile_ext.cxx b/panda/src/express/ramfile_ext.cxx index fc1047487c..0652692f75 100644 --- a/panda/src/express/ramfile_ext.cxx +++ b/panda/src/express/ramfile_ext.cxx @@ -26,11 +26,7 @@ read(size_t length) { length = std::min(length, data_length - _this->_pos); _this->_pos = std::min(_this->_pos + length, data_length); -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)data, length); -#else - return PyString_FromStringAndSize((char *)data, length); -#endif } /** @@ -44,11 +40,7 @@ read(size_t length) { PyObject *Extension:: readline() { std::string line = _this->readline(); -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize(line.data(), line.size()); -#else - return PyString_FromStringAndSize(line.data(), line.size()); -#endif } /** @@ -64,11 +56,7 @@ readlines() { std::string line = _this->readline(); while (!line.empty()) { -#if PY_MAJOR_VERSION >= 3 PyObject *py_line = PyBytes_FromStringAndSize(line.data(), line.size()); -#else - PyObject *py_line = PyString_FromStringAndSize(line.data(), line.size()); -#endif PyList_Append(lst, py_line); Py_DECREF(py_line); @@ -83,11 +71,7 @@ readlines() { */ PyObject *Extension:: get_data() const { -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize(_this->_data.data(), _this->_data.size()); -#else - return PyString_FromStringAndSize(_this->_data.data(), _this->_data.size()); -#endif } #endif diff --git a/panda/src/express/stringStream_ext.cxx b/panda/src/express/stringStream_ext.cxx index 631c6f4a04..e8a6549f44 100644 --- a/panda/src/express/stringStream_ext.cxx +++ b/panda/src/express/stringStream_ext.cxx @@ -31,17 +31,9 @@ get_data() { _this->flush(); const vector_uchar &data = _this->_buf.get_data(); if (!data.empty()) { -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize((char *)&data[0], data.size()); -#else - return PyString_FromStringAndSize((char *)&data[0], data.size()); -#endif } -#if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize("", 0); -#else - return PyString_FromStringAndSize("", 0); -#endif } /** @@ -55,7 +47,6 @@ set_data(PyObject *data) { return; } -#if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(data)) { Py_buffer view; if (PyObject_GetBuffer(data, &view, PyBUF_CONTIG_RO) == -1) { @@ -67,18 +58,6 @@ set_data(PyObject *data) { PyBuffer_Release(&view); return; } -#endif - -#if PY_MAJOR_VERSION < 3 - if (PyString_Check(data)) { - char *buffer; - Py_ssize_t length; - if (PyString_AsStringAndSize(data, &buffer, &length) != -1) { - _this->set_data((const unsigned char *)buffer, (size_t)length); - } - return; - } -#endif PyErr_SetString(PyExc_TypeError, "StringStream requires a bytes or buffer object"); diff --git a/panda/src/express/virtualFileSystem_ext.cxx b/panda/src/express/virtualFileSystem_ext.cxx index 6018378f90..d8062a69b5 100644 --- a/panda/src/express/virtualFileSystem_ext.cxx +++ b/panda/src/express/virtualFileSystem_ext.cxx @@ -43,19 +43,11 @@ read_file(const Filename &filename, bool auto_unwrap) const { return PyErr_Format(PyExc_IOError, "Failed to read file: '%s'", filename.c_str()); } -#if PY_MAJOR_VERSION >= 3 if (pv.empty()) { return PyBytes_FromStringAndSize("", 0); } else { return PyBytes_FromStringAndSize((const char *)&pv[0], pv.size()); } -#else - if (pv.empty()) { - return PyString_FromStringAndSize("", 0); - } else { - return PyString_FromStringAndSize((const char *)&pv[0], pv.size()); - } -#endif } /** @@ -71,15 +63,9 @@ write_file(const Filename &filename, PyObject *data, bool auto_wrap) { char *buffer; Py_ssize_t length; -#if PY_MAJOR_VERSION >= 3 if (PyBytes_AsStringAndSize(data, &buffer, &length) == -1) { return nullptr; } -#else - if (PyString_AsStringAndSize(data, &buffer, &length) == -1) { - return nullptr; - } -#endif bool result = _this->write_file(filename, (const unsigned char *)buffer, length, auto_wrap); return PyBool_FromLong(result); diff --git a/panda/src/express/virtualFile_ext.cxx b/panda/src/express/virtualFile_ext.cxx index afe7473bbd..8419a4ab75 100644 --- a/panda/src/express/virtualFile_ext.cxx +++ b/panda/src/express/virtualFile_ext.cxx @@ -44,19 +44,11 @@ read_file(bool auto_unwrap) const { return PyErr_Format(PyExc_IOError, "Failed to read file: '%s'", fn.c_str()); } -#if PY_MAJOR_VERSION >= 3 if (pv.empty()) { return PyBytes_FromStringAndSize("", 0); } else { return PyBytes_FromStringAndSize((const char *)&pv[0], pv.size()); } -#else - if (pv.empty()) { - return PyString_FromStringAndSize("", 0); - } else { - return PyString_FromStringAndSize((const char *)&pv[0], pv.size()); - } -#endif } /** @@ -72,15 +64,9 @@ write_file(PyObject *data, bool auto_wrap) { char *buffer; Py_ssize_t length; -#if PY_MAJOR_VERSION >= 3 if (PyBytes_AsStringAndSize(data, &buffer, &length) == -1) { return nullptr; } -#else - if (PyString_AsStringAndSize(data, &buffer, &length) == -1) { - return nullptr; - } -#endif // Release the GIL while we do this potentially slow operation. #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) diff --git a/panda/src/gobj/geomVertexArrayData_ext.cxx b/panda/src/gobj/geomVertexArrayData_ext.cxx index 73c795f0b5..bc135cd184 100644 --- a/panda/src/gobj/geomVertexArrayData_ext.cxx +++ b/panda/src/gobj/geomVertexArrayData_ext.cxx @@ -28,7 +28,6 @@ struct InternalBufferData { */ int Extension:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) { -#if PY_VERSION_HEX >= 0x02060000 PT(GeomVertexArrayDataHandle) handle = _this->modify_handle(); CPT(GeomVertexArrayFormat) format = handle->get_array_format(); @@ -78,9 +77,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { view->suboffsets = nullptr; return 0; -#else - return -1; -#endif } /** @@ -88,7 +84,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) { */ int Extension:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { -#if PY_VERSION_HEX >= 0x02060000 if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable."); @@ -144,9 +139,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { view->suboffsets = nullptr; return 0; -#else - return -1; -#endif } /** @@ -154,7 +146,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { */ void Extension:: __releasebuffer__(PyObject *self, Py_buffer *view) const { -#if PY_VERSION_HEX >= 0x02060000 // Note: PyBuffer_Release automatically decrements view->obj. InternalBufferData *data; data = (InternalBufferData *) view->internal; @@ -163,7 +154,6 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const { } delete data; view->internal = nullptr; -#endif } /** @@ -172,11 +162,6 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const { */ void Extension:: copy_data_from(PyObject *buffer) { - -#if PY_VERSION_HEX < 0x02060000 - PyErr_SetString(PyExc_TypeError, "buffer interface not supported before Python 2.6"); - -#else if (!PyObject_CheckBuffer(buffer)) { PyErr_SetString(PyExc_TypeError, "buffer object expected"); return; @@ -191,7 +176,6 @@ copy_data_from(PyObject *buffer) { _this->copy_data_from((const unsigned char *) view.buf, view.len); PyBuffer_Release(&view); -#endif } /** @@ -201,11 +185,6 @@ copy_data_from(PyObject *buffer) { */ void Extension:: copy_subdata_from(size_t to_start, size_t to_size, PyObject *buffer) { - -#if PY_VERSION_HEX < 0x02060000 - PyErr_SetString(PyExc_TypeError, "buffer interface not supported before Python 2.6"); - -#else if (!PyObject_CheckBuffer(buffer)) { PyErr_SetString(PyExc_TypeError, "buffer object expected"); return; @@ -222,7 +201,6 @@ copy_subdata_from(size_t to_start, size_t to_size, PyObject *buffer) { 0, (size_t) view.len); PyBuffer_Release(&view); -#endif } /** @@ -234,11 +212,6 @@ void Extension:: copy_subdata_from(size_t to_start, size_t to_size, PyObject *buffer, size_t from_start, size_t from_size) { - -#if PY_VERSION_HEX < 0x02060000 - PyErr_SetString(PyExc_TypeError, "buffer interface not supported before Python 2.6"); - -#else if (!PyObject_CheckBuffer(buffer)) { PyErr_SetString(PyExc_TypeError, "buffer object expected"); return; @@ -259,7 +232,6 @@ copy_subdata_from(size_t to_start, size_t to_size, from_start, from_size); PyBuffer_Release(&view); -#endif } #endif // HAVE_PYTHON diff --git a/panda/src/gobj/geomVertexColumn.cxx b/panda/src/gobj/geomVertexColumn.cxx index 9e6c7bd188..f6554fc8c1 100644 --- a/panda/src/gobj/geomVertexColumn.cxx +++ b/panda/src/gobj/geomVertexColumn.cxx @@ -228,10 +228,7 @@ setup() { } _total_bytes = _element_stride * _num_elements; - if (_packer != nullptr) { - delete _packer; - } - + delete _packer; _packer = make_packer(); _packer->_column = this; } diff --git a/panda/src/gobj/internalName_ext.cxx b/panda/src/gobj/internalName_ext.cxx index 1a28f8b4a1..c7a145f23c 100644 --- a/panda/src/gobj/internalName_ext.cxx +++ b/panda/src/gobj/internalName_ext.cxx @@ -24,7 +24,6 @@ extern struct Dtool_PyTypedObject Dtool_InternalName; * to InternalName objects more efficiently by storing a mapping between * Python and Panda interned strings. */ -#if PY_MAJOR_VERSION >= 3 PT(InternalName) Extension:: make(PyObject *str) { if (!PyUnicode_Check(str)) { @@ -55,31 +54,6 @@ make(PyObject *str) { const char *c_str = PyUnicode_AsUTF8AndSize((PyObject *)str, &len); string name(c_str, len); -#else -PT(InternalName) Extension:: -make(PyObject *str) { - if (!PyString_Check(str)) { - Dtool_Raise_ArgTypeError(str, 0, "InternalName.make", "str"); - return nullptr; - } - - if (!PyString_CHECK_INTERNED(str)) { - // Not an interned string; don't bother. - string name(PyString_AS_STRING(str), PyString_GET_SIZE(str)); - return InternalName::make(name); - } - - InternalName::PyInternTable::const_iterator it; - it = InternalName::_py_intern_table.find((PyObject*)str); - - if (it != InternalName::_py_intern_table.end()) { - return (*it).second; - - } else { - string name(PyString_AS_STRING(str), PyString_GET_SIZE(str)); - -#endif // PY_MAJOR_VERSION - PT(InternalName) iname = InternalName::make(name); // We basically leak references to both the PyObject and the InternalName. diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index a1067e9c9e..909b878adf 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -2525,6 +2525,7 @@ read(const ShaderFile &sfile, BamCacheRecord *record) { #else shader_cat.error() << "Tried to load Cg shader, but no Cg support is enabled.\n"; + return false; #endif } else { shader_cat.error() @@ -2618,6 +2619,7 @@ load(const ShaderFile &sbody, BamCacheRecord *record) { #else shader_cat.error() << "Tried to load Cg shader, but no Cg support is enabled.\n"; + return false; #endif } else { shader_cat.error() diff --git a/panda/src/gobj/texture_ext.cxx b/panda/src/gobj/texture_ext.cxx index 9af792be08..74f83a433b 100644 --- a/panda/src/gobj/texture_ext.cxx +++ b/panda/src/gobj/texture_ext.cxx @@ -43,7 +43,6 @@ set_ram_image(PyObject *image, Texture::CompressionMode compression, } } -#if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(image)) { // User passed a buffer object. Py_buffer view; @@ -82,30 +81,6 @@ set_ram_image(PyObject *image, Texture::CompressionMode compression, PyBuffer_Release(&view); return; } -#endif - -#if PY_MAJOR_VERSION < 3 - // The old, deprecated buffer interface, as used by eg. the array module. - const void *buffer; - Py_ssize_t buffer_len; - if (!PyUnicode_CheckExact(image) && - PyObject_AsReadBuffer(image, &buffer, &buffer_len) == 0) { - if (compression == Texture::CM_off) { - int component_width = _this->get_component_width(); - if (buffer_len % component_width != 0) { - PyErr_Format(PyExc_ValueError, - "byte buffer is not a multiple of %d bytes", - component_width); - return; - } - } - - PTA_uchar data = PTA_uchar::empty_array(buffer_len, Texture::get_class_type()); - memcpy(data.p(), buffer, buffer_len); - _this->set_ram_image(std::move(data), compression, page_size); - return; - } -#endif Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image", "CPTA_uchar or buffer"); } @@ -129,7 +104,6 @@ set_ram_image_as(PyObject *image, const std::string &provided_format) { } } -#if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(image)) { // User passed a buffer object. Py_buffer view; @@ -160,7 +134,6 @@ set_ram_image_as(PyObject *image, const std::string &provided_format) { PyBuffer_Release(&view); return; } -#endif Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image_as", "CPTA_uchar or buffer"); } diff --git a/panda/src/grutil/meshDrawer.I b/panda/src/grutil/meshDrawer.I index 030f646cb9..28a351bb2a 100644 --- a/panda/src/grutil/meshDrawer.I +++ b/panda/src/grutil/meshDrawer.I @@ -35,10 +35,10 @@ MeshDrawer() { INLINE MeshDrawer:: ~MeshDrawer() { _root.remove_node(); - if (_vertex != nullptr) delete _vertex; - if (_normal != nullptr) delete _normal; - if (_uv != nullptr) delete _uv; - if (_color != nullptr) delete _color; + delete _vertex; + delete _normal; + delete _uv; + delete _color; } /** diff --git a/panda/src/grutil/meshDrawer.cxx b/panda/src/grutil/meshDrawer.cxx index b87380d3b8..24ff840187 100644 --- a/panda/src/grutil/meshDrawer.cxx +++ b/panda/src/grutil/meshDrawer.cxx @@ -104,10 +104,10 @@ void MeshDrawer::begin(NodePath camera, NodePath render) { _b4 = - _right + _up; // recreate our rewriters - if (_vertex != nullptr) delete _vertex; - if (_normal != nullptr) delete _normal; - if (_uv != nullptr) delete _uv; - if (_color != nullptr) delete _color; + delete _vertex; + delete _normal; + delete _uv; + delete _color; if (_vdata == nullptr) { generator(_budget); diff --git a/panda/src/grutil/meshDrawer2D.I b/panda/src/grutil/meshDrawer2D.I index 4ff460c567..4a17a739f1 100644 --- a/panda/src/grutil/meshDrawer2D.I +++ b/panda/src/grutil/meshDrawer2D.I @@ -37,9 +37,9 @@ MeshDrawer2D() { INLINE MeshDrawer2D:: ~MeshDrawer2D() { _root.remove_node(); - if (_vertex != nullptr) delete _vertex; - if (_uv != nullptr) delete _uv; - if (_color != nullptr) delete _color; + delete _vertex; + delete _uv; + delete _color; } /** diff --git a/panda/src/grutil/meshDrawer2D.cxx b/panda/src/grutil/meshDrawer2D.cxx index a34f4b7d34..235b5478ea 100644 --- a/panda/src/grutil/meshDrawer2D.cxx +++ b/panda/src/grutil/meshDrawer2D.cxx @@ -88,9 +88,9 @@ void MeshDrawer2D::generator(int budget) { void MeshDrawer2D::begin() { // recreate our rewriters - if (_vertex != nullptr) delete _vertex; - if (_uv != nullptr) delete _uv; - if (_color != nullptr) delete _color; + delete _vertex; + delete _uv; + delete _color; _vertex = new GeomVertexRewriter(_vdata, "vertex"); _uv = new GeomVertexRewriter(_vdata, "texcoord"); diff --git a/panda/src/linmath/lvecBase2_ext_src.I b/panda/src/linmath/lvecBase2_ext_src.I index 886ade8d18..3f47003e9a 100644 --- a/panda/src/linmath/lvecBase2_ext_src.I +++ b/panda/src/linmath/lvecBase2_ext_src.I @@ -12,14 +12,9 @@ */ #ifdef FLOATTYPE_IS_INT -#if PY_MAJOR_VERSION >= 3 #define PYNUMBER_FLOATTYPE PyNumber_Long #define PY_AS_FLOATTYPE PyLong_AS_LONG #else -#define PYNUMBER_FLOATTYPE PyNumber_Int -#define PY_AS_FLOATTYPE PyInt_AS_LONG -#endif -#else #define PYNUMBER_FLOATTYPE PyNumber_Float #define PY_AS_FLOATTYPE (FLOATTYPE)PyFloat_AsDouble #endif diff --git a/panda/src/linmath/lvecBase3_ext_src.I b/panda/src/linmath/lvecBase3_ext_src.I index 0715f84235..b29d01fbc5 100644 --- a/panda/src/linmath/lvecBase3_ext_src.I +++ b/panda/src/linmath/lvecBase3_ext_src.I @@ -12,14 +12,9 @@ */ #ifdef FLOATTYPE_IS_INT -#if PY_MAJOR_VERSION >= 3 #define PYNUMBER_FLOATTYPE PyNumber_Long #define PY_AS_FLOATTYPE PyLong_AS_LONG #else -#define PYNUMBER_FLOATTYPE PyNumber_Int -#define PY_AS_FLOATTYPE PyInt_AS_LONG -#endif -#else #define PYNUMBER_FLOATTYPE PyNumber_Float #define PY_AS_FLOATTYPE (FLOATTYPE)PyFloat_AsDouble #endif diff --git a/panda/src/linmath/lvecBase4_ext_src.I b/panda/src/linmath/lvecBase4_ext_src.I index 0866e184ac..66d1bd6e0c 100644 --- a/panda/src/linmath/lvecBase4_ext_src.I +++ b/panda/src/linmath/lvecBase4_ext_src.I @@ -12,14 +12,9 @@ */ #ifdef FLOATTYPE_IS_INT -#if PY_MAJOR_VERSION >= 3 #define PYNUMBER_FLOATTYPE PyNumber_Long #define PY_AS_FLOATTYPE PyLong_AS_LONG #else -#define PYNUMBER_FLOATTYPE PyNumber_Int -#define PY_AS_FLOATTYPE PyInt_AS_LONG -#endif -#else #define PYNUMBER_FLOATTYPE PyNumber_Float #define PY_AS_FLOATTYPE (FLOATTYPE)PyFloat_AsDouble #endif diff --git a/panda/src/nativenet/time_accumulator.h b/panda/src/nativenet/time_accumulator.h index 3b7959a018..11fabd3538 100644 --- a/panda/src/nativenet/time_accumulator.h +++ b/panda/src/nativenet/time_accumulator.h @@ -1,96 +1,110 @@ -#ifndef __TIME_ACCUMULATOR_H__ -#define __TIME_ACCUMULATOR_H__ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file time_accumulator.h + */ + +#ifndef TIME_ACCUMULATOR_H +#define TIME_ACCUMULATOR_H + // Think of this as a stopwatch that can be restarted. -class Time_Accumulator -{ +class Time_Accumulator { public: - Time_Accumulator(); - ~Time_Accumulator(); + Time_Accumulator(); + ~Time_Accumulator(); - void Start(); - void Stop(); - void Reset(); - void Set(const Time_Span & in); + void Start(); + void Stop(); + void Reset(); + void Set(const Time_Span &in); + + Time_Span Report(); - Time_Span Report(); private: - - Time_Span _total_time; // the collected time from previous start/stops - Time_Clock *_accum_start; // the time of day the clock started + Time_Span _total_time; // the collected time from previous start/stops + Time_Clock *_accum_start; // the time of day the clock started }; -// you can set the internal accumilator to a value.. -inline void Time_Accumulator::Set(const Time_Span & in) -{ - _total_time = in; - // this seems to make the most since .. if you are running the clock right - // know... assume the timespane you are passing in is inclusive.. but keep - // clock running.. May need to rethink this... - if(_accum_start != nullptr) - { - Stop(); - Start(); - } -} -/** - * - */ -inline Time_Accumulator::Time_Accumulator() : _total_time(0,0,0,0,0), _accum_start(nullptr) -{ -} -/** - * - */ -inline Time_Accumulator::~Time_Accumulator() -{ - if(_accum_start != nullptr) - delete _accum_start; -} -/** - * - */ -inline void Time_Accumulator::Start() -{ - if(_accum_start == nullptr) - _accum_start = new Time_Clock(); -} -/** - * - */ -inline void Time_Accumulator::Stop() -{ - if(_accum_start != nullptr) - { - Time_Span work1(Time_Clock::GetCurrentTime() - *_accum_start); - _total_time += work1; - delete _accum_start; - _accum_start = nullptr; - } -} -/** - * - */ -void Time_Accumulator::Reset() -{ - if(_accum_start != nullptr) - { - delete _accum_start; - _accum_start = nullptr; - } - _total_time.Set(0,0,0,0,0); -} -/** - * - */ -inline Time_Span Time_Accumulator::Report() -{ - Time_Span answer(_total_time); - if(_accum_start != nullptr) - { - Time_Span ww(Time_Clock::GetCurrentTime() - *_accum_start); - answer += ww; - } - return answer; +// you can set the internal accumulator to a value.. +inline void Time_Accumulator:: +Set(const Time_Span &in) { + _total_time = in; + // this seems to make the most sense .. if you are running the clock right + // now... assume the timespan you are passing in is inclusive.. but keep + // clock running.. May need to rethink this... + if (_accum_start != nullptr) { + Stop(); + Start(); + } } -#endif //__TIME_ACCUMULATOR_H__ +/** + * + */ +inline Time_Accumulator:: +Time_Accumulator() : + _total_time(0, 0, 0, 0, 0), + _accum_start(nullptr) +{ +} + +/** + * + */ +inline Time_Accumulator:: +~Time_Accumulator() { + delete _accum_start; +} + +/** + * + */ +inline void Time_Accumulator:: +Start() { + if (_accum_start == nullptr) { + _accum_start = new Time_Clock(); + } +} + +/** + * + */ +inline void Time_Accumulator:: +Stop() { + if (_accum_start != nullptr) { + Time_Span work1(Time_Clock::GetCurrentTime() - *_accum_start); + _total_time += work1; + delete _accum_start; + _accum_start = nullptr; + } +} + +/** + * + */ +void Time_Accumulator:: +Reset() { + delete _accum_start; + _accum_start = nullptr; + _total_time.Set(0, 0, 0, 0, 0); +} + +/** + * + */ +inline Time_Span Time_Accumulator:: +Report() { + Time_Span answer(_total_time); + if (_accum_start != nullptr) { + Time_Span ww(Time_Clock::GetCurrentTime() - *_accum_start); + answer += ww; + } + return answer; +} + +#endif // TIME_ACCUMULATOR_H diff --git a/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx b/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx index 20450e9195..6c9f78a876 100644 --- a/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx +++ b/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx @@ -48,13 +48,7 @@ register_deferred_type(PyObject *entry_point) { const char *name_str; Py_ssize_t name_len; -#if PY_MAJOR_VERSION >= 3 name_str = PyUnicode_AsUTF8AndSize(name, &name_len); -#else - if (PyString_AsStringAndSize(name, (char **)&name_str, &name_len) == -1) { - name_str = nullptr; - } -#endif Py_DECREF(name); if (name_str == nullptr) { diff --git a/panda/src/pgraph/nodePath_ext.cxx b/panda/src/pgraph/nodePath_ext.cxx index 4be58f3201..e46d11c337 100644 --- a/panda/src/pgraph/nodePath_ext.cxx +++ b/panda/src/pgraph/nodePath_ext.cxx @@ -286,12 +286,8 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { while (PyDict_Next(kwargs, &pos, &key, &value)) { char *buffer; Py_ssize_t length; -#if PY_MAJOR_VERSION >= 3 buffer = (char *)PyUnicode_AsUTF8AndSize(key, &length); if (buffer == nullptr) { -#else - if (PyString_AsStringAndSize(key, &buffer, &length) == -1) { -#endif Dtool_Raise_TypeError("NodePath.set_shader_inputs accepts only string keywords"); return; } diff --git a/panda/src/pgraph/pythonLoaderFileType.cxx b/panda/src/pgraph/pythonLoaderFileType.cxx index bbb0577106..636f30c752 100644 --- a/panda/src/pgraph/pythonLoaderFileType.cxx +++ b/panda/src/pgraph/pythonLoaderFileType.cxx @@ -84,11 +84,7 @@ init(PyObject *loader) { // it must occur in the list. PyObject *extensions = PyObject_GetAttrString(loader, "extensions"); if (extensions != nullptr) { - if (PyUnicode_Check(extensions) -#if PY_MAJOR_VERSION < 3 - || PyString_Check(extensions) -#endif - ) { + if (PyUnicode_Check(extensions)) { Dtool_Raise_TypeError("extensions list should be a list or tuple"); Py_DECREF(extensions); return false; @@ -111,14 +107,7 @@ init(PyObject *loader) { PyObject *extension = items[i]; const char *extension_str; Py_ssize_t extension_len; - #if PY_MAJOR_VERSION >= 3 extension_str = PyUnicode_AsUTF8AndSize(extension, &extension_len); - #else - if (PyString_AsStringAndSize(extension, (char **)&extension_str, &extension_len) == -1) { - extension_str = nullptr; - } - #endif - if (extension_str == nullptr) { Py_DECREF(sequence); return false; @@ -146,11 +135,7 @@ init(PyObject *loader) { loader_cat.error() << "Registered extension '" << _extension << "' does not occur in extensions list of " -#if PY_MAJOR_VERSION >= 3 << PyUnicode_AsUTF8(repr) << "\n"; -#else - << PyString_AsString(repr) << "\n"; -#endif Py_DECREF(repr); return false; } @@ -179,17 +164,9 @@ init(PyObject *loader) { PyErr_Clear(); if (_load_func == nullptr && _save_func == nullptr) { -#if PY_MAJOR_VERSION >= 3 PyErr_Format(PyExc_TypeError, "loader plug-in %R does not define load_file or save_file function", loader); -#else - PyObject *repr = PyObject_Repr(loader); - PyErr_Format(PyExc_TypeError, - "loader plug-in %s does not define load_file or save_file function", - PyString_AsString(repr)); - Py_DECREF(repr); -#endif return false; } @@ -219,11 +196,7 @@ ensure_loaded() const { loader_cat.info() << "loading file type module: " -#if PY_MAJOR_VERSION >= 3 << PyUnicode_AsUTF8(repr) << "\n"; -#else - << PyString_AsString(repr) << "\n"; -#endif Py_DECREF(repr); } @@ -238,11 +211,7 @@ ensure_loaded() const { loader_cat.error() << "unable to load " -#if PY_MAJOR_VERSION >= 3 << PyUnicode_AsUTF8(repr) << "\n"; -#else - << PyString_AsString(repr) << "\n"; -#endif Py_DECREF(repr); } diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index d232ecb00a..b722a4cc07 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -481,6 +481,34 @@ flush_level() { _cache_counter.flush_level(); } +/** + * Overrides this method to update PStats appropriately. + */ +INLINE void RenderState:: +cache_ref_only() const { +#ifdef DO_PSTATS + int old_referenced_bits = get_referenced_bits(); + NodeCachedReferenceCount::cache_ref_only(); + consider_update_pstats(old_referenced_bits); +#else // DO_PSTATS + NodeCachedReferenceCount::cache_ref_only(); +#endif // DO_PSTATS +} + +/** + * Overrides this method to update PStats appropriately. + */ +INLINE void RenderState:: +cache_unref_only() const { +#ifdef DO_PSTATS + int old_referenced_bits = get_referenced_bits(); + NodeCachedReferenceCount::cache_unref_only(); + consider_update_pstats(old_referenced_bits); +#else // DO_PSTATS + NodeCachedReferenceCount::cache_unref_only(); +#endif // DO_PSTATS +} + #ifndef CPPPARSER /** * Handy templated version of get_attrib that casts to the right type. @@ -533,7 +561,7 @@ check_hash() const { */ INLINE bool RenderState:: do_cache_unref() const { - cache_unref_only(); + NodeCachedReferenceCount::cache_unref_only(); return unref(); } diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index db4ebbd634..027dae3c3f 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -169,6 +169,11 @@ public: INLINE void get_attrib_def(CPT(AttribType) &attrib) const; #endif // CPPPARSER + INLINE void cache_ref_only() const; + +protected: + INLINE void cache_unref_only() const; + private: INLINE void check_hash() const; bool validate_filled_slots() const; diff --git a/panda/src/pgraph/shaderAttrib_ext.cxx b/panda/src/pgraph/shaderAttrib_ext.cxx index 54acefe0ec..b599d5ab25 100644 --- a/panda/src/pgraph/shaderAttrib_ext.cxx +++ b/panda/src/pgraph/shaderAttrib_ext.cxx @@ -49,12 +49,8 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) const { while (PyDict_Next(kwargs, &pos, &key, &value)) { char *buffer; Py_ssize_t length; -#if PY_MAJOR_VERSION >= 3 buffer = (char *)PyUnicode_AsUTF8AndSize(key, &length); if (buffer == nullptr) { -#else - if (PyString_AsStringAndSize(key, &buffer, &length) == -1) { -#endif Dtool_Raise_TypeError("ShaderAttrib.set_shader_inputs accepts only string keywords"); delete attrib; return nullptr; diff --git a/panda/src/pgraph/shaderInput_ext.cxx b/panda/src/pgraph/shaderInput_ext.cxx index 72a4d74de3..31c1e749bd 100644 --- a/panda/src/pgraph/shaderInput_ext.cxx +++ b/panda/src/pgraph/shaderInput_ext.cxx @@ -261,14 +261,6 @@ __init__(CPT_InternalName name, PyObject *value, int priority) { _this->_stored_ptr = vec; _this->_stored_vector = vec; -#if PY_MAJOR_VERSION < 3 - } else if (PyInt_Check(value)) { - LVecBase4i vec((int)PyInt_AS_LONG(value), 0, 0, 0); - _this->_type = ShaderInput::M_numeric; - _this->_stored_ptr = vec; - _this->_stored_vector.set((PN_stdfloat)vec[0], 0, 0, 0); -#endif - } else if (PyLong_Check(value)) { LVecBase4i vec((int)PyLong_AsLong(value), 0, 0, 0); _this->_type = ShaderInput::M_numeric; diff --git a/panda/src/pgraph/transformState.I b/panda/src/pgraph/transformState.I index 474b78891f..fe83edc991 100644 --- a/panda/src/pgraph/transformState.I +++ b/panda/src/pgraph/transformState.I @@ -753,6 +753,34 @@ flush_level() { _cache_counter.flush_level(); } +/** + * Overrides this method to update PStats appropriately. + */ +INLINE void TransformState:: +cache_ref_only() const { +#ifdef DO_PSTATS + int old_referenced_bits = get_referenced_bits(); + NodeCachedReferenceCount::cache_ref_only(); + consider_update_pstats(old_referenced_bits); +#else // DO_PSTATS + NodeCachedReferenceCount::cache_ref_only(); +#endif // DO_PSTATS +} + +/** + * Overrides this method to update PStats appropriately. + */ +INLINE void TransformState:: +cache_unref_only() const { +#ifdef DO_PSTATS + int old_referenced_bits = get_referenced_bits(); + NodeCachedReferenceCount::cache_unref_only(); + consider_update_pstats(old_referenced_bits); +#else // DO_PSTATS + NodeCachedReferenceCount::cache_unref_only(); +#endif // DO_PSTATS +} + /** * Reimplements NodeReferenceCount::node_unref(). We do this because we have * a non-virtual unref() method. @@ -769,7 +797,7 @@ do_node_unref() const { */ INLINE bool TransformState:: do_cache_unref() const { - cache_unref_only(); + NodeCachedReferenceCount::cache_unref_only(); return unref(); } diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 805e8da119..916280ff1c 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -81,10 +81,8 @@ TransformState:: set_destructing(); // Free the inverse matrix computation, if it has been stored. - if (_inv_mat != nullptr) { - delete _inv_mat; - _inv_mat = nullptr; - } + delete _inv_mat; + _inv_mat = nullptr; LightReMutexHolder holder(*_states_lock); diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 370517de9c..29702d327a 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -213,6 +213,11 @@ public: INLINE static void flush_level(); + INLINE void cache_ref_only() const; + +protected: + INLINE void cache_unref_only() const; + private: INLINE bool do_cache_unref() const; INLINE bool do_node_unref() const; diff --git a/panda/src/pnmimage/pfmFile_ext.cxx b/panda/src/pnmimage/pfmFile_ext.cxx index fb31f7ead5..baf1caf8e9 100644 --- a/panda/src/pnmimage/pfmFile_ext.cxx +++ b/panda/src/pnmimage/pfmFile_ext.cxx @@ -77,7 +77,6 @@ get_points() const { */ int Extension:: __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { -#if PY_VERSION_HEX >= 0x02060000 if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable."); @@ -117,9 +116,6 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { view->suboffsets = nullptr; return 0; -#else - return -1; -#endif } #endif // HAVE_PYTHON diff --git a/panda/src/pnmimage/pnmImage.cxx b/panda/src/pnmimage/pnmImage.cxx index a8deae0b6b..a39ef5c61e 100644 --- a/panda/src/pnmimage/pnmImage.cxx +++ b/panda/src/pnmimage/pnmImage.cxx @@ -1176,7 +1176,7 @@ add_sub_image(const PNMImage ©, int xto, int yto, if (has_alpha() && copy.has_alpha()) { for (y = ymin; y < ymax; y++) { for (x = xmin; x < xmax; x++) { - set_alpha(x, y, get_alpha(x, y) + copy.get_alpha(x, y) * pixel_scale); + set_alpha(x, y, get_alpha(x, y) + copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale); } } } @@ -1184,7 +1184,7 @@ add_sub_image(const PNMImage ©, int xto, int yto, for (y = ymin; y < ymax; y++) { for (x = xmin; x < xmax; x++) { LRGBColorf rgb1 = get_xel(x, y); - LRGBColorf rgb2 = copy.get_xel(x, y); + LRGBColorf rgb2 = copy.get_xel(x - xmin + xfrom, y - ymin + yfrom); set_xel(x, y, rgb1[0] + rgb2[0] * pixel_scale, rgb1[1] + rgb2[1] * pixel_scale, @@ -1210,7 +1210,7 @@ mult_sub_image(const PNMImage ©, int xto, int yto, if (has_alpha() && copy.has_alpha()) { for (y = ymin; y < ymax; y++) { for (x = xmin; x < xmax; x++) { - set_alpha(x, y, get_alpha(x, y) * copy.get_alpha(x, y) * pixel_scale); + set_alpha(x, y, get_alpha(x, y) * copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale); } } } @@ -1218,7 +1218,7 @@ mult_sub_image(const PNMImage ©, int xto, int yto, for (y = ymin; y < ymax; y++) { for (x = xmin; x < xmax; x++) { LRGBColorf rgb1 = get_xel(x, y); - LRGBColorf rgb2 = copy.get_xel(x, y); + LRGBColorf rgb2 = copy.get_xel(x - xmin + xfrom, y - ymin + yfrom); set_xel(x, y, rgb1[0] * rgb2[0] * pixel_scale, rgb1[1] * rgb2[1] * pixel_scale, diff --git a/panda/src/putil/bitArray_ext.cxx b/panda/src/putil/bitArray_ext.cxx index 215d920cb4..ec3a95b800 100644 --- a/panda/src/putil/bitArray_ext.cxx +++ b/panda/src/putil/bitArray_ext.cxx @@ -20,18 +20,6 @@ */ void Extension:: __init__(PyObject *init_value) { -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(init_value)) { - long value = PyInt_AS_LONG(init_value); - if (value >= 0) { - _this->set_word(0, value); - } else { - PyErr_SetString(PyExc_ValueError, "BitArray constructor requires a positive integer"); - } - return; - } -#endif - if (!PyLong_Check(init_value) || Py_SIZE(init_value) < 0) { PyErr_SetString(PyExc_ValueError, "BitArray constructor requires a positive integer"); return; diff --git a/panda/src/putil/doubleBitMask_ext.I b/panda/src/putil/doubleBitMask_ext.I index d46fa7a956..f63fbc5182 100644 --- a/panda/src/putil/doubleBitMask_ext.I +++ b/panda/src/putil/doubleBitMask_ext.I @@ -17,18 +17,6 @@ template INLINE void Extension >:: __init__(PyObject *init_value) { -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(init_value)) { - long value = PyInt_AS_LONG(init_value); - if (value >= 0) { - this->_this->store((typename BMType::WordType)value, 0, sizeof(long) * 8 - 1); - } else { - PyErr_SetString(PyExc_ValueError, "DoubleBitMask constructor requires a positive integer"); - } - return; - } -#endif - if (!PyLong_Check(init_value) || Py_SIZE(init_value) < 0) { PyErr_SetString(PyExc_ValueError, "DoubleBitMask constructor requires a positive integer"); return; diff --git a/panda/src/putil/pythonCallbackObject.cxx b/panda/src/putil/pythonCallbackObject.cxx index e8ef005c2e..262749074f 100644 --- a/panda/src/putil/pythonCallbackObject.cxx +++ b/panda/src/putil/pythonCallbackObject.cxx @@ -45,9 +45,7 @@ PythonCallbackObject(PyObject *function) { // Ensure that the Python threading system is initialized and ready to go. #ifdef WITH_THREAD // This symbol defined within Python.h -#if PY_VERSION_HEX >= 0x03020000 Py_Initialize(); -#endif PyEval_InitThreads(); #endif diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx index dc32a1ddcd..77521e2ff3 100644 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx @@ -208,6 +208,10 @@ get_properties_advanced(FrameBufferProperties &properties, ivalue_list[green_bits_i], ivalue_list[blue_bits_i], ivalue_list[alpha_bits_i]); + + if (ivalue_list[pixel_type_i] == WGL_TYPE_RGBA_FLOAT_ARB) { + properties.set_float_color(true); + } } if (ivalue_list[double_buffer_i]) { @@ -372,8 +376,11 @@ choose_pixel_format(const FrameBufferProperties &properties, iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB; iattrib_list[ni++] = true; - iattrib_list[ni++] = WGL_PIXEL_TYPE_ARB; - iattrib_list[ni++] = WGL_TYPE_RGBA_ARB; + + if (!properties.get_float_color()) { + iattrib_list[ni++] = WGL_PIXEL_TYPE_ARB; + iattrib_list[ni++] = WGL_TYPE_RGBA_ARB; + } if (need_pbuffer) { iattrib_list[ni++] = WGL_DRAW_TO_PBUFFER_ARB; diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index a67ff3659c..242729d9bf 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -426,18 +426,22 @@ set_properties_now(WindowProperties &properties) { if (properties.get_mouse_mode() != _properties.get_mouse_mode()) { switch (properties.get_mouse_mode()) { case WindowProperties::M_absolute: - case WindowProperties::M_relative: // not implemented, treat as absolute - - if (_properties.get_mouse_mode() == WindowProperties::M_confined) { + if (_properties.get_mouse_mode() != WindowProperties::M_absolute) { ClipCursor(nullptr); windisplay_cat.info() << "Unconfining cursor from window\n"; } _properties.set_mouse_mode(WindowProperties::M_absolute); break; + case WindowProperties::M_relative: + if (!enable_raw_input()) { + break; + } + // Fall through + case WindowProperties::M_confined: if (confine_cursor()) { - _properties.set_mouse_mode(WindowProperties::M_confined); + _properties.set_mouse_mode(properties.get_mouse_mode()); } break; } @@ -564,13 +568,8 @@ open_window() { } // Registers to receive the WM_INPUT messages - if (_input_devices.size() > 1) { - RAWINPUTDEVICE Rid; - Rid.usUsagePage = 0x01; - Rid.usUsage = 0x02; - Rid.dwFlags = 0;// RIDEV_NOLEGACY; // adds HID mouse and also ignores legacy mouse messages - Rid.hwndTarget = _hWnd; - RegisterRawInputDevices(&Rid, 1, sizeof (Rid)); + if (_input_devices.size() > 1 || _properties.get_mouse_mode() == WindowProperties::M_relative) { + enable_raw_input(); } // Create a WindowHandle for ourselves @@ -683,6 +682,32 @@ initialize_input_devices() { } } +/** + * Enables raw mouse input for this window. Returns true on success. + */ +bool WinGraphicsWindow:: +enable_raw_input() { + if (_raw_input_enabled) { + return true; + } + + RAWINPUTDEVICE rid; + rid.usUsagePage = 0x01; + rid.usUsage = 0x02; + rid.dwFlags = 0; + rid.hwndTarget = _hWnd; + if (RegisterRawInputDevices(&rid, 1, sizeof(rid))) { + windisplay_cat.info() + << "Enabled raw mouse input.\n"; + _raw_input_enabled = true; + return true; + } else { + windisplay_cat.warning() + << "Failed to enable raw mouse input.\n"; + return false; + } +} + /** * This is a hook for derived classes to do something special, if necessary, * when a fullscreen window has been minimized. The given WindowProperties @@ -1315,22 +1340,18 @@ track_mouse_leaving(HWND hwnd) { bool WinGraphicsWindow:: confine_cursor() { RECT clip; - if (!GetWindowRect(_hWnd, &clip)) { + get_client_rect_screen(_hWnd, &clip); + + windisplay_cat.info() + << "ClipCursor() to " << clip.left << "," << clip.top << " to " + << clip.right << "," << clip.bottom << endl; + + if (!ClipCursor(&clip)) { windisplay_cat.warning() - << "GetWindowRect() failed, cannot confine cursor.\n"; + << "Failed to confine cursor to window.\n"; return false; } else { - windisplay_cat.info() - << "ClipCursor() to " << clip.left << "," << clip.top << " to " - << clip.right << "," << clip.bottom << endl; - - if (!ClipCursor(&clip)) { - windisplay_cat.warning() - << "Failed to confine cursor to window.\n"; - return false; - } else { - return true; - } + return true; } } @@ -1590,7 +1611,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { resend_lost_keypresses(); } SetCapture(hwnd); - _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + if (_properties.get_mouse_mode() != WindowProperties::M_relative) { + _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + } _input->button_down(MouseButton::button(0), get_message_time()); // A button-click in the window means to grab the keyboard focus. @@ -1602,7 +1625,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { resend_lost_keypresses(); } SetCapture(hwnd); - _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + if (_properties.get_mouse_mode() != WindowProperties::M_relative) { + _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + } _input->button_down(MouseButton::button(1), get_message_time()); // A button-click in the window means to grab the keyboard focus. set_focus(); @@ -1613,7 +1638,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { resend_lost_keypresses(); } SetCapture(hwnd); - _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + if (_properties.get_mouse_mode() != WindowProperties::M_relative) { + _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + } _input->button_down(MouseButton::button(2), get_message_time()); // A button-click in the window means to grab the keyboard focus. set_focus(); @@ -1626,7 +1653,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } SetCapture(hwnd); int whichButton = GET_XBUTTON_WPARAM(wparam); - _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + if (_properties.get_mouse_mode() != WindowProperties::M_relative) { + _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + } if (whichButton == XBUTTON1) { _input->button_down(MouseButton::button(3), get_message_time()); } else if (whichButton == XBUTTON2) { @@ -2434,7 +2463,9 @@ show_error_message(DWORD message_id) { */ void WinGraphicsWindow:: handle_keypress(ButtonHandle key, int x, int y, double time) { - _input->set_pointer_in_window(x, y); + if (_properties.get_mouse_mode() != WindowProperties::M_relative) { + _input->set_pointer_in_window(x, y); + } if (key != ButtonHandle::none()) { _input->button_down(key, time); } @@ -2780,6 +2811,15 @@ handle_raw_input(HRAWINPUT hraw) { } RAWINPUT *raw = (RAWINPUT *)lpb; + if (_properties.get_mouse_mode() == WindowProperties::M_relative && + raw->header.dwType == RIM_TYPEMOUSE && + (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) == 0) { + double x = raw->data.mouse.lLastX; + double y = raw->data.mouse.lLastY; + PointerData md = _input->get_pointer(); + _input->set_pointer_in_window(md.get_x() + x, md.get_y() + y); + } + if (raw->header.hDevice == 0) { return; } @@ -2837,7 +2877,9 @@ handle_raw_input(HRAWINPUT hraw) { */ bool WinGraphicsWindow:: handle_mouse_motion(int x, int y) { - _input->set_pointer_in_window(x, y); + if (_properties.get_mouse_mode() != WindowProperties::M_relative) { + _input->set_pointer_in_window(x, y); + } return false; } diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index 083508087b..ca33615219 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -132,6 +132,7 @@ private: void adjust_z_order(WindowProperties::ZOrder last_z_order, WindowProperties::ZOrder this_z_order); void initialize_input_devices(); + bool enable_raw_input(); void handle_raw_input(HRAWINPUT hraw); void track_mouse_leaving(HWND hwnd); bool confine_cursor(); @@ -190,6 +191,7 @@ private: bool _ralt_down; GraphicsWindowInputDevice *_input; + bool _raw_input_enabled = false; // following adds support platform specfic window processing functions. typedef pset WinProcClasses; diff --git a/pandatool/src/daeegg/daeToEggConverter.cxx b/pandatool/src/daeegg/daeToEggConverter.cxx index 7e5aa6673e..95b146decb 100644 --- a/pandatool/src/daeegg/daeToEggConverter.cxx +++ b/pandatool/src/daeegg/daeToEggConverter.cxx @@ -78,9 +78,7 @@ DAEToEggConverter(const DAEToEggConverter ©) : */ DAEToEggConverter:: ~DAEToEggConverter() { - if (_error_handler != nullptr) { - delete _error_handler; - } + delete _error_handler; } /** diff --git a/pandatool/src/deploy-stub/deploy-stub.c b/pandatool/src/deploy-stub/deploy-stub.c index 7255b911b8..f5839d4ed8 100644 --- a/pandatool/src/deploy-stub/deploy-stub.c +++ b/pandatool/src/deploy-stub/deploy-stub.c @@ -22,13 +22,7 @@ #include #include -#if PY_MAJOR_VERSION >= 3 -# include - -# if PY_MINOR_VERSION < 5 -# define Py_DecodeLocale _Py_char2wchar -# endif -#endif +#include /* Leave room for future expansion. We only read pointer 0, but there are other pointers that are being read by configPageManager.cxx. */ @@ -70,10 +64,8 @@ static struct _inittab extensions[] = { {0, 0}, }; -#if PY_MAJOR_VERSION >= 3 # define WIN_UNICODE #endif -#endif #ifdef _WIN32 static wchar_t *log_pathw = NULL; @@ -356,7 +348,7 @@ int Py_FrozenMain(int argc, char **argv) int inspect = 0; int unbuffered = 0; -#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE) +#ifndef WIN_UNICODE int i; char *oldloc; wchar_t **argv_copy = NULL; @@ -397,7 +389,7 @@ int Py_FrozenMain(int argc, char **argv) setbuf(stderr, (char *)NULL); } -#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE) +#ifndef WIN_UNICODE oldloc = setlocale(LC_ALL, NULL); setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { @@ -418,7 +410,7 @@ int Py_FrozenMain(int argc, char **argv) #endif /* MS_WINDOWS */ if (argc >= 1) { -#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE) +#ifndef WIN_UNICODE Py_SetProgramName(argv_copy[0]); #else Py_SetProgramName(argv[0]); @@ -430,64 +422,11 @@ int Py_FrozenMain(int argc, char **argv) PyWinFreeze_ExeInit(); #endif -#if defined(MS_WINDOWS) && PY_VERSION_HEX < 0x03040000 - /* We can't rely on our overriding of the standard I/O to work on older - * versions of Python, since they are compiled with an incompatible CRT. - * The best solution I've found was to just replace sys.stdout/stderr with - * the log file reopened in append mode (which requires not locking it for - * write, and also passing in _O_APPEND above, and disabling buffering). - * It's not the most elegant solution, but it's better than crashing. */ -#if PY_MAJOR_VERSION < 3 - if (log_pathw != NULL) { - PyObject *uniobj = PyUnicode_FromWideChar(log_pathw, (Py_ssize_t)wcslen(log_pathw)); - PyObject *file = PyObject_CallFunction((PyObject*)&PyFile_Type, "Nsi", uniobj, "a", 0); - - if (file != NULL) { - PyFile_SetEncodingAndErrors(file, "utf-8", NULL); - - PySys_SetObject("stdout", file); - PySys_SetObject("stderr", file); - PySys_SetObject("__stdout__", file); - PySys_SetObject("__stderr__", file); - - /* Be sure to disable buffering, otherwise we'll get overlap */ - setbuf(stdout, (char *)NULL); - setbuf(stderr, (char *)NULL); - } - } - else -#endif - if (!supports_code_page(GetConsoleOutputCP()) || - !supports_code_page(GetConsoleCP())) { - /* Same hack as before except for Python 2.7, which doesn't seem to have - * a way to set the encoding ahead of time, and setting PYTHONIOENCODING - * doesn't seem to work. Fortunately, Python 2.7 doesn't usually start - * causing codec errors until the first print statement. */ - PyObject *sys_stream; - UINT acp = GetACP(); - SetConsoleCP(acp); - SetConsoleOutputCP(acp); - - sys_stream = PySys_GetObject("stdin"); - if (sys_stream && PyFile_Check(sys_stream)) { - PyFile_SetEncodingAndErrors(sys_stream, "mbcs", NULL); - } - sys_stream = PySys_GetObject("stdout"); - if (sys_stream && PyFile_Check(sys_stream)) { - PyFile_SetEncodingAndErrors(sys_stream, "mbcs", NULL); - } - sys_stream = PySys_GetObject("stderr"); - if (sys_stream && PyFile_Check(sys_stream)) { - PyFile_SetEncodingAndErrors(sys_stream, "mbcs", NULL); - } - } -#endif - if (Py_VerboseFlag) fprintf(stderr, "Python %s\n%s\n", Py_GetVersion(), Py_GetCopyright()); -#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE) +#ifndef WIN_UNICODE PySys_SetArgv(argc, argv_copy); #else PySys_SetArgv(argc, argv); @@ -510,11 +449,7 @@ int Py_FrozenMain(int argc, char **argv) sprintf(buffer, "%s/../Frameworks", dir); PyObject *sys_path = PyList_New(1); - #if PY_MAJOR_VERSION >= 3 PyList_SET_ITEM(sys_path, 0, PyUnicode_FromString(buffer)); - #else - PyList_SET_ITEM(sys_path, 0, PyString_FromString(buffer)); - #endif PySys_SetObject("path", sys_path); Py_DECREF(sys_path); @@ -546,15 +481,11 @@ int Py_FrozenMain(int argc, char **argv) #endif Py_Finalize(); -#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE) +#ifndef WIN_UNICODE error: if (argv_copy2) { for (i = 0; i < argc; i++) { -#if PY_MINOR_VERSION >= 4 PyMem_RawFree(argv_copy2[i]); -#else - PyMem_Free(argv_copy2[i]); -#endif } } #endif @@ -643,7 +574,7 @@ static void unmap_blob(void *blob) { /** * Main entry point to deploy-stub. */ -#if defined(_WIN32) && PY_MAJOR_VERSION >= 3 +#ifdef _WIN32 int wmain(int argc, wchar_t *argv[]) { #else int main(int argc, char *argv[]) { diff --git a/pandatool/src/eggcharbase/eggCharacterFilter.cxx b/pandatool/src/eggcharbase/eggCharacterFilter.cxx index 9b23e7804d..02289dbe0d 100644 --- a/pandatool/src/eggcharbase/eggCharacterFilter.cxx +++ b/pandatool/src/eggcharbase/eggCharacterFilter.cxx @@ -31,9 +31,7 @@ EggCharacterFilter() : EggMultiFilter(false) { */ EggCharacterFilter:: ~EggCharacterFilter() { - if (_collection != nullptr) { - delete _collection; - } + delete _collection; } /** diff --git a/pandatool/src/eggcharbase/eggComponentData.cxx b/pandatool/src/eggcharbase/eggComponentData.cxx index 5af9dd3d57..ab57e5bd53 100644 --- a/pandatool/src/eggcharbase/eggComponentData.cxx +++ b/pandatool/src/eggcharbase/eggComponentData.cxx @@ -36,12 +36,8 @@ EggComponentData(EggCharacterCollection *collection, */ EggComponentData:: ~EggComponentData() { - BackPointers::iterator bpi; - for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) { - EggBackPointer *back = (*bpi); - if (back != nullptr) { - delete back; - } + for (EggBackPointer *back : _back_pointers) { + delete back; } } diff --git a/pandatool/src/flt/fltRecordReader.cxx b/pandatool/src/flt/fltRecordReader.cxx index eb3ba94840..8e1993c90a 100644 --- a/pandatool/src/flt/fltRecordReader.cxx +++ b/pandatool/src/flt/fltRecordReader.cxx @@ -42,10 +42,8 @@ FltRecordReader(std::istream &in) : */ FltRecordReader:: ~FltRecordReader() { - if (_iterator != nullptr) { - delete _iterator; - _iterator = nullptr; - } + delete _iterator; + _iterator = nullptr; } /** diff --git a/pandatool/src/lwoegg/cLwoSurface.cxx b/pandatool/src/lwoegg/cLwoSurface.cxx index 63559dd62f..1bb0c14678 100644 --- a/pandatool/src/lwoegg/cLwoSurface.cxx +++ b/pandatool/src/lwoegg/cLwoSurface.cxx @@ -146,9 +146,7 @@ CLwoSurface(LwoToEggConverter *converter, const LwoSurface *surface) : */ CLwoSurface:: ~CLwoSurface() { - if (_block != nullptr) { - delete _block; - } + delete _block; } /** diff --git a/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx b/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx index 98d4c502f0..ebf5a5ac95 100644 --- a/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx +++ b/pandatool/src/lwoegg/cLwoSurfaceBlock.cxx @@ -144,7 +144,5 @@ CLwoSurfaceBlock(LwoToEggConverter *converter, const LwoSurfaceBlock *block) : */ CLwoSurfaceBlock:: ~CLwoSurfaceBlock() { - if (_tmap != nullptr) { - delete _tmap; - } + delete _tmap; } diff --git a/pandatool/src/lwoegg/lwoToEggConverter.cxx b/pandatool/src/lwoegg/lwoToEggConverter.cxx index 42844f19f0..524d60a8cf 100644 --- a/pandatool/src/lwoegg/lwoToEggConverter.cxx +++ b/pandatool/src/lwoegg/lwoToEggConverter.cxx @@ -199,39 +199,25 @@ void LwoToEggConverter:: cleanup() { _lwo_header.clear(); - if (_generic_layer != nullptr) { - delete _generic_layer; - _generic_layer = nullptr; - } + delete _generic_layer; + _generic_layer = nullptr; - Layers::iterator li; - for (li = _layers.begin(); li != _layers.end(); ++li) { - CLwoLayer *layer = (*li); - if (layer != nullptr) { - delete layer; - } + for (CLwoLayer *layer : _layers) { + delete layer; } _layers.clear(); - Clips::iterator ci; - for (ci = _clips.begin(); ci != _clips.end(); ++ci) { - CLwoClip *clip = (*ci); - if (clip != nullptr) { - delete clip; - } + for (CLwoClip *clip : _clips) { + delete clip; } _clips.clear(); - Points::iterator pi; - for (pi = _points.begin(); pi != _points.end(); ++pi) { - CLwoPoints *points = (*pi); + for (CLwoPoints *points : _points) { delete points; } _points.clear(); - Polygons::iterator gi; - for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) { - CLwoPolygons *polygons = (*gi); + for (CLwoPolygons *polygons : _polygons) { delete polygons; } _polygons.clear(); diff --git a/pandatool/src/maya/mayaShaderColorDef.cxx b/pandatool/src/maya/mayaShaderColorDef.cxx index cbaa82d5b7..38aa294949 100644 --- a/pandatool/src/maya/mayaShaderColorDef.cxx +++ b/pandatool/src/maya/mayaShaderColorDef.cxx @@ -131,9 +131,7 @@ MayaShaderColorDef(MayaShaderColorDef ©) { */ MayaShaderColorDef:: ~MayaShaderColorDef() { - if (_color_object != nullptr) { - delete _color_object; - } + delete _color_object; } /** diff --git a/pandatool/src/mayaegg/mayaNodeDesc.cxx b/pandatool/src/mayaegg/mayaNodeDesc.cxx index 8a86f1cb96..2c251ac9ca 100644 --- a/pandatool/src/mayaegg/mayaNodeDesc.cxx +++ b/pandatool/src/mayaegg/mayaNodeDesc.cxx @@ -72,9 +72,7 @@ MayaNodeDesc(MayaNodeTree *tree, MayaNodeDesc *parent, const string &name) : */ MayaNodeDesc:: ~MayaNodeDesc() { - if (_dag_path != nullptr) { - delete _dag_path; - } + delete _dag_path; } /** diff --git a/pandatool/src/pstatserver/pStatThreadData.cxx b/pandatool/src/pstatserver/pStatThreadData.cxx index bef18c8a24..141f927e8f 100644 --- a/pandatool/src/pstatserver/pStatThreadData.cxx +++ b/pandatool/src/pstatserver/pStatThreadData.cxx @@ -269,9 +269,7 @@ record_new_frame(int frame_number, PStatFrameData *frame_data) { (_frames.front() == nullptr || _frames.front()->is_empty() || _frames.front()->get_start() < oldest_allowable_time)) { - if (_frames.front() != nullptr) { - delete _frames.front(); - } + delete _frames.front(); _frames.pop_front(); _first_frame_number++; } diff --git a/setup.cfg b/setup.cfg index 65e752e756..282448f7bb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,8 +13,6 @@ classifiers = Operating System :: OS Independent Programming Language :: C++ Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 diff --git a/tests/collide/test_into_poly.py b/tests/collide/test_into_poly.py index ccfd15fcd1..600b9d667d 100644 --- a/tests/collide/test_into_poly.py +++ b/tests/collide/test_into_poly.py @@ -31,7 +31,7 @@ def test_sphere_into_poly(): # Colliding just on the edge entry, np_from, np_into = make_collision(CollisionSphere(0, 0, 3, 2), poly) - assert entry.get_surface_point(np_from) == Point3(0, 0, 3) + assert entry.get_surface_point(np_from) == Point3(0, 0, 1) assert entry.get_surface_normal(np_into) == Vec3(-1, 0, 0) # Testing surface normal # No collision diff --git a/tests/dtoolutil/test_filename.py b/tests/dtoolutil/test_filename.py index d24d9d52d7..a42305ae12 100644 --- a/tests/dtoolutil/test_filename.py +++ b/tests/dtoolutil/test_filename.py @@ -15,7 +15,6 @@ def test_filename_open(): open(fn, 'rb') -@pytest.mark.skipif(sys.version_info < (3, 4), reason="Requires Python 3.4") def test_filename_ctor_pathlib(): pathlib = pytest.importorskip('pathlib') diff --git a/tests/dtoolutil/test_textencoder.py b/tests/dtoolutil/test_textencoder.py index ef03c7d826..132773ec62 100644 --- a/tests/dtoolutil/test_textencoder.py +++ b/tests/dtoolutil/test_textencoder.py @@ -2,28 +2,24 @@ import sys import pytest from panda3d.core import TextEncoder -if sys.version_info >= (3, 0): - unichr = chr - xrange = range - def valid_characters(): """Generator yielding all valid Unicode code points.""" - for i in xrange(0xd800): - yield unichr(i) + for i in range(0xd800): + yield chr(i) - for i in xrange(0xe000, sys.maxunicode + 1): + for i in range(0xe000, sys.maxunicode + 1): if i != 0xfeff and i & 0xfffe != 0xfffe: - yield unichr(i) + yield chr(i) def test_text_decode_iso8859(): encoder = TextEncoder() encoder.set_encoding(TextEncoder.E_iso8859) - for i in xrange(255): - enc = unichr(i).encode('latin-1') + for i in range(255): + enc = chr(i).encode('latin-1') assert len(enc) == 1 dec = encoder.decode_text(enc) @@ -60,8 +56,8 @@ def test_text_encode_iso8859(): encoder = TextEncoder() encoder.set_encoding(TextEncoder.E_iso8859) - for i in xrange(255): - c = unichr(i) + for i in range(255): + c = chr(i) enc = encoder.encode_wtext(c) assert enc == c.encode('latin-1') diff --git a/tests/event/test_futures.py b/tests/event/test_futures.py index adef5b33fc..dcde328029 100644 --- a/tests/event/test_futures.py +++ b/tests/event/test_futures.py @@ -3,11 +3,10 @@ import pytest import time import sys -if sys.version_info >= (3,): - from concurrent.futures._base import TimeoutError, CancelledError +if sys.version_info >= (3, 8): + from asyncio.exceptions import TimeoutError, CancelledError else: - TimeoutError = Exception - CancelledError = Exception + from concurrent.futures._base import TimeoutError, CancelledError def test_future_cancelled(): diff --git a/tests/gui/test_DirectEntry.py b/tests/gui/test_DirectEntry.py index 3382be3bda..bc048b67a0 100644 --- a/tests/gui/test_DirectEntry.py +++ b/tests/gui/test_DirectEntry.py @@ -1,6 +1,5 @@ # coding=utf-8 from direct.gui.DirectEntry import DirectEntry -import sys def test_entry_destroy(): @@ -34,10 +33,3 @@ def test_entry_auto_capitalize(): assert entry.get() == u'àütò çapítalízè ţèsţ' entry._autoCapitalize() assert entry.get() == u'Àütò Çapítalízè Ţèsţ' - - # Also test it with a UTF-8 encoded byte string in Python 2. - if sys.version_info < (3, 0): - entry.set(u'àütò çapítalízè ţèsţ'.encode('utf-8')) - assert entry.get() == u'àütò çapítalízè ţèsţ' - entry._autoCapitalize() - assert entry.get() == u'Àütò Çapítalízè Ţèsţ' diff --git a/tests/interrogate/test_property.py b/tests/interrogate/test_property.py index fffcb78ac0..12da75f457 100755 --- a/tests/interrogate/test_property.py +++ b/tests/interrogate/test_property.py @@ -2,11 +2,7 @@ import sys import pytest from panda3d import core from contextlib import contextmanager - -if sys.version_info >= (3, 3): - import collections.abc as collections_abc -else: - import _abcoll as collections_abc +import collections.abc as collections_abc @contextmanager @@ -122,11 +118,6 @@ def test_seq_property_getitem(): assert prop[-2] == item_b assert prop[-3] == item_a - # Long index - if sys.version_info[0] < 3: - assert prop[long(1)] == item_b - assert prop[long(-1)] == item_b - # Out of bounds access with pytest.raises(IndexError): prop[-4] @@ -176,13 +167,6 @@ def test_seq_property_setitem(): prop[-3] = item_c assert tuple(prop) == (item_c, item_b, item_a) - # Long index - if sys.version_info[0] < 3: - prop[long(1)] = item_b - assert prop[1] == item_b - prop[long(-1)] = item_b - assert prop[-1] == item_b - # Out of bounds access with pytest.raises(IndexError): prop[-4] = item_c diff --git a/tests/linmath/test_lvector2.py b/tests/linmath/test_lvector2.py index 6861ec2c96..d6bff7c5aa 100644 --- a/tests/linmath/test_lvector2.py +++ b/tests/linmath/test_lvector2.py @@ -1,15 +1,9 @@ from math import floor, ceil -import sys from panda3d.core import Vec2, Vec3, Vec4, Vec2F, Vec2D import pytest -reason = '''Rounding in Python 2.7 expects to return a float value, since it returns a Vector it -does not work. When Python 2.7 gets deprecated, remove this check.''' - - -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_round(): original_vector = Vec2(2.3, -2.6) @@ -18,7 +12,6 @@ def test_round(): assert rounded_vector.y == -3 -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_floor(): original_vector = Vec2(2.3, -2.6) @@ -27,7 +20,6 @@ def test_floor(): assert rounded_vector.y == -3 -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_ceil(): original_vector = Vec2(2.3, -2.6) diff --git a/tests/linmath/test_lvector3.py b/tests/linmath/test_lvector3.py index 9b69262a3d..d4ae6e0429 100644 --- a/tests/linmath/test_lvector3.py +++ b/tests/linmath/test_lvector3.py @@ -1,14 +1,9 @@ from math import floor, ceil -import sys from panda3d.core import Vec2, Vec3, Vec3F, Vec3D import pytest -reason = '''Rounding in Python 2.7 expects to return a float value, since it returns a Vector it -does not work. When Python 2.7 gets deprecated, remove this check.''' - -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_round(): original_vector = Vec3(2.3, -2.6, 3.5) @@ -18,7 +13,6 @@ def test_round(): assert rounded_vector.z == 4 -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_floor(): original_vector = Vec3(2.3, -2.6, 3.5) @@ -28,7 +22,6 @@ def test_floor(): assert rounded_vector.z == 3 -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_ceil(): original_vector = Vec3(2.3, -2.6, 3.5) diff --git a/tests/linmath/test_lvector4.py b/tests/linmath/test_lvector4.py index cca9da2866..2b487b9cb4 100644 --- a/tests/linmath/test_lvector4.py +++ b/tests/linmath/test_lvector4.py @@ -1,14 +1,9 @@ from math import floor, ceil -import sys from panda3d.core import Vec2, Vec3, Vec4, Vec4F, Vec4D import pytest -reason = '''Rounding in Python 2.7 expects to return a float value, since it returns a Vector it -does not work. When Python 2.7 gets deprecated, remove this check.''' - -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_round(): original_vector = Vec4(2.3, -2.6, 3.5, 1) @@ -19,7 +14,6 @@ def test_round(): assert rounded_vector.w == 1 -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_floor(): original_vector = Vec4(2.3, -2.6, 3.5, 1) @@ -30,7 +24,6 @@ def test_floor(): assert rounded_vector.w == 1 -@pytest.mark.skipif(sys.version_info < (3, 5), reason=reason) def test_ceil(): original_vector = Vec4(2.3, -2.6, 3.5, 1) diff --git a/tests/pgraph/test_textureattrib.py b/tests/pgraph/test_textureattrib.py index 868f3f4b07..85c2aa8311 100644 --- a/tests/pgraph/test_textureattrib.py +++ b/tests/pgraph/test_textureattrib.py @@ -88,7 +88,50 @@ def test_textureattrib_compare(): assert tattr2.compare_to(tattr1) != 0 assert tattr2.compare_to(tattr1) == -tattr1.compare_to(tattr2) - # If both have the same texture, they are equal + # Empty stage is not the same as a single off stage + tattr1 = core.TextureAttrib.make() + tattr2 = core.TextureAttrib.make() + tattr2 = tattr2.add_off_stage(stage1) + assert tattr1.compare_to(tattr2) != 0 + assert tattr2.compare_to(tattr1) != 0 + assert tattr2.compare_to(tattr1) == -tattr1.compare_to(tattr2) + + # All-off stage is not the same as a single off stage + tattr1 = core.TextureAttrib.make_all_off() + tattr2 = core.TextureAttrib.make() + tattr2 = tattr2.add_off_stage(stage1) + assert tattr1.compare_to(tattr2) != 0 + assert tattr2.compare_to(tattr1) != 0 + assert tattr2.compare_to(tattr1) == -tattr1.compare_to(tattr2) + + # Different off stages are non-equal + tattr1 = core.TextureAttrib.make_all_off() + tattr1 = tattr2.add_off_stage(stage1) + tattr2 = core.TextureAttrib.make() + tattr2 = tattr2.add_off_stage(stage2) + assert tattr1.compare_to(tattr2) != 0 + assert tattr2.compare_to(tattr1) != 0 + assert tattr2.compare_to(tattr1) == -tattr1.compare_to(tattr2) + + # If both have a different texture, but same stage, they are not equal + tattr1 = core.TextureAttrib.make() + tattr1 = tattr1.add_on_stage(stage1, tex1) + tattr2 = core.TextureAttrib.make() + tattr2 = tattr2.add_on_stage(stage1, tex2) + assert tattr1.compare_to(tattr2) != 0 + assert tattr2.compare_to(tattr1) != 0 + assert tattr2.compare_to(tattr1) == -tattr1.compare_to(tattr2) + + # If both have the same texture, but different stage, they are not equal + tattr1 = core.TextureAttrib.make() + tattr1 = tattr1.add_on_stage(stage1, tex1) + tattr2 = core.TextureAttrib.make() + tattr2 = tattr2.add_on_stage(stage2, tex2) + assert tattr1.compare_to(tattr2) != 0 + assert tattr2.compare_to(tattr1) != 0 + assert tattr2.compare_to(tattr1) == -tattr1.compare_to(tattr2) + + # If both have the same texture and stage, they are equal tattr1 = core.TextureAttrib.make() tattr1 = tattr1.add_on_stage(stage1, tex1) tattr2 = core.TextureAttrib.make() diff --git a/tests/pnmimage/test_pnmimage.py b/tests/pnmimage/test_pnmimage.py index 40d8a88683..7148cbf89c 100644 --- a/tests/pnmimage/test_pnmimage.py +++ b/tests/pnmimage/test_pnmimage.py @@ -70,3 +70,40 @@ def test_pnmimage_quantize(): assert col.b in (0, 1) assert max_dist < 0.1 ** 2 + +def test_pnmimage_add_sub_image(): + dst = PNMImage(2, 2) + dst.fill(0.5, 0, 0) #adding color to dst + #dst_color will store rgb values at each pixel of dst + dst_color = ((dst.get_xel(0, 0), dst.get_xel(0, 1)), (dst.get_xel(1, 0), dst.get_xel(1, 1))) + + src = PNMImage(1, 1) + src.fill(0, 0.7, 0) #adding color to src + #src_color will store rgb values at each pixel of src + src_color = src.get_xel(0, 0) + + dst.add_sub_image(src, 1, 1, 0, 0, 1, 1) + final_color = ((dst.get_xel(0, 0), dst.get_xel(0, 1)), (dst.get_xel(1, 0), dst.get_xel(1, 1))) + assert final_color[0][0] == dst_color[0][0] + assert final_color[0][1] == dst_color[0][1] + assert final_color[1][0] == dst_color[1][0] + assert final_color[1][1] == dst_color[1][1] + src_color + + +def test_pnmimage_mult_sub_image(): + dst = PNMImage(2, 2) + dst.fill(0.5, 0, 0) #adding color to dst + #dst_color will store rgb values at each pixel of dst + dst_color = ((dst.get_xel(0, 0), dst.get_xel(0, 1)), (dst.get_xel(1, 0), dst.get_xel(1, 1))) + + src = PNMImage(1, 1) + src.fill(0, 0.7, 0) #adding color to src + #src_color will store rgb values at each pixel of src + src_color = src.get_xel(0, 0) + + dst.mult_sub_image(src, 1, 1, 0, 0, 1, 1) + final_color = ((dst.get_xel(0, 0), dst.get_xel(0, 1)), (dst.get_xel(1, 0), dst.get_xel(1, 1))) + assert final_color[0][0] == dst_color[0][0] + assert final_color[0][1] == dst_color[0][1] + assert final_color[1][0] == dst_color[1][0] + assert final_color[1][1][0] == dst_color[1][1][0] * src_color[0] and final_color[1][1][1] == dst_color[1][1][1] * src_color[1] and final_color[1][1][2] == dst_color[1][1][2] * src_color[2] diff --git a/tests/putil/test_bitarray.py b/tests/putil/test_bitarray.py index 6c258dfd37..1e39600c32 100644 --- a/tests/putil/test_bitarray.py +++ b/tests/putil/test_bitarray.py @@ -1,8 +1,12 @@ -from panda3d.core import BitArray +from panda3d.core import BitArray, SparseArray import pickle import pytest +def test_bitarray_type(): + assert BitArray.get_class_type().name == "BitArray" + + def test_bitarray_constructor(): assert BitArray().is_zero() assert BitArray(0).is_zero() @@ -18,8 +22,31 @@ def test_bitarray_constructor(): assert BitArray(-10000000000000000000) +def test_bitarray_constructor_sparse(): + # Create a BitArray from a SparseArray. + ba = BitArray(SparseArray.all_on()) + assert ba.is_all_on() + + ba = BitArray(SparseArray()) + assert ba.is_zero() + + sa = SparseArray() + sa.set_range(3, 64) + sa.set_range(0, 1) + sa.clear_range(60, 2) + ba = BitArray(sa) + exp = 0b1111100111111111111111111111111111111111111111111111111111111111001 + assert ba.__getstate__() == exp + + sa.invert_in_place() + ba = BitArray(sa) + assert ba.__getstate__() == ~exp + + def test_bitarray_allon(): assert BitArray.all_on().is_all_on() + assert BitArray.all_on().get_highest_on_bit() == -1 + assert BitArray.all_on().get_highest_off_bit() == -1 def test_bitarray_nonzero(): @@ -36,6 +63,41 @@ def test_bitarray_invert(): assert ~~BitArray(123) == BitArray(123) +def test_bitarray_set_word(): + # Non-inverted + expected = 9876 | (123456 << (BitArray.num_bits_per_word * 3)) + ba = BitArray(0) + ba.set_word(0, 9876) + ba.set_word(3, 123456) + assert ba.__getstate__() == expected + assert not ba.is_all_on() + + # Inverted + ba = BitArray(0) + ba.invert_in_place() + ba.set_word(2, 1234) + full_word = (1 << BitArray.num_bits_per_word) - 1 + expected = ~((full_word & ~1234) << (BitArray.num_bits_per_word * 2)) + assert ba.__getstate__() == expected + assert not ba.is_all_on() + + +def test_bitarray_clear(): + ba = BitArray(1234) + ba.clear() + assert ba.is_zero() + assert not ba.is_all_on() + assert ba.get_highest_on_bit() == -1 + assert ba.get_highest_off_bit() == -1 + + ba = BitArray.all_on() + ba.clear() + assert ba.is_zero() + assert not ba.is_all_on() + assert ba.get_highest_on_bit() == -1 + assert ba.get_highest_off_bit() == -1 + + def test_bitarray_getstate(): assert BitArray().__getstate__() == 0 assert BitArray(0).__getstate__() == 0 diff --git a/tests/putil/test_bitmask.py b/tests/putil/test_bitmask.py index 47fb6dc7ca..9e80758d78 100644 --- a/tests/putil/test_bitmask.py +++ b/tests/putil/test_bitmask.py @@ -8,6 +8,10 @@ double_num_bits = DoubleBitMaskNative.get_max_num_bits() quad_num_bits = QuadBitMaskNative.get_max_num_bits() +def test_bitmask_type(): + assert BitMask16.get_class_type().name == "BitMask16" + + def test_bitmask_allon(): assert BitMask16.all_on().is_all_on() assert BitMask32.all_on().is_all_on() @@ -34,6 +38,13 @@ def test_bitmask_overflow(): with pytest.raises(OverflowError): QuadBitMaskNative(1 << quad_num_bits) + with pytest.raises(Exception): + DoubleBitMaskNative(-1) + + +def test_bitmask_repr(): + repr(BitMask16(0)) == ' 0000 0000 0000 0000' + def test_bitmask_int(): assert int(BitMask16()) == 0 @@ -68,3 +79,10 @@ def test_bitmask_pickle(): data = pickle.dumps(mask1, -1) mask2 = pickle.loads(data) assert mask1 == mask2 + + assert pickle.loads(pickle.dumps(DoubleBitMaskNative(0), -1)).is_zero() + + mask1 = DoubleBitMaskNative(0xffff0001) + data = pickle.dumps(mask1, -1) + mask2 = pickle.loads(data) + assert mask1 == mask2 diff --git a/tests/putil/test_buttonhandle.py b/tests/putil/test_buttonhandle.py new file mode 100644 index 0000000000..3242e06a7a --- /dev/null +++ b/tests/putil/test_buttonhandle.py @@ -0,0 +1,64 @@ +from panda3d.core import ButtonHandle +from panda3d.core import GamepadButton +from panda3d.core import KeyboardButton +from panda3d.core import MouseButton + + +def test_buttonhandle_type(): + assert ButtonHandle.get_class_type().name == "ButtonHandle" + + +def test_buttonhandle_none(): + none = ButtonHandle.none() + assert none.index == 0 + assert none.name == "none" + assert none == ButtonHandle.none() + assert none.alias == none + assert repr(none) == "none" + assert str(none) == "none" + + +def test_gamepadbutton_joystick(): + # The first one is called "trigger" + assert GamepadButton.trigger() == GamepadButton.joystick(0) + assert GamepadButton.joystick(0).name == "trigger" + + for i in range(1, 8): + btn = GamepadButton.joystick(i) + assert btn.name == "joystick" + str(i + 1) + + +def test_keyboardbutton_ascii(): + assert KeyboardButton.space() == KeyboardButton.ascii_key(' ') + assert KeyboardButton.backspace() == KeyboardButton.ascii_key('\x08') + assert KeyboardButton.tab() == KeyboardButton.ascii_key('\x09') + assert KeyboardButton.enter() == KeyboardButton.ascii_key('\x0d') + assert KeyboardButton.escape() == KeyboardButton.ascii_key('\x1b') + + assert KeyboardButton.ascii_key(' ').name == 'space' + assert KeyboardButton.ascii_key('\x08').name == 'backspace' + assert KeyboardButton.ascii_key('\x09').name == 'tab' + assert KeyboardButton.ascii_key('\x0d').name == 'enter' + assert KeyboardButton.ascii_key('\x1b').name == 'escape' + assert KeyboardButton.ascii_key('\x7f').name == 'delete' + + assert KeyboardButton.ascii_key('a').name == 'a' + + +def test_mousebutton(): + btns = [MouseButton.one(), + MouseButton.two(), + MouseButton.three(), + MouseButton.four(), + MouseButton.five()] + + for i, btn in enumerate(btns): + assert MouseButton.button(i) == btn + assert MouseButton.is_mouse_button(btn) + + assert MouseButton.button(5) == ButtonHandle.none() + + assert MouseButton.is_mouse_button(MouseButton.wheel_up()) + assert MouseButton.is_mouse_button(MouseButton.wheel_down()) + assert MouseButton.is_mouse_button(MouseButton.wheel_left()) + assert MouseButton.is_mouse_button(MouseButton.wheel_right()) diff --git a/tests/putil/test_clockobject.py b/tests/putil/test_clockobject.py index afff7f9b3e..1bb563a0ee 100644 --- a/tests/putil/test_clockobject.py +++ b/tests/putil/test_clockobject.py @@ -1,23 +1,40 @@ import time -def test_get_frame_time(clockobj): + +def test_clock_get_frame_time(clockobj): current_time = clockobj.get_frame_time() - time.sleep(2) + time.sleep(0.2) assert clockobj.get_frame_time() == current_time -def test_jump_frame_time(clockobj): + +def test_clock_jump_frame_time(clockobj): current_time = clockobj.get_frame_time() clockobj.tick() assert clockobj.get_frame_time() == current_time + clockobj.get_frame_time() -def test_get_real_time(clockobj): - current_time = clockobj.get_real_time() - time.sleep(2) - assert current_time != clockobj.get_real_time() -def test_get_dt(clockobj): +def test_clock_get_real_time(clockobj): + current_time = clockobj.get_real_time() + time.sleep(0.4) + assert clockobj.get_real_time() - current_time >= 0.4 + + +def test_clock_get_long_time(clockobj): + current_time = clockobj.get_long_time() + time.sleep(0.4) + assert clockobj.get_long_time() - current_time >= 0.4 + + +def test_clock_get_dt(clockobj): clockobj.tick() first_tick = clockobj.get_frame_time() clockobj.tick() second_tick = clockobj.get_frame_time() assert clockobj.get_dt() == second_tick - first_tick + + +def test_clock_reset(clockobj): + clockobj.reset() + assert clockobj.get_dt() == 0 + assert clockobj.get_frame_time() == 0 + assert clockobj.get_real_time() < 0.01 diff --git a/tests/putil/test_datagram.py b/tests/putil/test_datagram.py index ad8ef9857c..9b0e1d0c0a 100644 --- a/tests/putil/test_datagram.py +++ b/tests/putil/test_datagram.py @@ -1,6 +1,5 @@ import pytest from panda3d import core -import sys import tempfile # Fixtures for generating interesting datagrams (and verification functions) on @@ -84,7 +83,7 @@ def datagram_large(): return dg, readback_function -@pytest.mark.skipif(sys.version_info < (3, 0), reason="Requires Python 3") + def test_datagram_bytes(): """Tests that we can put and get a bytes object on Datagram.""" dg = core.Datagram(b'abc\x00') @@ -111,6 +110,17 @@ def test_datagram_pickle(): assert pickle.loads(pickle.dumps(dg, -1)) == dg +def test_datagram_cow(): + dg1 = core.Datagram() + dg1.append_data(b'1234') + + dg2 = core.Datagram(dg1) + dg2.append_data(b'5678') + + assert dg1.get_message() == b'1234' + assert dg2.get_message() == b'12345678' + + def test_iterator(datagram_small): """This tests Datagram/DatagramIterator, and sort of serves as a self-check of the test fixtures too.""" diff --git a/tests/putil/test_modifierbuttons.py b/tests/putil/test_modifierbuttons.py index 289966d1df..b51a64d1ed 100644 --- a/tests/putil/test_modifierbuttons.py +++ b/tests/putil/test_modifierbuttons.py @@ -33,3 +33,53 @@ def test_modifierbuttons_cow(): btns3.add_button("escape") assert tuple(btns2.buttons) == ("space",) assert tuple(btns3.buttons) == ("space", "escape") + + +def test_modifierbuttons_assign(): + # Tests assignment operator. + btns1 = ModifierButtons() + btns1.add_button("space") + + btns2 = ModifierButtons() + btns2.assign(btns1) + + assert btns1 == btns2 + assert tuple(btns1.buttons) == tuple(btns2.buttons) + + +def test_modifierbuttons_state(): + btns = ModifierButtons() + btns.add_button("alt") + btns.add_button("shift") + btns.add_button("control") + assert not btns.is_any_down() + + # Not tracked + btns.button_down("enter") + assert not btns.is_any_down() + + # Tracked + btns.button_down("shift") + assert btns.is_any_down() + assert not btns.is_down(0) + assert btns.is_down(1) + assert not btns.is_down(2) + + btns.button_up("shift") + assert not btns.is_any_down() + assert not btns.is_down(0) + assert not btns.is_down(1) + assert not btns.is_down(2) + + btns.button_down("alt") + btns.button_down("shift") + assert btns.is_any_down() + assert btns.is_down(0) + assert btns.is_down(1) + assert not btns.is_down(2) + + btns.all_buttons_up() + assert not btns.is_any_down() + assert not btns.is_down(0) + assert not btns.is_down(1) + assert not btns.is_down(2) diff --git a/tests/putil/test_sparsearray.py b/tests/putil/test_sparsearray.py index e06a7adedb..9721ad495a 100644 --- a/tests/putil/test_sparsearray.py +++ b/tests/putil/test_sparsearray.py @@ -2,6 +2,10 @@ from panda3d import core import pickle +def test_sparse_array_type(): + assert core.SparseArray.get_class_type().name == "SparseArray" + + def test_sparse_array_set_bit_to(): """Tests SparseArray behavior for set_bit_to().""" diff --git a/tests/putil/test_updateseq.py b/tests/putil/test_updateseq.py index 5cd7312595..93617aaabe 100644 --- a/tests/putil/test_updateseq.py +++ b/tests/putil/test_updateseq.py @@ -103,3 +103,10 @@ def test_updateseq_old(): assert not (seq != old) assert not (seq > old) assert not (seq < old) + + +def test_updateseq_clear(): + seq = UpdateSeq(UpdateSeq.fresh()) + seq.clear() + assert seq == UpdateSeq.initial() + assert seq.is_initial() diff --git a/tests/showbase/test_ShowBase.py b/tests/showbase/test_ShowBase.py new file mode 100644 index 0000000000..baa83cc15e --- /dev/null +++ b/tests/showbase/test_ShowBase.py @@ -0,0 +1,16 @@ +from direct.showbase.ShowBase import ShowBase +import builtins + + +def test_showbase_create_destroy(): + sb = ShowBase(windowType='none') + try: + assert builtins.base == sb + finally: + sb.destroy() + sb = None + + assert not hasattr(builtins, 'base') + assert not hasattr(builtins, 'run') + assert not hasattr(builtins, 'loader') + assert not hasattr(builtins, 'taskMgr')