parent
0649302b51
commit
e1dad4d3a6
@ -0,0 +1 @@
|
||||
/importlib_resources-1.0.2.tar.gz
|
@ -0,0 +1,302 @@
|
||||
From a6a3a716c97b438ed64d5368e3462c6787ba0b85 Mon Sep 17 00:00:00 2001
|
||||
From: Ken Dreyer <kdreyer@redhat.com>
|
||||
Date: Fri, 8 Nov 2019 09:13:38 -0700
|
||||
Subject: [PATCH] raise NotImplementedError on Python 2
|
||||
|
||||
---
|
||||
importlib_resources/__init__.py | 4 +-
|
||||
importlib_resources/_py2.py | 270 ----------------------------------------
|
||||
2 files changed, 1 insertion(+), 273 deletions(-)
|
||||
delete mode 100644 importlib_resources/_py2.py
|
||||
|
||||
diff --git a/importlib_resources/__init__.py b/importlib_resources/__init__.py
|
||||
index fab437a..b012e5c 100644
|
||||
--- a/importlib_resources/__init__.py
|
||||
+++ b/importlib_resources/__init__.py
|
||||
@@ -28,9 +28,7 @@ elif sys.version_info >= (3,):
|
||||
from importlib_resources.abc import ResourceReader
|
||||
__all__.extend(['Package', 'Resource', 'ResourceReader'])
|
||||
else:
|
||||
- from importlib_resources._py2 import (
|
||||
- contents, is_resource, open_binary, open_text, path, read_binary,
|
||||
- read_text)
|
||||
+ raise NotImplementedError('Fedora package does not support Python 2')
|
||||
|
||||
|
||||
__version__ = read_text('importlib_resources', 'version.txt').strip()
|
||||
diff --git a/importlib_resources/_py2.py b/importlib_resources/_py2.py
|
||||
deleted file mode 100644
|
||||
index 376f0e3..0000000
|
||||
--- a/importlib_resources/_py2.py
|
||||
+++ /dev/null
|
||||
@@ -1,270 +0,0 @@
|
||||
-import os
|
||||
-import errno
|
||||
-import tempfile
|
||||
-
|
||||
-from ._compat import FileNotFoundError
|
||||
-from contextlib import contextmanager
|
||||
-from importlib import import_module
|
||||
-from io import BytesIO, TextIOWrapper, open as io_open
|
||||
-from pathlib2 import Path
|
||||
-from zipfile import ZipFile
|
||||
-
|
||||
-
|
||||
-def _get_package(package):
|
||||
- """Normalize a path by ensuring it is a string.
|
||||
-
|
||||
- If the resulting string contains path separators, an exception is raised.
|
||||
- """
|
||||
- if isinstance(package, basestring): # noqa: F821
|
||||
- module = import_module(package)
|
||||
- else:
|
||||
- module = package
|
||||
- if not hasattr(module, '__path__'):
|
||||
- raise TypeError("{!r} is not a package".format(package))
|
||||
- return module
|
||||
-
|
||||
-
|
||||
-def _normalize_path(path):
|
||||
- """Normalize a path by ensuring it is a string.
|
||||
-
|
||||
- If the resulting string contains path separators, an exception is raised.
|
||||
- """
|
||||
- str_path = str(path)
|
||||
- parent, file_name = os.path.split(str_path)
|
||||
- if parent:
|
||||
- raise ValueError("{!r} must be only a file name".format(path))
|
||||
- else:
|
||||
- return file_name
|
||||
-
|
||||
-
|
||||
-def open_binary(package, resource):
|
||||
- """Return a file-like object opened for binary reading of the resource."""
|
||||
- resource = _normalize_path(resource)
|
||||
- package = _get_package(package)
|
||||
- # Using pathlib doesn't work well here due to the lack of 'strict' argument
|
||||
- # for pathlib.Path.resolve() prior to Python 3.6.
|
||||
- package_path = os.path.dirname(package.__file__)
|
||||
- relative_path = os.path.join(package_path, resource)
|
||||
- full_path = os.path.abspath(relative_path)
|
||||
- try:
|
||||
- return io_open(full_path, 'rb')
|
||||
- except IOError:
|
||||
- # This might be a package in a zip file. zipimport provides a loader
|
||||
- # with a functioning get_data() method, however we have to strip the
|
||||
- # archive (i.e. the .zip file's name) off the front of the path. This
|
||||
- # is because the zipimport loader in Python 2 doesn't actually follow
|
||||
- # PEP 302. It should allow the full path, but actually requires that
|
||||
- # the path be relative to the zip file.
|
||||
- try:
|
||||
- loader = package.__loader__
|
||||
- full_path = relative_path[len(loader.archive)+1:]
|
||||
- data = loader.get_data(full_path)
|
||||
- except (IOError, AttributeError):
|
||||
- package_name = package.__name__
|
||||
- message = '{!r} resource not found in {!r}'.format(
|
||||
- resource, package_name)
|
||||
- raise FileNotFoundError(message)
|
||||
- else:
|
||||
- return BytesIO(data)
|
||||
-
|
||||
-
|
||||
-def open_text(package, resource, encoding='utf-8', errors='strict'):
|
||||
- """Return a file-like object opened for text reading of the resource."""
|
||||
- resource = _normalize_path(resource)
|
||||
- package = _get_package(package)
|
||||
- # Using pathlib doesn't work well here due to the lack of 'strict' argument
|
||||
- # for pathlib.Path.resolve() prior to Python 3.6.
|
||||
- package_path = os.path.dirname(package.__file__)
|
||||
- relative_path = os.path.join(package_path, resource)
|
||||
- full_path = os.path.abspath(relative_path)
|
||||
- try:
|
||||
- return io_open(full_path, mode='r', encoding=encoding, errors=errors)
|
||||
- except IOError:
|
||||
- # This might be a package in a zip file. zipimport provides a loader
|
||||
- # with a functioning get_data() method, however we have to strip the
|
||||
- # archive (i.e. the .zip file's name) off the front of the path. This
|
||||
- # is because the zipimport loader in Python 2 doesn't actually follow
|
||||
- # PEP 302. It should allow the full path, but actually requires that
|
||||
- # the path be relative to the zip file.
|
||||
- try:
|
||||
- loader = package.__loader__
|
||||
- full_path = relative_path[len(loader.archive)+1:]
|
||||
- data = loader.get_data(full_path)
|
||||
- except (IOError, AttributeError):
|
||||
- package_name = package.__name__
|
||||
- message = '{!r} resource not found in {!r}'.format(
|
||||
- resource, package_name)
|
||||
- raise FileNotFoundError(message)
|
||||
- else:
|
||||
- return TextIOWrapper(BytesIO(data), encoding, errors)
|
||||
-
|
||||
-
|
||||
-def read_binary(package, resource):
|
||||
- """Return the binary contents of the resource."""
|
||||
- resource = _normalize_path(resource)
|
||||
- package = _get_package(package)
|
||||
- with open_binary(package, resource) as fp:
|
||||
- return fp.read()
|
||||
-
|
||||
-
|
||||
-def read_text(package, resource, encoding='utf-8', errors='strict'):
|
||||
- """Return the decoded string of the resource.
|
||||
-
|
||||
- The decoding-related arguments have the same semantics as those of
|
||||
- bytes.decode().
|
||||
- """
|
||||
- resource = _normalize_path(resource)
|
||||
- package = _get_package(package)
|
||||
- with open_text(package, resource, encoding, errors) as fp:
|
||||
- return fp.read()
|
||||
-
|
||||
-
|
||||
-@contextmanager
|
||||
-def path(package, resource):
|
||||
- """A context manager providing a file path object to the resource.
|
||||
-
|
||||
- If the resource does not already exist on its own on the file system,
|
||||
- a temporary file will be created. If the file was created, the file
|
||||
- will be deleted upon exiting the context manager (no exception is
|
||||
- raised if the file was deleted prior to the context manager
|
||||
- exiting).
|
||||
- """
|
||||
- resource = _normalize_path(resource)
|
||||
- package = _get_package(package)
|
||||
- package_directory = Path(package.__file__).parent
|
||||
- file_path = package_directory / resource
|
||||
- # If the file actually exists on the file system, just return it.
|
||||
- # Otherwise, it's probably in a zip file, so we need to create a temporary
|
||||
- # file and copy the contents into that file, hence the contextmanager to
|
||||
- # clean up the temp file resource.
|
||||
- if file_path.exists():
|
||||
- yield file_path
|
||||
- else:
|
||||
- with open_binary(package, resource) as fp:
|
||||
- data = fp.read()
|
||||
- # Not using tempfile.NamedTemporaryFile as it leads to deeper 'try'
|
||||
- # blocks due to the need to close the temporary file to work on Windows
|
||||
- # properly.
|
||||
- fd, raw_path = tempfile.mkstemp()
|
||||
- try:
|
||||
- os.write(fd, data)
|
||||
- os.close(fd)
|
||||
- yield Path(raw_path)
|
||||
- finally:
|
||||
- try:
|
||||
- os.remove(raw_path)
|
||||
- except FileNotFoundError:
|
||||
- pass
|
||||
-
|
||||
-
|
||||
-def is_resource(package, name):
|
||||
- """True if name is a resource inside package.
|
||||
-
|
||||
- Directories are *not* resources.
|
||||
- """
|
||||
- package = _get_package(package)
|
||||
- _normalize_path(name)
|
||||
- try:
|
||||
- package_contents = set(contents(package))
|
||||
- except OSError as error:
|
||||
- if error.errno not in (errno.ENOENT, errno.ENOTDIR):
|
||||
- # We won't hit this in the Python 2 tests, so it'll appear
|
||||
- # uncovered. We could mock os.listdir() to return a non-ENOENT or
|
||||
- # ENOTDIR, but then we'd have to depend on another external
|
||||
- # library since Python 2 doesn't have unittest.mock. It's not
|
||||
- # worth it.
|
||||
- raise # pragma: nocover
|
||||
- return False
|
||||
- if name not in package_contents:
|
||||
- return False
|
||||
- # Just because the given file_name lives as an entry in the package's
|
||||
- # contents doesn't necessarily mean it's a resource. Directories are not
|
||||
- # resources, so let's try to find out if it's a directory or not.
|
||||
- path = Path(package.__file__).parent / name
|
||||
- if path.is_file():
|
||||
- return True
|
||||
- if path.is_dir():
|
||||
- return False
|
||||
- # If it's not a file and it's not a directory, what is it? Well, this
|
||||
- # means the file doesn't exist on the file system, so it probably lives
|
||||
- # inside a zip file. We have to crack open the zip, look at its table of
|
||||
- # contents, and make sure that this entry doesn't have sub-entries.
|
||||
- archive_path = package.__loader__.archive # type: ignore
|
||||
- package_directory = Path(package.__file__).parent
|
||||
- with ZipFile(archive_path) as zf:
|
||||
- toc = zf.namelist()
|
||||
- relpath = package_directory.relative_to(archive_path)
|
||||
- candidate_path = relpath / name
|
||||
- for entry in toc: # pragma: nobranch
|
||||
- try:
|
||||
- relative_to_candidate = Path(entry).relative_to(candidate_path)
|
||||
- except ValueError:
|
||||
- # The two paths aren't relative to each other so we can ignore it.
|
||||
- continue
|
||||
- # Since directories aren't explicitly listed in the zip file, we must
|
||||
- # infer their 'directory-ness' by looking at the number of path
|
||||
- # components in the path relative to the package resource we're
|
||||
- # looking up. If there are zero additional parts, it's a file, i.e. a
|
||||
- # resource. If there are more than zero it's a directory, i.e. not a
|
||||
- # resource. It has to be one of these two cases.
|
||||
- return len(relative_to_candidate.parts) == 0
|
||||
- # I think it's impossible to get here. It would mean that we are looking
|
||||
- # for a resource in a zip file, there's an entry matching it in the return
|
||||
- # value of contents(), but we never actually found it in the zip's table of
|
||||
- # contents.
|
||||
- raise AssertionError('Impossible situation')
|
||||
-
|
||||
-
|
||||
-def contents(package):
|
||||
- """Return an iterable of entries in `package`.
|
||||
-
|
||||
- Note that not all entries are resources. Specifically, directories are
|
||||
- not considered resources. Use `is_resource()` on each entry returned here
|
||||
- to check if it is a resource or not.
|
||||
- """
|
||||
- package = _get_package(package)
|
||||
- package_directory = Path(package.__file__).parent
|
||||
- try:
|
||||
- return os.listdir(str(package_directory))
|
||||
- except OSError as error:
|
||||
- if error.errno not in (errno.ENOENT, errno.ENOTDIR):
|
||||
- # We won't hit this in the Python 2 tests, so it'll appear
|
||||
- # uncovered. We could mock os.listdir() to return a non-ENOENT or
|
||||
- # ENOTDIR, but then we'd have to depend on another external
|
||||
- # library since Python 2 doesn't have unittest.mock. It's not
|
||||
- # worth it.
|
||||
- raise # pragma: nocover
|
||||
- # The package is probably in a zip file.
|
||||
- archive_path = getattr(package.__loader__, 'archive', None)
|
||||
- if archive_path is None:
|
||||
- raise
|
||||
- relpath = package_directory.relative_to(archive_path)
|
||||
- with ZipFile(archive_path) as zf:
|
||||
- toc = zf.namelist()
|
||||
- subdirs_seen = set() # type: Set
|
||||
- subdirs_returned = []
|
||||
- for filename in toc:
|
||||
- path = Path(filename)
|
||||
- # Strip off any path component parts that are in common with the
|
||||
- # package directory, relative to the zip archive's file system
|
||||
- # path. This gives us all the parts that live under the named
|
||||
- # package inside the zip file. If the length of these subparts is
|
||||
- # exactly 1, then it is situated inside the package. The resulting
|
||||
- # length will be 0 if it's above the package, and it will be
|
||||
- # greater than 1 if it lives in a subdirectory of the package
|
||||
- # directory.
|
||||
- #
|
||||
- # However, since directories themselves don't appear in the zip
|
||||
- # archive as a separate entry, we need to return the first path
|
||||
- # component for any case that has > 1 subparts -- but only once!
|
||||
- if path.parts[:len(relpath.parts)] != relpath.parts:
|
||||
- continue
|
||||
- subparts = path.parts[len(relpath.parts):]
|
||||
- if len(subparts) == 1:
|
||||
- subdirs_returned.append(subparts[0])
|
||||
- elif len(subparts) > 1: # pragma: nobranch
|
||||
- subdir = subparts[0]
|
||||
- if subdir not in subdirs_seen:
|
||||
- subdirs_seen.add(subdir)
|
||||
- subdirs_returned.append(subdir)
|
||||
- return subdirs_returned
|
@ -1,2 +0,0 @@
|
||||
[koji]
|
||||
targets = epel8 epel8-playground
|
@ -0,0 +1,72 @@
|
||||
%global pypi_name importlib_resources
|
||||
|
||||
%global desc \
|
||||
importlib_resources is a backport of Python 3.7's standard library\
|
||||
importlib.resources module for 3.4 through 3.6. Users of Python 3.7 and\
|
||||
beyond should use the standard library module, since for these\
|
||||
versions, importlib_resources just delegates to that module.
|
||||
|
||||
|
||||
Name: python-importlib-resources
|
||||
Version: 1.0.2
|
||||
Release: 1%{?dist}
|
||||
Summary: Read resources from Python packages
|
||||
|
||||
License: ASL 2.0
|
||||
URL: https://importlib-resources.readthedocs.io/
|
||||
Source0: %pypi_source
|
||||
|
||||
Patch0001: 0001-raise-NotImplementedError-on-Python-2.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3dist(sphinx)
|
||||
BuildRequires: python3dist(wheel)
|
||||
|
||||
%description %{desc}
|
||||
|
||||
%package -n python3-importlib-resources
|
||||
Summary: %{summary}
|
||||
%{?python_provide:%python_provide python3-%{pypi_name}}
|
||||
%description -n python3-importlib-resources %{desc}
|
||||
|
||||
%package doc
|
||||
Summary: importlib_resources documentation
|
||||
%description doc
|
||||
Documentation for importlib_resources
|
||||
|
||||
%prep
|
||||
%autosetup -p1 -n %{pypi_name}-%{version}
|
||||
# Remove bundled egg-info
|
||||
rm -rf %{pypi_name}.egg-info
|
||||
|
||||
%build
|
||||
%py3_build
|
||||
# generate html docs
|
||||
PYTHONPATH=${PWD} sphinx-build-3 importlib_resources/docs html
|
||||
# remove the sphinx-build leftovers
|
||||
rm -rf html/.{doctrees,buildinfo}
|
||||
|
||||
%install
|
||||
%py3_install
|
||||
|
||||
# Don't ship docs sources or tests
|
||||
rm -r %{buildroot}/%{python3_sitelib}/%{pypi_name}/{docs,tests}/
|
||||
|
||||
%check
|
||||
%{__python3} setup.py test
|
||||
|
||||
%files -n python3-importlib-resources
|
||||
%license LICENSE
|
||||
%doc README.rst
|
||||
%{python3_sitelib}/%{pypi_name}
|
||||
%{python3_sitelib}/%{pypi_name}-%{version}-py?.?.egg-info
|
||||
|
||||
%files doc
|
||||
%license LICENSE
|
||||
%doc html
|
||||
|
||||
%changelog
|
||||
* Thu Nov 07 2019 Ken Dreyer <kdreyer@redhat.com> - 1.0.2-1
|
||||
- Initial package.
|
Loading…
Reference in new issue