1--- setup/iso_codes.py.orig	2025-10-01 15:30:07 UTC
2+++ setup/iso_codes.py
3@@ -2,6 +2,7 @@ import fnmatch
4 # License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
5
6 import fnmatch
7+import glob
8 import optparse
9 import os
10 import shutil
11@@ -24,40 +25,60 @@ class ISOData(Command):
12     description = 'Get ISO codes name localization data'
13     top_level_filename = 'iso-codes-main'
14     _zip_data = None
15+    extracted = False
16
17     def add_options(self, parser):
18         with suppress(optparse.OptionConflictError):  # ignore if option already added
19             parser.add_option('--path-to-isocodes', help='Path to previously downloaded iso-codes-main.zip')
20+            parser.add_option('--isocodes-extracted', default=False, action='store_true',
21+                    help='Isocodes is a directory')
22
23     def run(self, opts):
24-        if self._zip_data is None and opts.path_to_isocodes:
25-            with open(opts.path_to_isocodes, 'rb') as f:
26-                self._zip_data = f.read()
27-            # get top level directory
28-            top = {item.split('/')[0] for item in zipfile.ZipFile(BytesIO(self.zip_data)).namelist()}
29-            assert len(top) == 1
30-            self.top_level_filename = top.pop()
31+        if opts.isocodes_extracted:
32+            self.top_level = opts.path_to_isocodes
33+            self.extracted = True
34+        else:
35+            if self._zip_data is None and opts.path_to_isocodes:
36+                with open(opts.path_to_isocodes, 'rb') as f:
37+                    self._zip_data = f.read()
38+                # get top level directory
39+                top = {item.split('/')[0] for item in zipfile.ZipFile(BytesIO(self.zip_data)).namelist()}
40+                assert len(top) == 1
41+                self.top_level_filename = top.pop()
42
43     @property
44     def zip_data(self):
45         return self._zip_data or iso_codes_data()
46
47     def db_data(self, name: str) -> bytes:
48-        with zipfile.ZipFile(BytesIO(self.zip_data)) as zf:
49-            with zf.open(f'{self.top_level_filename}/data/{name}') as f:
50+        if self.extracted:
51+            src = f'{self.top_level}/data/{name}'
52+            if not os.path.exists(src):
53+                raise Exception(src + ' does not exist')
54+            with open(src, 'rb') as f:
55                 return f.read()
56+        else:
57+            with zipfile.ZipFile(BytesIO(self.zip_data)) as zf:
58+                with zf.open(f'{self.top_level_filename}/data/{name}') as f:
59+                    return f.read()
60
61     def extract_po_files(self, name: str, output_dir: str) -> None:
62         name = name.split('.', 1)[0]
63-        pat = f'{self.top_level_filename}/{name}/*.po'
64-        with zipfile.ZipFile(BytesIO(self.zip_data)) as zf:
65-            for name in fnmatch.filter(zf.namelist(), pat):
66+        if self.extracted:
67+            pat = f'{self.top_level}/{name}/*.po'
68+            for name in glob.glob(pat):
69                 dest = os.path.join(output_dir, name.split('/')[-1])
70-                zi = zf.getinfo(name)
71-                with zf.open(zi) as src, open(dest, 'wb') as d:
72-                    shutil.copyfileobj(src, d)
73-                date_time = time.mktime(zi.date_time + (0, 0, -1))
74-                os.utime(dest, (date_time, date_time))
75+                shutil.copy2(name, dest)
76+        else:
77+            pat = f'{self.top_level_filename}/{name}/*.po'
78+            with zipfile.ZipFile(BytesIO(self.zip_data)) as zf:
79+                for name in fnmatch.filter(zf.namelist(), pat):
80+                    dest = os.path.join(output_dir, name.split('/')[-1])
81+                    zi = zf.getinfo(name)
82+                    with zf.open(zi) as src, open(dest, 'wb') as d:
83+                        shutil.copyfileobj(src, d)
84+                    date_time = time.mktime(zi.date_time + (0, 0, -1))
85+                    os.utime(dest, (date_time, date_time))
86
87
88 iso_data = ISOData()
89