diff --git a/Makefile b/Makefile index 3eb39f7..a4e9a9d 100644 --- a/Makefile +++ b/Makefile @@ -13,12 +13,10 @@ help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) @awk -F ':.*?## ' '/^[a-zA-Z]/ && NF==2 {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort -.PHONY: help Makefile upgrade requirements install +.PHONY: help Makefile upgrade requirements install serve_docs check_docs -sync-constraints: ## download and sync common_constraints.txt to pyproject.toml - uv run python sync_constraints.py - -upgrade: sync-constraints +upgrade: ## upgrade all packages in uv.lock and sync constraints from edx-lint + uv run --with edx-lint edx_lint write_uv_constraints pyproject.toml uv lock --upgrade requirements: ## install dependencies using uv diff --git a/pyproject.toml b/pyproject.toml index 6cc2f2e..ce8c7d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,17 +31,23 @@ Documentation = "https://docs.openedx.org/projects/openedx-aspects" Repository = "https://github.com/openedx/openedx-aspects" "Issue Tracker" = "https://github.com/openedx/openedx-aspects/issues" + [tool.uv] +# DO NOT EDIT constraint-dependencies DIRECTLY. +# This list is managed by `edx_lint write_uv_constraints` +# and will be overwritten the next time `make upgrade` is run. +# - GLOBAL constraints: edit edx_lint/files/common_constraints.txt +# - REPO-SPECIFIC constraints: edit [tool.edx_lint].uv_constraints in this file constraint-dependencies = [ - # Downloaded from edx-lint common_constraints.txt - # DO NOT EDIT - Use 'python sync_constraints.py' to update "Django<6.0", "elasticsearch<7.14.0", - # Local constraint - "greenlet>3.0.1", # playwright and sqlalchemy requirements conflict for greenlet<=3.0.1 + "greenlet>3.0.1", ] -# Common constraints from edx-lint -override-dependencies = [ - "Django<6.0", # using LTS django version - "elasticsearch<7.14.0", # 7.14.0+ contains breaking changes + +[tool.edx_lint] +# Repo-specific uv constraints merged with edx-lint's global constraints. +# Local entries override global ones for the same package. +# Run `make upgrade` to regenerate [tool.uv].constraint-dependencies. +uv_constraints = [ + "greenlet>3.0.1", # playwright and sqlalchemy requirements conflict for greenlet<=3.0.1 ] diff --git a/requirements/common_constraints.txt b/requirements/common_constraints.txt deleted file mode 100644 index 72cc4cc..0000000 --- a/requirements/common_constraints.txt +++ /dev/null @@ -1,20 +0,0 @@ -# A central location for most common version constraints -# (across edx repos) for pip-installation. -# -# Similar to other constraint files this file doesn't install any packages. -# It specifies version constraints that will be applied if a package is needed. -# When pinning something here, please provide an explanation of why it is a good -# idea to pin this package across all edx repos, Ideally, link to other information -# that will help people in the future to remove the pin when possible. -# Writing an issue against the offending project and linking to it here is good. -# -# Note: Changes to this file will automatically be used by other repos, referencing -# this file from Github directly. It does not require packaging in edx-lint. - -# using LTS django version -Django<6.0 - -# elasticsearch>=7.14.0 includes breaking changes in it which caused issues in discovery upgrade process. -# elastic search changelog: https://www.elastic.co/guide/en/enterprise-search/master/release-notes-7.14.0.html -# See https://github.com/openedx/edx-platform/issues/35126 for more info -elasticsearch<7.14.0 diff --git a/sync_constraints.py b/sync_constraints.py deleted file mode 100644 index 647cb8c..0000000 --- a/sync_constraints.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to sync common_constraints.txt into pyproject.toml. - -This script downloads the common_constraints.txt file from edx-lint and -updates the [tool.uv.constraint-dependencies] section in pyproject.toml. -""" - -import re -import sys -from pathlib import Path -from urllib.request import urlopen - -COMMON_CONSTRAINTS_URL = "https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt" -PYPROJECT_PATH = Path(__file__).parent / "pyproject.toml" -CONSTRAINTS_FILE_PATH = ( - Path(__file__).parent / "requirements" / "common_constraints.txt" -) - - -def download_constraints(): - """Download the common_constraints.txt file.""" - print(f"Downloading constraints from {COMMON_CONSTRAINTS_URL}...") - try: - with urlopen(COMMON_CONSTRAINTS_URL) as response: - content = response.read().decode("utf-8") - - # Save to requirements directory for reference - CONSTRAINTS_FILE_PATH.parent.mkdir(exist_ok=True) - CONSTRAINTS_FILE_PATH.write_text(content) - print(f"Saved constraints to {CONSTRAINTS_FILE_PATH}") - return content - except Exception as e: - print(f"Error downloading constraints: {e}", file=sys.stderr) - # Try to read from local file if download fails - if CONSTRAINTS_FILE_PATH.exists(): - print("Using existing local constraints file") - return CONSTRAINTS_FILE_PATH.read_text() - raise - - -def parse_constraints(content): - """ - Parse constraints from common_constraints.txt. - - Returns a list of constraint strings suitable for pyproject.toml. - """ - constraints = [] - - for line in content.split("\n"): - line = line.strip() - - # Skip empty lines and comments - if not line or line.startswith("#"): - continue - - # Parse constraint (e.g., "Django<6.0" or "pip<26.0") - # Keep the constraint as-is - constraints.append(line) - - return constraints - - -def update_pyproject_toml(constraints): - """ - Update pyproject.toml with the new constraints. - - This function updates the [tool.uv.constraint-dependencies] section. - """ - if not PYPROJECT_PATH.exists(): - print(f"Error: {PYPROJECT_PATH} not found", file=sys.stderr) - sys.exit(1) - - content = PYPROJECT_PATH.read_text() - - # Build the new constraint-dependencies section - constraints_section = "[tool.uv]\nconstraint-dependencies = [\n" - constraints_section += " # Downloaded from edx-lint common_constraints.txt\n" - constraints_section += ( - " # DO NOT EDIT - Use 'python sync_constraints.py' to update\n" - ) - - for constraint in constraints: - # Escape quotes if needed - constraint_str = constraint.replace('"', '\\"') - constraints_section += f' "{constraint_str}",\n' - - # Add local constraint (greenlet) - constraints_section += " # Local constraint\n" - constraints_section += ' "greenlet>3.0.1", # playwright and sqlalchemy requirements conflict for greenlet<=3.0.1\n' - constraints_section += "]\n" - - # Find and replace the [tool.uv] section - # Pattern to match [tool.uv] section with constraint-dependencies - pattern = r"\[tool\.uv\]\s*\nconstraint-dependencies\s*=\s*\[.*?\]" - - if re.search(pattern, content, re.DOTALL): - # Replace existing section - new_content = re.sub( - pattern, constraints_section.rstrip(), content, flags=re.DOTALL - ) - else: - # Check if [tool.uv] exists without constraint-dependencies - if "[tool.uv]" in content: - # Insert constraint-dependencies into existing [tool.uv] - new_content = content.replace("[tool.uv]", constraints_section.rstrip()) - else: - # Add new [tool.uv] section at the end - new_content = content.rstrip() + "\n\n" + constraints_section - - PYPROJECT_PATH.write_text(new_content) - print(f"Updated {PYPROJECT_PATH}") - - -def main(): - """Main function.""" - print("Syncing common_constraints.txt to pyproject.toml...") - - # Download constraints - constraints_content = download_constraints() - - # Parse constraints - constraints = parse_constraints(constraints_content) - print(f"Found {len(constraints)} constraints") - - # Update pyproject.toml - update_pyproject_toml(constraints) - - print( - "\nDone! Run 'uv lock --upgrade' to update the lock file with the new constraints." - ) - - -if __name__ == "__main__": - main()