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