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')