match_face/.venv/Lib/site-packages/pipenv/utils/fileutils.py

221 lines
7.5 KiB
Python
Raw Normal View History

"""A collection for utilities for working with files and paths."""
import atexit
import io
import os
import sys
import warnings
from contextlib import contextmanager
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Any, Optional
from urllib import parse as urllib_parse
from urllib import request as urllib_request
from urllib.parse import quote, urlparse
from pipenv.patched.pip._internal.locations import USER_CACHE_DIR
from pipenv.patched.pip._internal.network.download import PipSession
from pipenv.utils import err
def is_file_url(url: Any) -> bool:
"""Returns true if the given url is a file url."""
if not url:
return False
if not isinstance(url, str):
try:
url = url.url
except AttributeError:
raise ValueError(f"Cannot parse url from unknown type: {url!r}")
return urllib_parse.urlparse(url.lower()).scheme == "file"
def is_valid_url(url: str) -> bool:
"""Checks if a given string is an url."""
pieces = urlparse(url)
return all([pieces.scheme, pieces.netloc])
def url_to_path(url: str) -> str:
"""Convert a valid file url to a local filesystem path.
Follows logic taken from pip's equivalent function
"""
assert is_file_url(url), "Only file: urls can be converted to local paths"
_, netloc, path, _, _ = urllib_parse.urlsplit(url)
# Netlocs are UNC paths
if netloc:
netloc = "\\\\" + netloc
path = urllib_request.url2pathname(netloc + path)
return urllib_parse.unquote(path)
if os.name == "nt":
# from click _winconsole.py
from ctypes import create_unicode_buffer, windll
def get_long_path(short_path: str) -> str:
BUFFER_SIZE = 500
buffer = create_unicode_buffer(BUFFER_SIZE)
get_long_path_name = windll.kernel32.GetLongPathNameW
get_long_path_name(short_path, buffer, BUFFER_SIZE)
return buffer.value
def normalize_path(path: str) -> str:
"""Return a case-normalized absolute variable-expanded path."""
return os.path.expandvars(
os.path.expanduser(os.path.normcase(os.path.normpath(os.path.abspath(str(path)))))
)
def normalize_drive(path):
"""Normalize drive in path so they stay consistent.
This currently only affects local drives on Windows, which can be
identified with either upper or lower cased drive names. The case is
always converted to uppercase because it seems to be preferred.
"""
if os.name != "nt" or not isinstance(path, str):
return path
drive, tail = os.path.splitdrive(path)
# Only match (lower cased) local drives (e.g. 'c:'), not UNC mounts.
if drive.islower() and len(drive) == 2 and drive[1] == ":":
return f"{drive.upper()}{tail}"
return path
def path_to_url(path):
"""Convert the supplied local path to a file uri.
:param str path: A string pointing to or representing a local path
:return: A `file://` uri for the same location
:rtype: str
>>> path_to_url("/home/user/code/myrepo/myfile.zip")
'file:///home/user/code/myrepo/myfile.zip'
"""
if not path:
return path # type: ignore
normalized_path = Path(normalize_drive(os.path.abspath(path))).as_posix()
if os.name == "nt" and normalized_path[1] == ":":
drive, _, path = normalized_path.partition(":")
# XXX: This enables us to handle half-surrogates that were never
# XXX: actually part of a surrogate pair, but were just incidentally
# XXX: passed in as a piece of a filename
quoted_path = quote(path, errors="backslashreplace")
return f"file:///{drive}:{quoted_path}"
# XXX: This is also here to help deal with incidental dangling surrogates
# XXX: on linux, by making sure they are preserved during encoding so that
# XXX: we can urlencode the backslash correctly
# bytes_path = to_bytes(normalized_path, errors="backslashreplace")
return "file://{}".format(quote(path, errors="backslashreplace"))
@contextmanager
def open_file(link, session: Optional[PipSession] = None, stream: bool = False):
"""Open local or remote file for reading.
:param pipenv.patched.pip._internal.index.Link link: A link object from resolving dependencies with
pip, or else a URL.
:param Optional[PipSession] session: A :class:`~PipSession` instance
:param bool stream: Whether to stream the content if remote, default True
:raises ValueError: If link points to a local directory.
:return: a context manager to the opened file-like object
"""
if not isinstance(link, str):
try:
link = link.url_without_fragment
except AttributeError:
raise ValueError(f"Cannot parse url from unknown type: {link!r}")
if not is_valid_url(link) and os.path.exists(link):
link = path_to_url(link)
if is_file_url(link):
# Local URL
local_path = url_to_path(link)
if os.path.isdir(local_path):
raise ValueError(f"Cannot open directory for read: {link}")
else:
with open(local_path, "rb") as local_file:
yield local_file
else:
# Remote URL
headers = {"Accept-Encoding": "identity"}
if not session:
session = PipSession(cache=USER_CACHE_DIR)
resp = session.get(link, headers=headers, stream=stream)
if resp.status_code != 200:
err.print(f"HTTP error {resp.status_code} while getting {link}")
yield None
else:
# Creating a buffer-like object
buffer = io.BytesIO(resp.content)
yield buffer
@contextmanager
def temp_path():
# type: () -> Iterator[None]
"""A context manager which allows the ability to set sys.path temporarily.
>>> path_from_virtualenv = load_path("/path/to/venv/bin/python")
>>> print(sys.path)
[
'/home/user/.pyenv/versions/3.7.0/bin',
'/home/user/.pyenv/versions/3.7.0/lib/python37.zip',
'/home/user/.pyenv/versions/3.7.0/lib/python3.7',
'/home/user/.pyenv/versions/3.7.0/lib/python3.7/lib-dynload',
'/home/user/.pyenv/versions/3.7.0/lib/python3.7/site-packages'
]
>>> with temp_path():
sys.path = path_from_virtualenv
# Running in the context of the path above
run(["pip", "install", "stuff"])
>>> print(sys.path)
[
'/home/user/.pyenv/versions/3.7.0/bin',
'/home/user/.pyenv/versions/3.7.0/lib/python37.zip',
'/home/user/.pyenv/versions/3.7.0/lib/python3.7',
'/home/user/.pyenv/versions/3.7.0/lib/python3.7/lib-dynload',
'/home/user/.pyenv/versions/3.7.0/lib/python3.7/site-packages'
]
"""
path = list(sys.path)
try:
yield
finally:
sys.path = list(path)
TRACKED_TEMPORARY_DIRECTORIES = []
def create_tracked_tempdir(*args: Any, **kwargs: Any) -> str:
"""Create a tracked temporary directory.
This uses `TemporaryDirectory`, but does not remove the directory
when the return value goes out of scope, instead registers a handler
to clean up on program exit. The return value is the path to the
created directory.
"""
tempdir = TemporaryDirectory(*args, **kwargs)
TRACKED_TEMPORARY_DIRECTORIES.append(tempdir)
atexit.register(tempdir.cleanup)
warnings.simplefilter("ignore", ResourceWarning)
return tempdir.name
def check_for_unc_path(path):
# type: (Path) -> bool
"""Checks to see if a pathlib `Path` object is a unc path or not."""
return bool(
os.name == "nt"
and len(path.drive) > 2
and not path.drive[0].isalpha()
and path.drive[1] != ":"
)