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.
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:
| Piece | Module | Built from |
|---|---|---|
find_interfaces() | parsers | L3 accumulator + .startswith() |
find_serial() | parsers | L5 regex + the None contract |
missing_descriptions() | audit | L3’s challenge, now packaged |
vlan_drift() | audit | L4 set difference, both directions |
render() | report | L1/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.
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.
You import netparse and a demo report immediately prints, uninvited. What's wrong with netparse.py?
What makes the directory netaudit/ importable as a package?
Why is netaudit split into parsers / audit / report instead of one big file?
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.