Daankular commited on
Commit
cae2ac0
·
1 Parent(s): ae1c75a

Fix exec()+locals() for all 4 xinntao packages (basicsr/realesrgan/gfpgan/facexlib)

Browse files

All four share the identical broken Python 3.13 pattern. Extract a shared
_patch_exec_locals() helper and loop over all repos: clone, patch, install.
face-alignment (different author) still installed normally.

Files changed (1) hide show
  1. app.py +37 -37
app.py CHANGED
@@ -41,12 +41,14 @@ _NO_ISOLATION_PACKAGES = [
41
  "skel @ git+https://github.com/MarilynKeller/SKEL.git@c32cf16581295bff19399379efe5b776d707cd95",
42
  ]
43
 
44
- # Face enhancement packages that depend on basicsr
45
- _FACE_ENHANCE_PACKAGES = [
46
- "realesrgan",
47
- "gfpgan",
48
- "facexlib",
49
- "face-alignment",
 
 
50
  ]
51
 
52
  # 2. Packages with over-pinned deps that conflict with our stack; install --no-deps
@@ -64,6 +66,21 @@ _CUDA_PACKAGES = [
64
  "detectron2 @ git+https://github.com/facebookresearch/detectron2.git@8a9d885b3d4dcf1bef015f0593b872ed8d32b4ab",
65
  ]
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  def _install_runtime_packages():
68
  if _RUNTIME_PKG_MARKER.exists():
69
  return
@@ -85,43 +102,26 @@ def _install_runtime_packages():
85
  [sys.executable, "-m", "pip", "install", "--quiet", "--upgrade",
86
  "numpy>=2", "moderngl-window>=3.0.0"], check=True,
87
  )
88
- # basicsr Python 3.13 fix: setup.py get_version() uses exec(compile(...))+locals()
89
- # which is broken on Python 3.13 exec() no longer populates the caller's locals().
90
- # Fix: clone the repo, patch setup.py to use an explicit namespace dict, then install.
91
- _basicsr_src = Path("/tmp/basicsr-build")
92
- if not _basicsr_src.exists():
 
 
 
 
 
93
  subprocess.run(
94
- ["git", "clone", "--depth=1",
95
- "https://github.com/XPixelGroup/BasicSR.git", str(_basicsr_src)],
96
  check=True,
97
  )
98
- # Patch get_version() in setup.py for Python 3.13 compatibility.
99
- # Original code (inside `with open(...) as f:` block):
100
- # exec(compile(f.read(), version_file, 'exec'))
101
- # return locals()['__version__'] ← broken on 3.13
102
- # Fix: two independent single-line replacements so indentation is untouched
103
- # and _ns is defined on the same line as exec (still inside the with block,
104
- # so f is still open when f.read() is called).
105
- _basicsr_setup = _basicsr_src / "setup.py"
106
- _setup_src = _basicsr_setup.read_text(encoding="utf-8")
107
- _patched = _setup_src.replace(
108
- "exec(compile(f.read(), version_file, 'exec'))",
109
- "_ns = {}; exec(compile(f.read(), version_file, 'exec'), _ns)",
110
- ).replace(
111
- "return locals()['__version__']",
112
- "return _ns['__version__']",
113
- )
114
- _basicsr_setup.write_text(_patched, encoding="utf-8")
115
  subprocess.run(
116
- [sys.executable, "-m", "pip", "install", "--quiet", "--no-build-isolation",
117
- str(_basicsr_src)],
118
  check=True,
119
  )
120
- # Install face enhancement packages that depend on basicsr
121
- subprocess.run(
122
- [sys.executable, "-m", "pip", "install", "--quiet", "--no-build-isolation"]
123
- + _FACE_ENHANCE_PACKAGES, check=True,
124
- )
125
  subprocess.run(
126
  [sys.executable, "-m", "pip", "install", "--quiet", "--no-deps"]
127
  + _NO_DEPS_PACKAGES, check=True,
 
41
  "skel @ git+https://github.com/MarilynKeller/SKEL.git@c32cf16581295bff19399379efe5b776d707cd95",
42
  ]
43
 
44
+ # basicsr / realesrgan / gfpgan / facexlib all use the same xinntao setup.py
45
+ # pattern: exec(compile(f.read(), version_file, 'exec')) + return locals()['__version__']
46
+ # which is broken on Python 3.13. Clone each, patch, install from local.
47
+ _XINNTAO_REPOS = [
48
+ ("https://github.com/XPixelGroup/BasicSR.git", "basicsr-build"),
49
+ ("https://github.com/xinntao/Real-ESRGAN.git", "realesrgan-build"),
50
+ ("https://github.com/TencentARC/GFPGAN.git", "gfpgan-build"),
51
+ ("https://github.com/xinntao/facexlib.git", "facexlib-build"),
52
  ]
53
 
54
  # 2. Packages with over-pinned deps that conflict with our stack; install --no-deps
 
66
  "detectron2 @ git+https://github.com/facebookresearch/detectron2.git@8a9d885b3d4dcf1bef015f0593b872ed8d32b4ab",
67
  ]
68
 
69
+ def _patch_exec_locals(src_dir: Path):
70
+ """Patch the xinntao exec()+locals() setup.py pattern for Python 3.13.
71
+ exec() no longer populates the caller's locals() in 3.13; use explicit _ns dict."""
72
+ setup_py = src_dir / "setup.py"
73
+ src = setup_py.read_text(encoding="utf-8")
74
+ patched = src.replace(
75
+ "exec(compile(f.read(), version_file, 'exec'))",
76
+ "_ns = {}; exec(compile(f.read(), version_file, 'exec'), _ns)",
77
+ ).replace(
78
+ "return locals()['__version__']",
79
+ "return _ns['__version__']",
80
+ )
81
+ setup_py.write_text(patched, encoding="utf-8")
82
+
83
+
84
  def _install_runtime_packages():
85
  if _RUNTIME_PKG_MARKER.exists():
86
  return
 
102
  [sys.executable, "-m", "pip", "install", "--quiet", "--upgrade",
103
  "numpy>=2", "moderngl-window>=3.0.0"], check=True,
104
  )
105
+ # basicsr / realesrgan / gfpgan / facexlib all share the broken exec()+locals()
106
+ # setup.py pattern. Clone each, patch, install from local path.
107
+ for _repo_url, _build_name in _XINNTAO_REPOS:
108
+ _src = Path(f"/tmp/{_build_name}")
109
+ if not _src.exists():
110
+ subprocess.run(
111
+ ["git", "clone", "--depth=1", _repo_url, str(_src)],
112
+ check=True,
113
+ )
114
+ _patch_exec_locals(_src)
115
  subprocess.run(
116
+ [sys.executable, "-m", "pip", "install", "--quiet",
117
+ "--no-build-isolation", str(_src)],
118
  check=True,
119
  )
120
+ # face-alignment is from a different author and doesn't have the exec() issue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  subprocess.run(
122
+ [sys.executable, "-m", "pip", "install", "--quiet", "face-alignment"],
 
123
  check=True,
124
  )
 
 
 
 
 
125
  subprocess.run(
126
  [sys.executable, "-m", "pip", "install", "--quiet", "--no-deps"]
127
  + _NO_DEPS_PACKAGES, check=True,