Current File : /home/inlingua/miniconda3/lib/python3.1/site-packages/conda/common/path/__init__.py |
# Copyright (C) 2012 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
"""Common path utilities."""
from __future__ import annotations
import os
import re
from functools import cache
from logging import getLogger
from os.path import (
abspath,
basename,
expanduser,
expandvars,
normcase,
split,
)
from shutil import which
from typing import TYPE_CHECKING
from urllib.parse import urlsplit
from ... import CondaError
from ...deprecations import deprecated
from ..compat import on_win
from .directories import (
explode_directories,
get_all_directories,
get_leaf_directories,
tokenized_startswith,
)
from .python import (
_VERSION_REGEX,
get_major_minor_version,
get_python_noarch_target_path,
get_python_short_path,
get_python_site_packages_short_path,
missing_pyc_files,
parse_entry_point_def,
pyc_path,
)
from .windows import (
unix_path_to_win,
win_path_backout,
win_path_double_escape,
win_path_ok,
win_path_to_unix,
)
if TYPE_CHECKING:
from collections.abc import Iterable
from typing import Union
PathType = Union[str, os.PathLike[str]]
PathsType = Iterable[PathType]
__all__ = [
"explode_directories",
"get_all_directories",
"get_leaf_directories",
"get_major_minor_version",
"get_python_noarch_target_path",
"get_python_short_path",
"get_python_site_packages_short_path",
"missing_pyc_files",
"parse_entry_point_def",
"pyc_path",
"tokenized_startswith",
"unix_path_to_win",
"win_path_backout",
"win_path_double_escape",
"win_path_ok",
"win_path_to_unix",
]
log = getLogger(__name__)
PATH_MATCH_REGEX = (
r"\./" # ./
r"|\.\." # ..
r"|~" # ~
r"|/" # /
r"|[a-zA-Z]:[/\\]" # drive letter, colon, forward or backslash
r"|\\\\" # windows UNC path
r"|//" # windows UNC path
)
# any other extension will be mangled by CondaSession.get() as it tries to find
# channel names from URLs, through strip_pkg_extension()
KNOWN_EXTENSIONS = (".conda", ".tar.bz2", ".json", ".jlap", ".json.zst")
deprecated.constant(
"25.3",
"25.9",
"_VERSION_REGEX",
_VERSION_REGEX,
addendum="Use `conda.common.path.python._VERSION_REGEX` instead.",
)
del _VERSION_REGEX
def is_path(value):
if "://" in value:
return False
return re.match(PATH_MATCH_REGEX, value)
def expand(path):
return abspath(expanduser(expandvars(path)))
def paths_equal(path1, path2):
"""
Examples:
>>> paths_equal('/a/b/c', '/a/b/c/d/..')
True
"""
if on_win:
return normcase(abspath(path1)) == normcase(abspath(path2))
else:
return abspath(path1) == abspath(path2)
@cache
def url_to_path(url):
"""Convert a file:// URL to a path.
Relative file URLs (i.e. `file:relative/path`) are not supported.
"""
if is_path(url):
return url
if not url.startswith("file://"): # pragma: no cover
raise CondaError(
f"You can only turn absolute file: urls into paths (not {url})"
)
_, netloc, path, _, _ = urlsplit(url)
from ..url import percent_decode
path = percent_decode(path)
if netloc not in ("", "localhost", "127.0.0.1", "::1"):
if not netloc.startswith("\\\\"):
# The only net location potentially accessible is a Windows UNC path
netloc = "//" + netloc
else:
netloc = ""
# Handle Windows drive letters if present
if re.match("^/([a-z])[:|]", path, re.I):
path = path[1] + ":" + path[3:]
return netloc + path
BIN_DIRECTORY = "Scripts" if on_win else "bin"
@deprecated("25.3", "25.9", addendum="Use `conda.common.path.BIN_DIRECTORY` instead.")
def get_bin_directory_short_path():
return BIN_DIRECTORY
def ensure_pad(name, pad="_"):
"""
Examples:
>>> ensure_pad('conda')
'_conda_'
>>> ensure_pad('_conda')
'__conda_'
>>> ensure_pad('')
''
"""
if not name or name[0] == name[-1] == pad:
return name
else:
return f"{pad}{name}{pad}"
@deprecated("25.3", "25.9")
def is_private_env_name(env_name):
"""
Examples:
>>> is_private_env_name("_conda")
False
>>> is_private_env_name("_conda_")
True
"""
return env_name and env_name[0] == env_name[-1] == "_"
@deprecated("25.3", "25.9")
def is_private_env_path(env_path):
"""
Examples:
>>> is_private_env_path('/some/path/to/envs/_conda_')
True
>>> is_private_env_path('/not/an/envs_dir/_conda_')
False
"""
if env_path is not None:
envs_directory, env_name = split(env_path)
if basename(envs_directory) != "envs":
return False
return is_private_env_name(env_name)
return False
def right_pad_os_sep(path):
return path if path.endswith(os.sep) else path + os.sep
def split_filename(path_or_url):
dn, fn = split(path_or_url)
return (dn or None, fn) if "." in fn else (path_or_url, None)
deprecated.constant(
"25.3",
"25.9",
"which",
which,
addendum="Use builtin `shutil.which` instead.",
)
del which
def strip_pkg_extension(path: str):
"""
Examples:
>>> strip_pkg_extension("/path/_license-1.1-py27_1.tar.bz2")
('/path/_license-1.1-py27_1', '.tar.bz2')
>>> strip_pkg_extension("/path/_license-1.1-py27_1.conda")
('/path/_license-1.1-py27_1', '.conda')
>>> strip_pkg_extension("/path/_license-1.1-py27_1")
('/path/_license-1.1-py27_1', None)
"""
# NOTE: not using CONDA_TARBALL_EXTENSION_V1 or CONDA_TARBALL_EXTENSION_V2 to comply with
# import rules and to avoid a global lookup.
for extension in KNOWN_EXTENSIONS:
if path.endswith(extension):
return path[: -len(extension)], extension
return path, None
def is_package_file(path):
"""
Examples:
>>> is_package_file("/path/_license-1.1-py27_1.tar.bz2")
True
>>> is_package_file("/path/_license-1.1-py27_1.conda")
True
>>> is_package_file("/path/_license-1.1-py27_1")
False
"""
# NOTE: not using CONDA_TARBALL_EXTENSION_V1 or CONDA_TARBALL_EXTENSION_V2 to comply with
# import rules and to avoid a global lookup.
return path[-6:] == ".conda" or path[-8:] == ".tar.bz2"
def path_identity(paths: PathType | PathsType | None) -> str | tuple[str, ...] | None:
if paths is None:
return None
elif isinstance(paths, (str, os.PathLike)):
return os.path.normpath(paths)
else:
return tuple(os.path.normpath(path) for path in paths)