# Copyright (C) 2012 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
import json
import os
import re
import sys
from logging import getLogger
from os.path import exists, expanduser, isfile, join
from .. import CONDA_PACKAGE_ROOT
from .. import __version__ as conda_version
from ..base.context import context, env_name, sys_rc_path, user_rc_path
from ..common.compat import on_win
from ..common.url import mask_anaconda_token
from ..core.index import _supplement_index_with_system
from ..deprecations import deprecated
from ..models.channel import all_channel_urls, offline_keep
from ..models.match_spec import MatchSpec
from ..utils import human_bytes
from .common import print_envs_list, stdout_json
log = getLogger(__name__)
def get_user_site(): # pragma: no cover
site_dirs = []
try:
if not on_win:
if exists(expanduser("~/.local/lib")):
python_re = re.compile(r"python\d\.\d")
for path in os.listdir(expanduser("~/.local/lib/")):
if python_re.match(path):
site_dirs.append("~/.local/lib/%s" % path)
else:
if "APPDATA" not in os.environ:
return site_dirs
APPDATA = os.environ["APPDATA"]
if exists(join(APPDATA, "Python")):
site_dirs = [
join(APPDATA, "Python", i)
for i in os.listdir(join(APPDATA, "PYTHON"))
]
except OSError as e:
log.debug("Error accessing user site directory.\n%r", e)
return site_dirs
IGNORE_FIELDS = {"files", "auth", "preferred_env", "priority"}
SKIP_FIELDS = IGNORE_FIELDS | {
"name",
"version",
"build",
"build_number",
"channel",
"schannel",
"size",
"fn",
"depends",
}
def dump_record(pkg):
return {k: v for k, v in pkg.dump().items() if k not in IGNORE_FIELDS}
def pretty_package(prec):
pkg = dump_record(prec)
d = {
"file name": prec.fn,
"name": pkg["name"],
"version": pkg["version"],
"build string": pkg["build"],
"build number": pkg["build_number"],
"channel": str(prec.channel),
"size": human_bytes(pkg["size"]),
}
for key in sorted(set(pkg.keys()) - SKIP_FIELDS):
d[key] = pkg[key]
print()
header = "{} {} {}".format(d["name"], d["version"], d["build string"])
print(header)
print("-" * len(header))
for key in d:
print("%-12s: %s" % (key, d[key]))
print("dependencies:")
for dep in pkg["depends"]:
print(" %s" % dep)
def print_package_info(packages):
from ..core.subdir_data import SubdirData
results = {}
for package in packages:
spec = MatchSpec(package)
results[package] = tuple(SubdirData.query_all(spec))
if context.json:
stdout_json({package: results[package] for package in packages})
else:
for result in results.values():
for prec in result:
pretty_package(prec)
deprecated.topic(
"23.9",
"24.3",
topic="`conda info package_name`",
addendum="Use `conda search package_name --info` instead.",
)
def get_info_dict(system=False):
try:
from requests import __version__ as requests_version
# These environment variables can influence requests' behavior, along with configuration
# in a .netrc file
# CURL_CA_BUNDLE
# REQUESTS_CA_BUNDLE
# HTTP_PROXY
# HTTPS_PROXY
except ImportError: # pragma: no cover
try:
from pip._vendor.requests import __version__ as requests_version
except Exception as e: # pragma: no cover
requests_version = "Error %r" % e
except Exception as e: # pragma: no cover
requests_version = "Error %r" % e
try:
import conda_build
except ImportError: # pragma: no cover
conda_build_version = "not installed"
except Exception as e: # pragma: no cover
conda_build_version = "Error %s" % e
else: # pragma: no cover
conda_build_version = conda_build.__version__
virtual_pkg_index = {}
_supplement_index_with_system(virtual_pkg_index)
virtual_pkgs = [[p.name, p.version, p.build] for p in virtual_pkg_index.values()]
channels = list(all_channel_urls(context.channels))
if not context.json:
channels = [c + ("" if offline_keep(c) else " (offline)") for c in channels]
channels = [mask_anaconda_token(c) for c in channels]
netrc_file = os.environ.get("NETRC")
if not netrc_file:
user_netrc = expanduser("~/.netrc")
if isfile(user_netrc):
netrc_file = user_netrc
active_prefix_name = env_name(context.active_prefix)
info_dict = dict(
platform=context.subdir,
conda_version=conda_version,
conda_env_version=conda_version,
conda_build_version=conda_build_version,
root_prefix=context.root_prefix,
conda_prefix=context.conda_prefix,
av_data_dir=context.av_data_dir,
av_metadata_url_base=context.signing_metadata_url_base,
root_writable=context.root_writable,
pkgs_dirs=context.pkgs_dirs,
envs_dirs=context.envs_dirs,
default_prefix=context.default_prefix,
active_prefix=context.active_prefix,
active_prefix_name=active_prefix_name,
conda_shlvl=context.shlvl,
channels=channels,
user_rc_path=user_rc_path,
rc_path=user_rc_path,
sys_rc_path=sys_rc_path,
# is_foreign=bool(foreign),
offline=context.offline,
envs=[],
python_version=".".join(map(str, sys.version_info)),
requests_version=requests_version,
user_agent=context.user_agent,
conda_location=CONDA_PACKAGE_ROOT,
config_files=context.config_files,
netrc_file=netrc_file,
virtual_pkgs=virtual_pkgs,
)
if on_win:
from ..common._os.windows import is_admin_on_windows
info_dict["is_windows_admin"] = is_admin_on_windows()
else:
info_dict["UID"] = os.geteuid()
info_dict["GID"] = os.getegid()
env_var_keys = {
"CIO_TEST",
"CURL_CA_BUNDLE",
"REQUESTS_CA_BUNDLE",
"SSL_CERT_FILE",
"LD_PRELOAD",
}
# add all relevant env vars, e.g. startswith('CONDA') or endswith('PATH')
env_var_keys.update(v for v in os.environ if v.upper().startswith("CONDA"))
env_var_keys.update(v for v in os.environ if v.upper().startswith("PYTHON"))
env_var_keys.update(v for v in os.environ if v.upper().endswith("PATH"))
env_var_keys.update(v for v in os.environ if v.upper().startswith("SUDO"))
env_vars = {
ev: os.getenv(ev, os.getenv(ev.lower(), "<not set>")) for ev in env_var_keys
}
proxy_keys = (v for v in os.environ if v.upper().endswith("PROXY"))
env_vars.update({ev: "<set>" for ev in proxy_keys})
info_dict.update(
{
"sys.version": sys.version,
"sys.prefix": sys.prefix,
"sys.executable": sys.executable,
"site_dirs": get_user_site(),
"env_vars": env_vars,
}
)
return info_dict
def get_env_vars_str(info_dict):
from textwrap import wrap
builder = []
builder.append("%23s:" % "environment variables")
env_vars = info_dict.get("env_vars", {})
for key in sorted(env_vars):
value = wrap(env_vars[key])
first_line = value[0] if len(value) else ""
other_lines = value[1:] if len(value) > 1 else ()
builder.append("%25s=%s" % (key, first_line))
for val in other_lines:
builder.append(" " * 26 + val)
return "\n".join(builder)
def get_main_info_str(info_dict):
for key in "pkgs_dirs", "envs_dirs", "channels", "config_files":
info_dict["_" + key] = ("\n" + 26 * " ").join(info_dict[key])
info_dict["_virtual_pkgs"] = ("\n" + 26 * " ").join(
["%s=%s=%s" % tuple(x) for x in info_dict["virtual_pkgs"]]
)
info_dict["_rtwro"] = "writable" if info_dict["root_writable"] else "read only"
format_param = lambda nm, val: "%23s : %s" % (nm, val)
builder = [""]
if info_dict["active_prefix_name"]:
builder.append(
format_param("active environment", info_dict["active_prefix_name"])
)
builder.append(format_param("active env location", info_dict["active_prefix"]))
else:
builder.append(format_param("active environment", info_dict["active_prefix"]))
if info_dict["conda_shlvl"] >= 0:
builder.append(format_param("shell level", info_dict["conda_shlvl"]))
builder.extend(
(
format_param("user config file", info_dict["user_rc_path"]),
format_param("populated config files", info_dict["_config_files"]),
format_param("conda version", info_dict["conda_version"]),
format_param("conda-build version", info_dict["conda_build_version"]),
format_param("python version", info_dict["python_version"]),
format_param("virtual packages", info_dict["_virtual_pkgs"]),
format_param(
"base environment",
"{} ({})".format(info_dict["root_prefix"], info_dict["_rtwro"]),
),
format_param("conda av data dir", info_dict["av_data_dir"]),
format_param("conda av metadata url", info_dict["av_metadata_url_base"]),
format_param("channel URLs", info_dict["_channels"]),
format_param("package cache", info_dict["_pkgs_dirs"]),
format_param("envs directories", info_dict["_envs_dirs"]),
format_param("platform", info_dict["platform"]),
format_param("user-agent", info_dict["user_agent"]),
)
)
if on_win:
builder.append(format_param("administrator", info_dict["is_windows_admin"]))
else:
builder.append(
format_param("UID:GID", "{}:{}".format(info_dict["UID"], info_dict["GID"]))
)
builder.extend(
(
format_param("netrc file", info_dict["netrc_file"]),
format_param("offline mode", info_dict["offline"]),
)
)
builder.append("")
return "\n".join(builder)
def execute(args, parser):
if args.base:
if context.json:
stdout_json({"root_prefix": context.root_prefix})
else:
print(f"{context.root_prefix}")
return
if args.packages:
from ..resolve import ResolvePackageNotFound
try:
print_package_info(args.packages)
return
except ResolvePackageNotFound as e: # pragma: no cover
from ..exceptions import PackagesNotFoundError
raise PackagesNotFoundError(e.bad_deps)
if args.unsafe_channels:
if not context.json:
print("\n".join(context.channels))
else:
print(json.dumps({"channels": context.channels}))
return 0
options = "envs", "system"
if args.all or context.json:
for option in options:
setattr(args, option, True)
info_dict = get_info_dict(args.system)
if (
args.all or all(not getattr(args, opt) for opt in options)
) and not context.json:
print(get_main_info_str(info_dict) + "\n")
if args.envs:
from ..core.envs_manager import list_all_known_prefixes
info_dict["envs"] = list_all_known_prefixes()
print_envs_list(info_dict["envs"], not context.json)
if args.system:
if not context.json:
from .find_commands import find_commands, find_executable
print("sys.version: %s..." % (sys.version[:40]))
print("sys.prefix: %s" % sys.prefix)
print("sys.executable: %s" % sys.executable)
print("conda location: %s" % info_dict["conda_location"])
for cmd in sorted(set(find_commands() + ("build",))):
print("conda-{}: {}".format(cmd, find_executable("conda-" + cmd)))
print("user site dirs: ", end="")
site_dirs = info_dict["site_dirs"]
if site_dirs:
print(site_dirs[0])
else:
print()
for site_dir in site_dirs[1:]:
print(" %s" % site_dir)
print()
for name, value in sorted(info_dict["env_vars"].items()):
print(f"{name}: {value}")
print()
if context.json:
stdout_json(info_dict)