git: 09d8d156ea97 - main - misc/py-pytorch: update 2.13.0 → 2.14.0

From: Yuri Victorovich <yuri_at_FreeBSD.org>
Date: Sun, 13 Sep 2026 03:06:58 UTC
The branch main has been updated by yuri:

URL: https://cgit.FreeBSD.org/ports/commit/?id=09d8d156ea97c4f1b30c8996a8fce705589ac50c

commit 09d8d156ea97c4f1b30c8996a8fce705589ac50c
Author:     Yuri Victorovich <yuri@FreeBSD.org>
AuthorDate: 2026-09-13 03:03:03 +0000
Commit:     Yuri Victorovich <yuri@FreeBSD.org>
CommitDate: 2026-09-13 03:06:18 +0000

    misc/py-pytorch: update 2.13.0 → 2.14.0
    
    ChangeLog: https://github.com/pytorch/pytorch/releases/tag/v2.14.0
    
    Also:
    - Build changed to the scikit-build-core backend.
    - files/example.py added for quick testing.
---
 math/dgl/Makefile                                  |   5 +-
 misc/py-pytorch/Makefile                           |  30 ++++-
 misc/py-pytorch/distinfo                           |   6 +-
 misc/py-pytorch/files/example.py                   | 132 +++++++++++++++++++++
 misc/py-pytorch/files/patch-CMakeLists.txt         |  14 +--
 misc/py-pytorch/files/patch-pyproject.toml         |  23 +---
 misc/py-pytorch/files/patch-requirements-build.txt |  11 +-
 misc/py-pytorch/files/patch-setup.py               |  83 -------------
 .../files/patch-test_dynamo_test__aot__autograd.py |   8 +-
 ...patch-test_dynamo_test__guard__serialization.py |  10 +-
 .../files/patch-test_dynamo_test__repros.py        |   4 +-
 .../patch-third__party_fmt_include_fmt_format.h    |  10 --
 .../files/patch-tools_metadata_dependencies.py     |  20 ++++
 ...orch___inductor_compile__worker_____main____.py |   8 +-
 14 files changed, 219 insertions(+), 145 deletions(-)

diff --git a/math/dgl/Makefile b/math/dgl/Makefile
index fc23867ff0b8..a2cb34684cc4 100644
--- a/math/dgl/Makefile
+++ b/math/dgl/Makefile
@@ -5,11 +5,14 @@ CATEGORIES=	math # machine-learning
 
 MAINTAINER=	yuri@FreeBSD.org
 COMMENT=	Deep Graph Library
-WWW=		https://www.dgl.ai/
+WWW=		https://www.dgl.ai/ \
+		https://github.com/dmlc/dgl/
 
 LICENSE=	APACHE20
 LICENSE_FILE=	${WRKSRC}/LICENSE
 
+BROKEN=		not compatible with pytorch-2.14.0, see https://github.com/dmlc/dgl/issues/7934
+
 BUILD_DEPENDS=	${BACKEND_DEPENDS} \
 		bash:shells/bash \
 		gmake:devel/gmake
diff --git a/misc/py-pytorch/Makefile b/misc/py-pytorch/Makefile
index 8c897546999c..20a580d0a863 100644
--- a/misc/py-pytorch/Makefile
+++ b/misc/py-pytorch/Makefile
@@ -1,6 +1,6 @@
 PORTNAME=	pytorch
 DISTVERSIONPREFIX=	v
-DISTVERSION=	2.13.0
+DISTVERSION=	2.14.0
 CATEGORIES=	misc # machine-learning
 MASTER_SITES=	https://github.com/pytorch/pytorch/releases/download/v${DISTVERSION}/
 PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
@@ -19,8 +19,7 @@ BROKEN_aarch64=	build fails: CMake Error at third_party/QNNPACK/CMakeLists.txt:4
 BROKEN_armv7=	build fails: CMake Error at third_party/QNNPACK/CMakeLists.txt:47 (MESSAGE): Unrecognized CMAKE_SYSTEM_NAME = FreeBSD, see https://github.com/pytorch/pytorch/issues/144608
 BROKEN_i386=	build fails: DispatchStub.cpp:162:29: [0m[0;1;31merror: [0m[1muse of undeclared identifier 'AVX2'[0m
 
-BUILD_DEPENDS=	${PY_SETUPTOOLS} \
-		cmake:devel/cmake-core \
+BUILD_DEPENDS=	cmake:devel/cmake-core \
 		gmake:devel/gmake \
 		pybind11>0:devel/pybind11 \
 		${PYTHON_PKGNAMEPREFIX}numpy>=1.16:math/py-numpy@${PY_FLAVOR} \
@@ -34,6 +33,7 @@ BUILD_DEPENDS=	${PY_SETUPTOOLS} \
 		${PYTHON_PKGNAMEPREFIX}psutil>0:sysutils/py-psutil@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}pyyaml>0:devel/py-pyyaml@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}requests>0:www/py-requests@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}scikit-build-core>=1.0:devel/py-scikit-build-core@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}six>0:devel/py-six@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}sympy>=1.13.3:math/py-sympy@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}typing-extensions>0:devel/py-typing-extensions@${PY_FLAVOR} \
@@ -54,11 +54,14 @@ RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}filelock>0:sysutils/py-filelock@${PY_FLAVOR}
 RUN_DEPENDS+=	${PYTHON_PKGNAMEPREFIX}astunparse>0:devel/py-astunparse@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}dill>0:devel/py-dill@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}protobuf>0:devel/py-protobuf@${PY_FLAVOR} # optional dependencies
-TEST_DEPENDS=	${PYTHON_PKGNAMEPREFIX}pytest-rerunfailures>0:devel/py-pytest-rerunfailures@${PY_FLAVOR} \
+TEST_DEPENDS=	${PYTHON_PKGNAMEPREFIX}expecttest>0:devel/py-expecttest@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}pytest-rerunfailures>0:devel/py-pytest-rerunfailures@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}pytest-xdist>0:devel/py-pytest-xdist@${PY_FLAVOR}
 
-USES=		compiler:c++17-lang localbase:ldflags mpi:openmpi python
+USES=		compiler:c++17-lang localbase:ldflags mpi:openmpi python shebangfix
 USE_PYTHON=	pep517 autoplist
+
+SHEBANG_FILES=	torch/utils/hipify/hipify_python.py # installed executable, unlike with the pre-2.14 setuptools build
 USE_LDCONFIG=	${PYTHON_SITELIBDIR}/torch/lib
 
 # The Python package is named "torch" not "pytorch"
@@ -75,6 +78,11 @@ MAKE_ENV+=	USE_CUDNN=0
 MAKE_ENV+=	USE_LAPACK=1 # needed on FreeBSD to run w/out GPU
 MAKE_ENV+=	USE_QNNPACK=0
 MAKE_ENV+=	USE_DISTRIBUTED=1
+# point FindMPI at the openmpi requested by USES=mpi, otherwise it picks up the
+# mpicc/mpicxx wrappers that net/mpich installs into LOCALBASE/bin, which link
+# libmpi/libmpicxx from mpich and drag in lang/gcc14 via the wrapper's -rpath
+MAKE_ENV+=	CMAKE_ARGS="-DMPI_C_COMPILER=${MPI_HOME}/bin/mpicc -DMPI_CXX_COMPILER=${MPI_HOME}/bin/mpicxx" \
+		MAX_JOBS=${MAKE_JOBS_NUMBER}
 LDFLAGS+=	-lexecinfo
 LDFLAGS_powerpc64le=	-pthread
 
@@ -92,8 +100,15 @@ VULKAN_BUILD_DEPENDS=	glslc:graphics/shaderc \
 			vulkan-headers>0:graphics/vulkan-headers
 VULKAN_LIB_DEPENDS=	libvulkan.so:graphics/vulkan-loader
 
+CONFLICTS_BUILD=	mpich # binaries are still linked with mpich when it is present
+
 .include <bsd.port.options.mk>
 
+post-extract:
+	# upstream ships a stray *.orig file that 'make makepatch' would otherwise
+	# mistake for a patch baseline and turn into a bogus binary patch
+	@${RM} ${WRKSRC}/third_party/aiter/hsa/gfx950/pa/pa_bf16_noquant_gqa8_1tg_4w.co.orig
+
 post-patch:
 	@cd ${WRKSRC} && \
 		${RM} -r third_party/cpuinfo third_party/fbgemm/external/cpuinfo && \
@@ -126,4 +141,9 @@ do-install: # port should be moved to 'torch', but keep this for now with the ha
 do-test:
 	@cd ${TEST_WRKSRC} && ${SETENV} ${TEST_ENV} ${PYTHON_CMD} run_test.py
 
+test-quick:
+	@cd ${TEST_WRKSRC} && ${SETENV} ${TEST_ENV} ${PYTHON_CMD} ${FILESDIR}/example.py
+
+# tests as of 2.14.0: 231 passed 6 skipped
+
 .include <bsd.port.mk>
diff --git a/misc/py-pytorch/distinfo b/misc/py-pytorch/distinfo
index d51bf5ed6c82..159be4c30252 100644
--- a/misc/py-pytorch/distinfo
+++ b/misc/py-pytorch/distinfo
@@ -1,5 +1,5 @@
-TIMESTAMP = 1784075507
-SHA256 (pytorch/pytorch-v2.13.0.tar.gz) = 66614a19060f69cfd63cd0295f65a1241bd15df2fa65c60ae51066c11c2ce812
-SIZE (pytorch/pytorch-v2.13.0.tar.gz) = 485291648
+TIMESTAMP = 1789232118
+SHA256 (pytorch/pytorch-v2.14.0.tar.gz) = e4bc64b802db095a8a53e216e5aba168eba629b99dd397cfa44e72d9c84e7657
+SIZE (pytorch/pytorch-v2.14.0.tar.gz) = 797590021
 SHA256 (pytorch/pytorch-cpuinfo-bc3c01e_GH0.tar.gz) = 09459e830a588fee730feb19d8a32fedf2d36d48db7bd9b18c3159c7e74ea0ce
 SIZE (pytorch/pytorch-cpuinfo-bc3c01e_GH0.tar.gz) = 3547453
diff --git a/misc/py-pytorch/files/example.py b/misc/py-pytorch/files/example.py
new file mode 100644
index 000000000000..0c8046ca603e
--- /dev/null
+++ b/misc/py-pytorch/files/example.py
@@ -0,0 +1,132 @@
+import torch
+import torch.nn as nn
+import torch.optim as optim
+import numpy as np
+
+# Set random seed for reproducibility
+torch.manual_seed(42)
+np.random.seed(42)
+
+# Define the target mathematical function
+def target_function(a, b, c):
+    return 18*a*b*c - 4*(a**3)*c + (a**2)*(b**2) - 4*(b**3) - 27*(c**2)
+
+# ==========================================
+# (1) Define Neural Network and Train
+# ==========================================
+
+# A deep network with architectural modifications to easily map polynomial boundaries
+class DiscriminantNN(nn.Module):
+    def __init__(self):
+        super(DiscriminantNN, self).__init__()
+        self.net = nn.Sequential(
+            nn.Linear(3, 128),
+            nn.GELU(),
+            nn.Linear(128, 128),
+            nn.GELU(),
+            nn.Linear(128, 128),
+            nn.GELU(),
+            nn.Linear(128, 64),
+            nn.GELU(),
+            nn.Linear(64, 1)
+        )
+        
+    def forward(self, x):
+        return self.net(x)
+
+# Generate dense grid data for the 0..1 interval with 0.05 step to cover the domain topology
+grid_steps = np.linspace(0.0, 1.0, 21)
+a_grid, b_grid, c_grid = np.meshgrid(grid_steps, grid_steps, grid_steps)
+X_train_np = np.stack([a_grid.ravel(), b_grid.ravel(), c_grid.ravel()], axis=1)
+y_train_np = target_function(X_train_np[:, 0], X_train_np[:, 1], X_train_np[:, 2]).reshape(-1, 1)
+
+X_train = torch.tensor(X_train_np, dtype=torch.float32)
+y_train = torch.tensor(y_train_np, dtype=torch.float32)
+
+# Model initialization
+model = DiscriminantNN()
+criterion = nn.MSELoss()
+optimizer = optim.AdamW(model.parameters(), lr=0.005, weight_decay=1e-5)
+scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=100)
+
+print("Training started...")
+epoch = 0
+max_epochs = 300000
+
+while epoch < max_epochs:
+    #print(f"Epoch {epoch:04d} | Learning Rate: {optimizer.param_groups[0]['lr']:.6f}")
+    model.train()
+    optimizer.zero_grad()
+    predictions = model(X_train)
+    loss = criterion(predictions, y_train)
+    loss.backward()
+    optimizer.step()
+    
+    # Calculate absolute errors on the training set
+    with torch.no_grad():
+        abs_errors = torch.abs(predictions - y_train)
+        max_error = torch.max(abs_errors).item()
+        mean_error = torch.mean(abs_errors).item()
+        scheduler.step(loss)
+        
+    if epoch % 500 == 0 or max_error < 0.001:
+        print(f"Epoch {epoch:04d} | Loss: {loss.item():.2e} | Max Abs Error: {max_error:.5f} | Mean Abs Error: {mean_error:.5f}")
+        
+    # Stop explicitly once the entire domain satisfies the 0.001 precision threshold
+    if max_error < 0.001:
+        print(f"\nTarget precision of 0.001 achieved globally across training domain at epoch {epoch}!")
+        break
+        
+    epoch += 1
+
+# ==========================================
+# (2) Evaluate within the 0..1 range
+# ==========================================
+print("\n--- Evaluation Inside [0, 1]^3 Domain ---")
+model.eval()
+
+# Generate 10,000 completely random uniform points inside the unit cube
+X_inside_np = np.random.uniform(0.0, 1.0, (10000, 3))
+y_inside_exact = target_function(X_inside_np[:, 0], X_inside_np[:, 1], X_inside_np[:, 2]).reshape(-1, 1)
+
+X_inside = torch.tensor(X_inside_np, dtype=torch.float32)
+y_inside_exact = torch.tensor(y_inside_exact, dtype=torch.float32)
+
+with torch.no_grad():
+    y_inside_pred = model(X_inside)
+    errors_inside = torch.abs(y_inside_pred - y_inside_exact)
+    within_precision_inside = torch.sum(errors_inside <= 0.001).item()
+
+print(f"Total validation points evaluated: {len(X_inside_np)}")
+print(f"Points within 0.001 precision: {within_precision_inside} / 10,000 ({within_precision_inside/100:.2f}%)")
+
+# ==========================================
+# (3) Evaluate Outside the 0..1 Range
+# ==========================================
+print("\n--- Evaluation Outside [0, 1]^3 Domain (Extrapolation) ---")
+
+X_outside_list = []
+# Rejection sampling loop to get 10,000 points strictly within [-0.5, 1.5] but outside [0, 1]
+while len(X_outside_list) < 10000:
+    candidates = np.random.uniform(-0.5, 1.5, (20000, 3))
+    # A point is outside if any coordinate falls outside [0, 1]
+    is_outside = np.any((candidates < 0.0) | (candidates > 1.0), axis=1)
+    filtered = candidates[is_outside]
+    X_outside_list.extend(filtered)
+
+X_outside_np = np.array(X_outside_list[:10000])
+y_outside_exact = target_function(X_outside_np[:, 0], X_outside_np[:, 1], X_outside_np[:, 2]).reshape(-1, 1)
+
+X_outside = torch.tensor(X_outside_np, dtype=torch.float32)
+y_outside_exact = torch.tensor(y_outside_exact, dtype=torch.float32)
+
+with torch.no_grad():
+    y_outside_pred = model(X_outside)
+    errors_outside = torch.abs(y_outside_pred - y_outside_exact)
+    within_precision_outside = torch.sum(errors_outside <= 0.001).item()
+    failed_precision_outside = 10000 - within_precision_outside
+
+print(f"Total extrapolation points evaluated: {len(X_outside_np)}")
+print(f"Points within 0.001 precision: {within_precision_outside}")
+print(f"Points outside 0.001 precision: {failed_precision_outside}")
+
diff --git a/misc/py-pytorch/files/patch-CMakeLists.txt b/misc/py-pytorch/files/patch-CMakeLists.txt
index 28c06933b2eb..e85dec48b683 100644
--- a/misc/py-pytorch/files/patch-CMakeLists.txt
+++ b/misc/py-pytorch/files/patch-CMakeLists.txt
@@ -1,15 +1,15 @@
---- CMakeLists.txt.orig	2026-07-08 17:44:27 UTC
+--- CMakeLists.txt.orig	2026-09-02 17:43:46 UTC
 +++ CMakeLists.txt
-@@ -185,7 +185,7 @@ set(CPU_RISCV OFF)
+@@ -216,7 +216,7 @@ set(CPU_RISCV OFF)
  set(CPU_POWER OFF)
  set(CPU_RISCV OFF)
  
 -if(CMAKE_SYSTEM_PROCESSOR MATCHES "(AMD64|x86_64)")
 +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(amd64|x86_64)")
    set(CPU_INTEL ON)
- elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)")
-   set(CPU_AARCH64 ON)
-@@ -217,7 +217,7 @@ option(BUILD_CUSTOM_PROTOBUF
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
+   # Linux reports "aarch64", macOS "arm64", and native Windows on Arm "ARM64".
+@@ -250,7 +250,7 @@ option(BUILD_CUSTOM_PROTOBUF
  option(ATEN_NO_TEST "Do not build ATen test binaries" OFF)
  option(BUILD_BINARY "Build C++ binaries" OFF)
  option(BUILD_CUSTOM_PROTOBUF
@@ -18,7 +18,7 @@
  option(BUILD_PYTHON "Build Python binaries" ON)
  option(BUILD_LITE_INTERPRETER "Master flag to build Lite Interpreter" OFF)
  option(BUILD_SHARED_LIBS "Build libcaffe2.so" ON)
-@@ -283,7 +283,7 @@ option(USE_GLOG "Use GLOG" OFF)
+@@ -323,7 +323,7 @@ option(USE_GLOG "Use GLOG" OFF)
  option(USE_CUPTI_SO "Use CUPTI as a shared library" ON)
  option(USE_GFLAGS "Use GFLAGS" OFF)
  option(USE_GLOG "Use GLOG" OFF)
@@ -27,7 +27,7 @@
  option(USE_MAGMA "Use MAGMA" ON)
  option(USE_PYTORCH_METAL "Use Metal for PyTorch iOS build" OFF)
  option(USE_PYTORCH_METAL_EXPORT "Export Metal models on MacOSX desktop" OFF)
-@@ -498,15 +498,15 @@ option(USE_SYSTEM_CPUINFO "Use system-provided cpuinfo
+@@ -533,15 +533,15 @@ option(USE_SYSTEM_CPUINFO "Use system-provided cpuinfo
  # USE_SYSTEM_LIBS being "OFF".
  option(USE_SYSTEM_LIBS "Use all available system-provided libraries." OFF)
  option(USE_SYSTEM_CPUINFO "Use system-provided cpuinfo." OFF)
diff --git a/misc/py-pytorch/files/patch-pyproject.toml b/misc/py-pytorch/files/patch-pyproject.toml
index 8abe8b9877eb..8f1cc4f133e8 100644
--- a/misc/py-pytorch/files/patch-pyproject.toml
+++ b/misc/py-pytorch/files/patch-pyproject.toml
@@ -1,28 +1,18 @@
---- pyproject.toml.orig	2026-07-08 17:44:27 UTC
+--- pyproject.toml.orig	2026-09-02 17:43:46 UTC
 +++ pyproject.toml
-@@ -2,9 +2,7 @@ requires = [
- 
- [build-system]
- requires = [
--    "setuptools>=77.0.0,<82",  # 77.0 is the first release with PEP 639 license-files support
--    "cmake>=3.27",
--    "ninja",
-+    "setuptools",  # 77.0 is the first release with PEP 639 license-files support
-     "numpy",
-     "packaging>=24.2",  # required by setuptools>=77 to validate PEP 639 license expressions
-     "pyyaml",
-@@ -20,9 +18,7 @@ dev = [
-     # in PyTorch root until the project fully migrates to pyproject.toml
+@@ -312,10 +312,8 @@ dev = [
      # after which this can be removed as it is already specified in the
      # [build-system] section
+     "scikit-build-core>=1.0",
 -    "setuptools>=77.0.0,<82",  # 77.0 is the first release with PEP 639 license-files support
++    "setuptools",  # 77.0 is the first release with PEP 639 license-files support
+     "spin",
 -    "cmake>=3.27",
 -    "ninja",
-+    "setuptools",  # 77.0 is the first release with PEP 639 license-files support
      "numpy",
      "packaging>=24.2",  # required by setuptools>=77 to validate PEP 639 license expressions
      "pyyaml",
-@@ -55,14 +51,6 @@ requires-python = ">=3.10"
+@@ -349,13 +347,6 @@ requires-python = ">=3.10"
  # License info:
  #   - The main Pytorch project license is BSD-3-Clause.
  #   - The SPDX license expression below reflects installed pytorch packages.
@@ -32,7 +22,6 @@
 -    "third_party/**/LICENSE",
 -    "third_party/**/LICENSE.txt",
 -    "third_party/**/LICENSE.rst",
--    "third_party/**/COPYING.BSD",
 -]
  authors = [{ name = "PyTorch Team", email = "packages@pytorch.org" }]
  keywords = ["pytorch", "machine learning"]
diff --git a/misc/py-pytorch/files/patch-requirements-build.txt b/misc/py-pytorch/files/patch-requirements-build.txt
index 18fc1118b990..f6da96af1e8b 100644
--- a/misc/py-pytorch/files/patch-requirements-build.txt
+++ b/misc/py-pytorch/files/patch-requirements-build.txt
@@ -1,11 +1,14 @@
---- requirements-build.txt.orig	2026-07-08 17:44:27 UTC
+--- requirements-build.txt.orig	2026-09-02 17:43:46 UTC
 +++ requirements-build.txt
-@@ -1,7 +1,5 @@
- # Build System requirements
+@@ -2,10 +2,8 @@ scikit-build-core>=1.0
+ # 1.0 is required for [[tool.dynamic-metadata]] and the env table; see
+ # pyproject.toml for the rationale on this lower bound.
+ scikit-build-core>=1.0
 -setuptools>=77.0.0,<82  # 77.0 is the first release with PEP 639 license-files support
++setuptools # 77.0 is the first release with PEP 639 license-files support
+ spin
 -cmake>=3.27
 -ninja
-+setuptools  # 77.0 is the first release with PEP 639 license-files support
  numpy
  packaging>=24.2  # required by setuptools>=77 to validate PEP 639 license expressions
  pyyaml
diff --git a/misc/py-pytorch/files/patch-setup.py b/misc/py-pytorch/files/patch-setup.py
deleted file mode 100644
index 55d07b9aadf3..000000000000
--- a/misc/py-pytorch/files/patch-setup.py
+++ /dev/null
@@ -1,83 +0,0 @@
--- Avoid dependency on the setuptools.command.bdist_wheel module if wheel is not installed.
--- This ensures setup.py runs correctly during build when wheel is not present.
---- setup.py.orig	2026-07-08 17:44:27 UTC
-+++ setup.py
-@@ -282,7 +282,7 @@ from typing import Any, ClassVar, IO
- from pathlib import Path
- from typing import Any, ClassVar, IO
- 
--import setuptools.command.bdist_wheel
-+# import setuptools.command.bdist_wheel
- import setuptools.command.build_ext
- import setuptools.errors
- from setuptools import Command, Extension, find_packages, setup
-@@ -980,25 +980,30 @@ class build_ext(setuptools.command.build_ext.build_ext
-         return outputs
- 
- 
--class bdist_wheel(setuptools.command.bdist_wheel.bdist_wheel):
--    def write_wheelfile(self, *args: Any, **kwargs: Any) -> None:
--        super().write_wheelfile(*args, **kwargs)
-+try:
-+    from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
-+except ImportError:
-+    bdist_wheel = None
-+else:
-+    class bdist_wheel(_bdist_wheel):
-+        def write_wheelfile(self, *args: Any, **kwargs: Any) -> None:
-+            super().write_wheelfile(*args, **kwargs)
- 
--        if BUILD_LIBTORCH_WHL:
--            if self.bdist_dir is None:
--                raise AssertionError("self.bdist_dir must not be None")
--            bdist_dir = Path(self.bdist_dir)
--            # Remove extraneneous files in the libtorch wheel
--            for file in itertools.chain(
--                bdist_dir.rglob("*.a"),
--                bdist_dir.rglob("*.so"),
--            ):
--                if (bdist_dir / file.name).is_file():
-+            if BUILD_LIBTORCH_WHL:
-+                if self.bdist_dir is None:
-+                    raise AssertionError("self.bdist_dir must not be None")
-+                bdist_dir = Path(self.bdist_dir)
-+                # Remove extraneneous files in the libtorch wheel
-+                for file in itertools.chain(
-+                    bdist_dir.rglob("*.a"),
-+                    bdist_dir.rglob("*.so"),
-+                ):
-+                    if (bdist_dir / file.name).is_file():
-+                        file.unlink()
-+                for file in bdist_dir.rglob("*.py"):
-                     file.unlink()
--            for file in bdist_dir.rglob("*.py"):
--                file.unlink()
--            # need an __init__.py file otherwise we wouldn't have a package
--            (bdist_dir / "torch" / "__init__.py").touch()
-+                # need an __init__.py file otherwise we wouldn't have a package
-+                (bdist_dir / "torch" / "__init__.py").touch()
- 
- 
- class clean(Command):
-@@ -1082,10 +1087,11 @@ def configure_extension_build() -> tuple[
-     packages = find_packages(include=includes, exclude=excludes)
- 
-     cmdclass = {
--        "bdist_wheel": bdist_wheel,
-         "build_ext": build_ext,
-         "clean": clean,
-     }
-+    if bdist_wheel is not None:
-+        cmdclass["bdist_wheel"] = bdist_wheel
- 
-     entry_points = {
-         "console_scripts": [
-@@ -1137,7 +1143,7 @@ def main() -> None:
-     install_requires = [
-         "filelock",
-         "typing-extensions>=4.10.0",
--        "setuptools>=77.0.3",
-+        "setuptools",
-         "sympy>=1.13.3",
-         "networkx>=2.5.1",
-         "jinja2",
diff --git a/misc/py-pytorch/files/patch-test_dynamo_test__aot__autograd.py b/misc/py-pytorch/files/patch-test_dynamo_test__aot__autograd.py
index 3206709a1e5a..01b4fa9150e6 100644
--- a/misc/py-pytorch/files/patch-test_dynamo_test__aot__autograd.py
+++ b/misc/py-pytorch/files/patch-test_dynamo_test__aot__autograd.py
@@ -1,14 +1,14 @@
---- test/dynamo/test_aot_autograd.py.orig	2026-05-13 17:40:38 UTC
+--- test/dynamo/test_aot_autograd.py.orig	2026-09-02 17:43:46 UTC
 +++ test/dynamo/test_aot_autograd.py
-@@ -1,6 +1,7 @@ import re
- # Owner(s): ["module: dynamo"]
+@@ -2,6 +2,7 @@ import re
  import copy
+ import operator
  import re
 +import sys
  import unittest
  from textwrap import dedent
  from unittest.mock import patch
-@@ -1006,6 +1007,7 @@ SeqNr|OrigAten|SrcFn|FwdSrcFn
+@@ -1018,6 +1019,7 @@ SeqNr|OrigAten|SrcFn|FwdSrcFn
  
      # set donated_buffer=False due to create_graph=True
      @torch._functorch.config.patch("donated_buffer", False)
diff --git a/misc/py-pytorch/files/patch-test_dynamo_test__guard__serialization.py b/misc/py-pytorch/files/patch-test_dynamo_test__guard__serialization.py
index 009b5ad23daf..3070b6f46ecb 100644
--- a/misc/py-pytorch/files/patch-test_dynamo_test__guard__serialization.py
+++ b/misc/py-pytorch/files/patch-test_dynamo_test__guard__serialization.py
@@ -1,14 +1,14 @@
---- test/dynamo/test_guard_serialization.py.orig	2026-07-08 17:44:27 UTC
+--- test/dynamo/test_guard_serialization.py.orig	2026-09-02 17:43:46 UTC
 +++ test/dynamo/test_guard_serialization.py
-@@ -1526,6 +1526,7 @@ class TestGuardSerialization(TestGuardSerializationBas
+@@ -1582,6 +1582,7 @@ class TestGuardSerialization(TestGuardSerializationBas
+             True,
          )
  
-     @torch._dynamo.config.patch(nested_graph_breaks=False)
 +    @unittest.skipIf(sys.platform.startswith("freebsd"), "Gloo does not support FreeBSD")
      def test_ddp_module(self):
          import torch.distributed as dist
  
-@@ -1578,6 +1579,7 @@ class TestGuardSerialization(TestGuardSerializationBas
+@@ -1636,6 +1637,7 @@ class TestGuardSerialization(TestGuardSerializationBas
              True,
          )
  
@@ -16,7 +16,7 @@
      def test_unserializable_sharded_tensor(self):
          import torch.distributed as dist
  
-@@ -1693,6 +1695,7 @@ class TestGuardSerialization(TestGuardSerializationBas
+@@ -1751,6 +1753,7 @@ class TestGuardSerialization(TestGuardSerializationBas
          )
          self._test_check_fn(ref, loaded, {"inputs": Inputs(x, torch.Stream())}, True)
  
diff --git a/misc/py-pytorch/files/patch-test_dynamo_test__repros.py b/misc/py-pytorch/files/patch-test_dynamo_test__repros.py
index 5c27ec8fe60b..d78019bed4e6 100644
--- a/misc/py-pytorch/files/patch-test_dynamo_test__repros.py
+++ b/misc/py-pytorch/files/patch-test_dynamo_test__repros.py
@@ -1,6 +1,6 @@
---- test/dynamo/test_repros.py.orig	2026-07-08 17:44:27 UTC
+--- test/dynamo/test_repros.py.orig	2026-09-02 17:43:46 UTC
 +++ test/dynamo/test_repros.py
-@@ -6272,6 +6272,7 @@ def forward(self, s77 : torch.SymInt, s27 : torch.SymI
+@@ -6457,6 +6457,7 @@ def forward(self, L_x_ : torch.Tensor, s77 : torch.Sym
          graph_code = backend.graphs[0].print_readable(print_output=False)
          self.assertIn("torch._C._nn.linear", graph_code)
  
diff --git a/misc/py-pytorch/files/patch-third__party_fmt_include_fmt_format.h b/misc/py-pytorch/files/patch-third__party_fmt_include_fmt_format.h
deleted file mode 100644
index 28246dbb90da..000000000000
--- a/misc/py-pytorch/files/patch-third__party_fmt_include_fmt_format.h
+++ /dev/null
@@ -1,10 +0,0 @@
---- third_party/fmt/include/fmt/format.h.orig	2026-03-23 18:40:46 UTC
-+++ third_party/fmt/include/fmt/format.h
-@@ -52,6 +52,7 @@
- #  include <cmath>    // std::signbit
- #  include <cstddef>  // std::byte
- #  include <cstdint>  // uint32_t
-+#  include <cstdlib>  // malloc/free
- #  include <cstring>  // std::memcpy
- #  include <limits>   // std::numeric_limits
- #  include <new>      // std::bad_alloc
diff --git a/misc/py-pytorch/files/patch-tools_metadata_dependencies.py b/misc/py-pytorch/files/patch-tools_metadata_dependencies.py
new file mode 100644
index 000000000000..869602e003cd
--- /dev/null
+++ b/misc/py-pytorch/files/patch-tools_metadata_dependencies.py
@@ -0,0 +1,20 @@
+-- Relax the setuptools>=77.0.3 lower bound in the wheel's runtime dependency metadata.
+-- FreeBSD's devel/py-setuptools is currently 63.1.0, so the upstream bound would make
+-- the installed torch package declare a Requires-Dist that no port can satisfy.
+-- The bound only exists upstream for PEP 639 license-expression validation, which the
+-- port does not rely on (see files/patch-pyproject.toml, which drops the license-files key).
+-- This replaces the old files/patch-setup.py: as of 2.14.0 PyTorch builds via
+-- scikit-build-core and setup.py is a pip-forwarding shim, so the install_requires list
+-- it used to patch now lives here.
+-- see https://github.com/pytorch/pytorch/issues/152276 for the build-system migration
+--- tools/metadata/dependencies.py.orig	2026-09-02 17:44:01 UTC
++++ tools/metadata/dependencies.py
+@@ -27,7 +27,7 @@ BASE_DEPENDENCIES = [
+ BASE_DEPENDENCIES = [
+     "filelock",
+     "typing-extensions>=4.10.0",
+-    "setuptools>=77.0.3",
++    "setuptools",
+     "sympy>=1.13.3",
+     "networkx>=2.5.1",
+     "jinja2",
diff --git a/misc/py-pytorch/files/patch-torch___inductor_compile__worker_____main____.py b/misc/py-pytorch/files/patch-torch___inductor_compile__worker_____main____.py
index 115e1cf1fd23..2b692e94caa0 100644
--- a/misc/py-pytorch/files/patch-torch___inductor_compile__worker_____main____.py
+++ b/misc/py-pytorch/files/patch-torch___inductor_compile__worker_____main____.py
@@ -1,9 +1,9 @@
---- torch/_inductor/compile_worker/__main__.py.orig	2026-04-19 02:49:11 UTC
+--- torch/_inductor/compile_worker/__main__.py.orig	2026-09-02 17:44:01 UTC
 +++ torch/_inductor/compile_worker/__main__.py
-@@ -30,7 +30,7 @@ try:
-     import triton
+@@ -31,7 +31,7 @@ try:
  
-     assert triton is not None  # preload in parent
+     if triton is None:
+         raise AssertionError("triton failed to preload in parent")
 -except ImportError:
 +except (ImportError, AttributeError):
      pass