{"record":{"id":"5e588f5fbb26d49f","repo":"stamparm/maltrail","slug":"no-version-assignment-found-in-s","errorCode":null,"errorMessage":"[!] no VERSION assignment found in %s","messagePattern":"\\[!\\] no VERSION assignment found in (.+?)","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"sensor/tools/check_version.py","lineNumber":44,"sourceCode":"\nROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), \"..\", \"..\"))\nSETTINGS = os.path.join(ROOT, \"core\", \"settings.py\")\nCARGO = os.path.join(ROOT, \"sensor\", \"Cargo.toml\")\nCITATION = os.path.join(ROOT, \"CITATION.cff\")\nSETTINGS_GEN = os.path.join(ROOT, \"sensor\", \"src\", \"settings_gen.rs\")\nCARGO_LOCK = os.path.join(ROOT, \"sensor\", \"Cargo.lock\")\n\n\ndef _read(path):\n    with open(path, \"r\") as f:\n        return f.read()\n\n\ndef settings_version():\n    \"\"\"VERSION = \"3.0\" from core/settings.py, without importing it (it has side effects).\"\"\"\n    match = re.search(r\"^VERSION\\s*=\\s*[\\\"']([^\\\"']+)[\\\"']\", _read(SETTINGS), re.M)\n    if not match:\n        raise SystemExit(\"[!] no VERSION assignment found in %s\" % SETTINGS)\n    return match.group(1)\n\n\ndef cargo_version():\n    \"\"\"version = \"3.0.0\" from the [package] table only - dependency versions must not match.\"\"\"\n    text = _read(CARGO)\n    package = re.search(r\"^\\[package\\]\\s*$(.*?)(?=^\\[|\\Z)\", text, re.M | re.S)\n    if not package:\n        raise SystemExit(\"[!] no [package] table found in %s\" % CARGO)\n    match = re.search(r\"^version\\s*=\\s*\\\"([^\\\"]+)\\\"\", package.group(1), re.M)\n    if not match:\n        raise SystemExit(\"[!] no version key in the [package] table of %s\" % CARGO)\n    return match.group(1)\n\n\ndef citation_version():\n    \"\"\"version: \"3.0\" from CITATION.cff.\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/sensor/tools/check_version.py#L26-L62","documentation":"check_version.py's settings_version() reads core/settings.py as text and regex-extracts a top-level VERSION = \"x.y\" assignment (avoiding importing the module, which has side effects). If the regex ^VERSION\\s*=\\s*[\"']([^\"']+)[\"'] finds no match, it raises SystemExit telling the developer no VERSION assignment exists in that file — the script's first source of truth for the project version is missing or malformed.","triggerScenarios":"core/settings.py no longer contains a line starting with VERSION = (or VERSION='...') at line start; the assignment was renamed (e.g. APP_VERSION), quoted with backticks, written as VERSION: str = \"3.0\", built by concatenation, or the file path constant SETTINGS points to the wrong/missing file (though a missing file may instead fail in _read).","commonSituations":"A refactor of settings.py renamed or reformatted the version constant; a contributor replaced the literal with a computed value; the check tool was moved and SETTINGS now resolves to a different file after a layout change.","solutions":["Add or restore a line-level assignment in core/settings.py exactly like VERSION = \"3.0\" (name at start of line, = sign, single- or double-quoted string literal).","Check that the version constant wasn't renamed during a refactor and revert to the VERSION name expected by check_version.py.","Confirm the SETTINGS constant in check_version.py points at the actual core/settings.py path if the project layout changed.","Avoid computed or annotated version declarations (VERSION: str = ... or VERSION = compute()); keep a plain literal for the checker to find."],"exampleFix":"# before (settings.py)\nAPP_VERSION = \"3.0\"\n# after\nVERSION = \"3.0\"","handlingStrategy":"validation","validationCode":"import re\ntext = open(\"sensor/core/settings.py\").read()\nassert re.search(r'^VERSION\\s*=\\s*[\"\\'][^\"\\']+[\"\\']', text, re.M), \\\n    \"core/settings.py must contain a literal VERSION assignment before running check_version\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep VERSION as a plain, line-leading string literal in core/settings.py; never rename it during refactors without grepping for dependents.","Add a unit test that parses settings.py with the same regex and fails fast if the assignment disappears.","Avoid computed or annotated version declarations (VERSION: str = ..., VERSION = compute()).","If the project layout changes, update the SETTINGS path constant in check_version.py in the same commit."],"tags":["versioning","regex-parsing","config","ci"],"backgroundTag":"missing-required-config-field","analyzedSha":"77cfb06d7606506d101bbcec0786c77166c4255e","analyzedAt":"2026-09-13T03:50:16.010Z","contentChangedAt":"2026-09-13T03:50:16.010Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}