fix: vendor minimal pkg_resources shim so pyramid survives setuptools>=81
setuptools 81 removed pkg_resources from its distribution. pyramid 2.0.x (and 2.1) still does `import pkg_resources`. When setuptools 82.0.1 landed in /opt/remarkbox/env, pyramid failed to import, all three uwsgi services on origin crash-looped, and my.remarkbox.com / meta.remarkbox.com / foxhop.net / westworld2.com served 502. remarkbox/_vendor/pkg_resources/__init__.py is a 115-line shim backed by importlib.resources (stdlib only — no setuptools, no jaraco.text, no platformdirs). Exposes exactly the surface pyramid uses: resource_filename / resource_stream / resource_string / resource_exists / resource_isdir / resource_listdir / DefaultProvider / register_loader_type. remarkbox/__init__.py prepends our _vendor dir to sys.path before the first pyramid import so `import pkg_resources` always finds our shim, regardless of which setuptools is installed. Bleeding-edge friendly: upstream setuptools removals can no longer break us. 558 tests pass.
This commit is contained in:
parent
05f51ff965
commit
112d3fd3b1
3 changed files with 125 additions and 0 deletions
|
|
@ -1,3 +1,13 @@
|
|||
# Vendored pkg_resources shim: setuptools 81 dropped pkg_resources, but pyramid
|
||||
# still imports it. Inject our _vendor dir into sys.path BEFORE the pyramid
|
||||
# import below so `import pkg_resources` finds our shim. See
|
||||
# remarkbox/_vendor/pkg_resources/__init__.py.
|
||||
import os as _rb_os
|
||||
import sys as _rb_sys
|
||||
_rb_vendor = _rb_os.path.join(_rb_os.path.dirname(__file__), "_vendor")
|
||||
if _rb_vendor not in _rb_sys.path:
|
||||
_rb_sys.path.insert(0, _rb_vendor)
|
||||
|
||||
from pyramid.config import Configurator
|
||||
|
||||
from sqlalchemy import engine_from_config
|
||||
|
|
|
|||
0
remarkbox/_vendor/__init__.py
Normal file
0
remarkbox/_vendor/__init__.py
Normal file
115
remarkbox/_vendor/pkg_resources/__init__.py
Normal file
115
remarkbox/_vendor/pkg_resources/__init__.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
"""
|
||||
Minimal vendored pkg_resources shim for Remarkbox.
|
||||
|
||||
setuptools 81 dropped pkg_resources from its distribution. Pyramid (and a
|
||||
handful of other libraries) still import it. This shim provides the narrow
|
||||
surface pyramid actually uses, backed entirely by stdlib (importlib.resources,
|
||||
importlib.import_module). No setuptools coupling, no jaraco.text, no
|
||||
platformdirs. Bleeding-edge friendly.
|
||||
|
||||
Surface (only what pyramid touches):
|
||||
resource_filename(package, name) -> str
|
||||
resource_stream(package, name) -> IO[bytes]
|
||||
resource_string(package, name) -> bytes
|
||||
resource_exists(package, name) -> bool
|
||||
resource_isdir(package, name) -> bool
|
||||
resource_listdir(package, name) -> list[str]
|
||||
DefaultProvider -- class, subclassable
|
||||
register_loader_type -- no-op registry stub
|
||||
|
||||
If a future dependency needs more of the legacy pkg_resources API, extend
|
||||
this file. Do not pull in upstream setuptools' pkg_resources/__init__.py
|
||||
(3700 lines + jaraco.text + platformdirs); that defeats the point.
|
||||
"""
|
||||
|
||||
import os
|
||||
from importlib.resources import files
|
||||
|
||||
|
||||
def _ref(package, name=""):
|
||||
if not isinstance(package, str):
|
||||
package = package.__name__
|
||||
ref = files(package)
|
||||
if name:
|
||||
ref = ref / name
|
||||
return ref
|
||||
|
||||
|
||||
def resource_filename(package, name):
|
||||
return str(_ref(package, name))
|
||||
|
||||
|
||||
def resource_stream(package, name):
|
||||
return _ref(package, name).open("rb")
|
||||
|
||||
|
||||
def resource_string(package, name):
|
||||
return _ref(package, name).read_bytes()
|
||||
|
||||
|
||||
def resource_exists(package, name):
|
||||
try:
|
||||
ref = _ref(package, name)
|
||||
except (FileNotFoundError, ModuleNotFoundError):
|
||||
return False
|
||||
try:
|
||||
return ref.is_file() or ref.is_dir()
|
||||
except (FileNotFoundError, NotADirectoryError):
|
||||
return False
|
||||
|
||||
|
||||
def resource_isdir(package, name):
|
||||
try:
|
||||
return _ref(package, name).is_dir()
|
||||
except (FileNotFoundError, ModuleNotFoundError, NotADirectoryError):
|
||||
return False
|
||||
|
||||
|
||||
def resource_listdir(package, name):
|
||||
try:
|
||||
return [child.name for child in _ref(package, name).iterdir()]
|
||||
except (FileNotFoundError, ModuleNotFoundError, NotADirectoryError):
|
||||
return []
|
||||
|
||||
|
||||
class DefaultProvider:
|
||||
"""Minimal stand-in for pkg_resources.DefaultProvider.
|
||||
|
||||
Pyramid subclasses this to wire its asset-override system. The `manager`
|
||||
arg in get_resource_* (originally a ResourceManager for zip-egg cache
|
||||
extraction) is unused — modern pip installs are unpacked directories.
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.module_path = None
|
||||
if getattr(module, "__file__", None):
|
||||
self.module_path = os.path.dirname(module.__file__)
|
||||
|
||||
def _name(self):
|
||||
return self.module.__name__
|
||||
|
||||
def get_resource_filename(self, manager, resource_name):
|
||||
return resource_filename(self._name(), resource_name)
|
||||
|
||||
def get_resource_stream(self, manager, resource_name):
|
||||
return resource_stream(self._name(), resource_name)
|
||||
|
||||
def get_resource_string(self, manager, resource_name):
|
||||
return resource_string(self._name(), resource_name)
|
||||
|
||||
def has_resource(self, resource_name):
|
||||
return resource_exists(self._name(), resource_name)
|
||||
|
||||
def resource_isdir(self, resource_name):
|
||||
return resource_isdir(self._name(), resource_name)
|
||||
|
||||
def resource_listdir(self, resource_name):
|
||||
return resource_listdir(self._name(), resource_name)
|
||||
|
||||
|
||||
_LOADER_TYPES = {}
|
||||
|
||||
|
||||
def register_loader_type(loader_class, provider_class):
|
||||
_LOADER_TYPES[loader_class] = provider_class
|
||||
Loading…
Add table
Add a link
Reference in a new issue