diff --git a/remarkbox/__init__.py b/remarkbox/__init__.py index 92cbc40..a146f33 100644 --- a/remarkbox/__init__.py +++ b/remarkbox/__init__.py @@ -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 diff --git a/remarkbox/_vendor/__init__.py b/remarkbox/_vendor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/remarkbox/_vendor/pkg_resources/__init__.py b/remarkbox/_vendor/pkg_resources/__init__.py new file mode 100644 index 0000000..eaaaaf2 --- /dev/null +++ b/remarkbox/_vendor/pkg_resources/__init__.py @@ -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