Two plans: INF parser TDD (wave 1), upload endpoint + UI (wave 2). Covers DRV-01 through DRV-05. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9.5 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-driver-management | 01 | tdd | 1 |
|
true |
|
|
Purpose: This is the core novel logic of Phase 2. The INF parser is a pure function with defined I/O — ideal for TDD. All other Phase 2 work (upload endpoint, UI) consumes this parser's output.
Output: imptune/services/inf_parser.py with ParsedInf dataclass and parse_inf() function, plus comprehensive unit tests and INF fixture files.
<execution_context> @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/02-driver-management/02-RESEARCH.mdFrom imptune/config.py:
DATA_DIR = os.environ.get("DATA_DIR", "/data")
DRIVERS_DIR = str(Path(DATA_DIR) / "drivers")
From imptune/storage/driver_store.py:
class DriverStore:
def save(self, data: bytes) -> str: ... # returns SHA256 hex digest
def get_path(self, sha256: str) -> Path: ...
def exists(self, sha256: str) -> bool: ...
From imptune/db/models.py:
class Driver(BaseModel):
sha256 = CharField(unique=True, index=True)
original_filename = CharField()
size_bytes = IntegerField()
uploaded_at = DateTimeField(default=datetime.utcnow)
driver_desc = CharField(null=True) # Store json.dumps(list) for multi-model
inf_filename = CharField(null=True)
architecture = CharField(null=True) # 'x64', 'x86', 'arm64', or None
has_cat_file = BooleanField(default=False)
-
Create
tests/fixtures/directory if it does not exist. -
Create
tests/fixtures/sample.inf— minimal valid INF with %TOKEN% values:
[Version]
Signature="$Windows NT$"
Class=Printer
Provider=%MFG%
[Manufacturer]
%MFG%=Models,NTamd64
[Models.NTamd64]
%DRIVER_NAME%=Install,{GUID}
[Strings]
MFG="Test Manufacturer"
DRIVER_NAME="Test LaserJet Pro"
-
Create
tests/fixtures/sample_utf16.inf— same content as sample.inf but encoded as UTF-16 LE with BOM. Write using Python:content.encode('utf-16-le')prepended withb'\xff\xfe'. Actually, create this fixture programmatically within the test (or as a conftest fixture) since writing binary fixtures from plan text is fragile. -
Create
tests/fixtures/sample_multi_model.inf— INF with both decorated and undecorated sections:
[Version]
Signature="$Windows NT$"
Class=Printer
[Manufacturer]
%MFG%=Models,Models.NTamd64
[Models]
%DRIVER_A%=InstallA,{GUID1}
[Models.NTamd64]
%DRIVER_A%=InstallA,{GUID1}
%DRIVER_B%=InstallB,{GUID2}
[Strings]
MFG="Multi Corp"
DRIVER_A="Multi Printer 1000"
DRIVER_B="Multi Printer 2000"
-
Create
imptune/services/__init__.py— empty package marker. -
Create
tests/test_inf_parser.pywith all 11 test functions listed in behavior. Tests import fromimptune.services.inf_parserand callparse_inf()/_detect_encoding(). Each test asserts specific expected outputs. For the UTF-16 test, generate the fixture bytes inline:sample_text.encode('utf-16'). -
Run
pytest tests/test_inf_parser.py -x— all tests MUST FAIL (ImportError or assertion errors). Commit:test(02-01): add failing tests for INF parser
Phase: GREEN
-
Create
imptune/services/inf_parser.pyimplementing:ParsedInfdataclass with fields:driver_names: list[str],inf_filename: str,architecture: str | None,has_cat_file: bool,unused_files: list[str]_detect_encoding(raw: bytes) -> str— BOM sniffing (UTF-16 BOM -> 'utf-16', UTF-8 BOM -> 'utf-8-sig', else -> 'cp1252')_resolve_tokens(value: str, strings: dict[str, str]) -> str— regex%TOKEN%expansion from strings dictparse_inf(inf_text: str, inf_filename: str, zip_names: list[str]) -> ParsedInf— usesconfigparser.RawConfigParser(strict=False, comment_prefixes=(';', '#'), delimiters=('=',)), reads [Manufacturer] to find Models section names, iterates all matching sections (decorated: .NTamd64, .NTarm64, .NTx86; undecorated), extracts left-hand keys as device-descriptions, resolves tokens, deduplicates with set(), detects architecture from section suffix, detects .cat in zip_names, computes unused files by checking if each zip member's basename appears in inf_text (case-insensitive)
Follow the exact code patterns from 02-RESEARCH.md "Pattern 2: INF DriverDesc Extraction". Key points:
- Use
RawConfigParser(NOTConfigParser— avoids %(interpolation)s interference) strict=Falseto handle duplicate keys in real INFs- Strings dict keys must be lowercased (configparser lowercases keys by default)
- Strip surrounding double-quotes from [Strings] values
- Architecture: if exactly one arch hint in set -> return it; multiple -> None
sorted(driver_names)for deterministic dropdown order
-
Run
pytest tests/test_inf_parser.py -x— all tests MUST PASS. Commit:feat(02-01): implement INF parser with encoding detection and token resolutionpytest tests/test_inf_parser.py -v All 11 tests pass. ParsedInf dataclass and parse_inf() function correctly extract driver names from simple, tokenized, UTF-16, and multi-model INF files. Unused files detected. Architecture and .cat presence detected.
<success_criteria>
- parse_inf() extracts DriverDesc from all 3 fixture types (simple, UTF-16, multi-model)
- %TOKEN% references resolved to human-readable names
- Unused files correctly identified
- All 11+ unit tests green, zero regressions in existing suite </success_criteria>