-
Notifications
You must be signed in to change notification settings - Fork 36
FEAT: Modernize build system with pyproject.toml and custom build backend #408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7966b90
a5668d3
2fefac9
cc357ee
2aa2c05
3409a70
4129ff5
56186bd
a1667e6
c42f819
2084bb1
f797db3
6a50152
394b63a
43337f8
4b2a5cf
af72b63
9aa716b
da350de
aa36078
ee794b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| """ | ||
| build_ddbc - Build system for mssql-python native extensions. | ||
|
|
||
| This package provides: | ||
| 1. A CLI tool: `python -m build_ddbc` | ||
| 2. A PEP 517 build backend that auto-compiles ddbc_bindings | ||
|
|
||
| Usage: | ||
| python -m build_ddbc # Compile ddbc_bindings only | ||
| python -m build_ddbc --arch arm64 # Specify architecture (Windows) | ||
| python -m build_ddbc --coverage # Enable coverage (Linux) | ||
| python -m build # Compile + create wheel (automatic) | ||
| """ | ||
|
|
||
| from .compiler import compile_ddbc | ||
| from mssql_python.platform_utils import get_platform_info | ||
|
|
||
| __all__ = ["compile_ddbc", "get_platform_info"] | ||
| __version__ = "1.3.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| """ | ||
| CLI entry point for build_ddbc. | ||
|
|
||
| Usage: | ||
| python -m build_ddbc # Compile ddbc_bindings | ||
| python -m build_ddbc --arch arm64 # Specify architecture (Windows) | ||
| python -m build_ddbc --coverage # Enable coverage (Linux) | ||
| python -m build_ddbc --help # Show help | ||
| """ | ||
|
|
||
| import argparse | ||
| import sys | ||
|
|
||
| from . import __version__ | ||
| from .compiler import compile_ddbc, get_platform_info | ||
|
|
||
|
|
||
| def main() -> int: | ||
| """Main entry point for the CLI.""" | ||
| parser = argparse.ArgumentParser( | ||
| prog="python -m build_ddbc", | ||
| description="Compile ddbc_bindings native extension for mssql-python", | ||
| formatter_class=argparse.RawDescriptionHelpFormatter, | ||
| epilog=""" | ||
| Examples: | ||
| python -m build_ddbc # Build for current platform | ||
| python -m build_ddbc --arch arm64 # Build for ARM64 (Windows) | ||
| python -m build_ddbc --coverage # Build with coverage (Linux) | ||
| python -m build_ddbc --quiet # Build without output | ||
| """, | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--arch", "-a", | ||
| choices=["x64", "x86", "arm64", "x86_64", "aarch64", "universal2"], | ||
| help="Target architecture (Windows: x64, x86, arm64)", | ||
| ) | ||
bewithgaurav marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| parser.add_argument( | ||
| "--coverage", "-c", | ||
| action="store_true", | ||
| help="Enable coverage instrumentation (Linux only)", | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--quiet", "-q", | ||
| action="store_true", | ||
| help="Suppress build output", | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--version", "-V", | ||
| action="version", | ||
| version=f"%(prog)s {__version__}", | ||
| ) | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| # Show platform info | ||
| if not args.quiet: | ||
| arch, platform_tag = get_platform_info() | ||
| print(f"[build_ddbc] Platform: {sys.platform}") | ||
| print(f"[build_ddbc] Architecture: {arch}") | ||
| print(f"[build_ddbc] Platform tag: {platform_tag}") | ||
| print() | ||
|
|
||
| try: | ||
| compile_ddbc( | ||
| arch=args.arch, | ||
| coverage=args.coverage, | ||
| verbose=not args.quiet, | ||
| ) | ||
| return 0 | ||
| except FileNotFoundError as e: | ||
| print(f"Error: {e}", file=sys.stderr) | ||
| return 1 | ||
| except RuntimeError as e: | ||
| print(f"Build failed: {e}", file=sys.stderr) | ||
| return 1 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(main()) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| """ | ||
| PEP 517 Build Backend for mssql-python. | ||
|
|
||
| This module wraps setuptools' build backend and adds automatic | ||
| ddbc_bindings compilation before building wheels. | ||
|
|
||
| Usage in pyproject.toml: | ||
| [build-system] | ||
| requires = ["setuptools>=61.0", "wheel", "pybind11"] | ||
| build-backend = "build_ddbc.build_backend" | ||
| backend-path = ["."] | ||
| """ | ||
|
|
||
| # Import setuptools build backend - we'll wrap its functions | ||
| from setuptools.build_meta import ( | ||
| build_wheel as _setuptools_build_wheel, | ||
| build_sdist as _setuptools_build_sdist, | ||
| get_requires_for_build_wheel as _get_requires_for_build_wheel, | ||
| get_requires_for_build_sdist as _get_requires_for_build_sdist, | ||
| prepare_metadata_for_build_wheel as _prepare_metadata_for_build_wheel, | ||
| ) | ||
|
|
||
| from .compiler import compile_ddbc | ||
|
|
||
|
|
||
| # ============================================================================= | ||
| # PEP 517 Required Hooks | ||
| # ============================================================================= | ||
|
|
||
|
|
||
| def get_requires_for_build_wheel(config_settings=None): | ||
| """Return build requirements for wheel.""" | ||
| return _get_requires_for_build_wheel(config_settings) | ||
|
|
||
|
|
||
| def get_requires_for_build_sdist(config_settings=None): | ||
| """Return build requirements for sdist.""" | ||
| return _get_requires_for_build_sdist(config_settings) | ||
|
|
||
|
|
||
| def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): | ||
| """Prepare wheel metadata.""" | ||
| return _prepare_metadata_for_build_wheel(metadata_directory, config_settings) | ||
|
|
||
|
|
||
| def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): | ||
| """ | ||
| Build a wheel, compiling ddbc_bindings first. | ||
|
|
||
| This is the main hook - it compiles the native extension before | ||
| delegating to setuptools to create the wheel. | ||
| """ | ||
| print("[build_backend] Starting wheel build...") | ||
|
|
||
| # Check if we should skip compilation (e.g., for sdist-only builds) | ||
| skip_compile = False | ||
| if config_settings: | ||
| skip_compile = config_settings.get("--skip-ddbc-compile", False) | ||
|
|
||
| if not skip_compile: | ||
| # Extract build options from config_settings | ||
| arch = None | ||
| coverage = False | ||
|
|
||
| if config_settings: | ||
| arch = config_settings.get("--arch") | ||
| coverage = config_settings.get("--coverage", False) | ||
|
|
||
|
Comment on lines
+55
to
+68
|
||
| print("[build_backend] Compiling ddbc_bindings...") | ||
| try: | ||
| compile_ddbc(arch=arch, coverage=coverage, verbose=True) | ||
| print("[build_backend] Compilation successful!") | ||
| except FileNotFoundError: | ||
| # If build scripts don't exist, assume pre-compiled binaries | ||
| print("[build_backend] Build scripts not found, assuming pre-compiled binaries") | ||
bewithgaurav marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| except (RuntimeError, OSError) as e: | ||
| print(f"[build_backend] Compilation failed: {e}") | ||
| raise | ||
| else: | ||
| print("[build_backend] Skipping ddbc compilation (--skip-ddbc-compile)") | ||
|
|
||
| # Now build the wheel using setuptools | ||
| print("[build_backend] Creating wheel...") | ||
| return _setuptools_build_wheel(wheel_directory, config_settings, metadata_directory) | ||
|
|
||
|
|
||
| def build_sdist(sdist_directory, config_settings=None): | ||
| """ | ||
| Build a source distribution. | ||
|
|
||
| For sdist, we don't compile - just package the source including build scripts. | ||
| """ | ||
| print("[build_backend] Building source distribution...") | ||
| return _setuptools_build_sdist(sdist_directory, config_settings) | ||
|
|
||
|
|
||
| # ============================================================================= | ||
| # Optional PEP 660 Hooks (Editable Installs) | ||
| # ============================================================================= | ||
|
|
||
|
|
||
| def get_requires_for_build_editable(config_settings=None): | ||
| """Return build requirements for editable install.""" | ||
| return get_requires_for_build_wheel(config_settings) | ||
|
|
||
|
|
||
| def build_editable(wheel_directory, config_settings=None, metadata_directory=None): | ||
| """ | ||
| Build an editable wheel, compiling ddbc_bindings first. | ||
|
|
||
| This enables `pip install -e .` to automatically compile. | ||
| """ | ||
| print("[build_backend] Starting editable install...") | ||
|
|
||
| # Compile ddbc_bindings for editable installs too | ||
| print("[build_backend] Compiling ddbc_bindings for editable install...") | ||
| try: | ||
| compile_ddbc(verbose=True) | ||
| print("[build_backend] Compilation successful!") | ||
| except FileNotFoundError: | ||
| print("[build_backend] Build scripts not found, assuming pre-compiled binaries") | ||
| except (RuntimeError, OSError) as e: | ||
| print(f"[build_backend] Compilation failed: {e}") | ||
| raise | ||
|
|
||
| # Import here and handle absence gracefully for older setuptools versions | ||
| try: | ||
| from setuptools.build_meta import build_editable as _setuptools_build_editable | ||
| except ImportError as exc: | ||
| raise RuntimeError( | ||
| "Editable installs are not supported with this setuptools version. " | ||
| "Please install setuptools>=64.0.0 to use PEP 660 editable installs." | ||
| ) from exc | ||
| return _setuptools_build_editable(wheel_directory, config_settings, metadata_directory) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
build_ddbc.__main__importsget_platform_infofrom.compiler, butcompiler.pydoesn't define/export that symbol (it imports it frommssql_python.platform_utils). This will raiseImportErrorwhen runningpython -m build_ddbc. Importget_platform_infofrommssql_python.platform_utils(or frombuild_ddbcsince it’s re-exported in__init__.py).