Modules, Packages, and the Capstone

The last step from scripts to software: organizing your functions into modules and packages that import like the libraries do. Then the capstone — assembling everything from all ten lessons into netaudit, a small, graded, genuinely useful audit package.

In this lesson you will:
  • Turn a .py file into an importable module
  • Guard script behavior with if __name__ == "__main__"
  • Organize modules into a package with __init__.py
  • Build the netaudit capstone — parsers, audit logic, and reporting
  • Know exactly what the flagship course builds on top of this

Any file is a module

You’ve imported other people’s code for nine lessons. The mechanism was never special — import x looks for x.py, and yours qualifies:

# netparse.py
import re

def find_serial(text):
    m = re.search(r"Processor board ID (\S+)", text)
    return m.group(1) if m else None
>>> import netparse
>>> netparse.find_serial("Processor board ID FOC2217A0AB")
'FOC2217A0AB'

That’s it. The file’s name becomes the namespace, its functions become the API, and the docstrings you’ve been writing since Lesson 6 become its help() output. from netparse import find_serial imports the one name when that reads better.

name: import-safe and runnable

One subtlety with teeth: everything at a module’s top level runs at import time. If netparse.py ends with test calls and prints, every script that imports it triggers them. The guard:

# netparse.py (bottom of file)
if __name__ == "__main__":
    # runs ONLY when executed directly: python3 netparse.py
    sample = "Processor board ID FOC2217A0AB"
    print(find_serial(sample))

Python sets __name__ to "__main__" when a file is executed directly, and to the module’s own name when it’s imported. One file, two lives: a library to importers, a quick self-demo from the command line. You’ll find this guard at the bottom of practically every serious Python file on GitHub — now you can read it.

Packages: modules, organized

When one file gets crowded, a package is a directory of modules:

netaudit/
├── __init__.py        # marks the directory as a package (can be empty)
├── parsers.py         # extraction: text in, facts out
├── audit.py           # judgment: facts in, findings out
└── report.py          # rendering: findings in, humans informed
from netaudit.parsers import find_serial
from netaudit.audit import missing_descriptions
from netaudit.report import render

Notice the split isn’t alphabetical — it’s by responsibility, the composition discipline from Lesson 6 scaled up to files. Parsing doesn’t know about reporting; reporting doesn’t know about regex. When a parser breaks on a new platform’s output, you know which file to open before you’ve read a line of code.

⬡ netaudit — data flows left to right, cli.py drives
Rendering diagram…
View diagram source — it's just text (Mermaid). Diagrams-as-code is how modern network docs work; the flagship course has a free module on it.
flowchart LR
  CFG[/"config file"/] --> P["parsers.py<br/>text → facts"]
  P --> A["audit.py<br/>facts → findings"]
  A --> R["report.py<br/>findings → humans"]
  CLI["cli.py<br/>__main__ guard"] -.imports.-> P
  CLI -.imports.-> A
  CLI -.imports.-> R

(That figure, like every diagram in this course, is a Mermaid diagram — plain text that lives in Git next to the code, no Visio license required. The flagship course includes a free module on documenting entire networks this way.)

The capstone: netaudit

The final lab assembles the course. You implement five pieces across the three modules — every one of them a skill you already have:

PieceModuleBuilt from
find_interfaces()parsersL3 accumulator + .startswith()
find_serial()parsersL5 regex + the None contract
missing_descriptions()auditL3’s challenge, now packaged
vlan_drift()auditL4 set difference, both directions
render()reportL1/L6 f-strings + truthiness

A working cli.py ships with the lab — once your functions pass, it audits real config files from the command line via the __main__ guard. You don’t write it; you read it and recognize every line.

🖥 Your code becomes a package
▶ Try it yourself (Python runs in your browser)
Output appears here. First run downloads the Python runtime (~10 MB), so give it a few seconds.

Exercises (graded) — the final lab

cd labs/python-foundations/lesson10
pytest -q

The netaudit/ package skeleton is provided; you fill in the five functions across parsers.py, audit.py, and report.py. When the grader goes green, run the CLI you earned:

python3 cli.py sample-configs/den-acc-sw03.cfg

You’re done — here’s what you’re ready for

Ten lessons ago you set up a venv; today you shipped a package. You can read files, parse with string methods and regex, model devices as classes, detect drift with sets, survive bad input, and organize it all so the next person can use it. That is, precisely, the prerequisite list for Python Network Automation — the flagship course — where this exact skill set turns toward live devices: Netmiko sessions instead of saved files, structured parsing with TextFSM instead of hand-rolled regex, config generation with Jinja2 templates, multivendor fleets through Nornir, and a CI/CD capstone that takes a change from Git commit to validated deployment. Same bones. Real switches. See the course page for the curriculum and presale.

✅ Check your understanding

You import netparse and a demo report immediately prints, uninvited. What's wrong with netparse.py?

1 / 3

Summary

Modules are just files — your netparse.py imports exactly like the stdlib, with the __main__ guard keeping import-time side effects out and command-line convenience in. Packages organize modules by responsibility behind an __init__.py, and the parse/judge/render split of the capstone is real tooling architecture at learning scale. The capstone itself is the course in one artifact: every lesson’s skill, composed. What comes next — live SSH, structured parsing, templating, fleet-scale orchestration — is the flagship course’s job. You’ve built the foundation it stands on.