123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- # flake8: noqa
- import abc
- import os
- import sys
- import pathlib
- import warnings
- from contextlib import suppress
- from typing import Union
- if sys.version_info >= (3, 10):
- from zipfile import Path as ZipPath # type: ignore
- else:
- from zipp import Path as ZipPath # type: ignore
- try:
- from typing import runtime_checkable # type: ignore
- except ImportError:
- def runtime_checkable(cls): # type: ignore
- return cls
- try:
- from typing import Protocol # type: ignore
- except ImportError:
- Protocol = abc.ABC # type: ignore
- class TraversableResourcesLoader:
- """
- Adapt loaders to provide TraversableResources and other
- compatibility.
- Used primarily for Python 3.9 and earlier where the native
- loaders do not yet implement TraversableResources.
- """
- def __init__(self, spec):
- self.spec = spec
- @property
- def path(self):
- return self.spec.origin
- def get_resource_reader(self, name):
- from . import readers, _adapters
- def _zip_reader(spec):
- with suppress(AttributeError):
- return readers.ZipReader(spec.loader, spec.name)
- def _namespace_reader(spec):
- with suppress(AttributeError, ValueError):
- return readers.NamespaceReader(spec.submodule_search_locations)
- def _available_reader(spec):
- with suppress(AttributeError):
- return spec.loader.get_resource_reader(spec.name)
- def _native_reader(spec):
- reader = _available_reader(spec)
- return reader if hasattr(reader, 'files') else None
- def _file_reader(spec):
- try:
- path = pathlib.Path(self.path)
- except TypeError:
- return None
- if path.exists():
- return readers.FileReader(self)
- return (
- # local ZipReader if a zip module
- _zip_reader(self.spec)
- or
- # local NamespaceReader if a namespace module
- _namespace_reader(self.spec)
- or
- # local FileReader
- _file_reader(self.spec)
- or
- # native reader if it supplies 'files'
- _native_reader(self.spec)
- or
- # fallback - adapt the spec ResourceReader to TraversableReader
- _adapters.CompatibilityFiles(self.spec)
- )
- def wrap_spec(package):
- """
- Construct a package spec with traversable compatibility
- on the spec/loader/reader.
- Supersedes _adapters.wrap_spec to use TraversableResourcesLoader
- from above for older Python compatibility (<3.10).
- """
- from . import _adapters
- return _adapters.SpecLoaderAdapter(package.__spec__, TraversableResourcesLoader)
- if sys.version_info >= (3, 9):
- StrPath = Union[str, os.PathLike[str]]
- else:
- # PathLike is only subscriptable at runtime in 3.9+
- StrPath = Union[str, "os.PathLike[str]"]
- def ensure_traversable(path):
- """
- Convert deprecated string arguments to traversables (pathlib.Path).
- """
- if not isinstance(path, str):
- return path
- warnings.warn(
- "String arguments are deprecated. Pass a Traversable instead.",
- DeprecationWarning,
- stacklevel=3,
- )
- return pathlib.Path(path)
|