{"record":{"id":"ee011038c8a7e7a7","repo":"pytest-dev/pytest","slug":"ext-must-not-be-none","errorCode":null,"errorMessage":"ext must not be None","messagePattern":"ext must not be None","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/pytester.py","lineNumber":769,"sourceCode":"\n    def chdir(self) -> None:\n        \"\"\"Cd into the temporary directory.\n\n        This is done automatically upon instantiation.\n        \"\"\"\n        self._monkeypatch.chdir(self.path)\n\n    def _makefile(\n        self,\n        ext: str,\n        lines: Sequence[Any | bytes],\n        files: Mapping[str, _FileContent],\n        encoding: str = \"utf-8\",\n    ) -> Path:\n        items = list(files.items())\n\n        if ext is None:\n            raise TypeError(\"ext must not be None\")\n\n        if ext and not ext.startswith(\".\"):\n            raise ValueError(\n                f\"pytester.makefile expects a file extension, try .{ext} instead of {ext}\"\n            )\n\n        def to_text(s: Any | bytes) -> str:\n            return s.decode(encoding) if isinstance(s, bytes) else str(s)\n\n        if lines:\n            source = \"\\n\".join(to_text(x) for x in lines)\n            basename = self._name\n            items.insert(0, (basename, source))\n\n        ret = None\n        for basename, value in items:\n            p = self.path.joinpath(basename).with_suffix(ext)\n            p.parent.mkdir(parents=True, exist_ok=True)","sourceCodeStart":751,"sourceCodeEnd":787,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/pytester.py#L751-L787","documentation":"Thrown by Pytester._makefile() when the `ext` argument is None. The annotation says str but None slips in via makefile() callers; the guard converts it into a clear TypeError instead of an AttributeError later.","triggerScenarios":"Calling pytester.makefile(None, 'content') directly; a wrapper/helper that computes the extension dynamically and passes None when no extension was configured; programmatic test generation that forgets to set the extension.","commonSituations":"Test helper functions that accept an optional extension parameter; data-driven test frameworks building files dynamically; copy-paste from makepyfile()/maketxtfile() that hardcode extensions, into a generic makefile() call.","solutions":["Pass a concrete extension string starting with '.', e.g. '.py' or '.txt'.","Default the extension in your helper to '.py' instead of None.","Use the dedicated shortcut methods (makepyfile, makeini, maketxtfile) which set the extension for you."],"exampleFix":"// before\npytester.makefile(ext, \"content\")  # ext may be None\n// after\npytester.makefile(ext or \".txt\", \"content\")","handlingStrategy":"type-guard","validationCode":"ext = ext if ext is not None else '.txt'\npytester.makefile(ext, content)","typeGuard":"def is_valid_ext(ext: object) -> bool:\n    return isinstance(ext, str) and ext.startswith('.')","tryCatchPattern":null,"preventionTips":["Default optional extension params to '.py' or '.txt' rather than None.","Use makepyfile/maketxtfile shortcuts to avoid passing ext manually."],"tags":["pytester","makefile","validation","type-error"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}