From 85a646c7816c9a8e6799d08ff97c07028bbc2fef Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:31:08 -0800 Subject: [PATCH 01/12] enforce pyproject --- .../azure-sdk-tools/azpysdk/verify_whl.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 6968e9e78b74..d05126f2ec07 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -99,6 +99,45 @@ def should_verify_package(package_name): return package_name not in EXCLUDED_PACKAGES and "nspkg" not in package_name and "-mgmt" not in package_name +def has_stable_version_on_pypi(package_name: str) -> bool: + """Check if the package has any stable (non-prerelease) version on PyPI.""" + try: + all_versions = retrieve_versions_from_pypi(package_name) + stable_versions = [Version(v) for v in all_versions if not Version(v).is_prerelease] + return len(stable_versions) > 0 + except Exception: + return False + + +def verify_conda_section(package_dir: str, package_name: str) -> bool: + """Verify that packages with stable versions on PyPI have [tool.azure-sdk-conda] section in pyproject.toml.""" + if not has_stable_version_on_pypi(package_name): + logging.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") + return True + + pyproject_path = os.path.join(package_dir, "pyproject.toml") + if not os.path.exists(pyproject_path): + logging.error(f"Package {package_name} has a stable version on PyPI but is missing pyproject.toml") + return False + + try: + with open(pyproject_path, "r", encoding="utf-8") as f: + content = f.read() + + if "[tool.azure-sdk-conda]" not in content: + logging.error( + f"Package {package_name} has a stable version on PyPI but is missing " + "[tool.azure-sdk-conda] section in pyproject.toml" + ) + return False + + logging.info(f"Package {package_name} has required [tool.azure-sdk-conda] section") + return True + except Exception as e: + logging.error(f"Failed to read pyproject.toml for {package_name}: {e}") + return False + + def get_prior_version(package_name: str, current_version: str) -> Optional[str]: """Get prior stable version if it exists, otherwise get prior preview version, else return None.""" try: @@ -255,4 +294,12 @@ def run(self, args: argparse.Namespace) -> int: logger.error(f"Failed to verify whl for package {package_name}") results.append(1) + # Verify conda section for packages with stable versions on PyPI + if not verify_conda_section(package_dir, package_name): + logger.error(f"Failed conda section verification for package {package_name}") + logger.error( + "As part of releasing stable packages to Conda, the pyproject.toml must include a [tool.azure-sdk-conda] section and specify if the package should be released individually or bundled." + ) + results.append(1) + return max(results) if results else 0 From e9254319d243735c2e372219c672c378bbc975ef Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:38:54 -0800 Subject: [PATCH 02/12] minor --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index d05126f2ec07..8bada00b2ef0 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -130,8 +130,6 @@ def verify_conda_section(package_dir: str, package_name: str) -> bool: "[tool.azure-sdk-conda] section in pyproject.toml" ) return False - - logging.info(f"Package {package_name} has required [tool.azure-sdk-conda] section") return True except Exception as e: logging.error(f"Failed to read pyproject.toml for {package_name}: {e}") @@ -296,7 +294,6 @@ def run(self, args: argparse.Namespace) -> int: # Verify conda section for packages with stable versions on PyPI if not verify_conda_section(package_dir, package_name): - logger.error(f"Failed conda section verification for package {package_name}") logger.error( "As part of releasing stable packages to Conda, the pyproject.toml must include a [tool.azure-sdk-conda] section and specify if the package should be released individually or bundled." ) From 0823b79bffe35fc8c6349462578e80d6e8feaac4 Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:43:26 -0800 Subject: [PATCH 03/12] use logger instead of logging --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 8bada00b2ef0..0fb69b356c0b 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -1,5 +1,4 @@ import argparse -import logging import os import sys import glob @@ -77,7 +76,7 @@ def verify_whl_root_directory( non_azure_folders = [d for d in root_folders if d != expected_top_level_module and not d.endswith(".dist-info")] if non_azure_folders: - logging.error( + logger.error( "whl has following incorrect directory at root level [%s]", non_azure_folders, ) @@ -112,12 +111,12 @@ def has_stable_version_on_pypi(package_name: str) -> bool: def verify_conda_section(package_dir: str, package_name: str) -> bool: """Verify that packages with stable versions on PyPI have [tool.azure-sdk-conda] section in pyproject.toml.""" if not has_stable_version_on_pypi(package_name): - logging.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") + logger.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") return True pyproject_path = os.path.join(package_dir, "pyproject.toml") if not os.path.exists(pyproject_path): - logging.error(f"Package {package_name} has a stable version on PyPI but is missing pyproject.toml") + logger.error(f"Package {package_name} has a stable version on PyPI but is missing pyproject.toml") return False try: @@ -125,14 +124,14 @@ def verify_conda_section(package_dir: str, package_name: str) -> bool: content = f.read() if "[tool.azure-sdk-conda]" not in content: - logging.error( + logger.error( f"Package {package_name} has a stable version on PyPI but is missing " "[tool.azure-sdk-conda] section in pyproject.toml" ) return False return True except Exception as e: - logging.error(f"Failed to read pyproject.toml for {package_name}: {e}") + logger.error(f"Failed to read pyproject.toml for {package_name}: {e}") return False @@ -216,7 +215,7 @@ def verify_metadata_compatibility(current_metadata: Dict[str, Any], prior_metada repo_urls = ["homepage", "repository"] current_keys_lower = {k.lower() for k in current_metadata.keys()} if not any(key in current_keys_lower for key in repo_urls): - logging.error(f"Current metadata must contain at least one of: {repo_urls}") + logger.error(f"Current metadata must contain at least one of: {repo_urls}") return False if not prior_metadata: @@ -229,7 +228,7 @@ def verify_metadata_compatibility(current_metadata: Dict[str, Any], prior_metada is_compatible = prior_keys_filtered.issubset(current_keys) if not is_compatible: missing_keys = prior_keys_filtered - current_keys - logging.error("Metadata compatibility failed. Missing keys: %s", missing_keys) + logger.error("Metadata compatibility failed. Missing keys: %s", missing_keys) return is_compatible From c2621344da6a440ca886b21a2945195c8469b916 Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:24:17 -0800 Subject: [PATCH 04/12] dedupe error msg --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 0fb69b356c0b..79d69506a4f1 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -126,7 +126,8 @@ def verify_conda_section(package_dir: str, package_name: str) -> bool: if "[tool.azure-sdk-conda]" not in content: logger.error( f"Package {package_name} has a stable version on PyPI but is missing " - "[tool.azure-sdk-conda] section in pyproject.toml" + "[tool.azure-sdk-conda] section in pyproject.toml. This section is required to " + "specify if the package should be released individually or bundled to Conda." ) return False return True @@ -293,9 +294,6 @@ def run(self, args: argparse.Namespace) -> int: # Verify conda section for packages with stable versions on PyPI if not verify_conda_section(package_dir, package_name): - logger.error( - "As part of releasing stable packages to Conda, the pyproject.toml must include a [tool.azure-sdk-conda] section and specify if the package should be released individually or bundled." - ) results.append(1) return max(results) if results else 0 From 75681c667f18475909c194ff5e8bfce4adffd92e Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Thu, 12 Feb 2026 09:35:10 -0800 Subject: [PATCH 05/12] check for section field --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 79d69506a4f1..121dcce5fe08 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -130,6 +130,9 @@ def verify_conda_section(package_dir: str, package_name: str) -> bool: "specify if the package should be released individually or bundled to Conda." ) return False + elif "in_bundle" not in content: + logger.error(f"[tool.azure-sdk-conda] section in pyproject.toml is missing required field `in_bundle`.") + return False return True except Exception as e: logger.error(f"Failed to read pyproject.toml for {package_name}: {e}") From 497c6770f1f0e7bdad189b8b4e8c209aeabcd728 Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:29:44 -0800 Subject: [PATCH 06/12] only query pypi once --- .../azure-sdk-tools/azpysdk/verify_whl.py | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 75ef16e9f735..c6f56211e870 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -58,12 +58,16 @@ def extract_whl(dist_dir, version): def verify_whl_root_directory( - dist_dir: str, expected_top_level_module: str, parsed_pkg: ParsedSetup, executable: str + dist_dir: str, + expected_top_level_module: str, + parsed_pkg: ParsedSetup, + executable: str, + pypi_versions: List[str], ) -> bool: # Verify metadata compatibility with prior version version: str = parsed_pkg.version metadata: Dict[str, Any] = extract_package_metadata(get_path_to_zip(dist_dir, version)) - prior_version = get_prior_version(parsed_pkg.name, version) + prior_version = get_prior_version(parsed_pkg.name, version, pypi_versions=pypi_versions) if prior_version: if not verify_prior_version_metadata(parsed_pkg.name, prior_version, metadata, executable): return False @@ -98,19 +102,19 @@ def should_verify_package(package_name): return package_name not in EXCLUDED_PACKAGES and "nspkg" not in package_name and "-mgmt" not in package_name -def has_stable_version_on_pypi(package_name: str) -> bool: +def has_stable_version_on_pypi(package_name: str, pypi_versions: List[str]) -> bool: """Check if the package has any stable (non-prerelease) version on PyPI.""" try: - all_versions = retrieve_versions_from_pypi(package_name) + all_versions = pypi_versions stable_versions = [Version(v) for v in all_versions if not Version(v).is_prerelease] return len(stable_versions) > 0 except Exception: return False -def verify_conda_section(package_dir: str, package_name: str) -> bool: +def verify_conda_section(package_dir: str, package_name: str, pypi_versions: List[str]) -> bool: """Verify that packages with stable versions on PyPI have [tool.azure-sdk-conda] section in pyproject.toml.""" - if not has_stable_version_on_pypi(package_name): + if not has_stable_version_on_pypi(package_name, pypi_versions=pypi_versions): logger.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") return True @@ -139,10 +143,15 @@ def verify_conda_section(package_dir: str, package_name: str) -> bool: return False -def get_prior_version(package_name: str, current_version: str) -> Optional[str]: - """Get prior stable version if it exists, otherwise get prior preview version, else return None.""" +def get_prior_version( + package_name: str, current_version: str, pypi_versions: Optional[List[str]] = None +) -> Optional[str]: + """Get prior stable version if it exists, otherwise get prior preview version, else return None. + + pypi_versions can be optionally passed in to avoid redundant PyPI calls + """ try: - all_versions = retrieve_versions_from_pypi(package_name) + all_versions = pypi_versions if pypi_versions is not None else retrieve_versions_from_pypi(package_name) current_ver = Version(current_version) prior_versions = [Version(v) for v in all_versions if Version(v) < current_ver] if not prior_versions: @@ -290,15 +299,21 @@ def run(self, args: argparse.Namespace) -> int: ) if should_verify_package(package_name): + pypi_versions = retrieve_versions_from_pypi(package_name) + logger.info(f"Verifying whl for package: {package_name}") - if verify_whl_root_directory(staging_directory, top_level_module, parsed, executable): + if verify_whl_root_directory( + staging_directory, top_level_module, parsed, executable, pypi_versions=pypi_versions + ): logger.info(f"Verified whl for package {package_name}") else: logger.error(f"Failed to verify whl for package {package_name}") results.append(1) # Verify conda section for packages with stable versions on PyPI - if not verify_conda_section(package_dir, package_name): + if verify_conda_section(package_dir, package_name, pypi_versions=pypi_versions): + logger.info(f"Verified conda section for package {package_name}") + else: results.append(1) return max(results) if results else 0 From 05e0e3c37f6348650d52cabde90669ace7578b10 Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:37:52 -0800 Subject: [PATCH 07/12] simplify conda config checking --- .../azure-sdk-tools/azpysdk/verify_whl.py | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index c6f56211e870..536c5d5eadd7 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -112,7 +112,7 @@ def has_stable_version_on_pypi(package_name: str, pypi_versions: List[str]) -> b return False -def verify_conda_section(package_dir: str, package_name: str, pypi_versions: List[str]) -> bool: +def verify_conda_section(package_dir: str, package_name: str, parsed_pkg: ParsedSetup, pypi_versions: List[str]) -> bool: """Verify that packages with stable versions on PyPI have [tool.azure-sdk-conda] section in pyproject.toml.""" if not has_stable_version_on_pypi(package_name, pypi_versions=pypi_versions): logger.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") @@ -122,26 +122,19 @@ def verify_conda_section(package_dir: str, package_name: str, pypi_versions: Lis if not os.path.exists(pyproject_path): logger.error(f"Package {package_name} has a stable version on PyPI but is missing pyproject.toml") return False - - try: - with open(pyproject_path, "r", encoding="utf-8") as f: - content = f.read() - - if "[tool.azure-sdk-conda]" not in content: - logger.error( - f"Package {package_name} has a stable version on PyPI but is missing " - "[tool.azure-sdk-conda] section in pyproject.toml. This section is required to " - "specify if the package should be released individually or bundled to Conda." - ) - return False - elif "in_bundle" not in content: - logger.error(f"[tool.azure-sdk-conda] section in pyproject.toml is missing required field `in_bundle`.") - return False - return True - except Exception as e: - logger.error(f"Failed to read pyproject.toml for {package_name}: {e}") + + config = parsed_pkg.get_conda_config() + if not config: + logger.error( + f"Package {package_name} has a stable version on PyPI but is missing " + "[tool.azure-sdk-conda] section in pyproject.toml. This section is required to " + "specify if the package should be released individually or bundled to Conda." + ) return False - + elif "in_bundle" not in config: + logger.error(f"[tool.azure-sdk-conda] section in pyproject.toml is missing required field `in_bundle`.") + return False + return True def get_prior_version( package_name: str, current_version: str, pypi_versions: Optional[List[str]] = None @@ -311,7 +304,7 @@ def run(self, args: argparse.Namespace) -> int: results.append(1) # Verify conda section for packages with stable versions on PyPI - if verify_conda_section(package_dir, package_name, pypi_versions=pypi_versions): + if verify_conda_section(package_dir, package_name, parsed, pypi_versions=pypi_versions): logger.info(f"Verified conda section for package {package_name}") else: results.append(1) From 1b6096a97012a87d3b1ae2b05cb4d5293b0eecdf Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Thu, 12 Feb 2026 11:06:47 -0800 Subject: [PATCH 08/12] format --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 536c5d5eadd7..d3875101dbc2 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -112,7 +112,9 @@ def has_stable_version_on_pypi(package_name: str, pypi_versions: List[str]) -> b return False -def verify_conda_section(package_dir: str, package_name: str, parsed_pkg: ParsedSetup, pypi_versions: List[str]) -> bool: +def verify_conda_section( + package_dir: str, package_name: str, parsed_pkg: ParsedSetup, pypi_versions: List[str] +) -> bool: """Verify that packages with stable versions on PyPI have [tool.azure-sdk-conda] section in pyproject.toml.""" if not has_stable_version_on_pypi(package_name, pypi_versions=pypi_versions): logger.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") @@ -122,7 +124,7 @@ def verify_conda_section(package_dir: str, package_name: str, parsed_pkg: Parsed if not os.path.exists(pyproject_path): logger.error(f"Package {package_name} has a stable version on PyPI but is missing pyproject.toml") return False - + config = parsed_pkg.get_conda_config() if not config: logger.error( @@ -136,6 +138,7 @@ def verify_conda_section(package_dir: str, package_name: str, parsed_pkg: Parsed return False return True + def get_prior_version( package_name: str, current_version: str, pypi_versions: Optional[List[str]] = None ) -> Optional[str]: From 86cc90536334c2d14c79c4a197baa379cbde4ccd Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Thu, 12 Feb 2026 11:25:10 -0800 Subject: [PATCH 09/12] minor fix --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index d3875101dbc2..f958367a448c 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -102,10 +102,9 @@ def should_verify_package(package_name): return package_name not in EXCLUDED_PACKAGES and "nspkg" not in package_name and "-mgmt" not in package_name -def has_stable_version_on_pypi(package_name: str, pypi_versions: List[str]) -> bool: +def has_stable_version_on_pypi(all_versions: List[str]) -> bool: """Check if the package has any stable (non-prerelease) version on PyPI.""" try: - all_versions = pypi_versions stable_versions = [Version(v) for v in all_versions if not Version(v).is_prerelease] return len(stable_versions) > 0 except Exception: @@ -116,7 +115,7 @@ def verify_conda_section( package_dir: str, package_name: str, parsed_pkg: ParsedSetup, pypi_versions: List[str] ) -> bool: """Verify that packages with stable versions on PyPI have [tool.azure-sdk-conda] section in pyproject.toml.""" - if not has_stable_version_on_pypi(package_name, pypi_versions=pypi_versions): + if not has_stable_version_on_pypi(pypi_versions): logger.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") return True @@ -136,6 +135,7 @@ def verify_conda_section( elif "in_bundle" not in config: logger.error(f"[tool.azure-sdk-conda] section in pyproject.toml is missing required field `in_bundle`.") return False + logger.info(f"Verified conda section for package {package_name}") return True @@ -307,9 +307,7 @@ def run(self, args: argparse.Namespace) -> int: results.append(1) # Verify conda section for packages with stable versions on PyPI - if verify_conda_section(package_dir, package_name, parsed, pypi_versions=pypi_versions): - logger.info(f"Verified conda section for package {package_name}") - else: + if not verify_conda_section(package_dir, package_name, parsed, pypi_versions=pypi_versions): results.append(1) return max(results) if results else 0 From 3863e26c27e7b4961e27df6c66e64077d22c5b42 Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:30:38 -0800 Subject: [PATCH 10/12] ignore yanked versions --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 5 ++++- eng/tools/azure-sdk-tools/pypi_tools/pypi.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index f958367a448c..1c75d245d078 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -105,7 +105,10 @@ def should_verify_package(package_name): def has_stable_version_on_pypi(all_versions: List[str]) -> bool: """Check if the package has any stable (non-prerelease) version on PyPI.""" try: - stable_versions = [Version(v) for v in all_versions if not Version(v).is_prerelease] + stable_versions = [ + pv for v in all_versions + if not (pv := Version(v)).is_prerelease and pv > Version("0.0.0") + ] return len(stable_versions) > 0 except Exception: return False diff --git a/eng/tools/azure-sdk-tools/pypi_tools/pypi.py b/eng/tools/azure-sdk-tools/pypi_tools/pypi.py index d9efb71bb326..b373029ff06e 100644 --- a/eng/tools/azure-sdk-tools/pypi_tools/pypi.py +++ b/eng/tools/azure-sdk-tools/pypi_tools/pypi.py @@ -61,8 +61,11 @@ def get_ordered_versions(self, package_name, filter_by_compatibility=False) -> L project = self.project(package_name) versions: List[Version] = [] - for package_version in project["releases"].keys(): + for package_version, files in project["releases"].items(): try: + # Skip yanked versions (no files or all files yanked) + if not files or all(f.get("yanked", False) for f in files): + continue versions.append(parse(package_version)) except InvalidVersion as e: logging.warn(f"Invalid version {package_version} for package {package_name}") From bbb21afa17d997274bbfee893d8d1c5ff3b69f01 Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:37:57 -0800 Subject: [PATCH 11/12] format --- eng/tools/azure-sdk-tools/azpysdk/verify_whl.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 1c75d245d078..0b7101dcf8da 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -105,10 +105,7 @@ def should_verify_package(package_name): def has_stable_version_on_pypi(all_versions: List[str]) -> bool: """Check if the package has any stable (non-prerelease) version on PyPI.""" try: - stable_versions = [ - pv for v in all_versions - if not (pv := Version(v)).is_prerelease and pv > Version("0.0.0") - ] + stable_versions = [pv for v in all_versions if not (pv := Version(v)).is_prerelease and pv > Version("0.0.0")] return len(stable_versions) > 0 except Exception: return False From e9738efc410b8e35700858b6525ee128f8971533 Mon Sep 17 00:00:00 2001 From: jennypng <63012604+JennyPng@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:27:50 -0800 Subject: [PATCH 12/12] update tests --- .../azure-sdk-tools/azpysdk/verify_whl.py | 2 +- .../tests/test_metadata_verification.py | 99 +++++++++++++++---- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py index 0b7101dcf8da..005d0493790e 100644 --- a/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py +++ b/eng/tools/azure-sdk-tools/azpysdk/verify_whl.py @@ -62,7 +62,7 @@ def verify_whl_root_directory( expected_top_level_module: str, parsed_pkg: ParsedSetup, executable: str, - pypi_versions: List[str], + pypi_versions: Optional[List[str]] = None, ) -> bool: # Verify metadata compatibility with prior version version: str = parsed_pkg.version diff --git a/eng/tools/azure-sdk-tools/tests/test_metadata_verification.py b/eng/tools/azure-sdk-tools/tests/test_metadata_verification.py index 793dd7712ff2..fd81ebfb9249 100644 --- a/eng/tools/azure-sdk-tools/tests/test_metadata_verification.py +++ b/eng/tools/azure-sdk-tools/tests/test_metadata_verification.py @@ -13,20 +13,14 @@ import glob import sys +from unittest.mock import MagicMock from ci_tools.parsing import ParsedSetup - -# Import the functions we want to test from the verify modules -tox_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", "tox")) -if tox_path not in sys.path: - sys.path.append(tox_path) - -# Also add the azure-sdk-tools path so pypi_tools can be imported -tools_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) -if tools_path not in sys.path: - sys.path.append(tools_path) - -from verify_whl import verify_whl_root_directory -from verify_sdist import verify_sdist +from azpysdk.verify_whl import ( + verify_whl_root_directory, + has_stable_version_on_pypi, + verify_conda_section, +) +from azpysdk.verify_sdist import verify_sdist_helper # Test scenario paths scenarios_folder = os.path.join(os.path.dirname(__file__), "integration", "scenarios") @@ -99,9 +93,13 @@ def test_verify_valid_metadata_passes(package_type, scenario_name, scenario_path # Run the appropriate verification function if package_type == "wheel": expected_module = parsed_pkg.namespace.split(".")[0] if parsed_pkg.namespace else "azure" - result = verify_whl_root_directory(os.path.dirname(package_path), expected_module, parsed_pkg) + result = verify_whl_root_directory( + os.path.dirname(package_path), expected_module, parsed_pkg, sys.executable, pypi_versions=[] + ) else: - result = verify_sdist(actual_scenario_path, os.path.dirname(package_path), parsed_pkg) + result = verify_sdist_helper( + actual_scenario_path, os.path.dirname(package_path), parsed_pkg, sys.executable + ) # The valid metadata should pass verification (return True) assert result is True, f"verify_{package_type} should return True for valid {scenario_name} metadata scenario" @@ -142,9 +140,13 @@ def test_verify_invalid_metadata_fails(package_type, scenario_name, scenario_pat with caplog.at_level("ERROR"): if package_type == "wheel": expected_module = parsed_pkg.namespace.split(".")[0] if parsed_pkg.namespace else "azure" - result = verify_whl_root_directory(os.path.dirname(package_path), expected_module, parsed_pkg) + result = verify_whl_root_directory( + os.path.dirname(package_path), expected_module, parsed_pkg, sys.executable, pypi_versions=None + ) else: - result = verify_sdist(actual_scenario_path, os.path.dirname(package_path), parsed_pkg) + result = verify_sdist_helper( + actual_scenario_path, os.path.dirname(package_path), parsed_pkg, sys.executable + ) # The invalid metadata should fail verification (return False) assert ( @@ -173,3 +175,66 @@ def test_verify_invalid_metadata_fails(package_type, scenario_name, scenario_pat # Cleanup dist directory if os.path.exists(dist_dir): shutil.rmtree(dist_dir) + + +# ======================= has_stable_version_on_pypi tests ======================= + + +def test_has_stable_version_on_pypi_with_stable(): + """Returns True when at least one stable version exists.""" + assert has_stable_version_on_pypi(["1.0.0", "2.0.0b1", "0.1.0"]) is True + + +def test_has_stable_version_on_pypi_only_previews(): + """Returns False when all versions are pre-releases.""" + assert has_stable_version_on_pypi(["1.0.0b1", "2.0.0a3", "0.1.0rc1"]) is False + + +def test_has_stable_version_on_pypi_empty(): + """Returns False for an empty version list.""" + assert has_stable_version_on_pypi([]) is False + + +def test_has_stable_version_on_pypi_only_zero(): + """Returns False when the only stable version is 0.0.0.""" + assert has_stable_version_on_pypi(["0.0.0"]) is False + + +# ======================= verify_conda_section tests ======================= + + +def test_verify_conda_section_skips_when_no_stable_version(): + """Should return True (pass) when there are no stable versions on PyPI.""" + parsed_pkg = MagicMock() + result = verify_conda_section("/fake/path", "pkg", parsed_pkg, pypi_versions=["1.0.0b1"]) + assert result is True + + +def test_verify_conda_section_fails_missing_conda_section(tmp_path): + """Should fail when pyproject.toml exists but has no [tool.azure-sdk-conda] section.""" + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text("[project]\nname = 'pkg'\n") + parsed_pkg = MagicMock() + parsed_pkg.get_conda_config.return_value = None + result = verify_conda_section(str(tmp_path), "pkg", parsed_pkg, pypi_versions=["1.0.0"]) + assert result is False + + +def test_verify_conda_section_fails_missing_in_bundle(tmp_path): + """Should fail when [tool.azure-sdk-conda] exists but 'in_bundle' key is missing.""" + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text("[tool.azure-sdk-conda]\nsome_other_key = true\n") + parsed_pkg = MagicMock() + parsed_pkg.get_conda_config.return_value = {"some_other_key": True} + result = verify_conda_section(str(tmp_path), "pkg", parsed_pkg, pypi_versions=["1.0.0"]) + assert result is False + + +def test_verify_conda_section_passes_with_valid_config(tmp_path): + """Should pass when [tool.azure-sdk-conda] has 'in_bundle' defined.""" + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text("[tool.azure-sdk-conda]\nin_bundle = true\n") + parsed_pkg = MagicMock() + parsed_pkg.get_conda_config.return_value = {"in_bundle": True} + result = verify_conda_section(str(tmp_path), "pkg", parsed_pkg, pypi_versions=["1.0.0"]) + assert result is True