diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 326e8a2873..8d95999728 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,16 +120,16 @@ jobs: uses: actions/cache@v1 with: path: thirdparty - key: ci-cmake-${{ runner.OS }}-thirdparty-v1.10.13-r1 + key: ci-cmake-${{ runner.OS }}-thirdparty-v1.10.14-r1 - name: Install dependencies (Windows) if: runner.os == 'Windows' shell: powershell run: | if (!(Test-Path thirdparty/win-libs-vc14-x64)) { $wc = New-Object System.Net.WebClient - $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-win64.zip", "thirdparty-tools.zip") + $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-win64.zip", "thirdparty-tools.zip") Expand-Archive -Path thirdparty-tools.zip - Move-Item -Path thirdparty-tools/panda3d-1.10.13/thirdparty -Destination . + Move-Item -Path thirdparty-tools/panda3d-1.10.14/thirdparty -Destination . } - name: ccache (non-Windows) @@ -308,6 +308,38 @@ jobs: $PYTHON_EXECUTABLE -m pytest ../tests --cov=. # END B + - name: Setup Python (Python 3.12) + if: contains(matrix.python, 'YES') + uses: actions/setup-python@v4 + with: + python-version: '3.12' + - name: Configure (Python 3.12) + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + run: > + cmake -DWANT_PYTHON_VERSION=3.12 -DHAVE_PYTHON=YES + -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" . + - name: Build (Python 3.12) + if: contains(matrix.python, 'YES') + # BEGIN A + working-directory: build + run: cmake --build . --config ${{ matrix.config }} --parallel 4 + # END A + - name: Test (Python 3.12) + # 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 -r ../requirements-test.txt + export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw + $PYTHON_EXECUTABLE -m pytest ../tests --cov=. + # END B + - name: Upload coverage reports if: always() && matrix.config == 'Coverage' working-directory: build @@ -343,9 +375,9 @@ jobs: shell: powershell run: | $wc = New-Object System.Net.WebClient - $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-win64.zip", "thirdparty-tools.zip") + $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-win64.zip", "thirdparty-tools.zip") Expand-Archive -Path thirdparty-tools.zip - Move-Item -Path thirdparty-tools/panda3d-1.10.13/thirdparty -Destination . + Move-Item -Path thirdparty-tools/panda3d-1.10.14/thirdparty -Destination . - name: Get thirdparty packages (macOS) if: runner.os == 'macOS' run: | @@ -356,21 +388,18 @@ jobs: (cd thirdparty/darwin-libs-a && rm -rf rocket) - name: Set up Python 3.12 - if: matrix.os != 'windows-2019' uses: actions/setup-python@v4 with: python-version: '3.12' - name: Build Python 3.12 - if: matrix.os != 'windows-2019' shell: bash run: | python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 - name: Test Python 3.12 - if: matrix.os != 'windows-2019' shell: bash run: | python -m pip install -r requirements-test.txt - PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.11 uses: actions/setup-python@v4 @@ -384,7 +413,7 @@ jobs: shell: bash run: | python -m pip install -r requirements-test.txt - PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.10 uses: actions/setup-python@v4 @@ -398,7 +427,7 @@ jobs: shell: bash run: | python -m pip install -r requirements-test.txt - PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.9 uses: actions/setup-python@v4 @@ -412,7 +441,7 @@ jobs: shell: bash run: | python -m pip install -r requirements-test.txt - PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.8 uses: actions/setup-python@v4 @@ -426,7 +455,7 @@ jobs: shell: bash run: | python -m pip install -r requirements-test.txt - PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Make installer run: | diff --git a/README.md b/README.md index 2d9a2f4519..2f474e6c64 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,8 @@ depending on whether you are on a 32-bit or 64-bit system, or you can [click here](https://github.com/rdb/panda3d-thirdparty) for instructions on building them from source. -- https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-win64.zip -- https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-win32.zip +- https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-win64.zip +- https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-win32.zip After acquiring these dependencies, you can build Panda3D from the command prompt using the following command. Change the `--msvc-version` option based diff --git a/direct/src/showbase/Loader.py b/direct/src/showbase/Loader.py index 3aad55647a..b43b2adb45 100644 --- a/direct/src/showbase/Loader.py +++ b/direct/src/showbase/Loader.py @@ -151,16 +151,17 @@ class Loader(DirectObject): if not ConfigVariableBool('loader-support-entry-points', True): return - import importlib - try: - pkg_resources = importlib.import_module('pkg_resources') - except ImportError: - pkg_resources = None + from importlib.metadata import entry_points + eps = entry_points() + if isinstance(eps, dict): # Python 3.8 and 3.9 + loaders = eps.get('panda3d.loaders', ()) + else: + loaders = entry_points().select(group='panda3d.loaders') - if pkg_resources: + if loaders: registry = LoaderFileTypeRegistry.getGlobalPtr() - for entry_point in pkg_resources.iter_entry_points('panda3d.loaders'): + for entry_point in loaders: registry.register_deferred_type(entry_point) cls._loadedPythonFileTypes = True diff --git a/panda/src/tinydisplay/zmath.h b/panda/src/tinydisplay/zmath.h index 5296a8ad06..73fae86d6c 100644 --- a/panda/src/tinydisplay/zmath.h +++ b/panda/src/tinydisplay/zmath.h @@ -1,6 +1,8 @@ #ifndef __ZMATH__ #define __ZMATH__ +#include "numeric_types.h" + /* Matrix & Vertex */ typedef struct { diff --git a/setup.cfg b/setup.cfg index 50078db334..c51eeef48f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -37,3 +37,4 @@ project_urls = [tool:pytest] testpaths = tests +norecursedirs = *.egg .* _darcs build CVS node_modules venv {arch} diff --git a/tests/dist/test_FreezeTool.py b/tests/dist/test_FreezeTool.py index 32ae5fd2bc..9484e45451 100644 --- a/tests/dist/test_FreezeTool.py +++ b/tests/dist/test_FreezeTool.py @@ -1,5 +1,9 @@ from direct.dist.FreezeTool import Freezer, PandaModuleFinder +import pytest +import os import sys +import subprocess +import platform def test_Freezer_moduleSuffixes(): @@ -56,3 +60,47 @@ def test_Freezer_getModulePath_getModuleStar(tmp_path): assert freezer.getModuleStar("module2") == None finally: sys.path = backup + + +@pytest.mark.parametrize("use_console", (False, True)) +def test_Freezer_generateRuntimeFromStub(tmp_path, use_console): + try: + # If installed as a wheel + import panda3d_tools + bin_dir = os.path.dirname(panda3d_tools.__file__) + except: + import panda3d + bin_dir = os.path.join(os.path.dirname(os.path.dirname(panda3d.__file__)), 'bin') + + if sys.platform == 'win32': + suffix = '.exe' + else: + suffix = '' + + if not use_console: + stub_file = os.path.join(bin_dir, 'deploy-stubw' + suffix) + + if use_console or not os.path.isfile(stub_file): + stub_file = os.path.join(bin_dir, 'deploy-stub' + suffix) + + if not os.path.isfile(stub_file): + pytest.skip("Unable to find deploy-stub executable") + + target = str(tmp_path / ('stubtest' + suffix)) + + freezer = Freezer() + freezer.addModule('module2', filename='module2.py', text='print("Module imported")') + freezer.addModule('__main__', filename='main.py', text='import module2\nprint("Hello world")') + assert '__main__' in freezer.modules + + freezer.done(addStartupModules=True) + assert '__main__' in dict(freezer.getModuleDefs()) + + freezer.generateRuntimeFromStub(target, open(stub_file, 'rb'), use_console) + + if sys.platform == 'darwin' and platform.machine().lower() == 'arm64': + # Not supported; see #1348 + return + + output = subprocess.check_output(target) + assert output.replace(b'\r\n', b'\n') == b'Module imported\nHello world\n' diff --git a/tests/requirements.txt b/tests/requirements.txt index 3bc9b3f390..1019c223b6 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,2 +1,3 @@ pytest==3.2.0 panda3d +setuptools diff --git a/tests/showbase/test_Loader.py b/tests/showbase/test_Loader.py index 0dadecb384..dbbe78e8e8 100644 --- a/tests/showbase/test_Loader.py +++ b/tests/showbase/test_Loader.py @@ -1,6 +1,7 @@ -from panda3d.core import Filename, NodePath +from panda3d.core import Filename, NodePath, LoaderFileTypeRegistry from direct.showbase.Loader import Loader import pytest +import sys @pytest.fixture @@ -68,3 +69,93 @@ def test_load_model_missing(loader): def test_load_model_okmissing(loader): model = loader.load_model('/nonexistent.bam', okMissing=True) assert model is None + + +def test_loader_entry_points(tmp_path): + # A dummy loader for .fnrgl files. + (tmp_path / "fnargle.py").write_text(""" +from panda3d.core import ModelRoot +import sys + +sys._fnargle_loaded = True + +class FnargleLoader: + name = "Fnargle" + extensions = ['fnrgl'] + supports_compressed = False + + @staticmethod + def load_file(path, options, record=None): + return ModelRoot("fnargle") +""") + (tmp_path / "fnargle.dist-info").mkdir() + (tmp_path / "fnargle.dist-info" / "METADATA").write_text(""" +Metadata-Version: 2.0 +Name: fnargle +Version: 1.0.0 +""") + (tmp_path / "fnargle.dist-info" / "entry_points.txt").write_text(""" +[panda3d.loaders] +fnrgl = fnargle:FnargleLoader +""") + + model_path = tmp_path / "test.fnrgl" + model_path.write_text("") + + if sys.version_info >= (3, 11): + import sysconfig + stdlib = sysconfig.get_path("stdlib") + platstdlib = sysconfig.get_path("platstdlib") + else: + from distutils import sysconfig + stdlib = sysconfig.get_python_lib(False, True) + platstdlib = sysconfig.get_python_lib(True, True) + + registry = LoaderFileTypeRegistry.get_global_ptr() + prev_loaded = Loader._loadedPythonFileTypes + prev_path = sys.path + file_type = None + try: + # We do this so we don't re-register thirdparty loaders + sys.path = [str(tmp_path), platstdlib, stdlib] + + Loader._loadedPythonFileTypes = False + + # base parameter is only used for audio + loader = Loader(None) + assert Loader._loadedPythonFileTypes + + # Should be registered, not yet loaded + file_type = registry.get_type_from_extension('fnrgl') + assert file_type is not None + assert not hasattr(sys, '_fnargle_loaded') + + assert file_type.supports_load() + assert not file_type.supports_save() + assert not file_type.supports_compressed() + assert file_type.get_extension() == 'fnrgl' + + # The above should have caused it to load + assert sys._fnargle_loaded + assert 'fnargle' in sys.modules + + # Now try loading a fnargle file + model_fn = Filename(model_path) + model_fn.make_true_case() + model = loader.load_model(model_fn, noCache=True) + assert model is not None + assert model.name == "fnargle" + + finally: + # Set everything back to what it was + Loader._loadedPythonFileTypes = prev_loaded + sys.path = prev_path + + if hasattr(sys, '_fnargle_loaded'): + del sys._fnargle_loaded + + if 'fnargle' in sys.modules: + del sys.modules['fnargle'] + + if file_type is not None: + registry.unregister_type(file_type)