Reading Python classifiers from pyproject.toml
How would this feature be useful?
We could convert python classifiers to a Python version list.
Describe the solution you'd like
Here's the current way to do it:
ALL_PYTHONS = [
c.split()[-1]
for c in nox.project.load_toml("pyproject.toml")["project"]["classifiers"]
if c.startswith("Programming Language :: Python :: 3.")
]
Describe alternatives you've considered
No response
Anything else?
No response
I just started utilizing nox and was looking for a way to get rid of the code duplication regarding the specified Python requirement from pyproject.toml and nox. For me, I was more looking into a way to use requires-python instead of the classifiers (since they are optional and requires-python is not). But this would work as well.
BTW: This could add great value to the documentation.
Keep up the great work!
I think it would be fine to fall back to that if classifier are missing, but classifiers have an upper bound, while you should never put an upper cap for requires-Python.
Here is my stupid implementation (with uv).
I make sure that the DEV python version is the lowest one. And also sort them using Version. Maybe this can help someone
from packaging.specifiers import SpecifierSet
from packaging.version import Version
CWD = Path(__file__).parent.resolve()
pyproject = nox.project.load_toml(CWD / "pyproject.toml")
# Parse our python versions
def check_python_versions() -> list[str]:
"""Parse and check the python versions
It also check the ruff settings.
Raises:
RuntimeError: If we have a version mismatch
"""
project = pyproject["project"]
python_versions = [
_.split("::")[-1].strip()
for _ in project.get("classifiers", [])
if re.match(
r"Programming Language :: Python :: 3.\d+$",
_,
)
]
python_versions = sorted(
python_versions,
key=Version,
reverse=False,
)
requires_python = SpecifierSet(project["requires-python"])
assert all(
requires_python.contains(Version(version)) for version in python_versions
), "Please fix your python versions!"
# Check ruff configuration
if (CWD / "ruff.toml").is_file():
ruff = nox.project.load_toml(CWD / "ruff.toml")
ruff_version = ruff.get("target-version", "ruff_version")
expected_ruff_version = re.sub(r"\.", "", f"py{python_versions[0]}")
if ruff_version and expected_ruff_version != ruff_version:
raise RuntimeError(f"Please fix your ruff version to {expected_ruff_version!r} instead of {ruff_version!r}")
return python_versions