fixture function `makepyfile` does not encode files properly
makepyfile is ignoring the encoding parameter, in both pytester and testdir fixtures.
found the issue working on windows with cp1252 encoding and using pytest-doctestplus.
i traced the issue to makepyfile, arguments and kwargs are passed unpacked.
make_file = testdir.makepyfile(
f"""
def f():
'''
>>> print('{a}')
{b}
'''
pass
""".encode(encoding=encoding),
encoding=encoding, # will be packed into `files` and default utf-8 encoding will be used
)
$ python --version
Python 3.13.2
$ pip freeze
colorama==0.4.6
iniconfig==2.0.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.3
I don't see a bug here, as such an argument simply doesn't exist, and neither is it valid to pass bytes in in the first place.
From the docs:
kwargs (str) – Each keyword is the name of a file, while the value of it will be written as contents of the file.
That passing in bytes works is a coincidence, and seems to be a historic artifact from Python 2 times (see e.g. f47ae749817df967e1ba2c07e67eda49ae328077). The encoding= argument for _makefile was apparently added for pytest's selftests: d254c6b0aeb872a791889d5e3497fa3ca679c482, but is not actually used since 4588653b2497ed25976b7aaff225b889fb476756.
I think we should simply drop all the code dealing with bytes from Pytester._makefile and add proper type annotations to Pytester.makepyfile (not sure why everything but that has those!).
As for your tests, you should probably do something like this instead:
(pytester.path / "myfile.py").write_bytes(content)
for testing i agree, its no big issue.
basically _makefile was confusing me, it has a parameter encoding but kwargs are not unpacked instead passed on as dict seemed wrong to me.
def makepyfile(self, *args, **kwargs) -> Path:
return self._makefile(".py", args, kwargs)
def _makefile(
self,
ext: str, # ".py"
lines: Sequence[Any | bytes], # contains args
files: dict[str, str], # contains kwargs
encoding: str = "utf-8", # useless? move into function as 'const'
) -> Path:
...