|
1 | 1 | # Copyright (c) 2023-2026 Arista Networks, Inc. |
2 | 2 | # Use of this source code is governed by the Apache License 2.0 |
3 | 3 | # that can be found in the LICENSE file. |
| 4 | +from __future__ import annotations |
4 | 5 |
|
5 | 6 | import json |
6 | 7 | import sys |
7 | 8 | import warnings |
8 | 9 | from importlib import import_module |
9 | | -from importlib.metadata import Distribution, PackageNotFoundError, metadata, version |
| 10 | +from importlib.metadata import Distribution, PackageNotFoundError, version |
10 | 11 | from logging import getLogger |
11 | 12 | from pathlib import Path |
12 | 13 | from subprocess import PIPE, Popen |
13 | | -from typing import Any |
| 14 | +from typing import TYPE_CHECKING, Any |
14 | 15 |
|
15 | 16 | import yaml |
16 | 17 | from ansible import constants as C # noqa: N812 |
|
20 | 21 | from ansible_collections.arista.avd.plugins import PYTHON_AVD_PATH, RUNNING_FROM_SOURCE |
21 | 22 | from ansible_collections.arista.avd.plugins.plugin_utils.utils.avd_action_plugin import AvdActionPlugin, AvdLoggingConfig |
22 | 23 |
|
| 24 | +if TYPE_CHECKING: |
| 25 | + # Relying on packaging installed by ansible |
| 26 | + from packaging.requirements import Requirement |
| 27 | + from packaging.specifiers import SpecifierSet |
| 28 | + |
23 | 29 | try: |
24 | 30 | # Relying on packaging installed by ansible |
25 | | - from packaging.requirements import InvalidRequirement, Requirement |
| 31 | + from packaging.requirements import Requirement |
26 | 32 | from packaging.specifiers import SpecifierSet |
27 | 33 |
|
28 | 34 | HAS_PACKAGING = True |
29 | 35 | except ImportError: |
30 | 36 | HAS_PACKAGING = False |
31 | | - # Making ansible-test sanity happy |
32 | | - Requirement = object |
33 | 37 |
|
34 | 38 | LOGGER = getLogger("ansible_collections.arista.avd") |
35 | 39 | DISPLAY = Display() |
@@ -81,24 +85,6 @@ def _validate_python_version(info: dict[str, Any]) -> bool: |
81 | 85 | return True |
82 | 86 |
|
83 | 87 |
|
84 | | -def _parse_requirements(req_str: str) -> tuple[Requirement, list[str]]: |
85 | | - """Parse a requirement string and return the parsed object and a list of extras requirements to parse if any.""" |
86 | | - try: |
87 | | - req = Requirement(req_str) |
88 | | - except InvalidRequirement as exc: |
89 | | - msg = f"Wrong format for requirement {req_str}" |
90 | | - raise ValueError(msg) from exc |
91 | | - |
92 | | - extras = [] |
93 | | - if req.extras: |
94 | | - for subreq_name in metadata(req.name).get_all("Requires-Dist"): |
95 | | - subreq = Requirement(subreq_name) |
96 | | - if subreq.marker: |
97 | | - extras.extend([subreq_name for marker in subreq.marker._markers if str(marker[0]) == "extra" and str(marker[2]) in req.extras]) |
98 | | - |
99 | | - return req, extras |
100 | | - |
101 | | - |
102 | 88 | def _check_requirement(req: Requirement, requirements_dict: dict[str, Any]) -> bool: |
103 | 89 | """ |
104 | 90 | Check one requirement and in-place update requirement_dict. |
@@ -195,19 +181,17 @@ def _validate_python_requirements(requirements: list[str], info: dict[str, Any]) |
195 | 181 | } |
196 | 182 |
|
197 | 183 | # Remove the comments including inline comments |
198 | | - requirements = [req.split(" #", maxsplit=1)[0] for req in requirements if req[0] != "#"] |
| 184 | + requirements = [req.split(" #", maxsplit=1)[0] for req in requirements if req != "" and req[0] != "#"] |
199 | 185 | for raw_req in requirements: |
200 | | - req, extras = _parse_requirements(raw_req) |
| 186 | + req = Requirement(raw_req) |
201 | 187 | if RUNNING_FROM_SOURCE and req.name == "pyavd": |
202 | | - LOGGER.debug("AVD is running from source, *not* checking pyavd version nor any extra.") |
| 188 | + LOGGER.debug("AVD is running from source, *not* checking pyavd version.") |
203 | 189 | requirements_dict["valid"][req.name] = { |
204 | 190 | "installed": "running from source", |
205 | 191 | "required_version": str(req.specifier) if len(req.specifier) > 0 else None, |
206 | 192 | } |
207 | 193 | continue |
208 | 194 |
|
209 | | - requirements.extend(extras) |
210 | | - |
211 | 195 | valid = valid and _check_requirement(req, requirements_dict) |
212 | 196 |
|
213 | 197 | info["python_requirements"] = requirements_dict |
|
0 commit comments