| name | python-tooling |
| description | Python package management with UV, performance profiling, optimization techniques, and CI/CD integration. Use this skill for dependency management, Docker integration, code profiling, and build optimization. |
| auto_load | {"enabled":true,"triggers":{"keywords":["docker","ci","cd","github","profile","optimize","performance","benchmark"],"file_patterns":["Dockerfile","*.yaml","*.yml",".github/**/*.yml"]},"priority":"medium","load_with":["python-package-management","python-fundamentals"]} |
Python Tooling
Master Python package management with UV, performance profiling, optimization techniques, and CI/CD integration. Use this skill for dependency management, Docker integration, code profiling, and build optimization.
When to Use This Skill
- Setting up Python projects with UV
- Managing dependencies and virtual environments
- Profiling Python code for performance
- Optimizing slow code
- Setting up CI/CD pipelines
- Docker integration for Python apps
UV Package Manager
Installation
curl -LsSf https://astral.sh/uv/install.sh | sh
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
pip install uv
brew install uv
Quick Start
uv init my-project
cd my-project
uv init .
Install Dependencies
uv add requests pandas
uv add --dev pytest black ruff
uv pip install -r requirements.txt
uv sync
Virtual Environment Management
uv venv
uv venv --python 3.13
uv venv my-env
uv run python script.py
uv run pytest
Locking Dependencies
uv lock
uv lock --upgrade
uv sync --frozen
uv lock --check
Python Version Management
uv python install 3.13
uv python install 3.11 3.12 3.13
uv python pin 3.13
Project Configuration
[project]
name = "my-project"
version = "0.1.0"
description = "My awesome project"
requires-python = ">=3.13"
dependencies = [
"requests>=2.31.0",
"pydantic>=2.0.0",
"click>=8.1.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"black>=23.0.0",
"ruff>=0.1.0",
"mypy>=1.5.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.uv]
dev-dependencies = []
Performance Profiling
Basic Timing
import time
def measure_time():
"""Simple timing measurement."""
start = time.time()
result = sum(range(1000000))
elapsed = time.time() - start
print(f"Execution time: {elapsed:.4f} seconds")
return result
import timeit
execution_time = timeit.timeit(
"sum(range(1000000))",
number=100
)
print(f"Average time: {execution_time/100:.6f} seconds")
cProfile - CPU Profiling
import cProfile
import pstats
from pstats import SortKey
def main():
"""Main function to profile."""
result1 = slow_function()
result2 = another_function()
return result1, result2
if __name__ == "__main__":
profiler = cProfile.Profile()
profiler.enable()
main()
profiler.disable()
stats = pstats.Stats(profiler)
stats.sort_stats(SortKey.CUMULATIVE)
stats.print_stats(10)
stats.dump_stats("profile_output.prof")
Command-line profiling:
python -m cProfile -o output.prof script.py
python -m pstats output.prof
line_profiler - Line-by-Line Profiling
@profile
def process_data(data):
"""Process data with line profiling."""
result = []
for item in data:
processed = item * 2
result.append(processed)
return result
memory_profiler - Memory Usage
from memory_profiler import profile
@profile
def memory_intensive():
"""Function that uses lots of memory."""
big_list = [i for i in range(1000000)]
big_dict = {i: i**2 for i in range(100000)}
result = sum(big_list)
return result
py-spy - Production Profiling
py-spy top --pid 12345
py-spy record -o profile.svg --pid 12345
py-spy record -o profile.svg -- python script.py
py-spy dump --pid 12345
Optimization Patterns
List Comprehensions vs Loops
def slow_squares(n):
result = []
for i in range(n):
result.append(i**2)
return result
def fast_squares(n):
return [i**2 for i in range(n)]
Generator Expressions for Memory
def list_approach():
data = [i**2 for i in range(1000000)]
return sum(data)
def generator_approach():
data = (i**2 for i in range(1000000))
return sum(data)
String Concatenation
def slow_concat(items):
result = ""
for item in items:
result += str(item)
return result
def fast_concat(items):
return "".join(str(item) for item in items)
Dictionary Lookups vs List Searches
def list_search(items, target):
return target in items
def dict_search(lookup_dict, target):
return target in lookup_dict
Caching with functools.lru_cache
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci_fast(n):
"""Recursive fibonacci with caching."""
if n < 2:
return n
return fibonacci_fast(n-1) + fibonacci_fast(n-2)
Multiprocessing for CPU-Bound Tasks
import multiprocessing as mp
def cpu_intensive_task(n):
return sum(i**2 for i in range(n))
def parallel_processing():
with mp.Pool(processes=4) as pool:
results = pool.map(cpu_intensive_task, [1000000] * 4)
return results
Async I/O for I/O-Bound Tasks
import asyncio
import aiohttp
async def asynchronous_requests(urls: list[str]):
async with aiohttp.ClientSession() as session:
tasks = [async_fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
Database Optimization
Batch Database Operations
def slow_inserts(conn, count):
cursor = conn.cursor()
for i in range(count):
cursor.execute("INSERT INTO users (name) VALUES (?)", (f"User {i}",))
conn.commit()
def fast_inserts(conn, count):
cursor = conn.cursor()
data = [(f"User {i}",) for i in range(count)]
cursor.executemany("INSERT INTO users (name) VALUES (?)", data)
conn.commit()
Query Optimization
"""
-- Slow: No index
SELECT * FROM users WHERE email = 'user@example.com';
-- Fast: With index
CREATE INDEX idx_users_email ON users(email);
SELECT * FROM users WHERE email = 'user@example.com';
"""
cursor.execute("EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = ?", ("test@example.com",))
Memory Optimization
Detecting Memory Leaks
import tracemalloc
import gc
def track_memory_usage():
tracemalloc.start()
snapshot1 = tracemalloc.take_snapshot()
memory_leak_example()
snapshot2 = tracemalloc.take_snapshot()
top_stats = snapshot2.compare_to(snapshot1, 'lineno')
print("Top 10 memory allocations:")
for stat in top_stats[:10]:
print(stat)
tracemalloc.stop()
gc.collect()
Using slots for Memory
class RegularClass:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
class SlottedClass:
__slots__ = ['x', 'y', 'z']
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
Weakref for Caches
import weakref
weak_cache = weakref.WeakValueDictionary()
def get_resource_weak(key):
resource = weak_cache.get(key)
if resource is None:
resource = CachedResource(f"Data for {key}")
weak_cache[key] = resource
return resource
Docker Integration
Basic Dockerfile
FROM python:3.13-slim
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
# Copy dependency files
COPY pyproject.toml uv.lock ./
# Install dependencies
RUN uv sync --frozen --no-dev
# Copy application code
COPY . .
# Run application
CMD ["uv", "run", "python", "app.py"]
Multi-stage Dockerfile
FROM python:3.13-slim AS builder
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
# Install dependencies to venv
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-editable
# Runtime stage
FROM python:3.13-slim
WORKDIR /app
# Copy venv from builder
COPY --from=builder /app/.venv .venv
COPY . .
# Use venv
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "app.py"]
CI/CD Integration
GitHub Actions
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.13
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Run tests
run: uv run pytest
- name: Run linting
run: |
uv run ruff check .
uv run ruff format --check .
Pre-commit Hooks
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
hooks:
- id: mypy
additional_dependencies: [pydantic]
args: [--strict]
- repo: local
hooks:
- id: pytest
name: pytest
entry: pytest tests/unit -x --tb=short
language: system
pass_filenames: false
always_run: true
Benchmarking Tools
pytest-benchmark
def test_list_comprehension(benchmark):
result = benchmark(lambda: [i**2 for i in range(10000)])
assert len(result) == 10000
def test_map_function(benchmark):
result = benchmark(lambda: list(map(lambda x: x**2, range(10000))))
assert len(result) == 10000
Custom Benchmark Decorator
import time
from functools import wraps
def benchmark(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} took {elapsed:.6f} seconds")
return result
return wrapper
@benchmark
def slow_function():
time.sleep(0.5)
return sum(range(1000000))
Best Practices
- Profile before optimizing - Measure to find real bottlenecks
- Focus on hot paths - Optimize code that runs most frequently
- Use appropriate data structures - Dict for lookups, set for membership
- Avoid premature optimization - Clarity first, then optimize
- Use built-in functions - They're implemented in C
- Cache expensive computations - Use lru_cache
- Batch I/O operations - Reduce system calls
- Use generators for large datasets
- Consider NumPy for numerical operations
- Profile production code - Use py-spy for live systems
References