GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — bpo-25711: Move _ZipImportResourceReader from importlib to zipimport. by serhiy-storchaka · Pull Request #9406 · python/cpython

bpo-25711: Move _ZipImportResourceReader from importlib to zipimport. #9406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Sign up for GitHub

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
serhiy-storchaka merged 1 commit into python:master from serhiy-storchaka:zipimport-resource-reader
Sep 19, 2018

Uh oh!

There was an error while loading. Please reload this page.

Merged

bpo-25711: Move _ZipImportResourceReader from importlib to zipimport. #9406

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
1 commit
Select commit
c734452
bpo-25711: Move _ZipImportResourceReader from importlib to zipimport.
serhiy-storchaka Sep 18, 2018
File filter
Filter by extension

Clear filters
Conversations
Failed to load comments.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Jump to
Jump to file
Failed to load files.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Diff view
Diff view

There are no files selected for viewing

84 changes: 0 additions & 84 deletions 84 Lib/importlib/resources.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -257,87 +257,3 @@ def contents(package: Package) -> Iterable[str]:
else:
package_directory = Path(package.__spec__.origin).parent
return os.listdir(package_directory)


# Private implementation of ResourceReader and get_resource_reader() called
# from zipimport.c. Don't use these directly! We're implementing these in
# Python because 1) it's easier, 2) zipimport may get rewritten in Python
# itself at some point, so doing this all in C would difficult and a waste of
# effort.

class _ZipImportResourceReader(resources_abc.ResourceReader):
"""Private class used to support ZipImport.get_resource_reader().

This class is allowed to reference all the innards and private parts of
the zipimporter.
"""

def __init__(self, zipimporter, fullname):
self.zipimporter = zipimporter
self.fullname = fullname

def open_resource(self, resource):
fullname_as_path = self.fullname.replace('.', '/')
path = f'{fullname_as_path}/{resource}'
try:
return BytesIO(self.zipimporter.get_data(path))
except OSError:
raise FileNotFoundError(path)

def resource_path(self, resource):
# All resources are in the zip file, so there is no path to the file.
# Raising FileNotFoundError tells the higher level API to extract the
# binary data and create a temporary file.
raise FileNotFoundError

def is_resource(self, name):
# Maybe we could do better, but if we can get the data, it's a
# resource. Otherwise it isn't.
fullname_as_path = self.fullname.replace('.', '/')
path = f'{fullname_as_path}/{name}'
try:
self.zipimporter.get_data(path)
except OSError:
return False
return True

def contents(self):
# This is a bit convoluted, because fullname will be a module path,
# but _files is a list of file names relative to the top of the
# archive's namespace. We want to compare file paths to find all the
# names of things inside the module represented by fullname. So we
# turn the module path of fullname into a file path relative to the
# top of the archive, and then we iterate through _files looking for
# names inside that "directory".
fullname_path = Path(self.zipimporter.get_filename(self.fullname))
relative_path = fullname_path.relative_to(self.zipimporter.archive)
# Don't forget that fullname names a package, so its path will include
# __init__.py, which we want to ignore.
assert relative_path.name == '__init__.py'
package_path = relative_path.parent
subdirs_seen = set()
for filename in self.zipimporter._files:
try:
relative = Path(filename).relative_to(package_path)
except ValueError:
continue
# If the path of the file (which is relative to the top of the zip
# namespace), relative to the package given when the resource
# reader was created, has a parent, then it's a name in a
# subdirectory and thus we skip it.
parent_name = relative.parent.name
if len(parent_name) == 0:
yield relative.name
elif parent_name not in subdirs_seen:
subdirs_seen.add(parent_name)
yield parent_name


# Called from zipimport.c
def _zipimport_get_resource_reader(zipimporter, fullname):
try:
if not zipimporter.is_package(fullname):
return None
except ZipImportError:
return None
return _ZipImportResourceReader(zipimporter, fullname)
83 changes: 81 additions & 2 deletions 83 Lib/zipimport.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,16 @@ def get_resource_reader(self, fullname):
If 'fullname' is a package within the zip file, return the
'ResourceReader' object for the package. Otherwise return None.
"""
from importlib import resources
return resources._zipimport_get_resource_reader(self, fullname)
try:
if not self.is_package(fullname):
return None
except ZipImportError:
return None
if not _ZipImportResourceReader._registered:
from importlib.abc import ResourceReader
ResourceReader.register(_ZipImportResourceReader)
_ZipImportResourceReader._registered = True
return _ZipImportResourceReader(self, fullname)


def __repr__(self):
Expand Down Expand Up @@ -648,3 +656,74 @@ def _get_module_code(self, fullname):
return code, ispackage, modpath
else:
raise ZipImportError(f"can't find module {fullname!r}", name=fullname)


class _ZipImportResourceReader:
"""Private class used to support ZipImport.get_resource_reader().

This class is allowed to reference all the innards and private parts of
the zipimporter.
"""
_registered = False

def __init__(self, zipimporter, fullname):
self.zipimporter = zipimporter
self.fullname = fullname

def open_resource(self, resource):
fullname_as_path = self.fullname.replace('.', '/')
path = f'{fullname_as_path}/{resource}'
from io import BytesIO
try:
return BytesIO(self.zipimporter.get_data(path))
except OSError:
raise FileNotFoundError(path)

def resource_path(self, resource):
# All resources are in the zip file, so there is no path to the file.
# Raising FileNotFoundError tells the higher level API to extract the
# binary data and create a temporary file.
raise FileNotFoundError

def is_resource(self, name):
# Maybe we could do better, but if we can get the data, it's a
# resource. Otherwise it isn't.
fullname_as_path = self.fullname.replace('.', '/')
path = f'{fullname_as_path}/{name}'
try:
self.zipimporter.get_data(path)
except OSError:
return False
return True

def contents(self):
# This is a bit convoluted, because fullname will be a module path,
# but _files is a list of file names relative to the top of the
# archive's namespace. We want to compare file paths to find all the
# names of things inside the module represented by fullname. So we
# turn the module path of fullname into a file path relative to the
# top of the archive, and then we iterate through _files looking for
# names inside that "directory".
from pathlib import Path
fullname_path = Path(self.zipimporter.get_filename(self.fullname))
relative_path = fullname_path.relative_to(self.zipimporter.archive)
# Don't forget that fullname names a package, so its path will include
# __init__.py, which we want to ignore.
assert relative_path.name == '__init__.py'
package_path = relative_path.parent
subdirs_seen = set()
for filename in self.zipimporter._files:
try:
relative = Path(filename).relative_to(package_path)
except ValueError:
continue
# If the path of the file (which is relative to the top of the zip
# namespace), relative to the package given when the resource
# reader was created, has a parent, then it's a name in a
# subdirectory and thus we skip it.
parent_name = relative.parent.name
if len(parent_name) == 0:
yield relative.name
elif parent_name not in subdirs_seen:
subdirs_seen.add(parent_name)
yield parent_name
Loading
Oops, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.