Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion edx_lint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
edx_lint standardizes lint configuration and additional plugins for use in
Open edX code.
"""
__version__ = "6.0.0"
__version__ = "6.1.0"
5 changes: 4 additions & 1 deletion edx_lint/cmd/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from edx_lint.cmd.list import list_main
from edx_lint.cmd.write import write_main
from edx_lint.cmd.update import update_main
from edx_lint.cmd.write_uv_constraints import write_uv_constraints_main


def main(argv=None):
Expand All @@ -25,6 +26,8 @@ def main(argv=None):
return write_main(argv[1:])
elif argv[0] == "update":
return update_main(argv[1:])
elif argv[0] == "write_uv_constraints":
return write_uv_constraints_main(argv[1:])
else:
print("Don't understand {!r}".format(" ".join(argv)))
show_help()
Expand All @@ -40,5 +43,5 @@ def show_help():
Commands:
""".format(VERSION=__version__)
)
for cmd in [write_main, check_main, list_main, update_main]:
for cmd in [write_main, check_main, list_main, update_main, write_uv_constraints_main]:
print(cmd.__doc__.lstrip("\n"))
107 changes: 107 additions & 0 deletions edx_lint/cmd/write_uv_constraints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""The edx_lint write_uv_constraints command."""

import argparse
import importlib.resources
import re

import tomlkit


def _package_name(spec):
"""Return the normalized package name from a constraint specifier like 'Django<6.0'."""
name = re.split(r"[<>=!~\[;@]", spec, maxsplit=1)[0].strip()
return name.lower().replace("-", "_").replace(".", "_")


def _parse_constraints(text):
"""Parse constraints file text, stripping comments and blank lines.

Returns a tuple of (constraints, directives) where:
constraints: valid package-specifier lines
directives: pip directive lines (-c, -r, etc.) that are not valid here
"""
constraints = []
directives = []
for line in text.splitlines():
line = line.split("#")[0].strip()
if not line:
continue
if line.startswith("-"):
directives.append(line)
else:
constraints.append(line)
return constraints, directives


def write_uv_constraints_main(argv):
"""
write_uv_constraints [pyproject.toml]
Write [tool.uv].constraint-dependencies in pyproject.toml by merging
edx-lint's global constraints with optional repo-specific constraints
from [tool.edx_lint].uv_constraints in the same file.
"""
parser = argparse.ArgumentParser(prog="edx_lint write_uv_constraints", add_help=False)
parser.add_argument("pyproject", nargs="?", default="pyproject.toml")
args, unknown = parser.parse_known_args(argv)

if unknown:
print(f"Unknown arguments: {' '.join(unknown)}")
return 1

global_text = (
importlib.resources.files("edx_lint")
.joinpath("files/common_constraints.txt")
.read_text(encoding="utf-8")
)
global_constraints, _ = _parse_constraints(global_text)

try:
with open(args.pyproject, encoding="utf-8") as f:
data = tomlkit.load(f)
except FileNotFoundError:
print(f"File not found: {args.pyproject}")
return 2

# Read optional repo-specific constraints from [tool.edx_lint].uv_constraints.
# These live in the same pyproject.toml so everything is in one place.
try:
local_constraints = list(data["tool"]["edx_lint"]["uv_constraints"])
except KeyError:
local_constraints = []

# Merge global and local constraints, keyed by normalized package name so
# that a local entry for the same package overrides the global one. This
# lets repos tighten or pin a constraint during testing without the global
# version clobbering their pin.
merged = {_package_name(c): c for c in global_constraints}
for c in local_constraints:
merged[_package_name(c)] = c # local takes precedence
constraints = list(merged.values())

if "tool" not in data:
data.add("tool", tomlkit.table())
if "uv" not in data["tool"]:
data["tool"].add("uv", tomlkit.table())

uv_table = data["tool"]["uv"]
constraint_array = tomlkit.array()
constraint_array.multiline(True)
constraint_array.extend(constraints)

if "constraint-dependencies" in uv_table:
# Replace in-place so any existing comment above the key is preserved.
uv_table["constraint-dependencies"] = constraint_array
else:
# First write: add a prominent comment so humans know not to edit this.
uv_table.add(tomlkit.comment(" DO NOT EDIT constraint-dependencies DIRECTLY."))
uv_table.add(tomlkit.comment(" This list is managed by `edx_lint write_uv_constraints`"))
uv_table.add(tomlkit.comment(" and will be overwritten the next time `make upgrade` is run."))
uv_table.add(tomlkit.comment(" - GLOBAL constraints: edit edx_lint/files/common_constraints.txt"))
uv_table.add(tomlkit.comment(" - REPO-SPECIFIC constraints: edit [tool.edx_lint].uv_constraints in this file"))
uv_table.add("constraint-dependencies", constraint_array)

with open(args.pyproject, "w", encoding="utf-8") as f:
tomlkit.dump(data, f)

print(f"Wrote {len(constraints)} constraints to {args.pyproject}")
return 0
1 change: 1 addition & 0 deletions requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pylint
pylint-django
pylint-celery
six
tomlkit
10 changes: 6 additions & 4 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ astroid==4.0.4
# via
# pylint
# pylint-celery
click==8.3.1
click==8.3.3
# via
# -r requirements/base.in
# click-log
# code-annotations
click-log==0.4.0
# via -r requirements/base.in
code-annotations==2.3.2
code-annotations==3.0.0
# via
# -c requirements/constraints.txt
# -r requirements/base.in
Expand All @@ -29,7 +29,7 @@ markupsafe==3.0.3
# via jinja2
mccabe==0.7.0
# via pylint
platformdirs==4.9.4
platformdirs==4.9.6
# via pylint
pylint==4.0.5
# via
Expand All @@ -56,4 +56,6 @@ stevedore==5.7.0
text-unidecode==1.3
# via python-slugify
tomlkit==0.14.0
# via pylint
# via
# -r requirements/base.in
# pylint
18 changes: 10 additions & 8 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
#
# make upgrade
#
cachetools==7.0.3
cachetools==7.0.6
# via tox
colorama==0.4.6
# via tox
distlib==0.4.0
# via virtualenv
filelock==3.25.0
filelock==3.29.0
# via
# python-discovery
# tox
# virtualenv
packaging==26.0
packaging==26.1
# via
# pyproject-api
# tox
platformdirs==4.9.4
platformdirs==4.9.6
# via
# python-discovery
# tox
Expand All @@ -28,11 +28,13 @@ pluggy==1.6.0
# via tox
pyproject-api==1.10.0
# via tox
python-discovery==1.1.0
# via virtualenv
python-discovery==1.2.2
# via
# tox
# virtualenv
tomli-w==1.2.0
# via tox
tox==4.49.0
tox==4.53.0
# via -r requirements/ci.in
virtualenv==21.1.0
virtualenv==21.2.4
# via tox
18 changes: 10 additions & 8 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ astroid==4.0.4
# -r requirements/base.txt
# pylint
# pylint-celery
click==8.3.1
click==8.3.3
# via
# -r requirements/base.txt
# click-log
# code-annotations
click-log==0.4.0
# via -r requirements/base.txt
code-annotations==2.3.2
code-annotations==3.0.0
# via
# -c requirements/constraints.txt
# -r requirements/base.txt
Expand All @@ -26,7 +26,7 @@ dill==0.4.1
# pylint
distlib==0.4.0
# via virtualenv
filelock==3.25.0
filelock==3.29.0
# via
# python-discovery
# tox
Expand All @@ -47,11 +47,11 @@ mccabe==0.7.0
# via
# -r requirements/base.txt
# pylint
packaging==26.0
packaging==26.1
# via
# pyproject-api
# tox
platformdirs==4.9.4
platformdirs==4.9.6
# via
# -r requirements/base.txt
# pylint
Expand All @@ -76,8 +76,10 @@ pylint-plugin-utils==0.9.0
# -r requirements/base.txt
# pylint-celery
# pylint-django
python-discovery==1.1.0
# via virtualenv
python-discovery==1.2.2
# via
# tox
# virtualenv
python-slugify==8.0.4
# via
# -r requirements/base.txt
Expand Down Expand Up @@ -108,5 +110,5 @@ tox==3.28.0
# tox-battery
tox-battery==0.6.2
# via -r requirements/dev.in
virtualenv==21.1.0
virtualenv==21.2.4
# via tox
10 changes: 5 additions & 5 deletions requirements/pip-tools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
#
# make upgrade
#
build==1.4.0
build==1.4.4
# via pip-tools
click==8.3.1
click==8.3.3
# via pip-tools
packaging==26.0
packaging==26.1
# via
# build
# wheel
Expand All @@ -18,11 +18,11 @@ pyproject-hooks==1.2.0
# via
# build
# pip-tools
wheel==0.46.3
wheel==0.47.0
# via pip-tools

# The following packages are considered to be unsafe in a requirements file:
pip==26.0.1
# via pip-tools
setuptools==82.0.0
setuptools==82.0.1
# via pip-tools
20 changes: 10 additions & 10 deletions requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ astroid==4.0.4
# -r requirements/dev.txt
# pylint
# pylint-celery
click==8.3.1
click==8.3.3
# via
# -r requirements/dev.txt
# click-log
# code-annotations
click-log==0.4.0
# via -r requirements/dev.txt
code-annotations==2.3.2
code-annotations==3.0.0
# via
# -c requirements/constraints.txt
# -r requirements/dev.txt
coverage==7.13.4
coverage==7.13.5
# via -r requirements/test.in
dill==0.4.1
# via
Expand All @@ -35,7 +35,7 @@ distlib==0.4.0
# via
# -c edx_lint/files/common_constraints.txt
# -r requirements/test.in
filelock==3.25.0
filelock==3.29.0
# via
# -r requirements/dev.txt
# python-discovery
Expand All @@ -59,12 +59,12 @@ mccabe==0.7.0
# via
# -r requirements/dev.txt
# pylint
packaging==26.0
packaging==26.1
# via
# -r requirements/dev.txt
# pytest
# tox
platformdirs==4.9.4
platformdirs==4.9.6
# via
# -r requirements/dev.txt
# pylint
Expand All @@ -79,7 +79,7 @@ py==1.11.0
# via
# -r requirements/dev.txt
# tox
pygments==2.19.2
pygments==2.20.0
# via pytest
pylint==4.0.5
# via
Expand All @@ -96,9 +96,9 @@ pylint-plugin-utils==0.9.0
# -r requirements/dev.txt
# pylint-celery
# pylint-django
pytest==9.0.2
pytest==9.0.3
# via -r requirements/test.in
python-discovery==1.1.0
python-discovery==1.2.2
# via
# -r requirements/dev.txt
# virtualenv
Expand Down Expand Up @@ -134,7 +134,7 @@ tox==3.28.0
# tox-battery
tox-battery==0.6.2
# via -r requirements/dev.txt
virtualenv==21.1.0
virtualenv==21.2.4
# via
# -r requirements/dev.txt
# tox
Loading
Loading