From f249b3fa8a10812844c8fc6701e5c231e84f0ca2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:02:34 +0000 Subject: [PATCH 1/9] Initial plan From cb8ff0ba6da1acba34391c55772d7e24038f20d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:07:34 +0000 Subject: [PATCH 2/9] Add pyproject.toml and update setup.py to support both setup.py and pyproject.toml packages Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- pyproject.toml | 40 ++++++++++++++++++++++++++++++++++++++++ setup.py | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000000..87d9ede4de88 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,40 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +[build-system] +requires = ["setuptools>=77.0.3", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "azure-sdk-for-python" +version = "1.0.0" +description = "Azure SDK for Python - Meta package for installing all Azure SDK packages" +readme = "README.md" +license = {text = "MIT"} +authors = [ + {name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com"} +] +requires-python = ">=3.9" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "License :: OSI Approved :: MIT License", +] +keywords = ["azure", "azure sdk"] + +[project.urls] +Homepage = "https://github.com/Azure/azure-sdk-for-python" +Repository = "https://github.com/Azure/azure-sdk-for-python" +Documentation = "https://docs.microsoft.com/python/azure/" + +[tool.setuptools] +py-modules = [] diff --git a/setup.py b/setup.py index dd1c2bcee4ab..f4fe53cc9520 100644 --- a/setup.py +++ b/setup.py @@ -11,13 +11,17 @@ import copy import sys import runpy +import subprocess root_folder = os.path.abspath(os.path.dirname(__file__)) # pull in any packages that exist in the root directory +# Support both setup.py and pyproject.toml packages packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} +packages.update({('.', os.path.dirname(p)) for p in glob.glob('azure*/pyproject.toml')}) # Handle the SDK folder as well packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) +packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/pyproject.toml')}) # [(base_folder, package_name), ...] to {package_name: base_folder, ...} packages = {package_name: base_folder for (base_folder, package_name) in packages} @@ -32,8 +36,9 @@ content_package = sorted([p for p in packages.keys() if p not in meta_package+nspkg_packages]) # Move azure-common at the beginning, it's important this goes first -content_package.remove("azure-common") -content_package.insert(0, "azure-common") +if "azure-common" in content_package: + content_package.remove("azure-common") + content_package.insert(0, "azure-common") # Package final: if "install" in sys.argv: @@ -44,6 +49,7 @@ for pkg_name in packages_for_installation: pkg_setup_folder = os.path.join(root_folder, packages[pkg_name], pkg_name) pkg_setup_path = os.path.join(pkg_setup_folder, 'setup.py') + pkg_pyproject_path = os.path.join(pkg_setup_folder, 'pyproject.toml') try: saved_dir = os.getcwd() @@ -52,8 +58,39 @@ os.chdir(pkg_setup_folder) sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) - print("Start ", pkg_setup_path) - result = runpy.run_path(pkg_setup_path) + # Determine which file to use: pyproject.toml with [project] or setup.py + use_pyproject = False + if os.path.exists(pkg_pyproject_path): + # Check if pyproject.toml has [project] section + try: + with open(pkg_pyproject_path, 'r') as f: + content = f.read() + if '[project]' in content: + use_pyproject = True + except Exception: + pass + + if use_pyproject: + # Use pip to install pyproject.toml-based packages + print("Start ", pkg_pyproject_path) + # Map setup.py commands to pip commands + if "install" in sys.argv: + cmd = [sys.executable, '-m', 'pip', 'install', '.'] + elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): + cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] + else: + # For other commands like --version, --help, etc., just show the package info + cmd = [sys.executable, '-m', 'pip', 'show', pkg_name] + + result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) + if result.returncode != 0 and "install" in sys.argv: + print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) + elif os.path.exists(pkg_setup_path): + # Use the traditional setup.py approach + print("Start ", pkg_setup_path) + result = runpy.run_path(pkg_setup_path) + else: + print(f"Warning: No setup.py or pyproject.toml found for {pkg_name}", file=sys.stderr) except Exception as e: print(e, file=sys.stderr) finally: From 881eb2faf9505faab808fe0d95a828a66f7cea6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:10:03 +0000 Subject: [PATCH 3/9] Add documentation and improve setup.py comments Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- setup.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/setup.py b/setup.py index f4fe53cc9520..d40ce2271616 100644 --- a/setup.py +++ b/setup.py @@ -5,6 +5,22 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. #-------------------------------------------------------------------------- +# +# This setup.py supports discovery and installation of Azure SDK packages +# from both traditional setup.py and modern pyproject.toml configurations. +# +# Package Discovery: +# - Finds packages with setup.py at root or in sdk/*/ directories +# - Finds packages with pyproject.toml at root or in sdk/*/ directories +# +# Installation Logic: +# - Packages with pyproject.toml containing [project] section: +# Installed using pip (PEP 621 compliant) +# - Packages with setup.py: +# Installed using traditional setuptools via runpy +# - Packages with both setup.py and pyproject.toml (without [project]): +# Prefer setup.py for backward compatibility +#-------------------------------------------------------------------------- import os.path import glob From 9bf77bfafcfe25c8c8c69f8d46b284b5c2804ab7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:12:31 +0000 Subject: [PATCH 4/9] Address code review feedback: use TOML parser, improve command handling, and fix error reporting Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- setup.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index d40ce2271616..f992c5f5d6cb 100644 --- a/setup.py +++ b/setup.py @@ -77,29 +77,38 @@ # Determine which file to use: pyproject.toml with [project] or setup.py use_pyproject = False if os.path.exists(pkg_pyproject_path): - # Check if pyproject.toml has [project] section + # Check if pyproject.toml has [project] section using TOML parser try: - with open(pkg_pyproject_path, 'r') as f: - content = f.read() - if '[project]' in content: + # Use tomllib for Python 3.11+, fallback to tomli for older versions + try: + import tomllib as toml + except ImportError: + import tomli as toml + + with open(pkg_pyproject_path, 'rb') as f: + pyproject_data = toml.load(f) + if 'project' in pyproject_data: use_pyproject = True except Exception: + # If parsing fails, fallback to setup.py if available pass if use_pyproject: # Use pip to install pyproject.toml-based packages - print("Start ", pkg_pyproject_path) # Map setup.py commands to pip commands if "install" in sys.argv: + print("Start ", pkg_pyproject_path) cmd = [sys.executable, '-m', 'pip', 'install', '.'] elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): + print("Start ", pkg_pyproject_path) cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] else: - # For other commands like --version, --help, etc., just show the package info - cmd = [sys.executable, '-m', 'pip', 'show', pkg_name] + # For other commands like --version, --help, etc., skip pyproject.toml packages + # These commands are meant for the root setup.py, not individual packages + continue result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) - if result.returncode != 0 and "install" in sys.argv: + if result.returncode != 0: print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) elif os.path.exists(pkg_setup_path): # Use the traditional setup.py approach From 3d2b7a8faa2c748a4c5699faa4494b10d551a0a1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:23:59 +0000 Subject: [PATCH 5/9] Remove setup.py and move logic to install_packages.py with pyproject.toml configuration Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- INSTALL.md | 92 ++++++++++++++++++++++++++++++++ install_packages.py | 127 ++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 5 +- setup.py | 123 ------------------------------------------ 4 files changed, 223 insertions(+), 124 deletions(-) create mode 100644 INSTALL.md create mode 100644 install_packages.py delete mode 100644 setup.py diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 000000000000..111671333812 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,92 @@ +# Azure SDK for Python - Root Installation + +## Overview + +The root of this repository contains a `pyproject.toml` and an `install_packages.py` script that can discover and install all Azure SDK packages in the repository. + +## Installation Methods + +### Method 1: Using the install script directly (Recommended) + +To install all Azure SDK packages: + +```bash +python install_packages.py install +``` + +To install packages in development/editable mode: + +```bash +python install_packages.py develop +``` + +To see available packages without installing: + +```bash +python install_packages.py --version +``` + +### Method 2: Using pip with the root package + +After installing this root package, you can use the CLI tool: + +```bash +# Install the root package first +pip install . + +# Then use the CLI tool +install-azure-sdk-packages install +``` + +## How It Works + +The installation script: + +1. **Discovers packages** by searching for: + - `azure*/setup.py` and `azure*/pyproject.toml` at the root level + - `sdk/*/azure*/setup.py` and `sdk/*/azure*/pyproject.toml` in SDK directories + +2. **Determines installation method** for each package: + - Packages with `pyproject.toml` containing `[project]` section → Uses `pip install` + - Packages with `setup.py` → Uses traditional setuptools + - Packages with both → Prefers `setup.py` for backward compatibility + +3. **Installs packages** in the correct order: + - Namespace packages (nspkg) first + - `azure-common` (if present) + - All other content packages + +## Package Types Supported + +- **Modern pyproject.toml packages** (PEP 621 compliant) +- **Traditional setup.py packages** +- **Mixed packages** (both files present) + +## Examples + +### Install a subset of packages + +The script installs all discovered packages. To install specific packages, use pip directly: + +```bash +pip install ./sdk/core/azure-core +pip install ./sdk/ai/azure-ai-projects +``` + +### Verify package discovery + +To see which packages will be discovered without installing: + +```bash +python install_packages.py --version +``` + +This will list all packages found in the repository. + +## Migration from setup.py + +Previously, this repository had a `setup.py` at the root. This has been replaced with: +- `pyproject.toml` - Modern Python package configuration (PEP 621) +- `install_packages.py` - Installation orchestration script + +The functionality remains the same, but now uses standard Python packaging tools. diff --git a/install_packages.py b/install_packages.py new file mode 100644 index 000000000000..98b99224fd6e --- /dev/null +++ b/install_packages.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- +# +# This script supports discovery and installation of Azure SDK packages +# from both traditional setup.py and modern pyproject.toml configurations. +# +# Package Discovery: +# - Finds packages with setup.py at root or in sdk/*/ directories +# - Finds packages with pyproject.toml at root or in sdk/*/ directories +# +# Installation Logic: +# - Packages with pyproject.toml containing [project] section: +# Installed using pip (PEP 621 compliant) +# - Packages with setup.py: +# Installed using traditional setuptools via runpy +# - Packages with both setup.py and pyproject.toml (without [project]): +# Prefer setup.py for backward compatibility +#-------------------------------------------------------------------------- + +import os.path +import glob +import copy +import sys +import runpy +import subprocess + +def main(): + root_folder = os.path.abspath(os.path.dirname(__file__)) + + # pull in any packages that exist in the root directory + # Support both setup.py and pyproject.toml packages + packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} + packages.update({('.', os.path.dirname(p)) for p in glob.glob('azure*/pyproject.toml')}) + # Handle the SDK folder as well + packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) + packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/pyproject.toml')}) + # [(base_folder, package_name), ...] to {package_name: base_folder, ...} + packages = {package_name: base_folder for (base_folder, package_name) in packages} + + # Extract nspkg and sort nspkg by number of "-" + nspkg_packages = [p for p in packages.keys() if "nspkg" in p] + nspkg_packages.sort(key = lambda x: len([c for c in x if c == '-'])) + + # Meta-packages to ignore + meta_package = ['azure-keyvault', 'azure-mgmt', 'azure', 'azure-storage'] + + # content packages are packages that are not meta nor nspkg + content_package = sorted([p for p in packages.keys() if p not in meta_package+nspkg_packages]) + + # Move azure-common at the beginning, it's important this goes first + if "azure-common" in content_package: + content_package.remove("azure-common") + content_package.insert(0, "azure-common") + + # Package final: + if "install" in sys.argv: + packages_for_installation = content_package + else: + packages_for_installation = nspkg_packages + content_package + + for pkg_name in packages_for_installation: + pkg_setup_folder = os.path.join(root_folder, packages[pkg_name], pkg_name) + pkg_setup_path = os.path.join(pkg_setup_folder, 'setup.py') + pkg_pyproject_path = os.path.join(pkg_setup_folder, 'pyproject.toml') + + try: + saved_dir = os.getcwd() + saved_syspath = sys.path + + os.chdir(pkg_setup_folder) + sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) + + # Determine which file to use: pyproject.toml with [project] or setup.py + use_pyproject = False + if os.path.exists(pkg_pyproject_path): + # Check if pyproject.toml has [project] section using TOML parser + try: + # Use tomllib for Python 3.11+, fallback to tomli for older versions + try: + import tomllib as toml + except ImportError: + import tomli as toml + + with open(pkg_pyproject_path, 'rb') as f: + pyproject_data = toml.load(f) + if 'project' in pyproject_data: + use_pyproject = True + except Exception: + # If parsing fails, fallback to setup.py if available + pass + + if use_pyproject: + # Use pip to install pyproject.toml-based packages + # Map setup.py commands to pip commands + if "install" in sys.argv: + print("Start ", pkg_pyproject_path) + cmd = [sys.executable, '-m', 'pip', 'install', '.'] + elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): + print("Start ", pkg_pyproject_path) + cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] + else: + # For other commands like --version, --help, etc., skip pyproject.toml packages + # These commands are meant for the root setup.py, not individual packages + continue + + result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) + if result.returncode != 0: + print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) + elif os.path.exists(pkg_setup_path): + # Use the traditional setup.py approach + print("Start ", pkg_setup_path) + result = runpy.run_path(pkg_setup_path) + else: + print(f"Warning: No setup.py or pyproject.toml found for {pkg_name}", file=sys.stderr) + except Exception as e: + print(e, file=sys.stderr) + finally: + os.chdir(saved_dir) + sys.path = saved_syspath + +if __name__ == '__main__': + main() diff --git a/pyproject.toml b/pyproject.toml index 87d9ede4de88..60a31a923f03 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,5 +36,8 @@ Homepage = "https://github.com/Azure/azure-sdk-for-python" Repository = "https://github.com/Azure/azure-sdk-for-python" Documentation = "https://docs.microsoft.com/python/azure/" +[project.scripts] +install-azure-sdk-packages = "install_packages:main" + [tool.setuptools] -py-modules = [] +py-modules = ["install_packages"] diff --git a/setup.py b/setup.py deleted file mode 100644 index f992c5f5d6cb..000000000000 --- a/setup.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python - -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -#-------------------------------------------------------------------------- -# -# This setup.py supports discovery and installation of Azure SDK packages -# from both traditional setup.py and modern pyproject.toml configurations. -# -# Package Discovery: -# - Finds packages with setup.py at root or in sdk/*/ directories -# - Finds packages with pyproject.toml at root or in sdk/*/ directories -# -# Installation Logic: -# - Packages with pyproject.toml containing [project] section: -# Installed using pip (PEP 621 compliant) -# - Packages with setup.py: -# Installed using traditional setuptools via runpy -# - Packages with both setup.py and pyproject.toml (without [project]): -# Prefer setup.py for backward compatibility -#-------------------------------------------------------------------------- - -import os.path -import glob -import copy -import sys -import runpy -import subprocess - -root_folder = os.path.abspath(os.path.dirname(__file__)) - -# pull in any packages that exist in the root directory -# Support both setup.py and pyproject.toml packages -packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} -packages.update({('.', os.path.dirname(p)) for p in glob.glob('azure*/pyproject.toml')}) -# Handle the SDK folder as well -packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) -packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/pyproject.toml')}) -# [(base_folder, package_name), ...] to {package_name: base_folder, ...} -packages = {package_name: base_folder for (base_folder, package_name) in packages} - -# Extract nspkg and sort nspkg by number of "-" -nspkg_packages = [p for p in packages.keys() if "nspkg" in p] -nspkg_packages.sort(key = lambda x: len([c for c in x if c == '-'])) - -# Meta-packages to ignore -meta_package = ['azure-keyvault', 'azure-mgmt', 'azure', 'azure-storage'] - -# content packages are packages that are not meta nor nspkg -content_package = sorted([p for p in packages.keys() if p not in meta_package+nspkg_packages]) - -# Move azure-common at the beginning, it's important this goes first -if "azure-common" in content_package: - content_package.remove("azure-common") - content_package.insert(0, "azure-common") - -# Package final: -if "install" in sys.argv: - packages_for_installation = content_package -else: - packages_for_installation = nspkg_packages + content_package - -for pkg_name in packages_for_installation: - pkg_setup_folder = os.path.join(root_folder, packages[pkg_name], pkg_name) - pkg_setup_path = os.path.join(pkg_setup_folder, 'setup.py') - pkg_pyproject_path = os.path.join(pkg_setup_folder, 'pyproject.toml') - - try: - saved_dir = os.getcwd() - saved_syspath = sys.path - - os.chdir(pkg_setup_folder) - sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) - - # Determine which file to use: pyproject.toml with [project] or setup.py - use_pyproject = False - if os.path.exists(pkg_pyproject_path): - # Check if pyproject.toml has [project] section using TOML parser - try: - # Use tomllib for Python 3.11+, fallback to tomli for older versions - try: - import tomllib as toml - except ImportError: - import tomli as toml - - with open(pkg_pyproject_path, 'rb') as f: - pyproject_data = toml.load(f) - if 'project' in pyproject_data: - use_pyproject = True - except Exception: - # If parsing fails, fallback to setup.py if available - pass - - if use_pyproject: - # Use pip to install pyproject.toml-based packages - # Map setup.py commands to pip commands - if "install" in sys.argv: - print("Start ", pkg_pyproject_path) - cmd = [sys.executable, '-m', 'pip', 'install', '.'] - elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): - print("Start ", pkg_pyproject_path) - cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] - else: - # For other commands like --version, --help, etc., skip pyproject.toml packages - # These commands are meant for the root setup.py, not individual packages - continue - - result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) - if result.returncode != 0: - print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) - elif os.path.exists(pkg_setup_path): - # Use the traditional setup.py approach - print("Start ", pkg_setup_path) - result = runpy.run_path(pkg_setup_path) - else: - print(f"Warning: No setup.py or pyproject.toml found for {pkg_name}", file=sys.stderr) - except Exception as e: - print(e, file=sys.stderr) - finally: - os.chdir(saved_dir) - sys.path = saved_syspath From 9f9c4ead570cb53c9c234a1fa1dcdf41ef206c4e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:33:59 +0000 Subject: [PATCH 6/9] Restore setup.py and remove install_packages.py and INSTALL.md Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- INSTALL.md | 92 -------------------------------- install_packages.py | 127 -------------------------------------------- pyproject.toml | 5 +- setup.py | 123 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 223 deletions(-) delete mode 100644 INSTALL.md delete mode 100644 install_packages.py create mode 100644 setup.py diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index 111671333812..000000000000 --- a/INSTALL.md +++ /dev/null @@ -1,92 +0,0 @@ -# Azure SDK for Python - Root Installation - -## Overview - -The root of this repository contains a `pyproject.toml` and an `install_packages.py` script that can discover and install all Azure SDK packages in the repository. - -## Installation Methods - -### Method 1: Using the install script directly (Recommended) - -To install all Azure SDK packages: - -```bash -python install_packages.py install -``` - -To install packages in development/editable mode: - -```bash -python install_packages.py develop -``` - -To see available packages without installing: - -```bash -python install_packages.py --version -``` - -### Method 2: Using pip with the root package - -After installing this root package, you can use the CLI tool: - -```bash -# Install the root package first -pip install . - -# Then use the CLI tool -install-azure-sdk-packages install -``` - -## How It Works - -The installation script: - -1. **Discovers packages** by searching for: - - `azure*/setup.py` and `azure*/pyproject.toml` at the root level - - `sdk/*/azure*/setup.py` and `sdk/*/azure*/pyproject.toml` in SDK directories - -2. **Determines installation method** for each package: - - Packages with `pyproject.toml` containing `[project]` section → Uses `pip install` - - Packages with `setup.py` → Uses traditional setuptools - - Packages with both → Prefers `setup.py` for backward compatibility - -3. **Installs packages** in the correct order: - - Namespace packages (nspkg) first - - `azure-common` (if present) - - All other content packages - -## Package Types Supported - -- **Modern pyproject.toml packages** (PEP 621 compliant) -- **Traditional setup.py packages** -- **Mixed packages** (both files present) - -## Examples - -### Install a subset of packages - -The script installs all discovered packages. To install specific packages, use pip directly: - -```bash -pip install ./sdk/core/azure-core -pip install ./sdk/ai/azure-ai-projects -``` - -### Verify package discovery - -To see which packages will be discovered without installing: - -```bash -python install_packages.py --version -``` - -This will list all packages found in the repository. - -## Migration from setup.py - -Previously, this repository had a `setup.py` at the root. This has been replaced with: -- `pyproject.toml` - Modern Python package configuration (PEP 621) -- `install_packages.py` - Installation orchestration script - -The functionality remains the same, but now uses standard Python packaging tools. diff --git a/install_packages.py b/install_packages.py deleted file mode 100644 index 98b99224fd6e..000000000000 --- a/install_packages.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python - -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -#-------------------------------------------------------------------------- -# -# This script supports discovery and installation of Azure SDK packages -# from both traditional setup.py and modern pyproject.toml configurations. -# -# Package Discovery: -# - Finds packages with setup.py at root or in sdk/*/ directories -# - Finds packages with pyproject.toml at root or in sdk/*/ directories -# -# Installation Logic: -# - Packages with pyproject.toml containing [project] section: -# Installed using pip (PEP 621 compliant) -# - Packages with setup.py: -# Installed using traditional setuptools via runpy -# - Packages with both setup.py and pyproject.toml (without [project]): -# Prefer setup.py for backward compatibility -#-------------------------------------------------------------------------- - -import os.path -import glob -import copy -import sys -import runpy -import subprocess - -def main(): - root_folder = os.path.abspath(os.path.dirname(__file__)) - - # pull in any packages that exist in the root directory - # Support both setup.py and pyproject.toml packages - packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} - packages.update({('.', os.path.dirname(p)) for p in glob.glob('azure*/pyproject.toml')}) - # Handle the SDK folder as well - packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) - packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/pyproject.toml')}) - # [(base_folder, package_name), ...] to {package_name: base_folder, ...} - packages = {package_name: base_folder for (base_folder, package_name) in packages} - - # Extract nspkg and sort nspkg by number of "-" - nspkg_packages = [p for p in packages.keys() if "nspkg" in p] - nspkg_packages.sort(key = lambda x: len([c for c in x if c == '-'])) - - # Meta-packages to ignore - meta_package = ['azure-keyvault', 'azure-mgmt', 'azure', 'azure-storage'] - - # content packages are packages that are not meta nor nspkg - content_package = sorted([p for p in packages.keys() if p not in meta_package+nspkg_packages]) - - # Move azure-common at the beginning, it's important this goes first - if "azure-common" in content_package: - content_package.remove("azure-common") - content_package.insert(0, "azure-common") - - # Package final: - if "install" in sys.argv: - packages_for_installation = content_package - else: - packages_for_installation = nspkg_packages + content_package - - for pkg_name in packages_for_installation: - pkg_setup_folder = os.path.join(root_folder, packages[pkg_name], pkg_name) - pkg_setup_path = os.path.join(pkg_setup_folder, 'setup.py') - pkg_pyproject_path = os.path.join(pkg_setup_folder, 'pyproject.toml') - - try: - saved_dir = os.getcwd() - saved_syspath = sys.path - - os.chdir(pkg_setup_folder) - sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) - - # Determine which file to use: pyproject.toml with [project] or setup.py - use_pyproject = False - if os.path.exists(pkg_pyproject_path): - # Check if pyproject.toml has [project] section using TOML parser - try: - # Use tomllib for Python 3.11+, fallback to tomli for older versions - try: - import tomllib as toml - except ImportError: - import tomli as toml - - with open(pkg_pyproject_path, 'rb') as f: - pyproject_data = toml.load(f) - if 'project' in pyproject_data: - use_pyproject = True - except Exception: - # If parsing fails, fallback to setup.py if available - pass - - if use_pyproject: - # Use pip to install pyproject.toml-based packages - # Map setup.py commands to pip commands - if "install" in sys.argv: - print("Start ", pkg_pyproject_path) - cmd = [sys.executable, '-m', 'pip', 'install', '.'] - elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): - print("Start ", pkg_pyproject_path) - cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] - else: - # For other commands like --version, --help, etc., skip pyproject.toml packages - # These commands are meant for the root setup.py, not individual packages - continue - - result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) - if result.returncode != 0: - print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) - elif os.path.exists(pkg_setup_path): - # Use the traditional setup.py approach - print("Start ", pkg_setup_path) - result = runpy.run_path(pkg_setup_path) - else: - print(f"Warning: No setup.py or pyproject.toml found for {pkg_name}", file=sys.stderr) - except Exception as e: - print(e, file=sys.stderr) - finally: - os.chdir(saved_dir) - sys.path = saved_syspath - -if __name__ == '__main__': - main() diff --git a/pyproject.toml b/pyproject.toml index 60a31a923f03..87d9ede4de88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,8 +36,5 @@ Homepage = "https://github.com/Azure/azure-sdk-for-python" Repository = "https://github.com/Azure/azure-sdk-for-python" Documentation = "https://docs.microsoft.com/python/azure/" -[project.scripts] -install-azure-sdk-packages = "install_packages:main" - [tool.setuptools] -py-modules = ["install_packages"] +py-modules = [] diff --git a/setup.py b/setup.py new file mode 100644 index 000000000000..f992c5f5d6cb --- /dev/null +++ b/setup.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python + +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- +# +# This setup.py supports discovery and installation of Azure SDK packages +# from both traditional setup.py and modern pyproject.toml configurations. +# +# Package Discovery: +# - Finds packages with setup.py at root or in sdk/*/ directories +# - Finds packages with pyproject.toml at root or in sdk/*/ directories +# +# Installation Logic: +# - Packages with pyproject.toml containing [project] section: +# Installed using pip (PEP 621 compliant) +# - Packages with setup.py: +# Installed using traditional setuptools via runpy +# - Packages with both setup.py and pyproject.toml (without [project]): +# Prefer setup.py for backward compatibility +#-------------------------------------------------------------------------- + +import os.path +import glob +import copy +import sys +import runpy +import subprocess + +root_folder = os.path.abspath(os.path.dirname(__file__)) + +# pull in any packages that exist in the root directory +# Support both setup.py and pyproject.toml packages +packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} +packages.update({('.', os.path.dirname(p)) for p in glob.glob('azure*/pyproject.toml')}) +# Handle the SDK folder as well +packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) +packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/pyproject.toml')}) +# [(base_folder, package_name), ...] to {package_name: base_folder, ...} +packages = {package_name: base_folder for (base_folder, package_name) in packages} + +# Extract nspkg and sort nspkg by number of "-" +nspkg_packages = [p for p in packages.keys() if "nspkg" in p] +nspkg_packages.sort(key = lambda x: len([c for c in x if c == '-'])) + +# Meta-packages to ignore +meta_package = ['azure-keyvault', 'azure-mgmt', 'azure', 'azure-storage'] + +# content packages are packages that are not meta nor nspkg +content_package = sorted([p for p in packages.keys() if p not in meta_package+nspkg_packages]) + +# Move azure-common at the beginning, it's important this goes first +if "azure-common" in content_package: + content_package.remove("azure-common") + content_package.insert(0, "azure-common") + +# Package final: +if "install" in sys.argv: + packages_for_installation = content_package +else: + packages_for_installation = nspkg_packages + content_package + +for pkg_name in packages_for_installation: + pkg_setup_folder = os.path.join(root_folder, packages[pkg_name], pkg_name) + pkg_setup_path = os.path.join(pkg_setup_folder, 'setup.py') + pkg_pyproject_path = os.path.join(pkg_setup_folder, 'pyproject.toml') + + try: + saved_dir = os.getcwd() + saved_syspath = sys.path + + os.chdir(pkg_setup_folder) + sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) + + # Determine which file to use: pyproject.toml with [project] or setup.py + use_pyproject = False + if os.path.exists(pkg_pyproject_path): + # Check if pyproject.toml has [project] section using TOML parser + try: + # Use tomllib for Python 3.11+, fallback to tomli for older versions + try: + import tomllib as toml + except ImportError: + import tomli as toml + + with open(pkg_pyproject_path, 'rb') as f: + pyproject_data = toml.load(f) + if 'project' in pyproject_data: + use_pyproject = True + except Exception: + # If parsing fails, fallback to setup.py if available + pass + + if use_pyproject: + # Use pip to install pyproject.toml-based packages + # Map setup.py commands to pip commands + if "install" in sys.argv: + print("Start ", pkg_pyproject_path) + cmd = [sys.executable, '-m', 'pip', 'install', '.'] + elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): + print("Start ", pkg_pyproject_path) + cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] + else: + # For other commands like --version, --help, etc., skip pyproject.toml packages + # These commands are meant for the root setup.py, not individual packages + continue + + result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) + if result.returncode != 0: + print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) + elif os.path.exists(pkg_setup_path): + # Use the traditional setup.py approach + print("Start ", pkg_setup_path) + result = runpy.run_path(pkg_setup_path) + else: + print(f"Warning: No setup.py or pyproject.toml found for {pkg_name}", file=sys.stderr) + except Exception as e: + print(e, file=sys.stderr) + finally: + os.chdir(saved_dir) + sys.path = saved_syspath From 377e4f18b2f224c9b54084a2902b19a6bd59f06b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:45:02 +0000 Subject: [PATCH 7/9] Remove copyright header from pyproject.toml and filter packages to only include pyproject.toml with [project] section Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- pyproject.toml | 6 ------ setup.py | 55 +++++++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 87d9ede4de88..4f7daff08dd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,3 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - [build-system] requires = ["setuptools>=77.0.3", "wheel"] build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index f992c5f5d6cb..45a65a739b3e 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ # # Package Discovery: # - Finds packages with setup.py at root or in sdk/*/ directories -# - Finds packages with pyproject.toml at root or in sdk/*/ directories +# - Finds packages with pyproject.toml (with [project] section) at root or in sdk/*/ directories # # Installation Logic: # - Packages with pyproject.toml containing [project] section: @@ -29,15 +29,39 @@ import runpy import subprocess +# Use tomllib for Python 3.11+, fallback to tomli for older versions +try: + import tomllib as toml +except ImportError: + import tomli as toml + root_folder = os.path.abspath(os.path.dirname(__file__)) -# pull in any packages that exist in the root directory -# Support both setup.py and pyproject.toml packages +# Helper function to check if pyproject.toml has [project] section +def has_project_section(pyproject_path): + """Check if a pyproject.toml file has a [project] section.""" + try: + with open(pyproject_path, 'rb') as f: + pyproject_data = toml.load(f) + return 'project' in pyproject_data + except Exception: + return False + +# Discover packages with setup.py packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} -packages.update({('.', os.path.dirname(p)) for p in glob.glob('azure*/pyproject.toml')}) -# Handle the SDK folder as well packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) -packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/pyproject.toml')}) + +# Discover packages with pyproject.toml that have [project] section +for pyproject_file in glob.glob('azure*/pyproject.toml'): + pyproject_path = os.path.join(root_folder, pyproject_file) + if has_project_section(pyproject_path): + packages.add(('.', os.path.dirname(pyproject_file))) + +for pyproject_file in glob.glob('sdk/*/azure*/pyproject.toml'): + pyproject_path = os.path.join(root_folder, pyproject_file) + if has_project_section(pyproject_path): + packages.add(tuple(os.path.dirname(pyproject_file).rsplit(os.sep, 1))) + # [(base_folder, package_name), ...] to {package_name: base_folder, ...} packages = {package_name: base_folder for (base_folder, package_name) in packages} @@ -75,23 +99,8 @@ sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) # Determine which file to use: pyproject.toml with [project] or setup.py - use_pyproject = False - if os.path.exists(pkg_pyproject_path): - # Check if pyproject.toml has [project] section using TOML parser - try: - # Use tomllib for Python 3.11+, fallback to tomli for older versions - try: - import tomllib as toml - except ImportError: - import tomli as toml - - with open(pkg_pyproject_path, 'rb') as f: - pyproject_data = toml.load(f) - if 'project' in pyproject_data: - use_pyproject = True - except Exception: - # If parsing fails, fallback to setup.py if available - pass + # Since we already filtered during discovery, if pyproject.toml exists it has [project] + use_pyproject = os.path.exists(pkg_pyproject_path) and has_project_section(pkg_pyproject_path) if use_pyproject: # Use pip to install pyproject.toml-based packages From 46fb773177d72e3129038f2e2ec1bd2d93cc0bf1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:49:22 +0000 Subject: [PATCH 8/9] Remove pyproject.toml and restore original setup.py Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- pyproject.toml | 34 --------------------- setup.py | 83 ++++---------------------------------------------- 2 files changed, 6 insertions(+), 111 deletions(-) delete mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 4f7daff08dd4..000000000000 --- a/pyproject.toml +++ /dev/null @@ -1,34 +0,0 @@ -[build-system] -requires = ["setuptools>=77.0.3", "wheel"] -build-backend = "setuptools.build_meta" - -[project] -name = "azure-sdk-for-python" -version = "1.0.0" -description = "Azure SDK for Python - Meta package for installing all Azure SDK packages" -readme = "README.md" -license = {text = "MIT"} -authors = [ - {name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com"} -] -requires-python = ">=3.9" -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Programming Language :: Python", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "License :: OSI Approved :: MIT License", -] -keywords = ["azure", "azure sdk"] - -[project.urls] -Homepage = "https://github.com/Azure/azure-sdk-for-python" -Repository = "https://github.com/Azure/azure-sdk-for-python" -Documentation = "https://docs.microsoft.com/python/azure/" - -[tool.setuptools] -py-modules = [] diff --git a/setup.py b/setup.py index 45a65a739b3e..dd1c2bcee4ab 100644 --- a/setup.py +++ b/setup.py @@ -5,63 +5,19 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. #-------------------------------------------------------------------------- -# -# This setup.py supports discovery and installation of Azure SDK packages -# from both traditional setup.py and modern pyproject.toml configurations. -# -# Package Discovery: -# - Finds packages with setup.py at root or in sdk/*/ directories -# - Finds packages with pyproject.toml (with [project] section) at root or in sdk/*/ directories -# -# Installation Logic: -# - Packages with pyproject.toml containing [project] section: -# Installed using pip (PEP 621 compliant) -# - Packages with setup.py: -# Installed using traditional setuptools via runpy -# - Packages with both setup.py and pyproject.toml (without [project]): -# Prefer setup.py for backward compatibility -#-------------------------------------------------------------------------- import os.path import glob import copy import sys import runpy -import subprocess - -# Use tomllib for Python 3.11+, fallback to tomli for older versions -try: - import tomllib as toml -except ImportError: - import tomli as toml root_folder = os.path.abspath(os.path.dirname(__file__)) -# Helper function to check if pyproject.toml has [project] section -def has_project_section(pyproject_path): - """Check if a pyproject.toml file has a [project] section.""" - try: - with open(pyproject_path, 'rb') as f: - pyproject_data = toml.load(f) - return 'project' in pyproject_data - except Exception: - return False - -# Discover packages with setup.py +# pull in any packages that exist in the root directory packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} +# Handle the SDK folder as well packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) - -# Discover packages with pyproject.toml that have [project] section -for pyproject_file in glob.glob('azure*/pyproject.toml'): - pyproject_path = os.path.join(root_folder, pyproject_file) - if has_project_section(pyproject_path): - packages.add(('.', os.path.dirname(pyproject_file))) - -for pyproject_file in glob.glob('sdk/*/azure*/pyproject.toml'): - pyproject_path = os.path.join(root_folder, pyproject_file) - if has_project_section(pyproject_path): - packages.add(tuple(os.path.dirname(pyproject_file).rsplit(os.sep, 1))) - # [(base_folder, package_name), ...] to {package_name: base_folder, ...} packages = {package_name: base_folder for (base_folder, package_name) in packages} @@ -76,9 +32,8 @@ def has_project_section(pyproject_path): content_package = sorted([p for p in packages.keys() if p not in meta_package+nspkg_packages]) # Move azure-common at the beginning, it's important this goes first -if "azure-common" in content_package: - content_package.remove("azure-common") - content_package.insert(0, "azure-common") +content_package.remove("azure-common") +content_package.insert(0, "azure-common") # Package final: if "install" in sys.argv: @@ -89,7 +44,6 @@ def has_project_section(pyproject_path): for pkg_name in packages_for_installation: pkg_setup_folder = os.path.join(root_folder, packages[pkg_name], pkg_name) pkg_setup_path = os.path.join(pkg_setup_folder, 'setup.py') - pkg_pyproject_path = os.path.join(pkg_setup_folder, 'pyproject.toml') try: saved_dir = os.getcwd() @@ -98,33 +52,8 @@ def has_project_section(pyproject_path): os.chdir(pkg_setup_folder) sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) - # Determine which file to use: pyproject.toml with [project] or setup.py - # Since we already filtered during discovery, if pyproject.toml exists it has [project] - use_pyproject = os.path.exists(pkg_pyproject_path) and has_project_section(pkg_pyproject_path) - - if use_pyproject: - # Use pip to install pyproject.toml-based packages - # Map setup.py commands to pip commands - if "install" in sys.argv: - print("Start ", pkg_pyproject_path) - cmd = [sys.executable, '-m', 'pip', 'install', '.'] - elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): - print("Start ", pkg_pyproject_path) - cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] - else: - # For other commands like --version, --help, etc., skip pyproject.toml packages - # These commands are meant for the root setup.py, not individual packages - continue - - result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) - if result.returncode != 0: - print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) - elif os.path.exists(pkg_setup_path): - # Use the traditional setup.py approach - print("Start ", pkg_setup_path) - result = runpy.run_path(pkg_setup_path) - else: - print(f"Warning: No setup.py or pyproject.toml found for {pkg_name}", file=sys.stderr) + print("Start ", pkg_setup_path) + result = runpy.run_path(pkg_setup_path) except Exception as e: print(e, file=sys.stderr) finally: From aa0c7ba377036e880ed34e7217b1eb56036733d4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:54:31 +0000 Subject: [PATCH 9/9] Add support for pyproject.toml packages with [project] section in setup.py Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- setup.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index dd1c2bcee4ab..d1967446ec76 100644 --- a/setup.py +++ b/setup.py @@ -11,13 +11,41 @@ import copy import sys import runpy +import subprocess + +# Use tomllib for Python 3.11+, fallback to tomli for older versions +try: + import tomllib as toml +except ImportError: + import tomli as toml root_folder = os.path.abspath(os.path.dirname(__file__)) -# pull in any packages that exist in the root directory +# Helper function to check if pyproject.toml has [project] section +def has_project_section(pyproject_path): + """Check if a pyproject.toml file has a [project] section.""" + try: + with open(pyproject_path, 'rb') as f: + pyproject_data = toml.load(f) + return 'project' in pyproject_data + except Exception: + return False + +# Discover packages with setup.py packages = {('.', os.path.dirname(p)) for p in glob.glob('azure*/setup.py')} -# Handle the SDK folder as well packages.update({tuple(os.path.dirname(f).rsplit(os.sep, 1)) for f in glob.glob('sdk/*/azure*/setup.py')}) + +# Discover packages with pyproject.toml that have [project] section +for pyproject_file in glob.glob('azure*/pyproject.toml'): + pyproject_path = os.path.join(root_folder, pyproject_file) + if has_project_section(pyproject_path): + packages.add(('.', os.path.dirname(pyproject_file))) + +for pyproject_file in glob.glob('sdk/*/azure*/pyproject.toml'): + pyproject_path = os.path.join(root_folder, pyproject_file) + if has_project_section(pyproject_path): + packages.add(tuple(os.path.dirname(pyproject_file).rsplit(os.sep, 1))) + # [(base_folder, package_name), ...] to {package_name: base_folder, ...} packages = {package_name: base_folder for (base_folder, package_name) in packages} @@ -32,8 +60,9 @@ content_package = sorted([p for p in packages.keys() if p not in meta_package+nspkg_packages]) # Move azure-common at the beginning, it's important this goes first -content_package.remove("azure-common") -content_package.insert(0, "azure-common") +if "azure-common" in content_package: + content_package.remove("azure-common") + content_package.insert(0, "azure-common") # Package final: if "install" in sys.argv: @@ -44,6 +73,7 @@ for pkg_name in packages_for_installation: pkg_setup_folder = os.path.join(root_folder, packages[pkg_name], pkg_name) pkg_setup_path = os.path.join(pkg_setup_folder, 'setup.py') + pkg_pyproject_path = os.path.join(pkg_setup_folder, 'pyproject.toml') try: saved_dir = os.getcwd() @@ -52,8 +82,33 @@ os.chdir(pkg_setup_folder) sys.path = [pkg_setup_folder] + copy.copy(saved_syspath) - print("Start ", pkg_setup_path) - result = runpy.run_path(pkg_setup_path) + # Determine which file to use: pyproject.toml with [project] or setup.py + # Since we already filtered during discovery, if pyproject.toml exists it has [project] + use_pyproject = os.path.exists(pkg_pyproject_path) and has_project_section(pkg_pyproject_path) + + if use_pyproject: + # Use pip to install pyproject.toml-based packages + # Map setup.py commands to pip commands + if "install" in sys.argv: + print("Start ", pkg_pyproject_path) + cmd = [sys.executable, '-m', 'pip', 'install', '.'] + elif "develop" in sys.argv or any(arg in sys.argv for arg in ['-e', '--editable']): + print("Start ", pkg_pyproject_path) + cmd = [sys.executable, '-m', 'pip', 'install', '-e', '.'] + else: + # For other commands like --version, --help, etc., skip pyproject.toml packages + # These commands are meant for the root setup.py, not individual packages + continue + + result = subprocess.run(cmd, cwd=pkg_setup_folder, capture_output=False) + if result.returncode != 0: + print(f"Warning: Package {pkg_name} installation returned non-zero exit code", file=sys.stderr) + elif os.path.exists(pkg_setup_path): + # Use the traditional setup.py approach + print("Start ", pkg_setup_path) + result = runpy.run_path(pkg_setup_path) + else: + print(f"Warning: No setup.py or pyproject.toml found for {pkg_name}", file=sys.stderr) except Exception as e: print(e, file=sys.stderr) finally: