When building a CLI testing, discovery, and behavioral regression engine in Python, the standard reaction in modern software development is to reach for pip. A typical production setup might pull in click for CLI parsing, pexpect for process control, hypothesis for test generation, pydantic for serialization, deepdiff for regression detection, and pytest-snapshot for snapshot management.
Before you know it, a "lightweight" testing tool drags along 20+ third-party dependencies, hundreds of transitive sub-packages, vendor lock-in, and security vulnerability supply-chain risks.
In CLI-KDG, we took a radically different engineering constraint: Zero Third-Party Dependencies. No pip install. No requirements.txt. No external binaries. Pure Python 3.11+ standard library and bare POSIX system calls.
Here is an honest, deep-dive breakdown of what packages developers normally install, and what it actually took to replace them with zero dependencies.
1. Process Control & Pipe Multiplexing
📦 What You'd Normally Install:
-
pexpect: For spawning child processes and interacting with pseudo-ttys. -
subprocess(high-level wrappers):subprocess.run(),subprocess.Popen(). -
psutil: For process lifecycle monitoring and killing child trees.
🛠️ What It Actually Took to Replace It:
High-level wrappers like subprocess.run() block execution and suffer from POSIX pipe buffer deadlocks if a process outputs more than ~64 KB to STDOUT or STDERR concurrently.
To solve this without pexpect or psutil, we went down to raw POSIX system call primitives in cli_kdg/process.py:
Process Spawning via
os.fork()andos.execvp():
We fork the current process usingos.fork(), set up isolated OS-level pipes usingos.pipe(), and duplicate file descriptors viaos.dup2()to redirect standard output and standard error handles before replacing the child image withos.execvp().Deadlock Protection via Non-Blocking
fcntl&select.select():
To prevent buffer deadlocks on massive output runs, we mark pipe read descriptors non-blocking usingfcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK). We multiplex stream reads inside a non-blockingselect.select()event loop that drains STDOUT and STDERR concurrently into dynamic byte buffers.Monotonic Timeout & Deterministic Child Reaping:
Instead of system clock-dependent timers, we usetime.monotonic()to track deadline execution. If a child process exceeds its deadline, we issueos.kill(pid, signal.SIGTERM)(followed bySIGKILLif necessary) and strictly reap the process using non-blocking status calls (os.waitpid(pid, os.WNOHANG)), preventing zombie processes.
# Low-level non-blocking pipe setup in cli_kdg/process.py
r_out, w_out = os.pipe()
r_err, w_err = os.pipe()
flags = fcntl.fcntl(r_out, fcntl.F_GETFL)
fcntl.fcntl(r_out, fcntl.F_SETFL, flags | os.O_NONBLOCK)
fcntl.fcntl(r_err, fcntl.F_SETFL, flags | os.O_NONBLOCK)
2. CLI Argument Parsing & Option Interrogation
📦 What You'd Normally Install:
-
argparse/click/typer: For subcommand parsing and CLI options. -
docopt: For regex-based--helptext parsing.
🛠️ What It Actually Took to Replace It:
Manual Command Vector Parser (
parse_args()incli_kdg/parser.py):
Instead of heavy CLI frameworks, we built a zero-dependency argument vector parser inparse_args(). It manually processessys.argv[1:]to extract subcommands (run,discover,snapshot,replay), parses--timeoutand-o/--outputflags, supports--timeout=SECequals syntax, and handles positional argument separators (--) gracefully.Deterministic
--helpText Tokenizer (parse_help_text()incli_kdg/help_parser.py):
To discover CLI option structures automatically, we wrote a line-by-line help parser inparse_help_text()without regex or external packages. It extracts short options (-v), long options (--verbose), inline assignments (--output=FILE), and value descriptors (FILE,INTEGER,<path>) by inspecting whitespace indentation and uppercase token patterns.
# Token-based option extraction in cli_kdg/help_parser.py
if "=" in token and token.startswith("-"):
flag_part, val_part = token.split("=", 1)
requires_value, value_hint = True, val_part.strip("<>[]")
3. Automated Test Case Generation
📦 What You'd Normally Install:
-
hypothesis: For property-based testing and input fuzzing. -
pytest-quickcheck: For generating test vectors.
🛠️ What It Actually Took to Replace It:
Random fuzzing creates noisy, non-deterministic test suites. In generate_test_cases() (cli_kdg/generator.py), we built a deterministic category-classified test case generator.
From any discovered CLIModel, generate_test_cases() systematically generates bounded, classified test cases:
-
HELP: Verifies standard--helpexecution. -
UNKNOWN_OPTION: Verifies error handling on unrecognized flags (--unknown-flag-xyz-kdg). -
FLAG_VALID&FLAG_UNEXPECTED_ARG: Tests boolean flag activation and boundary argument handling. -
OPTION_MISSING_VAL,OPTION_VALID_VAL,OPTION_INVALID_VAL: Tests value-requiring options against zero (0), negative (-1), and non-numeric string (abc) boundaries. - Bounded Safety: Automatically caps execution at 15 deterministic cases per run.
4. Snapshot Persistence & Data Modeling
📦 What You'd Normally Install:
-
pydantic/marshmallow: For schema validation and JSON serialization. -
pytest-snapshot: For snapshot file management.
🛠️ What It Actually Took to Replace It:
Standard Python Dataclass Equivalents (
cli_kdg/models.py):
We implemented clean, lightweight Python classes (ExecutionResult,TestObservation,Snapshot,ReplayResult) equipped with explicitto_dict()andfrom_dict()methods.Versioned JSON Persistence (
create_snapshot(),save_snapshot(),load_snapshot()incli_kdg/snapshot.py):
Snapshots created bycreate_snapshot()are saved viasave_snapshot()and loaded viaload_snapshot()in standardjsonformat with explicit versioning ("version": 1). If a snapshot file is corrupt, missing, or has an incompatible version schema, CLI-KDG catches the error and raises a controlledCLKDGUserError, producing clean terminal error messages without uncaught tracebacks.
5. Comparative Behavioral Regression Engine
📦 What You'd Normally Install:
-
deepdiff: For structural object comparisons and diff generation. -
pytest-regressions: For visual regression reporting.
🛠️ What It Actually Took to Replace It:
In replay_snapshot() and compare_observations() (cli_kdg/replay.py), we built an exact comparative replay engine. It loads historical test cases from a snapshot and replays them against an updated CLI target.
Field-by-Field Discrepancy Tracking via
compare_observations():
compare_observations()comparesexit_code,status,stdout,stderr, andtermination_typefield-by-field, recording structuredComparisonDetailobjects for any changes.Built-in Runtime Invariance:
A major flaw in naive snapshot tools is flagging minor execution time variations as test failures. In CLI-KDG, execution duration (runtime_ms) is treated strictly as metadata — runtime differences NEVER trigger behavioral regression diffs.
6. Dependency Policy Auditing & CI Enforcement
📦 What You'd Normally Install:
-
pip-audit/safety: For scanning dependency vulnerabilities. -
import-linter: For enforcing module boundary rules.
🛠️ What It Actually Took to Replace It:
To enforce our zero-dependency policy permanently in CI/CD, we wrote an automated AST import auditor in test_ast_import_audit() directly inside run_tests.py.
Using Python's built-in ast and importlib modules, test_ast_import_audit() traverses syntax trees via ast.walk() for every Python file in the codebase, inspecting all Import and ImportFrom nodes. It resolves module paths via importlib.import_module() and verifies that zero imported modules resolve to site-packages or dist-packages directories, asserting that no dependency manifests (requirements.txt, Pipfile, pyproject.toml) exist.
# AST import auditor snippet in run_tests.py
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
mod = importlib.import_module(alias.name.split('.')[0])
assert "site-packages" not in getattr(mod, "__file__", "")
Summary Comparison Matrix
| Capability | Standard Third-Party Stack | CLI-KDG Zero-Dependency Solution | Core Functions / Calls Used |
|---|---|---|---|
| Process Control |
pexpect, psutil
|
POSIX process engine (process.py) |
os.fork(), os.execvp(), os.pipe(), os.dup2(), os.waitpid(), os.kill()
|
| I/O Multiplexing |
asyncio, twisted
|
Non-blocking pipe event loop (process.py) |
fcntl.fcntl(), select.select()
|
| Argument Parsing |
click, argparse
|
Manual vector parser (parser.py) |
parse_args() |
| Help Interrogation |
docopt, regex |
Token-based text parser (help_parser.py) |
parse_help_text() |
| Test Case Generation | hypothesis |
Classified deterministic generator (generator.py) |
generate_test_cases() |
| Snapshot Persistence |
pydantic, pytest-snapshot
|
Built-in json + schema (snapshot.py) |
create_snapshot(), save_snapshot(), load_snapshot(), to_dict(), from_dict()
|
| Regression Engine | deepdiff |
Field comparator + Runtime Invariance (replay.py) |
replay_snapshot(), compare_observations()
|
| Dependency Audit |
pip-audit, import-linter
|
AST import scanner (run_tests.py) |
test_ast_import_audit(), ast.walk(), importlib.import_module()
|
Conclusion
Replacing 6 major third-party packages required discipline, clean modular design, and a deep understanding of POSIX process semantics.
The result?
- Zero supply-chain risk: 0 external dependencies to audit, patch, or update.
- Ultra-minimal codebase: Under 1,900 total lines of clean, human-interpretable Python.
- Lightning fast execution: Runs a full 38-test integration suite in under 2.5 seconds.
- 100% portable: Runs out-of-the-box on any standard Python 3.11+ environment on Linux, macOS, or BSD.
Top comments (0)