diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2025-12-27 14:52:41 +0100 |
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2025-12-27 14:52:41 +0100 |
| commit | 7f5a499ccc63a10302fcc8021dcfae90ee97866f (patch) | |
| tree | eb94bd3b5e67e4c91614853c9de20b76dc1d7dc2 | |
| parent | 33a7811d24ea88c558ec03acf5e016e7c84ddefa (diff) | |
| download | pyramid-main.tar.gz pyramid-main.tar.bz2 pyramid-main.zip | |
remove pkg_resources callsmain
This is mostly based on work by luhn.
From a quick test with my pyramid project, it seems to work fine, but I
haven't tested more complex setups. At least my template renderings and
static files didn't break, and I checked a single asset override which
also worked.
| -rw-r--r-- | src/pyramid/config/assets.py | 124 | ||||
| -rw-r--r-- | src/pyramid/config/views.py | 1 | ||||
| -rw-r--r-- | src/pyramid/path.py | 36 | ||||
| -rw-r--r-- | src/pyramid/static.py | 13 | ||||
| -rw-r--r-- | tests/test_config/test_assets.py | 211 | ||||
| -rw-r--r-- | tests/test_path.py | 29 |
6 files changed, 76 insertions, 338 deletions
diff --git a/src/pyramid/config/assets.py b/src/pyramid/config/assets.py index 3c6a8d360..66a532853 100644 --- a/src/pyramid/config/assets.py +++ b/src/pyramid/config/assets.py @@ -1,93 +1,17 @@ +import importlib.resources import os -import pkg_resources import sys from zope.interface import implementer from pyramid.config.actions import action_method from pyramid.exceptions import ConfigurationError from pyramid.interfaces import PHASE1_CONFIG, IPackageOverrides -from pyramid.threadlocal import get_current_registry - - -class OverrideProvider(pkg_resources.DefaultProvider): - def __init__(self, module): - pkg_resources.DefaultProvider.__init__(self, module) - self.module_name = module.__name__ - - def _get_overrides(self): - reg = get_current_registry() - overrides = reg.queryUtility(IPackageOverrides, self.module_name) - return overrides - - def get_resource_filename(self, manager, resource_name): - """Return a true filesystem path for resource_name, - co-ordinating the extraction with manager, if the resource - must be unpacked to the filesystem. - """ - overrides = self._get_overrides() - if overrides is not None: - filename = overrides.get_filename(resource_name) - if filename is not None: - return filename - return pkg_resources.DefaultProvider.get_resource_filename( - self, manager, resource_name - ) - - def get_resource_stream(self, manager, resource_name): - """Return a readable file-like object for resource_name.""" - overrides = self._get_overrides() - if overrides is not None: - stream = overrides.get_stream(resource_name) - if stream is not None: - return stream - return pkg_resources.DefaultProvider.get_resource_stream( - self, manager, resource_name - ) - - def get_resource_string(self, manager, resource_name): - """Return a string containing the contents of resource_name.""" - overrides = self._get_overrides() - if overrides is not None: - string = overrides.get_string(resource_name) - if string is not None: - return string - return pkg_resources.DefaultProvider.get_resource_string( - self, manager, resource_name - ) - - def has_resource(self, resource_name): - overrides = self._get_overrides() - if overrides is not None: - result = overrides.has_resource(resource_name) - if result is not None: - return result - return pkg_resources.DefaultProvider.has_resource(self, resource_name) - - def resource_isdir(self, resource_name): - overrides = self._get_overrides() - if overrides is not None: - result = overrides.isdir(resource_name) - if result is not None: - return result - return pkg_resources.DefaultProvider.resource_isdir( - self, resource_name - ) - - def resource_listdir(self, resource_name): - overrides = self._get_overrides() - if overrides is not None: - result = overrides.listdir(resource_name) - if result is not None: - return result - return pkg_resources.DefaultProvider.resource_listdir( - self, resource_name - ) @implementer(IPackageOverrides) class PackageOverrides: # pkg_resources arg in kw args below for testing - def __init__(self, package, pkg_resources=pkg_resources): + def __init__(self, package): loader = self._real_loader = getattr(package, '__loader__', None) if isinstance(loader, self.__class__): self._real_loader = None @@ -102,9 +26,6 @@ class PackageOverrides: # A __loader__ attribute is basically metadata, and setuptools # uses it as such. package.__loader__ = self - # we call register_loader_type for every instantiation of this - # class; that's OK, it's idempotent to do it more than once. - pkg_resources.register_loader_type(self.__class__, OverrideProvider) self.overrides = [] self.overridden_package_name = package.__name__ @@ -226,43 +147,60 @@ class PackageAssetSource: self.pkg_name = package self.prefix = prefix + def _exists(self, path): + res = importlib.resources.files(self.pkg_name).joinpath(path) + return res.is_dir() or res.is_file() + def get_path(self, resource_name): return f'{self.prefix}{resource_name}' def get_spec(self, resource_name): path = self.get_path(resource_name) - if pkg_resources.resource_exists(self.pkg_name, path): + if self._exists(path): return f'{self.pkg_name}:{path}' def get_filename(self, resource_name): path = self.get_path(resource_name) - if pkg_resources.resource_exists(self.pkg_name, path): - return pkg_resources.resource_filename(self.pkg_name, path) + # resource_filename doesn't work for .zip files, so it's fine to not + # mimic it + if self._exists(path): + with importlib.resources.path(self.pkg_name, path) as fname: + return str(fname) def get_stream(self, resource_name): path = self.get_path(resource_name) - if pkg_resources.resource_exists(self.pkg_name, path): - return pkg_resources.resource_stream(self.pkg_name, path) + if self._exists(path): + return importlib.resources.open_binary(self.pkg_name, path) def get_string(self, resource_name): path = self.get_path(resource_name) - if pkg_resources.resource_exists(self.pkg_name, path): - return pkg_resources.resource_string(self.pkg_name, path) + if self._exists(path): + return importlib.resources.read_binary(self.pkg_name, path) def exists(self, resource_name): path = self.get_path(resource_name) - if pkg_resources.resource_exists(self.pkg_name, path): + # exists() returns True or None, not True or False + if self._exists(path): return True def isdir(self, resource_name): path = self.get_path(resource_name) - if pkg_resources.resource_exists(self.pkg_name, path): - return pkg_resources.resource_isdir(self.pkg_name, path) + res = importlib.resources.files(self.pkg_name).joinpath(path) + if res.is_dir(): + return True + elif res.is_file(): + return False + return None def listdir(self, resource_name): path = self.get_path(resource_name) - if pkg_resources.resource_exists(self.pkg_name, path): - return pkg_resources.resource_listdir(self.pkg_name, path) + if self._exists(path): + return [ + resource.name + for resource in importlib.resources.files(self.pkg_name) + .joinpath(path) + .iterdir() + ] class FSAssetSource: diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index 302704c3e..7769ceef9 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -2,7 +2,6 @@ import functools import inspect import operator import os -import posixpath from urllib.parse import quote, urljoin, urlparse, urlunparse import warnings from webob.acceptparse import Accept diff --git a/src/pyramid/path.py b/src/pyramid/path.py index 3bc87b5f3..b3568748d 100644 --- a/src/pyramid/path.py +++ b/src/pyramid/path.py @@ -4,8 +4,8 @@ import functools from importlib.machinery import SOURCE_SUFFIXES import importlib.resources import os -import pkg_resources import sys +import zipfile from zope.interface import implementer from pyramid.interfaces import IAssetDescriptor @@ -118,8 +118,6 @@ CALLER_PACKAGE = _CALLER_PACKAGE() @implementer(IAssetDescriptor) class PkgResourcesAssetDescriptor: - pkg_resources = pkg_resources - def __init__(self, pkg_name, path, overrides=None): self.pkg_name = pkg_name self.path = path @@ -134,10 +132,14 @@ class PkgResourcesAssetDescriptor: else: filename = None if filename is None: - filename = self.pkg_resources.resource_filename( - self.pkg_name, - self.path, - ) + # pkg_resources.resource_filename is not supported for .zip files, + # so we don't need to provide a workaround here. + files = importlib.resources.files(self.pkg_name) + if isinstance(files, zipfile.Path): + raise NotImplementedError("abspath() not supported for .zip") + res = files.joinpath(self.path) + with importlib.resources.as_file(res) as path: + filename = str(path) return os.path.abspath(filename) def stream(self): @@ -145,28 +147,40 @@ class PkgResourcesAssetDescriptor: stream = self.overrides.get_stream(self.path) if stream is not None: return stream - return self.pkg_resources.resource_stream(self.pkg_name, self.path) + return importlib.resources.open_binary(self.pkg_name, self.path) def isdir(self): if self.overrides is not None: result = self.overrides.isdir(self.path) if result is not None: return result - return self.pkg_resources.resource_isdir(self.pkg_name, self.path) + return ( + importlib.resources.files(self.pkg_name) + .joinpath(self.path) + .is_dir() + ) def listdir(self): if self.overrides is not None: result = self.overrides.listdir(self.path) if result is not None: return result - return self.pkg_resources.resource_listdir(self.pkg_name, self.path) + return [ + resource.name + for resource in importlib.resources.files(self.pkg_name) + .joinpath(self.path) + .iterdir() + ] def exists(self): if self.overrides is not None: result = self.overrides.exists(self.path) if result is not None: return result - return self.pkg_resources.resource_exists(self.pkg_name, self.path) + # Cannot use importlib.resources.is_resource because it does not + # consider directories to be resources. + resource = importlib.resources.files(self.pkg_name).joinpath(self.path) + return resource.is_file() or resource.is_dir() @implementer(IAssetDescriptor) diff --git a/src/pyramid/static.py b/src/pyramid/static.py index 4091bbfbc..e19fcf654 100644 --- a/src/pyramid/static.py +++ b/src/pyramid/static.py @@ -1,9 +1,9 @@ from functools import lru_cache +import importlib.resources import json import mimetypes import os from os.path import exists, getmtime, getsize, isdir, join, normcase, normpath -from pkg_resources import resource_exists, resource_filename, resource_isdir import warnings from pyramid.asset import abspath_from_asset_spec, resolve_asset_spec @@ -153,7 +153,10 @@ class static_view: # normalize asset spec or fs path into resource_path if self.package_name: # package resource resource_path = '{}/{}'.format(self.docroot.rstrip('/'), path) - if resource_isdir(self.package_name, resource_path): + res = importlib.resources.files(self.package_name).joinpath( + resource_path + ) + if res.is_dir(): if not request.path_url.endswith('/'): raise self.add_slash_redirect(request) resource_path = '{}/{}'.format( @@ -178,8 +181,10 @@ class static_view: """ if self.package_name: - if resource_exists(self.package_name, name): - return resource_filename(self.package_name, name) + res = importlib.resources.files(self.package_name).joinpath(name) + if res.is_file(): + with importlib.resources.as_file(res) as fname: + return str(fname) elif exists(name): return name diff --git a/tests/test_config/test_assets.py b/tests/test_config/test_assets.py index ea2fff741..0125f73c2 100644 --- a/tests/test_config/test_assets.py +++ b/tests/test_config/test_assets.py @@ -1,8 +1,6 @@ import os.path import unittest -from pyramid.testing import cleanUp - # we use this folder here = os.path.dirname(os.path.abspath(__file__)) @@ -327,212 +325,17 @@ class TestAssetsConfiguratorMixin(unittest.TestCase): self.assertEqual(overrides.package, package) -class TestOverrideProvider(unittest.TestCase): - def setUp(self): - cleanUp() - - def tearDown(self): - cleanUp() - - def _getTargetClass(self): - from pyramid.config.assets import OverrideProvider - - return OverrideProvider - - def _makeOne(self, module): - klass = self._getTargetClass() - return klass(module) - - def _registerOverrides(self, overrides, name='tests.test_config'): - from pyramid.interfaces import IPackageOverrides - from pyramid.threadlocal import get_current_registry - - reg = get_current_registry() - reg.registerUtility(overrides, IPackageOverrides, name=name) - - def test_get_resource_filename_no_overrides(self): - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - expected = os.path.join(here, resource_name) - result = provider.get_resource_filename(None, resource_name) - self.assertEqual(result, expected) - - def test_get_resource_stream_no_overrides(self): - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - with provider.get_resource_stream(None, resource_name) as result: - _assertBody(result.read(), os.path.join(here, resource_name)) - - def test_get_resource_string_no_overrides(self): - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.get_resource_string(None, resource_name) - _assertBody(result, os.path.join(here, resource_name)) - - def test_has_resource_no_overrides(self): - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.has_resource(resource_name) - self.assertEqual(result, True) - - def test_resource_isdir_no_overrides(self): - file_resource_name = 'test_assets.py' - directory_resource_name = 'files' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.resource_isdir(file_resource_name) - self.assertEqual(result, False) - result = provider.resource_isdir(directory_resource_name) - self.assertEqual(result, True) - - def test_resource_listdir_no_overrides(self): - resource_name = 'files' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.resource_listdir(resource_name) - self.assertTrue(result) - - def test_get_resource_filename_override_returns_None(self): - overrides = DummyOverrides(None) - self._registerOverrides(overrides) - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - expected = os.path.join(here, resource_name) - result = provider.get_resource_filename(None, resource_name) - self.assertEqual(result, expected) - - def test_get_resource_stream_override_returns_None(self): - overrides = DummyOverrides(None) - self._registerOverrides(overrides) - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - with provider.get_resource_stream(None, resource_name) as result: - _assertBody(result.read(), os.path.join(here, resource_name)) - - def test_get_resource_string_override_returns_None(self): - overrides = DummyOverrides(None) - self._registerOverrides(overrides) - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.get_resource_string(None, resource_name) - _assertBody(result, os.path.join(here, resource_name)) - - def test_has_resource_override_returns_None(self): - overrides = DummyOverrides(None) - self._registerOverrides(overrides) - resource_name = 'test_assets.py' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.has_resource(resource_name) - self.assertEqual(result, True) - - def test_resource_isdir_override_returns_None(self): - overrides = DummyOverrides(None) - self._registerOverrides(overrides) - resource_name = 'files' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.resource_isdir(resource_name) - self.assertEqual(result, True) - - def test_resource_listdir_override_returns_None(self): - overrides = DummyOverrides(None) - self._registerOverrides(overrides) - resource_name = 'files' - import tests.test_config - - provider = self._makeOne(tests.test_config) - result = provider.resource_listdir(resource_name) - self.assertTrue(result) - - def test_get_resource_filename_override_returns_value(self): - overrides = DummyOverrides('value') - import tests.test_config - - self._registerOverrides(overrides) - provider = self._makeOne(tests.test_config) - result = provider.get_resource_filename(None, 'test_assets.py') - self.assertEqual(result, 'value') - - def test_get_resource_stream_override_returns_value(self): - from io import BytesIO - - overrides = DummyOverrides(BytesIO(b'value')) - import tests.test_config - - self._registerOverrides(overrides) - provider = self._makeOne(tests.test_config) - with provider.get_resource_stream(None, 'test_assets.py') as stream: - self.assertEqual(stream.getvalue(), b'value') - - def test_get_resource_string_override_returns_value(self): - overrides = DummyOverrides('value') - import tests.test_config - - self._registerOverrides(overrides) - provider = self._makeOne(tests.test_config) - result = provider.get_resource_string(None, 'test_assets.py') - self.assertEqual(result, 'value') - - def test_has_resource_override_returns_True(self): - overrides = DummyOverrides(True) - import tests.test_config - - self._registerOverrides(overrides) - provider = self._makeOne(tests.test_config) - result = provider.has_resource('test_assets.py') - self.assertEqual(result, True) - - def test_resource_isdir_override_returns_False(self): - overrides = DummyOverrides(False) - import tests.test_config - - self._registerOverrides(overrides) - provider = self._makeOne(tests.test_config) - result = provider.resource_isdir('files') - self.assertEqual(result, False) - - def test_resource_listdir_override_returns_values(self): - overrides = DummyOverrides(['a']) - import tests.test_config - - self._registerOverrides(overrides) - provider = self._makeOne(tests.test_config) - result = provider.resource_listdir('files') - self.assertEqual(result, ['a']) - - class TestPackageOverrides(unittest.TestCase): def _getTargetClass(self): from pyramid.config.assets import PackageOverrides return PackageOverrides - def _makeOne(self, package=None, pkg_resources=None): + def _makeOne(self, package=None): if package is None: package = DummyPackage('package') klass = self._getTargetClass() - if pkg_resources is None: - pkg_resources = DummyPkgResources() - return klass(package, pkg_resources=pkg_resources) + return klass(package) def test_class_conforms_to_IPackageOverrides(self): from zope.interface.verify import verifyClass @@ -580,16 +383,6 @@ class TestPackageOverrides(unittest.TestCase): po = self._makeOne(package) self.assertEqual(package.__loader__, po) - def test_ctor_registers_loader_type(self): - from pyramid.config.assets import OverrideProvider - - dummy_pkg_resources = DummyPkgResources() - package = DummyPackage('package') - po = self._makeOne(package, dummy_pkg_resources) - self.assertEqual( - dummy_pkg_resources.registered, [(po.__class__, OverrideProvider)] - ) - def test_ctor_sets_local_state(self): package = DummyPackage('package') po = self._makeOne(package) diff --git a/tests/test_path.py b/tests/test_path.py index f93b0ae90..12c0d4a64 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -259,34 +259,23 @@ class TestPkgResourcesAssetDescriptor(unittest.TestCase): def test_stream(self): inst = self._makeOne() - inst.pkg_resources = DummyPkgResource() - inst.pkg_resources.resource_stream = lambda x, y: f'{x}:{y}' - s = inst.stream() - self.assertEqual(s, '{}:{}'.format('tests', 'test_asset.py')) + stream = inst.stream() + data = stream.read(9) + self.assertEqual(data, b"import os") def test_isdir(self): inst = self._makeOne() - inst.pkg_resources = DummyPkgResource() - inst.pkg_resources.resource_isdir = lambda x, y: f'{x}:{y}' - self.assertEqual( - inst.isdir(), '{}:{}'.format('tests', 'test_asset.py') - ) + self.assertEqual(inst.isdir(), False) def test_listdir(self): - inst = self._makeOne() - inst.pkg_resources = DummyPkgResource() - inst.pkg_resources.resource_listdir = lambda x, y: f'{x}:{y}' - self.assertEqual( - inst.listdir(), '{}:{}'.format('tests', 'test_asset.py') - ) + inst = self._makeOne(path="") + content = inst.listdir() + self.assertIn("test_asset.py", content) + self.assertNotIn("test_foobardou", content) def test_exists(self): inst = self._makeOne() - inst.pkg_resources = DummyPkgResource() - inst.pkg_resources.resource_exists = lambda x, y: f'{x}:{y}' - self.assertEqual( - inst.exists(), '{}:{}'.format('tests', 'test_asset.py') - ) + self.assertEqual(inst.exists(), True) class TestFSAssetDescriptor(unittest.TestCase): |
