From c5b4b26dd3ceabd032b1cf6f1cadc5ac0031131c Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:23:49 +0200 Subject: [PATCH 1/9] Ignore .worktrees/ for parallel feature workspaces --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 435f23e3..76e23792 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ __pycache__ /.ruff_cache/ /.venv/ /.vscode/ +/.worktrees/ /build/ /constraints-mxdev.txt /dist/ From aa0dd6e6c113d98d36cfce2e6a221bd0309c8e3f Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:26:14 +0200 Subject: [PATCH 2/9] test: pin expected Makefile snapshot to post-fix output for issue #70 --- src/mxmake/tests/expected/Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mxmake/tests/expected/Makefile b/src/mxmake/tests/expected/Makefile index 99e62da5..9c5338aa 100644 --- a/src/mxmake/tests/expected/Makefile +++ b/src/mxmake/tests/expected/Makefile @@ -157,6 +157,13 @@ else PYTHON_PACKAGE_COMMAND=$(MXENV_PYTHON) -m pip endif +# Constraints file used by pip install recipes. Falls back to the project's +# own constraints.txt during bootstrap (before mxdev generates the rewritten +# constraints-mxdev.txt). Lazy assignment so $(wildcard) re-evaluates on use. +MXDEV_CONSTRAINTS?=constraints-mxdev.txt +PROJECT_CONSTRAINTS:=$(PYTHON_PROJECT_PREFIX)constraints.txt +PIP_CONSTRAINTS_FLAG=$(if $(wildcard $(MXDEV_CONSTRAINTS)),-c $(MXDEV_CONSTRAINTS),$(if $(wildcard $(PROJECT_CONSTRAINTS)),-c $(PROJECT_CONSTRAINTS),)) + # Auto-detect global uv availability (simple existence check) ifeq ("$(PYTHON_PACKAGE_INSTALLER)","uv") UV_AVAILABLE:=$(shell command -v uv >/dev/null 2>&1 && echo "true" || echo "false") @@ -222,9 +229,9 @@ ifeq ("$(USE_LOCAL_UV)","true") endif # Install/upgrade core packages - @$(PYTHON_PACKAGE_COMMAND) install -U pip setuptools wheel + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) pip setuptools wheel @echo "Install/Update MXStack Python packages" - @$(PYTHON_PACKAGE_COMMAND) install -U $(MXDEV) $(MXMAKE) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) $(MXDEV) $(MXMAKE) @touch $(MXENV_TARGET) .PHONY: mxenv From 44e70ced096a94e5b88152ac655cf94d5e7aa320 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:29:08 +0200 Subject: [PATCH 3/9] fix(mxenv): honor pinned constraints, drop -U on bootstrap installs (#70) --- src/mxmake/topics/core/mxenv.mk | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mxmake/topics/core/mxenv.mk b/src/mxmake/topics/core/mxenv.mk index 4777c247..c2906901 100644 --- a/src/mxmake/topics/core/mxenv.mk +++ b/src/mxmake/topics/core/mxenv.mk @@ -102,6 +102,13 @@ else PYTHON_PACKAGE_COMMAND=$(MXENV_PYTHON) -m pip endif +# Constraints file used by pip install recipes. Falls back to the project's +# own constraints.txt during bootstrap (before mxdev generates the rewritten +# constraints-mxdev.txt). Lazy assignment so $(wildcard) re-evaluates on use. +MXDEV_CONSTRAINTS?=constraints-mxdev.txt +PROJECT_CONSTRAINTS:=$(PYTHON_PROJECT_PREFIX)constraints.txt +PIP_CONSTRAINTS_FLAG=$(if $(wildcard $(MXDEV_CONSTRAINTS)),-c $(MXDEV_CONSTRAINTS),$(if $(wildcard $(PROJECT_CONSTRAINTS)),-c $(PROJECT_CONSTRAINTS),)) + # Auto-detect global uv availability (simple existence check) ifeq ("$(PYTHON_PACKAGE_INSTALLER)","uv") UV_AVAILABLE:=$(shell command -v uv >/dev/null 2>&1 && echo "true" || echo "false") @@ -167,9 +174,9 @@ ifeq ("$(USE_LOCAL_UV)","true") endif # Install/upgrade core packages - @$(PYTHON_PACKAGE_COMMAND) install -U pip setuptools wheel + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) pip setuptools wheel @echo "Install/Update MXStack Python packages" - @$(PYTHON_PACKAGE_COMMAND) install -U $(MXDEV) $(MXMAKE) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) $(MXDEV) $(MXMAKE) @touch $(MXENV_TARGET) .PHONY: mxenv From 6b380448ef8573d987b53e82ad84cb24eb481879 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:34:50 +0200 Subject: [PATCH 4/9] fix(sphinx): honor pinned constraints, drop -U on docs install (#70) --- src/mxmake/topics/docs/sphinx.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mxmake/topics/docs/sphinx.mk b/src/mxmake/topics/docs/sphinx.mk index 046931fa..fc6acc40 100644 --- a/src/mxmake/topics/docs/sphinx.mk +++ b/src/mxmake/topics/docs/sphinx.mk @@ -46,7 +46,7 @@ SPHINX_AUTOBUILD_BIN=sphinx-autobuild DOCS_TARGET:=$(SENTINEL_FOLDER)/sphinx.sentinel $(DOCS_TARGET): $(MXENV_TARGET) @echo "Install Sphinx" - @$(PYTHON_PACKAGE_COMMAND) install -U sphinx sphinx-autobuild $(DOCS_REQUIREMENTS) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) sphinx sphinx-autobuild $(DOCS_REQUIREMENTS) @touch $(DOCS_TARGET) .PHONY: docs From 7347ab792a332176aab1add7e8437e14acc703e8 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:36:27 +0200 Subject: [PATCH 5/9] fix(qa): honor pinned constraints in all QA tool installs (#70) --- src/mxmake/topics/qa/black.mk | 2 +- src/mxmake/topics/qa/coverage.mk | 2 +- src/mxmake/topics/qa/isort.mk | 2 +- src/mxmake/topics/qa/mypy.mk | 2 +- src/mxmake/topics/qa/pyrefly.mk | 2 +- src/mxmake/topics/qa/pyupgrade.mk | 2 +- src/mxmake/topics/qa/ruff.mk | 2 +- src/mxmake/topics/qa/test.mk | 2 +- src/mxmake/topics/qa/ty.mk | 2 +- src/mxmake/topics/qa/zpretty.mk | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mxmake/topics/qa/black.mk b/src/mxmake/topics/qa/black.mk index 65e44d68..0023684f 100644 --- a/src/mxmake/topics/qa/black.mk +++ b/src/mxmake/topics/qa/black.mk @@ -28,7 +28,7 @@ endif BLACK_TARGET:=$(SENTINEL_FOLDER)/black.sentinel $(BLACK_TARGET): $(MXENV_TARGET) @echo "Install Black" - @$(PYTHON_PACKAGE_COMMAND) install black + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) black @touch $(BLACK_TARGET) .PHONY: black-check diff --git a/src/mxmake/topics/qa/coverage.mk b/src/mxmake/topics/qa/coverage.mk index c6f37f26..a4d35f99 100644 --- a/src/mxmake/topics/qa/coverage.mk +++ b/src/mxmake/topics/qa/coverage.mk @@ -22,7 +22,7 @@ COVERAGE_TARGET:=$(SENTINEL_FOLDER)/coverage.sentinel $(COVERAGE_TARGET): $(TEST_TARGET) @echo "Install Coverage" - @$(PYTHON_PACKAGE_COMMAND) install -U coverage + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) coverage @touch $(COVERAGE_TARGET) .PHONY: coverage diff --git a/src/mxmake/topics/qa/isort.mk b/src/mxmake/topics/qa/isort.mk index 343b8471..3bc5e734 100644 --- a/src/mxmake/topics/qa/isort.mk +++ b/src/mxmake/topics/qa/isort.mk @@ -28,7 +28,7 @@ endif ISORT_TARGET:=$(SENTINEL_FOLDER)/isort.sentinel $(ISORT_TARGET): $(MXENV_TARGET) @echo "Install isort" - @$(PYTHON_PACKAGE_COMMAND) install isort + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) isort @touch $(ISORT_TARGET) .PHONY: isort-check diff --git a/src/mxmake/topics/qa/mypy.mk b/src/mxmake/topics/qa/mypy.mk index 18346a2a..a5c7fc7a 100644 --- a/src/mxmake/topics/qa/mypy.mk +++ b/src/mxmake/topics/qa/mypy.mk @@ -32,7 +32,7 @@ endif MYPY_TARGET:=$(SENTINEL_FOLDER)/mypy.sentinel $(MYPY_TARGET): $(MXENV_TARGET) @echo "Install mypy" - @$(PYTHON_PACKAGE_COMMAND) install mypy $(MYPY_REQUIREMENTS) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) mypy $(MYPY_REQUIREMENTS) @touch $(MYPY_TARGET) .PHONY: mypy diff --git a/src/mxmake/topics/qa/pyrefly.mk b/src/mxmake/topics/qa/pyrefly.mk index dbf1d8c5..18863c54 100644 --- a/src/mxmake/topics/qa/pyrefly.mk +++ b/src/mxmake/topics/qa/pyrefly.mk @@ -32,7 +32,7 @@ endif PYREFLY_TARGET:=$(SENTINEL_FOLDER)/pyrefly.sentinel $(PYREFLY_TARGET): $(MXENV_TARGET) @echo "Install pyrefly" - @$(PYTHON_PACKAGE_COMMAND) install pyrefly $(PYREFLY_REQUIREMENTS) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) pyrefly $(PYREFLY_REQUIREMENTS) @touch $(PYREFLY_TARGET) .PHONY: pyrefly diff --git a/src/mxmake/topics/qa/pyupgrade.mk b/src/mxmake/topics/qa/pyupgrade.mk index 3dfa204a..656f0d4a 100644 --- a/src/mxmake/topics/qa/pyupgrade.mk +++ b/src/mxmake/topics/qa/pyupgrade.mk @@ -32,7 +32,7 @@ endif PYUPGRADE_TARGET:=$(SENTINEL_FOLDER)/pyupgrade.sentinel $(PYUPGRADE_TARGET): $(MXENV_TARGET) @echo "Install pyupgrade" - @$(PYTHON_PACKAGE_COMMAND) install pyupgrade + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) pyupgrade @touch $(PYUPGRADE_TARGET) .PHONY: pyupgrade-format diff --git a/src/mxmake/topics/qa/ruff.mk b/src/mxmake/topics/qa/ruff.mk index 2b53c107..6d25fedf 100644 --- a/src/mxmake/topics/qa/ruff.mk +++ b/src/mxmake/topics/qa/ruff.mk @@ -50,7 +50,7 @@ endif RUFF_TARGET:=$(SENTINEL_FOLDER)/ruff.sentinel $(RUFF_TARGET): $(MXENV_TARGET) @echo "Install Ruff" - @$(PYTHON_PACKAGE_COMMAND) install ruff + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) ruff @touch $(RUFF_TARGET) .PHONY: ruff-check diff --git a/src/mxmake/topics/qa/test.mk b/src/mxmake/topics/qa/test.mk index 1ae982d5..7f7aa975 100644 --- a/src/mxmake/topics/qa/test.mk +++ b/src/mxmake/topics/qa/test.mk @@ -28,7 +28,7 @@ TEST_TARGET:=$(SENTINEL_FOLDER)/test.sentinel $(TEST_TARGET): $(MXENV_TARGET) @echo "Install $(TEST_REQUIREMENTS)" - @$(PYTHON_PACKAGE_COMMAND) install $(TEST_REQUIREMENTS) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) $(TEST_REQUIREMENTS) @touch $(TEST_TARGET) .PHONY: test diff --git a/src/mxmake/topics/qa/ty.mk b/src/mxmake/topics/qa/ty.mk index c6346722..b7e0c1f4 100644 --- a/src/mxmake/topics/qa/ty.mk +++ b/src/mxmake/topics/qa/ty.mk @@ -39,7 +39,7 @@ endif TY_TARGET:=$(SENTINEL_FOLDER)/ty.sentinel $(TY_TARGET): $(MXENV_TARGET) @echo "Install ty" - @$(PYTHON_PACKAGE_COMMAND) install ty + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) ty @touch $(TY_TARGET) .PHONY: ty diff --git a/src/mxmake/topics/qa/zpretty.mk b/src/mxmake/topics/qa/zpretty.mk index b2856a0b..4d745a5d 100644 --- a/src/mxmake/topics/qa/zpretty.mk +++ b/src/mxmake/topics/qa/zpretty.mk @@ -28,7 +28,7 @@ endif ZPRETTY_TARGET:=$(SENTINEL_FOLDER)/zpretty.sentinel $(ZPRETTY_TARGET): $(MXENV_TARGET) @echo "Install zpretty" - @$(PYTHON_PACKAGE_COMMAND) install zpretty + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) zpretty @touch $(ZPRETTY_TARGET) .PHONY: zpretty-check From 87ff7b1ddcfb48f2ca1f199df48ac76f41ad450b Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:38:13 +0200 Subject: [PATCH 6/9] fix(topics): honor pinned constraints in app/i18n/ldap installs (#70) --- src/mxmake/topics/applications/cookiecutter.mk | 2 +- src/mxmake/topics/applications/twisted.mk | 2 +- src/mxmake/topics/applications/zest-releaser.mk | 2 +- src/mxmake/topics/i18n/lingua.mk | 2 +- src/mxmake/topics/ldap/python-ldap.mk | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mxmake/topics/applications/cookiecutter.mk b/src/mxmake/topics/applications/cookiecutter.mk index 322ba6ad..7aafc767 100644 --- a/src/mxmake/topics/applications/cookiecutter.mk +++ b/src/mxmake/topics/applications/cookiecutter.mk @@ -19,7 +19,7 @@ COOKIECUTTER_TARGET:=$(SENTINEL_FOLDER)/cookiecutter.sentinel $(COOKIECUTTER_TARGET): $(MXENV_TARGET) @echo "Install cookiecutter" - @$(PYTHON_PACKAGE_COMMAND) install "cookiecutter>=2.6.0" + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) "cookiecutter>=2.6.0" @touch $(COOKIECUTTER_TARGET) .PHONY: cookiecutter diff --git a/src/mxmake/topics/applications/twisted.mk b/src/mxmake/topics/applications/twisted.mk index 3eb7949e..53979df8 100644 --- a/src/mxmake/topics/applications/twisted.mk +++ b/src/mxmake/topics/applications/twisted.mk @@ -21,7 +21,7 @@ TWISTED_TARGET:=$(SENTINEL_FOLDER)/twisted.sentinel $(TWISTED_TARGET): $(MXENV_TARGET) @echo "Install twisted" - @$(PYTHON_PACKAGE_COMMAND) install Twisted + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) Twisted @touch $(TWISTED_TARGET) .PHONY: twisted-start diff --git a/src/mxmake/topics/applications/zest-releaser.mk b/src/mxmake/topics/applications/zest-releaser.mk index 6fe525c5..6dab6e19 100644 --- a/src/mxmake/topics/applications/zest-releaser.mk +++ b/src/mxmake/topics/applications/zest-releaser.mk @@ -45,7 +45,7 @@ ZEST_RELEASER_TARGET:=$(SENTINEL_FOLDER)/zest-releaser.sentinel $(ZEST_RELEASER_TARGET): $(MXENV_TARGET) @echo "Install zest.releaser" - @$(PYTHON_PACKAGE_COMMAND) install zest.releaser + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) zest.releaser @touch $(ZEST_RELEASER_TARGET) .PHONY: zest-releaser-prerelease diff --git a/src/mxmake/topics/i18n/lingua.mk b/src/mxmake/topics/i18n/lingua.mk index 6a26808a..19ab7a62 100644 --- a/src/mxmake/topics/i18n/lingua.mk +++ b/src/mxmake/topics/i18n/lingua.mk @@ -31,7 +31,7 @@ LINGUA_TARGET:=$(SENTINEL_FOLDER)/lingua.sentinel $(LINGUA_TARGET): $(MXENV_TARGET) @echo "Install Lingua" - @$(PYTHON_PACKAGE_COMMAND) install chameleon lingua $(LINGUA_PLUGINS) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) chameleon lingua $(LINGUA_PLUGINS) @touch $(LINGUA_TARGET) PHONY: lingua-extract diff --git a/src/mxmake/topics/ldap/python-ldap.mk b/src/mxmake/topics/ldap/python-ldap.mk index 3618a23d..3ddbffc3 100644 --- a/src/mxmake/topics/ldap/python-ldap.mk +++ b/src/mxmake/topics/ldap/python-ldap.mk @@ -24,6 +24,7 @@ SYSTEM_DEPENDENCIES+=python3-dev libldap2-dev libssl-dev libsasl2-dev PYTHON_LDAP_TARGET:=$(SENTINEL_FOLDER)/python-ldap.sentinel $(PYTHON_LDAP_TARGET): $(MXENV_TARGET) $(OPENLDAP_TARGET) @$(PYTHON_PACKAGE_COMMAND) install \ + $(PIP_CONSTRAINTS_FLAG) \ --force-reinstall \ python-ldap @touch $(PYTHON_LDAP_TARGET) From 79f1df6cea4ed4aa7af8ce69494b53a0a2fc9f0e Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:39:44 +0200 Subject: [PATCH 7/9] chore: regenerate Makefile with constraints-aware installs (#70) --- Makefile | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 85670c22..a56e0b2b 100644 --- a/Makefile +++ b/Makefile @@ -119,12 +119,6 @@ RUFF_FIXES?=false # Default: false RUFF_UNSAFE_FIXES?=false -## qa.isort - -# Source folder to scan for Python files to run isort on. -# Default: src -ISORT_SRC?=src - ## docs.sphinx # Documentation source folder. @@ -253,6 +247,13 @@ else PYTHON_PACKAGE_COMMAND=$(MXENV_PYTHON) -m pip endif +# Constraints file used by pip install recipes. Falls back to the project's +# own constraints.txt during bootstrap (before mxdev generates the rewritten +# constraints-mxdev.txt). Lazy assignment so $(wildcard) re-evaluates on use. +MXDEV_CONSTRAINTS?=constraints-mxdev.txt +PROJECT_CONSTRAINTS:=$(PYTHON_PROJECT_PREFIX)constraints.txt +PIP_CONSTRAINTS_FLAG=$(if $(wildcard $(MXDEV_CONSTRAINTS)),-c $(MXDEV_CONSTRAINTS),$(if $(wildcard $(PROJECT_CONSTRAINTS)),-c $(PROJECT_CONSTRAINTS),)) + # Auto-detect global uv availability (simple existence check) ifeq ("$(PYTHON_PACKAGE_INSTALLER)","uv") UV_AVAILABLE:=$(shell command -v uv >/dev/null 2>&1 && echo "true" || echo "false") @@ -318,9 +319,9 @@ ifeq ("$(USE_LOCAL_UV)","true") endif # Install/upgrade core packages - @$(PYTHON_PACKAGE_COMMAND) install -U pip setuptools wheel + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) pip setuptools wheel @echo "Install/Update MXStack Python packages" - @$(PYTHON_PACKAGE_COMMAND) install -U $(MXDEV) $(MXMAKE) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) $(MXDEV) $(MXMAKE) @touch $(MXENV_TARGET) .PHONY: mxenv @@ -366,7 +367,7 @@ endif RUFF_TARGET:=$(SENTINEL_FOLDER)/ruff.sentinel $(RUFF_TARGET): $(MXENV_TARGET) @echo "Install Ruff" - @$(PYTHON_PACKAGE_COMMAND) install ruff + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) ruff @touch $(RUFF_TARGET) .PHONY: ruff-check @@ -411,7 +412,7 @@ SPHINX_AUTOBUILD_BIN=sphinx-autobuild DOCS_TARGET:=$(SENTINEL_FOLDER)/sphinx.sentinel $(DOCS_TARGET): $(MXENV_TARGET) @echo "Install Sphinx" - @$(PYTHON_PACKAGE_COMMAND) install -U sphinx sphinx-autobuild $(DOCS_REQUIREMENTS) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) sphinx sphinx-autobuild $(DOCS_REQUIREMENTS) @touch $(DOCS_TARGET) .PHONY: docs @@ -561,7 +562,7 @@ endif TY_TARGET:=$(SENTINEL_FOLDER)/ty.sentinel $(TY_TARGET): $(MXENV_TARGET) @echo "Install ty" - @$(PYTHON_PACKAGE_COMMAND) install ty + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) ty @touch $(TY_TARGET) .PHONY: ty @@ -591,7 +592,7 @@ DIRTY_TARGETS+=ty-dirty TEST_TARGET:=$(SENTINEL_FOLDER)/test.sentinel $(TEST_TARGET): $(MXENV_TARGET) @echo "Install $(TEST_REQUIREMENTS)" - @$(PYTHON_PACKAGE_COMMAND) install $(TEST_REQUIREMENTS) + @$(PYTHON_PACKAGE_COMMAND) install $(PIP_CONSTRAINTS_FLAG) $(TEST_REQUIREMENTS) @touch $(TEST_TARGET) .PHONY: test From 99b156512f6c1fbb1fd9e09fdd783b9eb36c2372 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:40:27 +0200 Subject: [PATCH 8/9] docs: document constraints-honoring install fix for 2.2.1 (#70) --- CHANGES.md | 9 +++++++++ docs/source/migration.md | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 4f71f594..5be8d7b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,14 @@ # Changelog +## 2.2.1 (unreleased) + +- Fix: `make install` now honors pinned versions from `constraints.txt` / + `constraints-mxdev.txt`. All `pip install` recipes in topic templates pass + `$(PIP_CONSTRAINTS_FLAG)` and no longer use `-U`, preventing transitive + dependencies from being silently upgraded past project pins. + Resolves [#70](https://github.com/mxstack/mxmake/issues/70). + [jensens, 2026-04-27] + ## 2.2.0 - Feature: Add optional `ruff check --fix` support to ruff-format target diff --git a/docs/source/migration.md b/docs/source/migration.md index 2cef992f..6e604f8a 100644 --- a/docs/source/migration.md +++ b/docs/source/migration.md @@ -2,6 +2,22 @@ This guide documents breaking changes between mxmake versions and how to migrate your projects. +## Version 2.2.1 (unreleased) + +### Behavior Change: `pip install` recipes now honor pinned constraints + +**What changed**: Topic templates no longer pass `-U` to `pip install` and now route through a new lazy-evaluated `PIP_CONSTRAINTS_FLAG` Makefile variable that resolves to `-c constraints-mxdev.txt` (or `-c constraints.txt` during bootstrap, if present). Previously, `make install` could silently upgrade transitive dependencies past pins because individual tool installs (sphinx, coverage, ruff, etc.) ignored constraint files. + +**Why**: Local venvs were diverging from CI builds, breaking reproducibility for projects that rely on pin discipline. See issue [#70](https://github.com/mxstack/mxmake/issues/70). + +**Migration**: + +- Run `mxmake update` to regenerate your `Makefile` with the new install recipes. +- If you intentionally relied on the old "upgrade everything to latest on every install" behavior, run `make clean && make install` after bumping pins to force a refresh. +- No other action required. Generated Makefiles continue to work without a `constraints.txt` — the new flag falls back to empty in that case. + +**No breaking changes**: All settings, targets, and CLI commands are unchanged. + ## Version 2.0.1 (unreleased) ### Added: Monorepo Support From 337af49f05ecfdd3464a7afd0338e6d8b6b62afd Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Mon, 27 Apr 2026 10:43:31 +0200 Subject: [PATCH 9/9] docs(packages): note that constraints are embedded via requirements file (#70) --- Makefile | 1 + src/mxmake/topics/core/packages.mk | 1 + 2 files changed, 2 insertions(+) diff --git a/Makefile b/Makefile index a56e0b2b..b993fb3b 100644 --- a/Makefile +++ b/Makefile @@ -521,6 +521,7 @@ endif PACKAGES_TARGET:=$(INSTALLED_PACKAGES) $(PACKAGES_TARGET): $(FILES_TARGET) $(ADDITIONAL_SOURCES_TARGETS) @echo "Install python packages" + # constraints already embedded in $(FILES_TARGET) via mxdev's `-c` line @$(PYTHON_PACKAGE_COMMAND) install $(PACKAGES_PRERELEASES) -r $(FILES_TARGET) @$(PYTHON_PACKAGE_COMMAND) freeze > $(INSTALLED_PACKAGES) @touch $(PACKAGES_TARGET) diff --git a/src/mxmake/topics/core/packages.mk b/src/mxmake/topics/core/packages.mk index 1511afdb..381af959 100644 --- a/src/mxmake/topics/core/packages.mk +++ b/src/mxmake/topics/core/packages.mk @@ -41,6 +41,7 @@ endif PACKAGES_TARGET:=$(INSTALLED_PACKAGES) $(PACKAGES_TARGET): $(FILES_TARGET) $(ADDITIONAL_SOURCES_TARGETS) @echo "Install python packages" + # constraints already embedded in $(FILES_TARGET) via mxdev's `-c` line @$(PYTHON_PACKAGE_COMMAND) install $(PACKAGES_PRERELEASES) -r $(FILES_TARGET) @$(PYTHON_PACKAGE_COMMAND) freeze > $(INSTALLED_PACKAGES) @touch $(PACKAGES_TARGET)