NetAuto Academy

Beginner Lab

Building a Device Inventory from CSV

Beginner20 min

Objective

Parse a CSV file into a list of dictionaries, then validate each row against required fields and a known-platform list, separating valid inventory from rejected rows with reasons.

Builds on Networking Data & Formats.

Prerequisites

  • Comfortable with Python dictionaries and lists
  • Familiar with reading CSV files (Reading and Writing CSV Inventory Files)
Local/offline only. The CSV below is fixed sample data, not a real fleet export.

Scenario

The problem

"Reading and Writing CSV Inventory Files" taught you csv.DictReader on a clean file. Real inventory exports aren't clean -- a row is missing an IP address, another has a platform value nobody recognizes. Loading that straight into an inventory without checking it means your automation silently breaks three modules from now, on a device nobody remembers was ever wrong. This lab is the validation step no earlier lesson needed, because no earlier lesson's data was ever actually broken.

Starter data

devices.csv — safe sample data
hostname,ip_address,platform
SW1,10.10.10.11,cisco_ios
SW2,,arista_eos
SW3,10.10.10.13,junos_wrong
RTR1,10.10.10.21,cisco_ios

Fixed sample text written for this lab. Row 2 is missing an IP address; row 3 has a platform value that isn't real -- both deliberate, not typos to ignore.

Task

Write load_inventory(raw_csv) that:

  1. Parses the CSV using csv.DictReader.
  2. For each row, checks that hostname, ip_address, and platform are all present and non-empty.
  3. Checks that platform (when present) is one of {"cisco_ios", "arista_eos", "junos"}.
  4. Returns two lists: valid (rows that passed every check) and rejected (a dict per bad row containing the original row and a list of errors describing exactly what's wrong).
starter.py
import csv
import io

RAW_CSV = """hostname,ip_address,platform
SW1,10.10.10.11,cisco_ios
SW2,,arista_eos
SW3,10.10.10.13,junos_wrong
RTR1,10.10.10.21,cisco_ios
"""

VALID_PLATFORMS = {"cisco_ios", "arista_eos", "junos"}
REQUIRED_FIELDS = ["hostname", "ip_address", "platform"]


def load_inventory(raw_csv):
  # Your code here. csv.DictReader(io.StringIO(raw_csv)) gives you one
  # dict per row -- check each REQUIRED_FIELDS entry, then check
  # platform against VALID_PLATFORMS.
  ...


if __name__ == "__main__":
  valid, rejected = load_inventory(RAW_CSV)
  for row in valid:
      print(row)
  for r in rejected:
      print(r)

Copy into a local .py file and run with plain python3 -- csv and io are both standard library, no install needed.

Hints

Expected output

expected output
{'hostname': 'SW1', 'ip_address': '10.10.10.11', 'platform': 'cisco_ios'}
{'hostname': 'RTR1', 'ip_address': '10.10.10.21', 'platform': 'cisco_ios'}
{'row': {'hostname': 'SW2', 'ip_address': '', 'platform': 'arista_eos'}, 'errors': ['missing ip_address']}
{'row': {'hostname': 'SW3', 'ip_address': '10.10.10.13', 'platform': 'junos_wrong'}, 'errors': ["unknown platform 'junos_wrong'"]}

Real, verified output from a working solution to this exact starter data.

Validation checklist

Self-check only -- nothing here is submitted or graded. Compare against your own output manually.

Solution

Solution

Try the task yourself first -- the full solution and explanation stay hidden until you click above.

Key takeaways

  • csv.DictReader turns rows into dicts -- but a dict with the right shape isn't the same as a dict with correct data.
  • Separating valid rows from rejected ones (with a specific reason each) is more useful than either silently dropping bad rows or crashing on the first one.
  • This is fixed, offline sample text -- not a real fleet export.

Related lessons

Done with this lesson?