summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pyramid/config/assets.py124
-rw-r--r--src/pyramid/config/views.py1
-rw-r--r--src/pyramid/path.py36
-rw-r--r--src/pyramid/static.py13
-rw-r--r--tests/test_config/test_assets.py211
-rw-r--r--tests/test_path.py29
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):