-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathutils.py
More file actions
73 lines (55 loc) · 2.04 KB
/
utils.py
File metadata and controls
73 lines (55 loc) · 2.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
from __future__ import annotations
import base64
import hashlib
import os
import sys
from logging import getLogger
from pathlib import Path
from typing import Iterator
from conda.base.context import context, locate_prefix_by_name
from conda.models.match_spec import MatchSpec
logger = getLogger(f"conda.{__name__}")
def hash_as_base64url(data: bytes, algorithm: str = "sha256") -> str:
"""Digest as PEP 376 RECORD style base64url (no padding)."""
return (
base64.urlsafe_b64encode(hashlib.new(algorithm, data).digest()).decode("ascii").rstrip("=")
)
def sha256_as_base64url(data: bytes) -> str:
"""SHA256 digest as PEP 376 RECORD style base64url (no padding)."""
return hash_as_base64url(data)
def sha256_base64url_to_hex(value: str | None) -> str | None:
"""Convert base64url hash (e.g. from installer) to hex for conda paths.json."""
if not value or not value.strip():
return None
try:
value = value.strip()
# Ensure value is padded to a multiple of 4 since installer strips padding
value += "=" * (-len(value) % 4)
return base64.urlsafe_b64decode(value).hex()
except ValueError:
return None
def get_prefix(prefix: os.PathLike = None, name: str = None) -> Path:
if prefix:
return Path(prefix)
elif name:
return Path(locate_prefix_by_name(name))
else:
return Path(context.target_prefix)
def pypi_spec_variants(spec_str: str) -> Iterator[str]:
yield spec_str
spec = MatchSpec(spec_str)
seen = {spec_str}
for name_variant in (
spec.name.replace("-", "_"),
spec.name.replace("_", "-"),
):
if name_variant not in seen: # only yield if actually different
yield str(MatchSpec(spec, name=name_variant))
seen.add(name_variant)
class SuppressOutput:
def __enter__(self):
self._original_stdout = sys.stdout
sys.stdout = open(os.devnull, "w")
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout.close()
sys.stdout = self._original_stdout