Closed icemac closed 2 years ago
As I understand it, Pyroma was developed back in the days before PEP 517 and most modern packaging standards, and there's been a lot of change to keep up with since then. In particular, distutils is deprecated, PEP 517 has been widely implemented and is started to be adopted in earnest, direct invocation of setup.py
is deprecated, and so are some of the other implementation details from back in the day that Pyroma relied on. Really, the overall approach needs some changes to reflect this or things will keep breaking; at some point, I hope to help revamp it to reflect the modern state of Python packaging and take advantage of the new tools (e.g. importlib_metadata
) and APIs (PEP 517) we have available now, but like anything its a matter of finding the time to do so.
I just ran it with setuptools 60.10, so I don't think that's the problem.
Implementing support for PEP517 would be nice, but I have no clue when I will have time for that.
I can also confirm, which I should have before, that I mostly cannot reproduce this with either pyroma .
and pipx run pyroma .
(in implied -d
mode), on both passing and failing packages, on Python 3.9 and Setuptools 60.9.3, at least on Windows. pyroma -f
also worked on passing and failing sdists, though wheels are not (yet) supported. Running pyroma BTrees
doesn't give me the error above, but neither does it give me any useful Pyroma results.
This issue seems to be something to do with something specific to the package, as pyroma setuptools
gives the expected output.
I'd have to investigate the project in question's packaging configuration to guess at what that might be.
OK, so this happens when running Pyroma against a package on PyPI that raises this warning. It means the end result isn't printed out. It's enough of a edge case that I'm not going to fix it now. It will get fixed when/if I get proper PEP 517 support and don't have to mess around with setup()
any more.
I'm keeping it open so I don't forget to test.
Seems reasonable, since its an indication of an actual problem with the project.
As to support for the modern Python packaging ecosystem, adding support to Pyroma should be a lot simpler than I initially thought, and greatly simplify the codebase as a whole (since the old hacks, monkeypatching and need to actually build the project are no longer needed, given the approach below works equally with both legacy and PEP 517 projects, and regardless of build system), as well as being generally more efficient. The entirety of pyroma/projectdata.py can be replaced with just:
import build, email, pathlib, tempfile
def get_data(path):
with tempfile.TemporaryDirectory() as tempdir:
metadata_dir = build.ProjectBuilder(str(path)).prepare("wheel", tempdir)
with open(pathlib.Path(metadata_dir) / "METADATA", "rb") as metadata_file:
metadata = email.message_from_binary_file(metadata_file)
return metadata
(Of course, you'll need to add build
to your dependencies.) Since metadata
is a dict-like object supports indexing and get
, it should be usable with the existing ratings.py
with no other changes.
Likewise, pyroma/distributiondata.py can be updated to support wheels alongside sdists, which looks like:
import email, pathlib, shutil, tarfile, tempfile, zipfile
from pyroma import projectdata
def get_data(path):
path = pathlib.Path(path).resolve()
with tempfile.TemporaryDirectory() as tempdir:
tempdir = pathlib.Path(tempdir)
if path.suffix == ".whl":
with zipfile.ZipFile(path, "r") as wheel_file:
wheel_file.extractall(tempdir)
metadata_path = list(tempdir.glob("*.dist-info/METADATA"))[0]
with open(metadata_path, "rb") as metadata_file:
data = email.message_from_binary_file(metadata_file)
elif ".tar" in path.name:
with tarfile.open(name=path, mode="r:*") as tar_file:
tar_file.extractall(tempdir)
data = projectdata.get_data(list(tempdir.glob("*"))[0])
else:
raise ValueError(f"Unknown file type: {path.suffix}")
return data
That should be all that is needed in terms of changes; everything else should work as it does now, as the above code preserves API-compatible inputs and outputs for both get_data()
functions. If you want me to propose that in a PR, I can.
Also, to take advantage of modern, standard tools and further reduce the amount of bepoke code and maintenance effort:
classifiers.py
, the fetch_classifiers
script and keeping them up to date is no longer needed, since the canonical classifier set is available in the trove-classifers
PyPI package, from which trove_classifiers.classifiers
is a 100% drop-in replacement for classifiers.CLASSIFIERS
.ratings.py
could be replaced with packaging.version.parse(version)
from the standard packaging package (checking if a Version
or a LegacyVersion
was returned) which is the canonical reference implementation of PEP 440.twine
, though without a few tweaks to the twine
codebase or hacks on Pyroma's end, it would require building either a sdist or a wheel for project directories (which is otherwise no longer necessary with the changes above)—so probably best to wait on this one.In total, this will add three direct dependencies (build
, packaging
and twine
), while also removing three (docutils
, setuptools
and pygments
).
Oh, nice. I didn't know about build
. That indeed makes it a lot easier, thanks!
I'll probably keep the old code as a deprecated backup for a while.
OK, 4.0b1 solves this issue. I'm keeping this issue open as there are discussions about PEP621 support in here.
I'm not sure I see anything directly related to reading metadata from a PEP 621 [project]
table in here, and that's more of an opportunistic optimization for certain cases rather than providing any new functionality. However, I do mention some other steps to take, and the need to update distributiondata.py
accordingly. I'm happy to create separate issues for each of those, if you'd like.
I'll create a future plans issue, and you can put it there.
OK, I opened #75 .
Thank you for fixing this issue. I can confirm that both variants I had problems with are fixed by 4.0b1
.
I installed
pyroma
usingpipx
for Python 3.9 and then tried to use it onzopefoundation/BTrees
:Trying to use a package name from PyPI leads to:
Installed packages in the venv: