- Регистрация
- 9 Май 2015
- Сообщения
- 1,483
- Баллы
- 155

Why Bazel is Revolutionary for Python Development
Before diving into code, let's understand why Google open-sourced their internal build system and why it's becoming essential for serious Python development.
The Problem with Traditional Python Build Systems
Most Python developers are familiar with this workflow:
pip install -r requirements.txt
python setup.py build
python -m pytest
This approach breaks down at scale:
- Inconsistent builds: "Works on my machine" syndrome
- Slow rebuilds: Everything rebuilds even when only one file changes
- Dependency hell: Version conflicts across projects
- No parallelization: Tests and builds run sequentially
- Language barriers: Hard to integrate C++, Java, or other languages
Bazel introduces several revolutionary concepts:
Hermetic Builds: Same inputs always produce identical outputs, regardless of the machine or environment.
Incremental Builds: Only rebuilds what actually changed, using cryptographic hashing to detect changes.
Massive Parallelization: Builds independent targets simultaneously across multiple cores.
Remote Caching: Share build artifacts across your entire team or CI/CD pipeline.
Multi-language Support: Python, Java, C++, Go, and more in a single build system.
Why MODULE.bazel Over WORKSPACE
Bazel is transitioning from WORKSPACE files to MODULE.bazel (called "Bzlmod") for several reasons:
- Better dependency resolution: Handles version conflicts automatically
- Simplified syntax: Less boilerplate, more intuitive
- Improved performance: Faster loading and resolution
- Future-proof: This is where Bazel is heading
Now let's build our first modern Bazel Python project!
Setting Up Your First Modern Bazel Python Project
Project Structure Overview
We'll create a minimal but complete Bazel project:
bazel-python-tutorial/
├── MODULE.bazel # Modern dependency management (replaces WORKSPACE)
├── .bazelrc # Build configuration
├── .bazelversion # Lock Bazel version for team consistency
├── BUILD.bazel # Build instructions for this directory
└── hello.py # Our Python source code
Step 1: Initialize Your Project
Create your project directory:
mkdir bazel-python-tutorial
cd bazel-python-tutorial
Step 2: Create MODULE.bazel - The Modern Way
The MODULE.bazel file is your project's dependency manifest. It's cleaner and more powerful than the old WORKSPACE approach.
# MODULE.bazel
"""
Modern Bazel module definition for Python projects.
This replaces the old WORKSPACE.bazel approach.
"""
# Define this project as a Bazel module
module(
name = "bazel_python_tutorial",
version = "1.0.0",
)
# Declare dependency on Python rules
# This tells Bazel: "We need Python build capabilities"
bazel_dep(name = "rules_python", version = "0.29.0")
# Configure Python toolchain using the modern extension API
# This ensures everyone uses the same Python version
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
python_version = "3.11",
is_default = True,
)
use_repo(python, "python_3_11")
Key Differences from WORKSPACE:
- No need for http_archive or SHA hashes
- Automatic version resolution
- Cleaner, more declarative syntax
- Built-in dependency management
# .bazelrc
# Configuration file that sets default behavior for Bazel commands
# Think of this as your "build preferences"
# === Build Configuration ===
# Show detailed error messages when builds fail
build --verbose_failures
# Show build progress (helpful for learning)
build --show_progress_rate_limit=5
# === Test Configuration ===
# Show test output when tests fail
test --test_output=errors
# Display detailed test summary
test --test_summary=detailed
# === Performance Optimizations ===
# Use multiple CPU cores for builds
build --jobs=auto
# === Modern Bazel Features ===
# Enable Bzlmod (MODULE.bazel support)
common --enable_bzlmod
# === Python Configuration (Windows Compatible) ===
# Use the registered Python toolchain
build --python_top=@python_3_11//:python_runtimes
Step 4: Lock Bazel Version
# .bazelversion
# This ensures your entire team uses the same Bazel version
# Prevents "works on my machine" issues
7.0.0
Step 5: Create BUILD.bazel - Build Instructions
# BUILD.bazel
"""
Build instructions for the root directory.
Every directory containing source code needs a BUILD.bazel file.
"""
# Import the py_binary rule from Python rules
load("@rules_python//python:defs.bzl", "py_binary")
# Define a Python executable target
py_binary(
name = "hello",
srcs = ["hello.py"], # Source files to include
main = "hello.py", # Entry point file
python_version = "PY3", # Explicitly use Python 3
)
Understanding py_binary:
- name: What you'll type in bazel run //:{name}
- srcs: List of Python files this target includes
- main: Which file contains if __name__ == "__main__":
- python_version: Ensures Python 3 compatibility
#!/usr/bin/env python3
# hello.py
"""
Your first Bazel Python program!
This demonstrates modern Bazel with Python.
"""
import sys
from typing import List
def create_greeting(name: str, enthusiasm_level: int = 1) -> str:
"""
Create a personalized greeting with variable enthusiasm.
Args:
name: The name to greet
enthusiasm_level: Number of exclamation marks (1-3)
Returns:
A formatted greeting string
"""
exclamation = "!" * min(max(enthusiasm_level, 1), 3)
return f"Hello, {name}{exclamation}"
def display_bazel_info() -> None:
"""Display information about this Bazel build."""
print("

print(f"Python version: {sys.version}")
print(f"Running from: {__file__}")
print("Built with: Bazel + MODULE.bazel (Bzlmod)")
print("-" * 50)
def main(args: List[str] = None) -> None:
"""
Main entry point of our application.
Args:
args: Command line arguments (optional)
"""
display_bazel_info()
# Basic greeting
print(create_greeting("Bazel World"))
# Enthusiastic greeting
print(create_greeting("Modern Python Developer", 3))
# Success message
print("\n

print(" • Set up modern Bazel with MODULE.bazel")
print(" • Built your first py_binary target")
print(" • Used Bzlmod for dependency management")
print(" • Created a reproducible, scalable build")
if __name__ == "__main__":
main(sys.argv[1:])
Building and Running Your First Modern Bazel Python Program
Build the Project
# Build your hello target
bazel build //:hello
What happens behind the scenes:
- Bazel reads MODULE.bazel and downloads Python rules
- Sets up Python 3.11 toolchain
- Analyzes BUILD.bazel to understand dependencies
- Compiles and packages your Python code
- Creates executable in bazel-bin/
# Run your hello target
bazel run //:hello
Expected Output:

Python version: 3.11.x (main, ...)
Running from: /path/to/your/project/hello.py
Built with: Bazel + MODULE.bazel (Bzlmod)
--------------------------------------------------
Hello, Bazel World!
Hello, Modern Python Developer!!!

• Set up modern Bazel with MODULE.bazel
• Built your first py_binary target
• Used Bzlmod for dependency management
• Created a reproducible, scalable build
Understanding Bazel Labels
The //:hello syntax is called a "Bazel label":
- // = Root of the workspace (where MODULE.bazel lives)
- : = Separator between package and target
- hello = Target name (from name = "hello" in BUILD.bazel)
# List all available targets in your project
bazel query //...
# Get detailed information about the hello target
bazel query //:hello --output=build
# See what files Bazel generated
ls -la bazel-bin/
# Clean all build outputs
bazel clean
# Build with verbose output (great for learning)
bazel build //:hello --verbose_failures --announce_rc
What Makes This Better Than Traditional Python?
Reproducible Builds
Every developer on your team will get identical builds because:
- Python version is locked via MODULE.bazel
- Bazel version is locked via .bazelversion
- All dependencies are precisely specified
Change one line in hello.py and rebuild:
# Edit hello.py, then rebuild
bazel build //:hello
Bazel only rebuilds what changed - incredibly fast!
Scalability Foundation
This simple setup scales to:
- Hundreds of Python modules
- Mixed-language projects (Python + C++ + Java)
- Microservices architectures
- Thousands of developers
Hope this helps! Follow me for more such updates!
Источник: