Zero Dependencies: The Architecture

How 260 CLI tools run on pure import — no pip, no npm, no cargo

📅 June 2026 ⚡ 260 tools · 0 deps · 1 install 📖 ~8 min read
⚡ The Promise

pip install evolver-tools installs 260 CLI tools. It adds zero packages to your pip list. The install takes ~3 seconds. There is nothing to compile, nothing to download from CDNs, and no version conflicts — ever.

Every tool is built using only Python's standard library. Not "mostly" — entirely. From CSV parsing to network requests, JSON processing to terminal graphics, the entire toolkit runs on modules that ship with every Python installation since 3.8.

Why Zero Dependencies Matters

Most Python packages depend on a web of transitive dependencies. A simple CLI tool often pulls in 20-50 packages. This creates real problems:

ProblemTraditional Packageevolver-tools
Install time30-120s (compiling native extensions)2-5s
Disk usage50-500 MB (with deps)<1 MB
pip list entries20-50 transitive packages1
CI/CD cacheMust cache venv + dependenciesNo cache needed
Air-gapped installRequires private PyPI mirrorWorks directly
Container image100+ MB base + deps12 MB slim image
Security surface100+ package versions to auditOne package to audit
Supply chain riskAny dep could be compromisedStdlib only — no supply chain

What Makes This Possible

Python's standard library is uniquely capable among mainstream languages. It includes modules that cover almost every computing need:

CSV
csv module — reader, writer, DictReader
JSON
json — load, dump, custom encoders
Network
http.client, socket, ssl
Encoding
base64, hashlib, binascii
System
os, sys, psutil? No — /proc
Images
struct + raw bytes — no PIL needed
Crypto
hashlib, hmac, secrets
Compression
gzip, bz2, lzma, zipfile

Behind the Scenes: Stdlib Modules Used

Here's a partial map of which Python stdlib modules power each tool category:

🔧 CSV Tools (csv-stats, csv-filter, csv-join, etc.)

csv — DictReader/DictWriter for all CSV I/O
io.StringIO — in-memory CSV processing
collections.Counter — frequency counts and stats
statistics — mean, median, stdev for numeric columns

🔧 JSON Tools (json-pretty, json-validate, json-merge)

json — load/dump with custom sort_keys, indent
json.JSONDecoder — per-line streaming parse for large files
collections.abc.MutableMapping — deep merge recursion
functools.reduce — accumulate merge operations

🔧 Network Tools (ping, dns-lookup, ssl-check, http-get)

http.client — HTTP/HTTPS requests (no requests library!)
socket — DNS resolution, port scanning, ICMP (via raw sockets)
ssl — TLS certificate chain validation, expiry checks
urllib.parse — URL parsing, validation, normalization

🔧 System Tools (system-info, disk-usage, process-list)

os — uname, cpu_count, getloadavg
/proc — parsed via open() for Linux-specific metrics
shutil — disk_usage for free/used/total
psutil would be 1.5MB — instead, /proc/[pid]/stat parsing

🔧 Encoding & Crypto (base64, hash-file, encrypt)

base64 — standard, URL-safe, base32, base16
hashlib — md5, sha1, sha256, sha512, blake2b
hmac — HMAC-based auth tokens
secrets — cryptographically secure random generation

The Hard Parts: What Stdlib Doesn't Give You

Building on stdlib-only isn't always easy. Here are the trade-offs:

1. Terminal Colors Without colorama

On Windows, ANSI escape codes don't work by default. colorama is the standard fix. Our approach:

# Check if ANSI is supported, fall back to plain text
import os, sys

def supports_color():
    if sys.platform == "win32":
        # Enable VT processing on Windows 10+
        os.system("")
    return hasattr(sys.stdout, "isatty") and sys.stdout.isatty()

2. Progress Bars Without tqdm

tqdm is everyone's go-to. We built a 40-line progress bar using sys.stdout.write() + \r carriage returns:

def progress_bar(current, total, width=40):
    pct = current / total
    filled = int(width * pct)
    bar = "█" * filled + "░" * (width - filled)
    sys.stdout.write(f"\r{bar} {pct:.1%}")
    sys.stdout.flush()

3. Tabular Output Without tabulate/rich

# Dynamic column-width table formatting with pure string ops
def format_table(headers, rows):
    widths = [len(h) for h in headers]
    for row in rows:
        for i, cell in enumerate(row):
            widths[i] = max(widths[i], len(str(cell)))
    # ... build format string from calculated widths

4. No argparse? Use argparse!

Surprisingly, argparse is stdlib — so CLI argument parsing is fully covered. No need for click or typer.

Architecture: Single File Tools

Each tool is a single Python file in src/evolver_tools/tools/. The discovery system reads tool metadata from embedded docstrings:

# Tool metadata from docstring convention
# Every tool has: name, description, args, examples embedded in its module
TOOLS = {}  # populated at import time by scanning the tools directory

def discover_tools():
    """Auto-discover all tool modules from tools/ directory."""
    tools_dir = Path(__file__).parent / "tools"
    for f in tools_dir.glob("*.py"):
        if f.name == "__init__.py":
            continue
        spec = importlib.util.spec_from_file_location("tool", f)
        mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(mod)
        TOOLS[mod.NAME] = mod
📦 Package Stats

260 files in the tools directory · ~250KB total Python code
Zero pip dependencies · ~3 second install time
3.8 to 3.13 Python versions supported · Linux / macOS / Windows

Real-World Impact

The zero-dependency approach isn't just academic — it creates real practical benefits:

CI/CD Pipelines

# .github/workflows/data-pipeline.yml
- name: Install and run data pipeline
  run: |
    pip install evolver-tools
    evtool csv-stats data.csv
    evtool csv-chart data.csv

No pip cache, no actions/setup-python with extra args, no venv restoration. Just install and go.

Docker Images

FROM python:3.12-slim
RUN pip install evolver-tools
CMD ["evtool", "list"]

Final image size: ~130 MB (Python slim base) + ~250 KB (our code) = basically the same as Python alone.

Air-Gapped Environments

No PyPI mirror needed. Just copy the .whl file to the target machine. Python stdlib is already there.

The Trade-off

Zero-dependency development has real costs that are worth being honest about:

Trade-offWith Stdlib OnlyWith External Deps
Development speedSlower — must reimplement basic patternsFast — install what you need
Feature depthLimited to what stdlib providesRich — battle-tested libraries
Edge casesMust handle manually (e.g., encoding, timezones)Often handled by the library
Code size~250KB for 260 toolsWould be much smaller per tool
Learning curveRequires stdlib expertiseRequires library API knowledge

The key is choosing the right tools for the right job. For quick data tasks in CI/CD, server-side automation, and air-gapped deployments, zero-dependency CLI tools shine. For complex data science or web scraping, purpose-built libraries like pandas or requests are better.

$ pip install evolver-tools Get Started →

Further Reading