A plain-UTF-8 text file with a .docx extension. The library must raise a typed opc-level exception (PackageNotFoundError or subclass — python-docx uses NotADocxError); a bare zipfile.BadZipFile leaks implementation detail and pins users to the library's zip backend choice.
Library verdicts: python-docx: — docxjs: —
| Feature id | docx/malformed-non-zip |
|---|---|
| Format | docx |
| Category | malformed-recovery |
| Spec | ecma-376-5-part-2 § 10.1.1 Package |
No XPath assertions declared.
No render assertions declared.
scripts/gen_malformed_non_zip_docx.py
#!/usr/bin/env python3
"""Generate ``fixtures/docx/malformed-non-zip.docx``.
A plain-UTF-8 text file with a ``.docx`` extension. The library must
raise a typed opc-level exception — python-docx uses
:class:`docx.opc.exceptions.NotADocxError`, a subclass of
``PackageNotFoundError``. A bare :class:`zipfile.BadZipFile` is NOT
sufficient: that leaks an implementation detail and pins users to
python-docx's choice of zip backend.
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from _malformed_common import write_plain_bytes
_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "docx" / "malformed-non-zip.docx"
_PAYLOAD = (
b"This file has a .docx extension but is plain UTF-8 text, not a "
b"ZIP archive. A conforming reader must reject it with a typed "
b"opc-level exception, not a bare zipfile.BadZipFile.\n"
) * 4
def main() -> int:
_OUT.parent.mkdir(parents=True, exist_ok=True)
write_plain_bytes(_OUT, _PAYLOAD)
print(_OUT)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"id": "docx/malformed-non-zip",
"title": "Malformed input: file is not a ZIP archive",
"format": "docx",
"category": "malformed-recovery",
"summary": "A plain-UTF-8 text file with a .docx extension. The library must raise a typed opc-level exception (PackageNotFoundError or subclass — python-docx uses NotADocxError); a bare zipfile.BadZipFile leaks implementation detail and pins users to the library's zip backend choice.",
"roles": [
"authoring"
],
"spec": {
"source": "ecma-376-5-part-2",
"clause": "10.1.1",
"element": "Package",
"notes": "An OPC package is a ZIP (ECMA-376 part 2 clause 10.1.1). Not-a-zip input is the most basic 'reject gracefully' case."
},
"fixtures": {
"machine": "docx/malformed-non-zip"
},
"generator": {
"python": "scripts/gen_malformed_non_zip_docx.py"
},
"behavior_assertions": [
{
"id": "raises-typed-exception",
"kind": "library_raises",
"library": "python-docx",
"method": "docx.Document",
"args": [
"{fixture_path}"
],
"expected_exception": [
"PackageNotFoundError",
"NotADocxError",
"OpcError"
],
"forbidden_exception": "BadZipFile",
"description": "Must raise a typed opc exception — NOT a bare zipfile.BadZipFile. python-docx raises NotADocxError today (a subclass of PackageNotFoundError)."
}
]
}
No rendered reference is available for this case.