mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 00:06:44 -04:00
showbase: Switch Loader entry point detection to importlib.metadata
Only in Python 3.8 and up, where this module is available, otherwise it falls back to pkg_resources Add unit test for custom entry point loaders
This commit is contained in:
parent
c77697a2c0
commit
c1c035d5c9
@ -8,6 +8,7 @@ from panda3d.core import *
|
|||||||
from panda3d.core import Loader as PandaLoader
|
from panda3d.core import Loader as PandaLoader
|
||||||
from direct.directnotify.DirectNotifyGlobal import *
|
from direct.directnotify.DirectNotifyGlobal import *
|
||||||
from direct.showbase.DirectObject import DirectObject
|
from direct.showbase.DirectObject import DirectObject
|
||||||
|
import sys
|
||||||
|
|
||||||
# You can specify a phaseChecker callback to check
|
# You can specify a phaseChecker callback to check
|
||||||
# a modelPath to see if it is being loaded in the correct
|
# a modelPath to see if it is being loaded in the correct
|
||||||
@ -167,16 +168,25 @@ class Loader(DirectObject):
|
|||||||
if not ConfigVariableBool('loader-support-entry-points', True):
|
if not ConfigVariableBool('loader-support-entry-points', True):
|
||||||
return
|
return
|
||||||
|
|
||||||
import importlib
|
if sys.version_info >= (3, 8):
|
||||||
try:
|
from importlib.metadata import entry_points
|
||||||
pkg_resources = importlib.import_module('pkg_resources')
|
eps = entry_points()
|
||||||
except ImportError:
|
if isinstance(eps, dict): # Python 3.8 and 3.9
|
||||||
pkg_resources = None
|
loaders = eps.get('panda3d.loaders', ())
|
||||||
|
else:
|
||||||
|
loaders = entry_points().select(group='panda3d.loaders')
|
||||||
|
else:
|
||||||
|
import importlib
|
||||||
|
try:
|
||||||
|
pkg_resources = importlib.import_module('pkg_resources')
|
||||||
|
loaders = pkg_resources.iter_entry_points('panda3d.loaders')
|
||||||
|
except ImportError:
|
||||||
|
loaders = ()
|
||||||
|
|
||||||
if pkg_resources:
|
if loaders:
|
||||||
registry = LoaderFileTypeRegistry.getGlobalPtr()
|
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)
|
registry.register_deferred_type(entry_point)
|
||||||
|
|
||||||
cls._loadedPythonFileTypes = True
|
cls._loadedPythonFileTypes = True
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from panda3d.core import Filename, NodePath
|
from panda3d.core import Filename, NodePath, LoaderFileTypeRegistry
|
||||||
from direct.showbase.Loader import Loader
|
from direct.showbase.Loader import Loader
|
||||||
import pytest
|
import pytest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -68,3 +69,105 @@ def test_load_model_missing(loader):
|
|||||||
def test_load_model_okmissing(loader):
|
def test_load_model_okmissing(loader):
|
||||||
model = loader.load_model('/nonexistent.bam', okMissing=True)
|
model = loader.load_model('/nonexistent.bam', okMissing=True)
|
||||||
assert model is None
|
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)
|
||||||
|
|
||||||
|
if sys.version_info < (3, 8):
|
||||||
|
# Older Python versions don't have importlib.metadata, so we rely on
|
||||||
|
# pkg_resources - but this caches the results once. Fortunately, it
|
||||||
|
# provides this function for reinitializing the cached entry points.
|
||||||
|
# See pypa/setuptools#373
|
||||||
|
pkg_resources = pytest.importorskip("pkg_resources")
|
||||||
|
if not hasattr(pkg_resources, "_initialize_master_working_set"):
|
||||||
|
pytest.skip("pkg_resources too old")
|
||||||
|
|
||||||
|
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]
|
||||||
|
if sys.version_info < (3, 8):
|
||||||
|
pkg_resources._initialize_master_working_set()
|
||||||
|
|
||||||
|
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 = loader.load_model(model_path)
|
||||||
|
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)
|
||||||
|
|
||||||
|
if sys.version_info < (3, 8):
|
||||||
|
pkg_resources._initialize_master_working_set()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user