Загрузить файлы в «venv/Lib/site-packages/pip/_internal/utils»
This commit is contained in:
201
venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py
Normal file
201
venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
"""Generate and work with PEP 425 Compatibility Tags."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from pip._vendor.packaging.tags import (
|
||||||
|
PythonVersion,
|
||||||
|
Tag,
|
||||||
|
android_platforms,
|
||||||
|
compatible_tags,
|
||||||
|
cpython_tags,
|
||||||
|
generic_tags,
|
||||||
|
interpreter_name,
|
||||||
|
interpreter_version,
|
||||||
|
ios_platforms,
|
||||||
|
mac_platforms,
|
||||||
|
)
|
||||||
|
|
||||||
|
_apple_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)")
|
||||||
|
|
||||||
|
|
||||||
|
def version_info_to_nodot(version_info: tuple[int, ...]) -> str:
|
||||||
|
# Only use up to the first two numbers.
|
||||||
|
return "".join(map(str, version_info[:2]))
|
||||||
|
|
||||||
|
|
||||||
|
def _mac_platforms(arch: str) -> list[str]:
|
||||||
|
match = _apple_arch_pat.match(arch)
|
||||||
|
if match:
|
||||||
|
name, major, minor, actual_arch = match.groups()
|
||||||
|
mac_version = (int(major), int(minor))
|
||||||
|
arches = [
|
||||||
|
# Since we have always only checked that the platform starts
|
||||||
|
# with "macosx", for backwards-compatibility we extract the
|
||||||
|
# actual prefix provided by the user in case they provided
|
||||||
|
# something like "macosxcustom_". It may be good to remove
|
||||||
|
# this as undocumented or deprecate it in the future.
|
||||||
|
"{}_{}".format(name, arch[len("macosx_") :])
|
||||||
|
for arch in mac_platforms(mac_version, actual_arch)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# arch pattern didn't match (?!)
|
||||||
|
arches = [arch]
|
||||||
|
return arches
|
||||||
|
|
||||||
|
|
||||||
|
def _ios_platforms(arch: str) -> list[str]:
|
||||||
|
match = _apple_arch_pat.match(arch)
|
||||||
|
if match:
|
||||||
|
name, major, minor, actual_multiarch = match.groups()
|
||||||
|
ios_version = (int(major), int(minor))
|
||||||
|
arches = [
|
||||||
|
# Since we have always only checked that the platform starts
|
||||||
|
# with "ios", for backwards-compatibility we extract the
|
||||||
|
# actual prefix provided by the user in case they provided
|
||||||
|
# something like "ioscustom_". It may be good to remove
|
||||||
|
# this as undocumented or deprecate it in the future.
|
||||||
|
"{}_{}".format(name, arch[len("ios_") :])
|
||||||
|
for arch in ios_platforms(ios_version, actual_multiarch)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# arch pattern didn't match (?!)
|
||||||
|
arches = [arch]
|
||||||
|
return arches
|
||||||
|
|
||||||
|
|
||||||
|
def _android_platforms(arch: str) -> list[str]:
|
||||||
|
match = re.fullmatch(r"android_(\d+)_(.+)", arch)
|
||||||
|
if match:
|
||||||
|
api_level, abi = match.groups()
|
||||||
|
return list(android_platforms(int(api_level), abi))
|
||||||
|
else:
|
||||||
|
# arch pattern didn't match (?!)
|
||||||
|
return [arch]
|
||||||
|
|
||||||
|
|
||||||
|
def _custom_manylinux_platforms(arch: str) -> list[str]:
|
||||||
|
arches = [arch]
|
||||||
|
arch_prefix, arch_sep, arch_suffix = arch.partition("_")
|
||||||
|
if arch_prefix == "manylinux2014":
|
||||||
|
# manylinux1/manylinux2010 wheels run on most manylinux2014 systems
|
||||||
|
# with the exception of wheels depending on ncurses. PEP 599 states
|
||||||
|
# manylinux1/manylinux2010 wheels should be considered
|
||||||
|
# manylinux2014 wheels:
|
||||||
|
# https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels
|
||||||
|
if arch_suffix in {"i686", "x86_64"}:
|
||||||
|
arches.append("manylinux2010" + arch_sep + arch_suffix)
|
||||||
|
arches.append("manylinux1" + arch_sep + arch_suffix)
|
||||||
|
elif arch_prefix == "manylinux2010":
|
||||||
|
# manylinux1 wheels run on most manylinux2010 systems with the
|
||||||
|
# exception of wheels depending on ncurses. PEP 571 states
|
||||||
|
# manylinux1 wheels should be considered manylinux2010 wheels:
|
||||||
|
# https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels
|
||||||
|
arches.append("manylinux1" + arch_sep + arch_suffix)
|
||||||
|
return arches
|
||||||
|
|
||||||
|
|
||||||
|
def _get_custom_platforms(arch: str) -> list[str]:
|
||||||
|
arch_prefix, arch_sep, arch_suffix = arch.partition("_")
|
||||||
|
if arch.startswith("macosx"):
|
||||||
|
arches = _mac_platforms(arch)
|
||||||
|
elif arch.startswith("ios"):
|
||||||
|
arches = _ios_platforms(arch)
|
||||||
|
elif arch_prefix == "android":
|
||||||
|
arches = _android_platforms(arch)
|
||||||
|
elif arch_prefix in ["manylinux2014", "manylinux2010"]:
|
||||||
|
arches = _custom_manylinux_platforms(arch)
|
||||||
|
else:
|
||||||
|
arches = [arch]
|
||||||
|
return arches
|
||||||
|
|
||||||
|
|
||||||
|
def _expand_allowed_platforms(platforms: list[str] | None) -> list[str] | None:
|
||||||
|
if not platforms:
|
||||||
|
return None
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for p in platforms:
|
||||||
|
if p in seen:
|
||||||
|
continue
|
||||||
|
additions = [c for c in _get_custom_platforms(p) if c not in seen]
|
||||||
|
seen.update(additions)
|
||||||
|
result.extend(additions)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _get_python_version(version: str) -> PythonVersion:
|
||||||
|
if len(version) > 1:
|
||||||
|
return int(version[0]), int(version[1:])
|
||||||
|
else:
|
||||||
|
return (int(version[0]),)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_custom_interpreter(
|
||||||
|
implementation: str | None = None, version: str | None = None
|
||||||
|
) -> str:
|
||||||
|
if implementation is None:
|
||||||
|
implementation = interpreter_name()
|
||||||
|
if version is None:
|
||||||
|
version = interpreter_version()
|
||||||
|
return f"{implementation}{version}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_supported(
|
||||||
|
version: str | None = None,
|
||||||
|
platforms: list[str] | None = None,
|
||||||
|
impl: str | None = None,
|
||||||
|
abis: list[str] | None = None,
|
||||||
|
) -> list[Tag]:
|
||||||
|
"""Return a list of supported tags for each version specified in
|
||||||
|
`versions`.
|
||||||
|
|
||||||
|
:param version: a string version, of the form "33" or "32",
|
||||||
|
or None. The version will be assumed to support our ABI.
|
||||||
|
:param platform: specify a list of platforms you want valid
|
||||||
|
tags for, or None. If None, use the local system platform.
|
||||||
|
:param impl: specify the exact implementation you want valid
|
||||||
|
tags for, or None. If None, use the local interpreter impl.
|
||||||
|
:param abis: specify a list of abis you want valid
|
||||||
|
tags for, or None. If None, use the local interpreter abi.
|
||||||
|
"""
|
||||||
|
supported: list[Tag] = []
|
||||||
|
|
||||||
|
python_version: PythonVersion | None = None
|
||||||
|
if version is not None:
|
||||||
|
python_version = _get_python_version(version)
|
||||||
|
|
||||||
|
interpreter = _get_custom_interpreter(impl, version)
|
||||||
|
|
||||||
|
platforms = _expand_allowed_platforms(platforms)
|
||||||
|
|
||||||
|
is_cpython = (impl or interpreter_name()) == "cp"
|
||||||
|
if is_cpython:
|
||||||
|
supported.extend(
|
||||||
|
cpython_tags(
|
||||||
|
python_version=python_version,
|
||||||
|
abis=abis,
|
||||||
|
platforms=platforms,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
supported.extend(
|
||||||
|
generic_tags(
|
||||||
|
interpreter=interpreter,
|
||||||
|
abis=abis,
|
||||||
|
platforms=platforms,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
supported.extend(
|
||||||
|
compatible_tags(
|
||||||
|
python_version=python_version,
|
||||||
|
interpreter=interpreter,
|
||||||
|
platforms=platforms,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return supported
|
||||||
28
venv/Lib/site-packages/pip/_internal/utils/datetime.py
Normal file
28
venv/Lib/site-packages/pip/_internal/utils/datetime.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
"""For when pip wants to check the date or time."""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def today_is_later_than(year: int, month: int, day: int) -> bool:
|
||||||
|
today = datetime.date.today()
|
||||||
|
given = datetime.date(year, month, day)
|
||||||
|
|
||||||
|
return today > given
|
||||||
|
|
||||||
|
|
||||||
|
def parse_iso_datetime(isodate: str) -> datetime.datetime:
|
||||||
|
"""Convert an ISO format string to a datetime.
|
||||||
|
|
||||||
|
Handles the format 2020-01-22T14:24:01Z (trailing Z)
|
||||||
|
which is not supported by older versions of fromisoformat.
|
||||||
|
"""
|
||||||
|
# Python 3.11+ supports Z suffix natively in fromisoformat
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
return datetime.datetime.fromisoformat(isodate)
|
||||||
|
else:
|
||||||
|
return datetime.datetime.fromisoformat(
|
||||||
|
isodate.replace("Z", "+00:00")
|
||||||
|
if isodate.endswith("Z") and ("T" in isodate or " " in isodate.strip())
|
||||||
|
else isodate
|
||||||
|
)
|
||||||
126
venv/Lib/site-packages/pip/_internal/utils/deprecation.py
Normal file
126
venv/Lib/site-packages/pip/_internal/utils/deprecation.py
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
"""
|
||||||
|
A module that implements tooling to enable easy warnings about deprecations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
from typing import Any, TextIO
|
||||||
|
|
||||||
|
from pip._vendor.packaging.version import parse
|
||||||
|
|
||||||
|
from pip import __version__ as current_version # NOTE: tests patch this name.
|
||||||
|
|
||||||
|
DEPRECATION_MSG_PREFIX = "DEPRECATION: "
|
||||||
|
|
||||||
|
|
||||||
|
class PipDeprecationWarning(Warning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
_original_showwarning: Any = None
|
||||||
|
|
||||||
|
|
||||||
|
# Warnings <-> Logging Integration
|
||||||
|
def _showwarning(
|
||||||
|
message: Warning | str,
|
||||||
|
category: type[Warning],
|
||||||
|
filename: str,
|
||||||
|
lineno: int,
|
||||||
|
file: TextIO | None = None,
|
||||||
|
line: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
if file is not None:
|
||||||
|
if _original_showwarning is not None:
|
||||||
|
_original_showwarning(message, category, filename, lineno, file, line)
|
||||||
|
elif issubclass(category, PipDeprecationWarning):
|
||||||
|
# We use a specially named logger which will handle all of the
|
||||||
|
# deprecation messages for pip.
|
||||||
|
logger = logging.getLogger("pip._internal.deprecations")
|
||||||
|
logger.warning(message)
|
||||||
|
else:
|
||||||
|
_original_showwarning(message, category, filename, lineno, file, line)
|
||||||
|
|
||||||
|
|
||||||
|
def install_warning_logger() -> None:
|
||||||
|
# Enable our Deprecation Warnings
|
||||||
|
warnings.simplefilter("default", PipDeprecationWarning, append=True)
|
||||||
|
|
||||||
|
global _original_showwarning
|
||||||
|
|
||||||
|
if _original_showwarning is None:
|
||||||
|
_original_showwarning = warnings.showwarning
|
||||||
|
warnings.showwarning = _showwarning
|
||||||
|
|
||||||
|
|
||||||
|
def deprecated(
|
||||||
|
*,
|
||||||
|
reason: str,
|
||||||
|
replacement: str | None,
|
||||||
|
gone_in: str | None,
|
||||||
|
feature_flag: str | None = None,
|
||||||
|
issue: int | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Helper to deprecate existing functionality.
|
||||||
|
|
||||||
|
reason:
|
||||||
|
Textual reason shown to the user about why this functionality has
|
||||||
|
been deprecated. Should be a complete sentence.
|
||||||
|
replacement:
|
||||||
|
Textual suggestion shown to the user about what alternative
|
||||||
|
functionality they can use.
|
||||||
|
gone_in:
|
||||||
|
The version of pip does this functionality should get removed in.
|
||||||
|
Raises an error if pip's current version is greater than or equal to
|
||||||
|
this.
|
||||||
|
feature_flag:
|
||||||
|
Command-line flag of the form --use-feature={feature_flag} for testing
|
||||||
|
upcoming functionality.
|
||||||
|
issue:
|
||||||
|
Issue number on the tracker that would serve as a useful place for
|
||||||
|
users to find related discussion and provide feedback.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Determine whether or not the feature is already gone in this version.
|
||||||
|
is_gone = gone_in is not None and parse(current_version) >= parse(gone_in)
|
||||||
|
|
||||||
|
message_parts = [
|
||||||
|
(reason, f"{DEPRECATION_MSG_PREFIX}{{}}"),
|
||||||
|
(
|
||||||
|
gone_in,
|
||||||
|
(
|
||||||
|
"pip {} will enforce this behaviour change."
|
||||||
|
if not is_gone
|
||||||
|
else "Since pip {}, this is no longer supported."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
replacement,
|
||||||
|
"A possible replacement is {}.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
feature_flag,
|
||||||
|
(
|
||||||
|
"You can use the flag --use-feature={} to test the upcoming behaviour."
|
||||||
|
if not is_gone
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
issue,
|
||||||
|
"Discussion can be found at https://github.com/pypa/pip/issues/{}",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
message = " ".join(
|
||||||
|
format_str.format(value)
|
||||||
|
for value, format_str in message_parts
|
||||||
|
if format_str is not None and value is not None
|
||||||
|
)
|
||||||
|
|
||||||
|
# Raise as an error if this behaviour is deprecated.
|
||||||
|
if is_gone:
|
||||||
|
raise PipDeprecationWarning(message)
|
||||||
|
|
||||||
|
warnings.warn(message, category=PipDeprecationWarning, stacklevel=2)
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pip._internal.models.direct_url import ArchiveInfo, DirectUrl, DirInfo, VcsInfo
|
||||||
|
from pip._internal.models.link import Link
|
||||||
|
from pip._internal.utils.urls import path_to_url
|
||||||
|
from pip._internal.vcs import vcs
|
||||||
|
|
||||||
|
|
||||||
|
def direct_url_as_pep440_direct_reference(direct_url: DirectUrl, name: str) -> str:
|
||||||
|
"""Convert a DirectUrl to a pip requirement string."""
|
||||||
|
direct_url.validate() # if invalid, this is a pip bug
|
||||||
|
requirement = name + " @ "
|
||||||
|
fragments = []
|
||||||
|
if isinstance(direct_url.info, VcsInfo):
|
||||||
|
requirement += (
|
||||||
|
f"{direct_url.info.vcs}+{direct_url.url}@{direct_url.info.commit_id}"
|
||||||
|
)
|
||||||
|
elif isinstance(direct_url.info, ArchiveInfo):
|
||||||
|
requirement += direct_url.url
|
||||||
|
if direct_url.info.hash:
|
||||||
|
fragments.append(direct_url.info.hash)
|
||||||
|
else:
|
||||||
|
assert isinstance(direct_url.info, DirInfo)
|
||||||
|
requirement += direct_url.url
|
||||||
|
if direct_url.subdirectory:
|
||||||
|
fragments.append("subdirectory=" + direct_url.subdirectory)
|
||||||
|
if fragments:
|
||||||
|
requirement += "#" + "&".join(fragments)
|
||||||
|
return requirement
|
||||||
|
|
||||||
|
|
||||||
|
def direct_url_for_editable(source_dir: str) -> DirectUrl:
|
||||||
|
return DirectUrl(
|
||||||
|
url=path_to_url(source_dir),
|
||||||
|
info=DirInfo(editable=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def direct_url_from_link(
|
||||||
|
link: Link, source_dir: str | None = None, link_is_in_wheel_cache: bool = False
|
||||||
|
) -> DirectUrl:
|
||||||
|
if link.is_vcs:
|
||||||
|
vcs_backend = vcs.get_backend_for_scheme(link.scheme)
|
||||||
|
assert vcs_backend
|
||||||
|
url, requested_revision, _ = vcs_backend.get_url_rev_and_auth(
|
||||||
|
link.url_without_fragment
|
||||||
|
)
|
||||||
|
# For VCS links, we need to find out and add commit_id.
|
||||||
|
if link_is_in_wheel_cache:
|
||||||
|
# If the requested VCS link corresponds to a cached
|
||||||
|
# wheel, it means the requested revision was an
|
||||||
|
# immutable commit hash, otherwise it would not have
|
||||||
|
# been cached. In that case we don't have a source_dir
|
||||||
|
# with the VCS checkout.
|
||||||
|
assert requested_revision
|
||||||
|
commit_id = requested_revision
|
||||||
|
else:
|
||||||
|
# If the wheel was not in cache, it means we have
|
||||||
|
# had to checkout from VCS to build and we have a source_dir
|
||||||
|
# which we can inspect to find out the commit id.
|
||||||
|
assert source_dir
|
||||||
|
commit_id = vcs_backend.get_revision(source_dir)
|
||||||
|
return DirectUrl(
|
||||||
|
url=url,
|
||||||
|
info=VcsInfo(
|
||||||
|
vcs=vcs_backend.name,
|
||||||
|
commit_id=commit_id,
|
||||||
|
requested_revision=requested_revision,
|
||||||
|
),
|
||||||
|
subdirectory=link.subdirectory_fragment,
|
||||||
|
)
|
||||||
|
elif link.is_existing_dir():
|
||||||
|
return DirectUrl(
|
||||||
|
url=link.url_without_fragment,
|
||||||
|
info=DirInfo(),
|
||||||
|
subdirectory=link.subdirectory_fragment,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
hash = None
|
||||||
|
hash_name = link.hash_name
|
||||||
|
if hash_name:
|
||||||
|
hash = f"{hash_name}={link.hash}"
|
||||||
|
return DirectUrl(
|
||||||
|
url=link.url_without_fragment,
|
||||||
|
info=ArchiveInfo(hash=hash),
|
||||||
|
subdirectory=link.subdirectory_fragment,
|
||||||
|
)
|
||||||
81
venv/Lib/site-packages/pip/_internal/utils/egg_link.py
Normal file
81
venv/Lib/site-packages/pip/_internal/utils/egg_link.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pip._internal.locations import site_packages, user_site
|
||||||
|
from pip._internal.utils.virtualenv import (
|
||||||
|
running_under_virtualenv,
|
||||||
|
virtualenv_no_global,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"egg_link_path_from_sys_path",
|
||||||
|
"egg_link_path_from_location",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _egg_link_names(raw_name: str) -> list[str]:
|
||||||
|
"""
|
||||||
|
Convert a Name metadata value to a .egg-link name, by applying
|
||||||
|
the same substitution as pkg_resources's safe_name function.
|
||||||
|
Note: we cannot use canonicalize_name because it has a different logic.
|
||||||
|
|
||||||
|
We also look for the raw name (without normalization) as setuptools 69 changed
|
||||||
|
the way it names .egg-link files (https://github.com/pypa/setuptools/issues/4167).
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
re.sub("[^A-Za-z0-9.]+", "-", raw_name) + ".egg-link",
|
||||||
|
f"{raw_name}.egg-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def egg_link_path_from_sys_path(raw_name: str) -> str | None:
|
||||||
|
"""
|
||||||
|
Look for a .egg-link file for project name, by walking sys.path.
|
||||||
|
"""
|
||||||
|
egg_link_names = _egg_link_names(raw_name)
|
||||||
|
for path_item in sys.path:
|
||||||
|
for egg_link_name in egg_link_names:
|
||||||
|
egg_link = os.path.join(path_item, egg_link_name)
|
||||||
|
if os.path.isfile(egg_link):
|
||||||
|
return egg_link
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def egg_link_path_from_location(raw_name: str) -> str | None:
|
||||||
|
"""
|
||||||
|
Return the path for the .egg-link file if it exists, otherwise, None.
|
||||||
|
|
||||||
|
There's 3 scenarios:
|
||||||
|
1) not in a virtualenv
|
||||||
|
try to find in site.USER_SITE, then site_packages
|
||||||
|
2) in a no-global virtualenv
|
||||||
|
try to find in site_packages
|
||||||
|
3) in a yes-global virtualenv
|
||||||
|
try to find in site_packages, then site.USER_SITE
|
||||||
|
(don't look in global location)
|
||||||
|
|
||||||
|
For #1 and #3, there could be odd cases, where there's an egg-link in 2
|
||||||
|
locations.
|
||||||
|
|
||||||
|
This method will just return the first one found.
|
||||||
|
"""
|
||||||
|
sites: list[str] = []
|
||||||
|
if running_under_virtualenv():
|
||||||
|
sites.append(site_packages)
|
||||||
|
if not virtualenv_no_global() and user_site:
|
||||||
|
sites.append(user_site)
|
||||||
|
else:
|
||||||
|
if user_site:
|
||||||
|
sites.append(user_site)
|
||||||
|
sites.append(site_packages)
|
||||||
|
|
||||||
|
egg_link_names = _egg_link_names(raw_name)
|
||||||
|
for site in sites:
|
||||||
|
for egg_link_name in egg_link_names:
|
||||||
|
egglink = os.path.join(site, egg_link_name)
|
||||||
|
if os.path.isfile(egglink):
|
||||||
|
return egglink
|
||||||
|
return None
|
||||||
Reference in New Issue
Block a user