Skip to content

Commit 5b994c1

Browse files
[ABI Dependency] Best-Effort support for pip
1 parent 9e335f8 commit 5b994c1

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

variantlib/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
)
6666
VALIDATION_PROVIDER_REQUIRES_REGEX = re.compile(r"[\S ]+")
6767

68+
VARIANT_ABI_DEPENDENCY_NAMESPACE: Literal["abi_dependency"] = "abi_dependency"
69+
6870

6971
# VALIDATION_PYTHON_PACKAGE_NAME_REGEX = re.compile(r"[^\s-]+?")
7072
# Per PEP 508: https://peps.python.org/pep-0508/#names

variantlib/resolver/lib.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
from __future__ import annotations
22

3+
import logging
4+
import os
5+
from importlib import metadata
36
from typing import TYPE_CHECKING
47

8+
from packaging.utils import canonicalize_name
9+
10+
from variantlib.constants import VARIANT_ABI_DEPENDENCY_NAMESPACE
511
from variantlib.models.variant import VariantDescription
612
from variantlib.models.variant import VariantFeature
713
from variantlib.models.variant import VariantProperty
@@ -20,6 +26,18 @@
2026
from variantlib.protocols import VariantFeatureValue
2127
from variantlib.protocols import VariantNamespace
2228

29+
logger = logging.getLogger(__name__)
30+
31+
32+
def _normalize_package_name(name: str) -> str:
33+
# VALIDATION_FEATURE_NAME_REGEX does not accepts "-"
34+
return canonicalize_name(name).replace("-", "_")
35+
36+
37+
def _normalize_package_version(version: str) -> str:
38+
# VALIDATION_VALUE_REGEX does not accepts "+"
39+
return version.split("+", maxsplit=1)[0]
40+
2341

2442
def filter_variants(
2543
vdescs: list[VariantDescription],
@@ -124,8 +142,62 @@ def sort_and_filter_supported_variants(
124142
:param property_priorities: Ordered list of `VariantProperty` objects.
125143
:return: Sorted and filtered list of `VariantDescription` objects.
126144
"""
145+
127146
validate_type(vdescs, list[VariantDescription])
147+
validate_type(supported_vprops, list[VariantProperty])
128148

149+
if namespace_priorities is None:
150+
namespace_priorities = []
151+
152+
# ======================================================================= #
153+
# ABI DEPENDENCY INJECTION #
154+
# ======================================================================= #
155+
156+
# 1. Manually fed from environment variable
157+
# Note: come first for "implicit higher priority"
158+
# Env Var Format: `VARIANT_ABI_DEPENDENCY=packageA==1.2.3,...,packageZ==7.8.9`
159+
if variant_abi_deps_env := os.environ.get("NV_VARIANT_PROVIDER_FORCE_SM_ARCH"):
160+
for pkg_spec in variant_abi_deps_env.split(","):
161+
try:
162+
pkg_name, pkg_version = pkg_spec.split("==", maxsplit=1)
163+
except ValueError:
164+
logger.exception(
165+
"`NV_VARIANT_PROVIDER_FORCE_SM_ARCH` received an invalid value "
166+
"`%(pkg_spec)s`. It will be ignored.\n"
167+
"Expected format: `packageA==1.2.3,...,packageZ==7.8.9`.",
168+
{"pkg_spec": pkg_spec},
169+
)
170+
continue
171+
172+
supported_vprops.append(
173+
VariantProperty(
174+
namespace=VARIANT_ABI_DEPENDENCY_NAMESPACE,
175+
feature=_normalize_package_name(pkg_name),
176+
value=_normalize_package_version(pkg_version),
177+
)
178+
)
179+
180+
# 2. Automatically populate from the current python environment
181+
packages = [
182+
(dist.metadata["Name"], dist.version) for dist in metadata.distributions()
183+
]
184+
for pkg_name, pkg_version in sorted(packages):
185+
supported_vprops.append(
186+
VariantProperty(
187+
namespace=VARIANT_ABI_DEPENDENCY_NAMESPACE,
188+
feature=_normalize_package_name(pkg_name),
189+
value=_normalize_package_version(pkg_version),
190+
)
191+
)
192+
193+
# 3. Adding `VARIANT_ABI_DEPENDENCY_NAMESPACE` at the back of`namespace_priorities`
194+
namespace_priorities.append(VARIANT_ABI_DEPENDENCY_NAMESPACE)
195+
196+
# ======================================================================= #
197+
# NULL VARIANT #
198+
# ======================================================================= #
199+
200+
# Adding the `null-variant` to the list - always "compatible"
129201
if (null_variant := VariantDescription()) not in vdescs:
130202
"""Add a null variant description to the list."""
131203
# This is needed to ensure that we always consider the null variant
@@ -139,7 +211,9 @@ def sort_and_filter_supported_variants(
139211
"""No supported properties provided, return no variants."""
140212
return []
141213

142-
validate_type(supported_vprops, list[VariantProperty])
214+
# ======================================================================= #
215+
# FILTERING #
216+
# ======================================================================= #
143217

144218
# Step 1: we remove any duplicate, or unsupported `VariantDescription` on
145219
# this platform.
@@ -153,6 +227,10 @@ def sort_and_filter_supported_variants(
153227
)
154228
)
155229

230+
# ======================================================================= #
231+
# SORTING #
232+
# ======================================================================= #
233+
156234
# Step 2: we sort the supported `VariantProperty`s based on their respective
157235
# priority.
158236
sorted_supported_vprops = sort_variant_properties(

0 commit comments

Comments
 (0)