diff options
| author | Jason R. Coombs <jaraco@jaraco.com> | 2017-09-03 14:06:34 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-09-03 14:06:34 -0400 |
| commit | 6d8381aa9dbe76ec9fdeb44ff78c8fd05c875a9f (patch) | |
| tree | c6b1314ffe471ff707ce5b30b7f3ff27c86e47bb | |
| parent | 10bcb50aef7dda858b0c351059778d265697ceb0 (diff) | |
| parent | 679ead9cc14287a1ba6cb8c0facdf42e20aef035 (diff) | |
| download | python-setuptools-git-6d8381aa9dbe76ec9fdeb44ff78c8fd05c875a9f.tar.gz | |
Merge pull request #1135 from jd/less-stat
pkg_resources: do not call stat() and access()
| -rw-r--r-- | CHANGES.rst | 7 | ||||
| -rw-r--r-- | pkg_resources/__init__.py | 95 |
2 files changed, 61 insertions, 41 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index ced6630c..8130511e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,8 +16,11 @@ v36.4.0 distributions (e.g. when using ``setup_requires`` with a conflicting transitive dependency, fix #1124). -* #1133: Improved handling of README files extensions and added - Markdown to the list of searched READMES. +* #1133: Improved handling of README files extensions and added + Markdown to the list of searched READMES. + +* #1135: Improve performance of pkg_resources import by not invoking + ``access`` or ``stat`` and using ``os.listdir`` instead. v36.3.0 ------- diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 9eb2a370..ce6053f1 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -34,6 +34,7 @@ import platform import collections import plistlib import email.parser +import errno import tempfile import textwrap import itertools @@ -80,6 +81,11 @@ __import__('pkg_resources.extern.packaging.markers') if (3, 0) < sys.version_info < (3, 3): raise RuntimeError("Python 3.3 or later is required") +if six.PY2: + # Those builtin exceptions are only defined in Python 3 + PermissionError = None + NotADirectoryError = None + # declare some globals that will be defined later to # satisfy the linters. require = None @@ -2016,46 +2022,57 @@ def find_on_path(importer, path_item, only=False): """Yield distributions accessible on a sys.path directory""" path_item = _normalize_cached(path_item) - if os.path.isdir(path_item) and os.access(path_item, os.R_OK): - if _is_unpacked_egg(path_item): - yield Distribution.from_filename( - path_item, metadata=PathMetadata( - path_item, os.path.join(path_item, 'EGG-INFO') - ) + if _is_unpacked_egg(path_item): + yield Distribution.from_filename( + path_item, metadata=PathMetadata( + path_item, os.path.join(path_item, 'EGG-INFO') ) - else: - # scan for .egg and .egg-info in directory - path_item_entries = _by_version_descending(os.listdir(path_item)) - for entry in path_item_entries: - lower = entry.lower() - if lower.endswith('.egg-info') or lower.endswith('.dist-info'): - fullpath = os.path.join(path_item, entry) - if os.path.isdir(fullpath): - # egg-info directory, allow getting metadata - if len(os.listdir(fullpath)) == 0: - # Empty egg directory, skip. - continue - metadata = PathMetadata(path_item, fullpath) - else: - metadata = FileMetadata(fullpath) - yield Distribution.from_location( - path_item, entry, metadata, precedence=DEVELOP_DIST - ) - elif not only and _is_egg_path(entry): - dists = find_distributions(os.path.join(path_item, entry)) - for dist in dists: - yield dist - elif not only and lower.endswith('.egg-link'): - with open(os.path.join(path_item, entry)) as entry_file: - entry_lines = entry_file.readlines() - for line in entry_lines: - if not line.strip(): - continue - path = os.path.join(path_item, line.rstrip()) - dists = find_distributions(path) - for item in dists: - yield item - break + ) + else: + try: + entries = os.listdir(path_item) + except (PermissionError, NotADirectoryError): + return + except OSError as e: + # Ignore the directory if does not exist, not a directory or we + # don't have permissions + if (e.errno in (errno.ENOTDIR, errno.EACCES, errno.ENOENT) + # Python 2 on Windows needs to be handled this way :( + or hasattr(e, "winerror") and e.winerror == 267): + return + raise + # scan for .egg and .egg-info in directory + path_item_entries = _by_version_descending(entries) + for entry in path_item_entries: + lower = entry.lower() + if lower.endswith('.egg-info') or lower.endswith('.dist-info'): + fullpath = os.path.join(path_item, entry) + if os.path.isdir(fullpath): + # egg-info directory, allow getting metadata + if len(os.listdir(fullpath)) == 0: + # Empty egg directory, skip. + continue + metadata = PathMetadata(path_item, fullpath) + else: + metadata = FileMetadata(fullpath) + yield Distribution.from_location( + path_item, entry, metadata, precedence=DEVELOP_DIST + ) + elif not only and _is_egg_path(entry): + dists = find_distributions(os.path.join(path_item, entry)) + for dist in dists: + yield dist + elif not only and lower.endswith('.egg-link'): + with open(os.path.join(path_item, entry)) as entry_file: + entry_lines = entry_file.readlines() + for line in entry_lines: + if not line.strip(): + continue + path = os.path.join(path_item, line.rstrip()) + dists = find_distributions(path) + for item in dists: + yield item + break register_finder(pkgutil.ImpImporter, find_on_path) |
