home · contact · privacy
Fix broken PageRange end_max handling.
authorPlom Heller <plom@plomlompom.com>
Sun, 1 Nov 2026 16:21:53 +0000 (17:21 +0100)
committerPlom Heller <plom@plomlompom.com>
Sun, 1 Nov 2026 16:21:53 +0000 (17:21 +0100)
src/bookmaker/misc.py

index bcd4c9c2c8e83aebcd1ab1751140995bcaa77621..fed10a9916209cfe5433240abd00ff006b8ae43e 100755 (executable)
@@ -48,20 +48,19 @@ _TOK_RANGE_END = 'end'
 class PageRange:
     'Section of multi-page document.'
     start = 0
-    end: int
+    end = -1
 
     def __init__(
             self,
-            code: Optional[str],
-            end_max: int = -1
+            code: Optional[str]
             ) -> None:
-        if code:
-            prefix = 'page range string'
-            if '-' not in code:
-                raise MsgFail(f'{prefix} lacks "-": {code}')
-            tokens = code.split('-')
+        self._code = code
+        if self._code:
+            if '-' not in self._code:
+                self._fail('lacks "-"')
+            tokens = self._code.split('-')
             if len(tokens) > 2:
-                raise MsgFail(f'{prefix} has too many "-": {code}')
+                self._fail(' has too many "-"')
             for i, token in enumerate(tokens):
                 if token == '':
                     continue
@@ -71,23 +70,33 @@ class PageRange:
                     continue
                 try:
                     int(token)
-                except ValueError as e:
-                    raise MsgFail(
-                        f'{prefix} carries value neither integer, nor '
-                        f'"{_TOK_RANGE_START}", nor "{_TOK_RANGE_END}": {code}'
-                        ) from e
+                except ValueError:
+                    self._fail('carries value neither integer, nor '
+                               f'"{_TOK_RANGE_START}", nor "{_TOK_RANGE_END}"')
                 if int(token) < 1:
-                    raise MsgFail(f'{prefix} carries page number <1: {code}')
-            str_start, str_end = code.split('-')
-            self.end = end_max
+                    self._fail('carries page number <1')
+            str_start, str_end = self._code.split('-')
             if str_end not in {'', _TOK_RANGE_END}:
                 self.end = int(str_end)
-                if self.end > end_max >= 0:
-                    raise MsgFail(
-                            f'{prefix} exceeds maximum {end_max}: {code}')
             if str_start not in {'', _TOK_RANGE_START}:
                 self.start = int(str_start) - 1
 
+    def _fail(
+            self,
+            msg: str
+            ) -> None:
+        raise MsgFail(f'page range string {msg}: {self._code}')
+
+    def to_max(
+            self,
+            end_max: int
+            ) -> None:
+        'Define outer limit for page end.'
+        if self.end > end_max:
+            self._fail(f'exceeds maximum {end_max}')
+        elif self.end < 0:
+            self.end = end_max
+
     def ranging(
             self
             ) -> range:
@@ -577,10 +586,10 @@ class Book:
                     to_close.close()
                 raise ArgFail('i',
                               f'cannot interpret {path} as PDF file') from e
-            for old_page_num in (
-                    args_page_range[i] if len(args_page_range) > i
-                    else PageRange(None, len(reader.pages))
-                                   ).ranging():
+            page_range = (args_page_range[i] if len(args_page_range) > i
+                          else PageRange(None))
+            page_range.to_max(len(reader.pages))
+            for old_page_num in page_range.ranging():
                 new_page_num += 1
                 page = (Page.new_blank() if old_page_num >= len(reader.pages)
                         else Page(reader.pages[old_page_num]))
@@ -606,7 +615,7 @@ class Book:
         if args_crops:
             for c_string in args_crops:
                 try:
-                    PageRange(split_crops_string(c_string)[0], len_ - 1)
+                    PageRange(split_crops_string(c_string)[0]).to_max(len_ - 1)
                 except MsgFail as e:
                     raise ArgFail('c', e.msg) from e
         if args_rotate_page:
@@ -684,7 +693,8 @@ class Book:
         if args_crops:
             for c_string in args_crops:
                 range_code, crops = split_crops_string(c_string)
-                page_range = PageRange(range_code, len(self))
+                page_range = PageRange(range_code)
+                page_range.to_max(len(self))
                 prefix = '-c, -t' if args_symmetry else '-c'
                 suffix = ((' (but alternating left and right crop '
                           'between even and odd pages)') if args_symmetry