A minimal Python CLI application demonstrating object-oriented design, dependency injection, and TDD with a real and simulated tape drive backend.
- Clean
ITapeDriveinterface with two interchangeable implementations - Dependency injection via a lightweight
Containerclass - Switch between the real hardware driver and the in-memory simulator with a single flag
- JSON-configurable logging (console + rotating file)
- Full pytest suite — atomic unit tests (mocked) and integration tests (simulator)
di-container/
├── main.py # CLI entry point
├── logging_config.json # Logging configuration
├── requirements.txt
├── pytest.ini
└── src/
├── interfaces/
│ └── i_tape_drive.py # ITapeDrive abstract interface
├── tape_drive.py # Real hardware driver (Linux mt/dev)
├── tape_drive_simulator.py # In-memory simulator
├── tape_drive_service.py # Service layer (receives ITapeDrive via DI)
├── container.py # DI container — wires the object graph
└── logging_setup.py # Loads logging config from JSON
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux / macOS
source .venv/bin/activate
pip install -r requirements.txtAll commands accept --driver real|simulator (default: simulator) and an optional --log-config path.
python main.py load TAPE-001
python main.py statusOK — tape loaded.
driver : simulator
tape_id : TAPE-001
loaded : True
position : 0
capacity : 10485760
python main.py load TAPE-001
python main.py write "Hello, tape!"
python main.py rewind
python main.py read 12OK — tape loaded.
OK — wrote 12 byte(s).
OK — tape rewound.
Read 12 byte(s): b'Hello, tape!'
python main.py load TAPE-001
python main.py seek 1024
python main.py write "offset data"
python main.py seek 1024
python main.py read 11python main.py unloadpython main.py --driver real statusThe real driver communicates with
/dev/nst0via themtutility (mt-stpackage).
It requires a Linux system with a connected tape device.
python main.py --log-config /etc/tapedrive/logging.json status# All tests
pytest
# Unit tests only (all dependencies mocked)
pytest tests/unit/
# Integration tests only (real simulator, no mocks)
pytest tests/integration/
# With coverage report
pytest --cov=src --cov-report=term-missingtests/unit/test_tape_drive_service.py 28 passed
tests/integration/test_tape_drive_simulator.py 41 passed
Logging is configured via logging_config.json using the standard Python logging.config.dictConfig schema.
- Console —
INFOand above, simple format - File (
tape_drive.log) —DEBUGand above, timestamped detailed format
Edit logging_config.json to change levels, add handlers, or switch formatters without touching the code.
{
"loggers": {
"tape_drive": {
"level": "DEBUG",
"handlers": ["console", "file"]
}
}
}| Concept | Implementation |
|---|---|
| Interface | ITapeDrive — Python ABC with @abstractmethod |
| Real driver | TapeDrive — delegates to mt and /dev/nst0 |
| Simulator | TapeDriveSimulator — bytearray in memory |
| Service layer | TapeDriveService — business logic, no I/O |
| DI container | Container — constructs and wires the graph |
| Logging config | LoggingSetup — loads from JSON, falls back to basicConfig |