{"record":{"id":"e30a1db6cb4ae433","repo":"hankcs/HanLP","slug":"self-filepath","errorCode":null,"errorMessage":"{self.filepath}","messagePattern":"\\{self\\.filepath\\}","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"hanlp/utils/io_util.py","lineNumber":647,"sourceCode":"    return cache_name, cache_valid\n\n\ndef merge_files(files: List[str], dst: str):\n    with open(dst, 'wb') as write:\n        for f in files:\n            with open(f, 'rb') as read:\n                shutil.copyfileobj(read, write)\n\n\nclass TimingFileIterator(CountdownTimer):\n\n    def __init__(self, filepath) -> None:\n        super().__init__(os.path.getsize(filepath))\n        self.filepath = filepath\n\n    def __iter__(self):\n        if not os.path.isfile(self.filepath):\n            raise FileNotFoundError(self.filepath)\n        fp = open(self.filepath, encoding='utf-8', errors='ignore')\n        line = fp.readline()\n        while line:\n            yield line\n            self.current = fp.tell()\n            line = fp.readline()\n        fp.close()\n\n    def log(self, info=None, ratio_percentage=True, ratio=True, step=0, interval=0.5, erase=True,\n            logger: Union[logging.Logger, bool] = None, newline=False, ratio_width=None):\n        assert step == 0\n        super().log(info, ratio_percentage, ratio, step, interval, erase, logger, newline, ratio_width)\n\n    @property\n    def ratio(self) -> str:\n        return f'{human_bytes(self.current)}/{human_bytes(self.total)}'\n\n    @property","sourceCodeStart":629,"sourceCodeEnd":665,"githubUrl":"https://github.com/hankcs/HanLP/blob/ddb1299bddff079e447af52ec12549c50636bfa8/hanlp/utils/io_util.py#L629-L665","documentation":"This progress-tracking file iterator checks that its filepath still exists each time iteration starts (it may have been deleted since construction, e.g. cached files cleaned mid-run) and raises FileNotFoundError with the path otherwise.","triggerScenarios":"Constructing the iterable, then deleting/moving the file (cache eviction, tmp cleanup) before iterating; or constructing with a path that never existed (size lookup happens at __init__ via os.path.getsize, which would already fail, so this guard mostly catches deletion between init and iter).","commonSituations":"Long pipelines where a cleanup task removes intermediate files; multi-process readers racing a deleter; rerunning after a partial cache purge.","solutions":["Re-generate or re-download the file before iterating.","If you control cleanup, delay deletion until all consumers finish (reference counting or a manifest).","Guard with os.path.isfile(path) before starting iteration and rebuild if missing."],"exampleFix":"# before\nit = SizeCorruptedTolerantIterable(path)\nresults = list(it)  # file deleted in between\n# after\nif not os.path.isfile(path):\n    rebuild(path)\nresults = list(SizeCorruptedTolerantIterable(path))","handlingStrategy":"validation","validationCode":"import os\nif not os.path.isfile(path):\n    regenerate(path)  # your rebuild/re-download hook","typeGuard":null,"tryCatchPattern":"try:\n    for line in iterable: ...\nexcept FileNotFoundError:\n    regenerate(path)\n    for line in SizeCorruptedTolerantIterable(path): ...","preventionTips":["Don't delete intermediate files until the pipeline completes.","Add existence checks before each long-running iteration stage."],"tags":["file-not-found","iterator","cache"],"backgroundTag":"file-deleted-during-read","analyzedSha":"ddb1299bddff079e447af52ec12549c50636bfa8","analyzedAt":"2026-08-27T03:36:54.287Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}