{"record":{"id":"c40206cd280b957d","repo":"StockSharp/StockSharp","slug":"section-not-found-title","errorCode":null,"errorMessage":"section not found: {title}","messagePattern":"section not found: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scripts/check-readme-connectors.py","lineNumber":89,"sourceCode":"                value = value[: -len(trailer)].strip()\n                break\n\n        return [item.strip() for item in value.rstrip(\".\\u3002\").split(\",\") if item.strip()]\n\n    return None\n\n\ndef section_bounds(lines: list[str], title: str) -> tuple[int, int]:\n    heading = f\"## {title}\"\n    start = None\n\n    for index, line in enumerate(lines):\n        if line.strip().startswith(heading):\n            start = index + 1\n            break\n\n    if start is None:\n        raise ValueError(f\"section not found: {title}\")\n\n    end = len(lines)\n    for index in range(start, len(lines)):\n        if lines[index].startswith(\"## \"):\n            end = index\n            break\n\n    return start, end\n\n\ndef parse_connector_rows(lines: list[str], title: str) -> list[tuple[str, str | None]]:\n    start, end = section_bounds(lines, title)\n    rows: list[tuple[str, str | None]] = []\n\n    for line in lines[start:end]:\n        if not line.startswith('|<img src=\"./Media/logos/'):\n            continue\n","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/StockSharp/StockSharp/blob/601a191de678bff83da28b14828f8885214ca71c/scripts/check-readme-connectors.py#L71-L107","documentation":"check-readme-connectors.py validates that each localized README (en, ru, zh) contains required connector sections. The section_bounds function searches for a line starting with '## {title}'. If no such heading is found, it raises ValueError with the missing section name. The script checks sections defined in COMMON_SECTIONS (crypto, dex, stock, forex) across all three languages.","triggerScenarios":"Running the README connector check when a required section heading (e.g., '## Crypto exchanges', '## Forex') is missing from one of the README files. The script calls section_bounds for every COMMON_SECTIONS title in every language.","commonSituations":"Renaming or removing a connector category heading in README.md without updating the ru or zh variants; adding a new COMMON_SECTIONS entry without adding the heading to all three READMEs; formatting changes that break the '## ' prefix.","solutions":["Add the missing '## {title}' heading to the README file indicated in the error message.","Ensure all three language READMEs (en, ru, zh) have the same set of section headings with exact text from COMMON_SECTIONS.","Check for exact heading text matches including capitalization and spacing."],"exampleFix":"# before — README.ru.md is missing the section\n(no '## Криптобиржи' heading)\n\n# after — add the heading with connector rows\n## Криптобиржи\n| <img src=\"./Media/logos/binance.svg\" /> | Binance |","handlingStrategy":"validation","validationCode":"def ensure_section(readme_path: Path, title: str) -> None:\n    lines = readme_path.read_text(encoding=\"utf-8-sig\").splitlines()\n    heading = f\"## {title}\"\n    if not any(line.strip().startswith(heading) for line in lines):\n        raise ValueError(f\"Add heading '{heading}' to {readme_path}\")","typeGuard":null,"tryCatchPattern":"try:\n    start, end = section_bounds(lines, title)\nexcept ValueError:\n    print(f\"WARNING: section '{title}' not found, skipping\")\n    return []","preventionTips":["Keep README sections synchronized across all three languages when adding or removing categories.","Run check-readme-connectors.py locally before pushing changes to README files.","Use the exact heading text from COMMON_SECTIONS — watch for translation mismatches."],"tags":["python","ci","readme","documentation"],"backgroundTag":null,"analyzedSha":"601a191de678bff83da28b14828f8885214ca71c","analyzedAt":"2026-08-13T20:43:24.460Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}