Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:pysiogame
User: [email protected]
Usertags: pu

[ Reason ]
Fix grave #1132223 which crashes the game. According to the
related bug report #1023469 the game was last functional with
bullseye.

[ Impact ]
Cannot play the game at all.

[ Tests ]
Starting the game without the patches results in a crash.
Starting with the patches is okay.

[ Risks ]
None, trixie users are not able to play.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
Apply two patches suggested by a Debian user.
diff -Nru pysiogame-4.20.01/debian/changelog pysiogame-4.20.01/debian/changelog
--- pysiogame-4.20.01/debian/changelog  2025-03-17 00:20:55.000000000 +0100
+++ pysiogame-4.20.01/debian/changelog  2026-10-03 00:44:49.000000000 +0200
@@ -1,3 +1,15 @@
+pysiogame (4.20.01-3+deb13u1) trixie; urgency=medium
+
+  * Team Upload
+  * Add patch subsurface to clip subsurface rectangles to the display, so that
+    the game no longer dies with "ValueError: subsurface rectangle outside
+    surface area". Closes: #1132223
+  * Add patch game-boards-import to load the game modules with importlib
+    instead of exec/eval, so that starting a game no longer dies with
+    "NameError: name 'game_boards' is not defined". Closes: #1132223
+
+ -- Bastian Germann <[email protected]>  Sat, 03 Oct 2026 00:44:49 +0200
+
 pysiogame (4.20.01-3) unstable; urgency=medium
 
   * Team Upload
diff -Nru pysiogame-4.20.01/debian/patches/game-boards-import.patch 
pysiogame-4.20.01/debian/patches/game-boards-import.patch
--- pysiogame-4.20.01/debian/patches/game-boards-import.patch   1970-01-01 
01:00:00.000000000 +0100
+++ pysiogame-4.20.01/debian/patches/game-boards-import.patch   2026-10-03 
00:44:19.000000000 +0200
@@ -0,0 +1,36 @@
+Description: Import the game board modules with importlib instead of exec/eval
+ "exec("import game_boards.game000")" followed by
+ "eval("game_boards.game000.Board")" relies on exec() making the imported name
+ visible to the eval() that follows.  That is implementation defined in Python
+ 3 and results in "NameError: name 'game_boards' is not defined", so no game
+ could be started on Debian 13.
+ .
+ Use importlib.import_module() and getattr() instead, which is both explicit
+ and safe.
+Author: william <[email protected]>
+Origin: https://bugs.debian.org/1132223
+Bug-Debian: https://bugs.debian.org/1132223
+Last-Update: 2026-10-03
+---
+--- a/eduactiv8.py
++++ b/eduactiv8.py
+@@ -37,6 +37,7 @@
+     android = None
+ 
+ import gc
++import importlib
+ import os
+ import pygame
+ import sys
+@@ -472,8 +473,9 @@
+                                 del (self.game_board)  # delete all previous 
game objects
+                                 self.game_board = None
+ 
+-                            exec("import game_boards.%s" % 
m.game_constructor[0:7])
+-                            self.game_const = eval("game_boards.%s" % 
m.game_constructor)
++                            game_module_name, game_class_name = 
m.game_constructor.rsplit(".", 1)
++                            game_module = 
importlib.import_module("game_boards.%s" % game_module_name)
++                            self.game_const = getattr(game_module, 
game_class_name)
+                             self.game_board = self.game_const(self, 
self.speaker, self.config, self.size[0], self.size[1])
+                             m.game_started_id = m.active_game_id
+                             self.layout = self.game_board.layout
diff -Nru pysiogame-4.20.01/debian/patches/series 
pysiogame-4.20.01/debian/patches/series
--- pysiogame-4.20.01/debian/patches/series     2025-03-17 00:14:50.000000000 
+0100
+++ pysiogame-4.20.01/debian/patches/series     2026-10-03 00:44:19.000000000 
+0200
@@ -1,2 +1,4 @@
 warnings.patch
 python3.patch
+subsurface.patch
+game-boards-import.patch
diff -Nru pysiogame-4.20.01/debian/patches/subsurface.patch 
pysiogame-4.20.01/debian/patches/subsurface.patch
--- pysiogame-4.20.01/debian/patches/subsurface.patch   1970-01-01 
01:00:00.000000000 +0100
+++ pysiogame-4.20.01/debian/patches/subsurface.patch   2026-10-03 
00:44:19.000000000 +0200
@@ -0,0 +1,80 @@
+Description: Do not crash when the display is smaller than the calculated 
layout
+ pygame raises "ValueError: subsurface rectangle outside surface area" if the
+ requested rectangle is not fully contained in the display surface.  This
+ happens at startup and on every resize, because the display surface handed
+ out by SDL can be smaller than the resolution the layout was calculated from,
+ and because sizer.py hardcodes the size of the dialog window to 620x400.
+ .
+ Clip every subsurface rectangle to the boundaries of the display surface
+ instead, so that an undersized window only degrades the layout instead of
+ killing the game.  The bare "except: pass" around the game panel subsurface
+ goes away as well - keeping a stale subsurface of a display that no longer
+ exists is worse than a freshly copied one.
+Author: william <[email protected]>
+Origin: https://bugs.debian.org/1132223
+Bug-Debian: https://bugs.debian.org/1132223
+Last-Update: 2026-10-03
+---
+diff --git a/eduactiv8.py b/eduactiv8.py
+index 2359cc7..6413444 100755
+--- a/eduactiv8.py
++++ b/eduactiv8.py
+@@ -125,22 +125,39 @@ class GamePlay:
+         # mouse over [surface, group of objects, top most object]
+         self.mouse_over = [None, None, None]
+ 
++    def get_subsurface(self, rect):
++        """return a subsurface of the display, clipped to the display area
++
++        pygame refuses rectangles that stick out of the display surface, so a
++        window that ended up smaller than the resolution the layout was
++        calculated for used to abort the game with "subsurface rectangle
++        outside surface area". Trim the rectangle to what actually fits and
++        fall back to the whole display if nothing is left of it."""
++        if rect is None:
++            return self.screen.copy()
++        screen_w, screen_h = self.screen.get_size()
++        x, y, w, h = rect
++        x = max(x, 0)
++        y = max(y, 0)
++        w = min(w, screen_w - x)
++        h = min(h, screen_h - y)
++        if w <= 0 or h <= 0:
++            return self.screen.copy()
++        return self.screen.subsurface((x, y, w, h))
++
+     def create_subsurfaces(self):
+         # create subsurfaces & set some of the initial layout constraints
+ 
+-        self.game_bg = self.screen.subsurface(self.sizer.game_bg_pos)
+-        #self.game = self.screen.subsurface(self.game_board.layout.game_pos)  
# game panel - all action happens here
+-        self.info_bar = self.screen.subsurface(self.sizer.info_bar_pos)  # 
info panel - level control, game info, etc.
+-        self.score_bar = self.screen.subsurface(self.sizer.score_bar_pos)  # 
top panel - holding username, score etc.
+-        self.dialogbg = self.screen.subsurface(self.sizer.dialogbg_pos)
+-        self.dialogwnd = self.screen.subsurface(self.sizer.dialogwnd_pos)
++        self.game_bg = self.get_subsurface(self.sizer.game_bg_pos)
++        #self.game = self.get_subsurface(self.game_board.layout.game_pos)  # 
game panel - all action happens here
++        self.info_bar = self.get_subsurface(self.sizer.info_bar_pos)  # info 
panel - level control, game info, etc.
++        self.score_bar = self.get_subsurface(self.sizer.score_bar_pos)  # top 
panel - holding username, score etc.
++        self.dialogbg = self.get_subsurface(self.sizer.dialogbg_pos)
++        self.dialogwnd = self.get_subsurface(self.sizer.dialogwnd_pos)
+         self.sb.resize()
+ 
+     def recreate_game_screen(self):
+-        try:
+-            self.game = self.screen.subsurface(self.layout.game_pos)
+-        except:
+-            pass
++        self.game = self.get_subsurface(self.layout.game_pos)
+ 
+     def fs_rescale(self, info):
+         """rescale the game after fullscreen toggle, this will restart the 
board
+@@ -154,7 +171,7 @@ class GamePlay:
+         # adjust the layout to accommodate changes to number of squares 
automatically added due to screen ratio change
+         self.game_board.layout.update_layout(self.game_board.data[0], 
self.game_board.data[1])
+         self.create_subsurfaces()
+-        self.game = self.screen.subsurface(self.game_board.layout.game_pos)
++        self.game = self.get_subsurface(self.game_board.layout.game_pos)
+         info.new_game(self.game_board, self.info_bar)
+         #self.m.reset_scroll()
+ 

Reply via email to