comparison roundup/pygettext.py @ 8083:60e92a540ca7

chore: some ruff linter cleanups.
author John Rouillard <rouilj@ieee.org>
date Sun, 14 Jul 2024 12:42:07 -0400
parents a4127d7afaa9
children 586f76eb33e8
comparison
equal deleted inserted replaced
8082:a4127d7afaa9 8083:60e92a540ca7
21 import fintl 21 import fintl
22 _ = fintl.gettext 22 _ = fintl.gettext
23 except ImportError: 23 except ImportError:
24 _ = lambda s: s 24 _ = lambda s: s
25 25
26 import getopt
27 import glob
28 import importlib
29 import operator
30 import os
31 import sys
32 import time
33 import token
34 import tokenize
35 from functools import reduce
36
37 __version__ = '1.5'
38
26 __doc__ = _("""pygettext -- Python equivalent of xgettext(1) 39 __doc__ = _("""pygettext -- Python equivalent of xgettext(1)
27 40
28 Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the 41 Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
29 internationalization of C programs. Most of these tools are independent of 42 internationalization of C programs. Most of these tools are independent of
30 the programming language and can be used from within Python programs. 43 the programming language and can be used from within Python programs.
155 should not have their docstrings extracted. This is only useful in 168 should not have their docstrings extracted. This is only useful in
156 conjunction with the -D option above. 169 conjunction with the -D option above.
157 170
158 If `inputfile' is -, standard input is read. 171 If `inputfile' is -, standard input is read.
159 """) 172 """)
160
161 import os
162 import importlib
163 import sys
164 import glob
165 import time
166 import getopt
167 import token
168 import tokenize
169 import operator
170
171 from functools import reduce
172
173 __version__ = '1.5'
174 173
175 default_keywords = ['_'] 174 default_keywords = ['_']
176 DEFAULTKEYWORDS = ', '.join(default_keywords) 175 DEFAULTKEYWORDS = ', '.join(default_keywords)
177 176
178 EMPTYSTRING = '' 177 EMPTYSTRING = ''
197 "Content-Transfer-Encoding: ENCODING\\n" 196 "Content-Transfer-Encoding: ENCODING\\n"
198 "Generated-By: pygettext.py %(version)s\\n" 197 "Generated-By: pygettext.py %(version)s\\n"
199 198
200 ''') 199 ''')
201 200
201
202 def usage(code, msg=''): 202 def usage(code, msg=''):
203 print(__doc__ % globals(), file=sys.stderr) 203 print(__doc__ % globals(), file=sys.stderr)
204 if msg: 204 if msg:
205 print(msg, file=sys.stderr) 205 print(msg, file=sys.stderr)
206 sys.exit(code) 206 sys.exit(code)
207 207
208 208
209 escapes = [] 209 escapes = []
210
210 211
211 def make_escapes(pass_iso8859): 212 def make_escapes(pass_iso8859):
212 global escapes 213 global escapes
213 escapes = [chr(i) for i in range(256)] 214 escapes = [chr(i) for i in range(256)]
214 if pass_iso8859: 215 if pass_iso8859:
217 # escape any character outside the 32..126 range. 218 # escape any character outside the 32..126 range.
218 mod = 128 219 mod = 128
219 else: 220 else:
220 mod = 256 221 mod = 256
221 for i in range(mod): 222 for i in range(mod):
222 if not(32 <= i <= 126): 223 if not (32 <= i <= 126):
223 escapes[i] = "\\%03o" % i 224 escapes[i] = "\\%03o" % i
224 escapes[ord('\\')] = '\\\\' 225 escapes[ord('\\')] = '\\\\'
225 escapes[ord('\t')] = '\\t' 226 escapes[ord('\t')] = '\\t'
226 escapes[ord('\r')] = '\\r' 227 escapes[ord('\r')] = '\\r'
227 escapes[ord('\n')] = '\\n' 228 escapes[ord('\n')] = '\\n'
236 return EMPTYSTRING.join(s) 237 return EMPTYSTRING.join(s)
237 238
238 239
239 def safe_eval(s): 240 def safe_eval(s):
240 # unwrap quotes, safely 241 # unwrap quotes, safely
241 return eval(s, {'__builtins__':{}}, {}) 242 return eval(s, {'__builtins__': {}}, {})
242 243
243 244
244 def normalize(s): 245 def normalize(s):
245 # This converts the various Python string types into a format that is 246 # This converts the various Python string types into a format that is
246 # appropriate for .po files, namely much closer to C style. 247 # appropriate for .po files, namely much closer to C style.
255 lines[i] = escape(lines[i]) 256 lines[i] = escape(lines[i])
256 lineterm = '\\n"\n"' 257 lineterm = '\\n"\n"'
257 s = '""\n"' + lineterm.join(lines) + '"' 258 s = '""\n"' + lineterm.join(lines) + '"'
258 return s 259 return s
259 260
260 def containsAny(str, set): 261
262 def containsAny(string, inset):
261 """Check whether 'str' contains ANY of the chars in 'set'""" 263 """Check whether 'str' contains ANY of the chars in 'set'"""
262 return 1 in [c in str for c in set] 264 return 1 in [c in string for c in inset]
263 265
264 266
265 def _get_modpkg_path(dotted_name, pathlist=None): 267 def _get_modpkg_path(dotted_name, pathlist=None):
266 """Get the filesystem path for a module or a package. 268 """Get the filesystem path for a module or a package.
267 269
268 Return the file system path to a file for a module, and to a directory for 270 Return the file system path to a file for a module, and to a directory for
269 a package. Return None if the name is not found, or is a builtin or 271 a package. Return None if the name is not found, or is a builtin or
270 extension module. 272 extension module.
271 """ 273 """
272 pathname = None 274 pathname = None
273 r = importlib.util.find_spec(dotted_name, pathlist) 275 r = importlib.util.find_spec(dotted_name, pathlist)
274 276
275 if r.loader.is_package(dotted_name): 277 if r.loader.is_package(dotted_name):
276 pathname = r.submodule_search_locations[0] 278 pathname = r.submodule_search_locations[0]
277 elif issubclass(r.loader.__class__,(importlib.abc.SourceLoader)): 279 elif issubclass(r.loader.__class__, (importlib.abc.SourceLoader)):
278 pathname = r.origin 280 pathname = r.origin
279 return pathname 281 return pathname
280 282
281 283
282 def getFilesForName(name): 284 def getFilesForName(name):
285 """ 287 """
286 if not os.path.exists(name): 288 if not os.path.exists(name):
287 # check for glob chars 289 # check for glob chars
288 if containsAny(name, "*?[]"): 290 if containsAny(name, "*?[]"):
289 files = glob.glob(name) 291 files = glob.glob(name)
290 list = [] 292 lst = []
291 for file in files: 293 for file in files:
292 list.extend(getFilesForName(file)) 294 lst.extend(getFilesForName(file))
293 return list 295 return lst
294 296
295 # try to find module or package 297 # try to find module or package
296 name = _get_modpkg_path(name) 298 name = _get_modpkg_path(name)
297 if not name: 299 if not name:
298 return [] 300 return []
299 301
300 if os.path.isdir(name): 302 if os.path.isdir(name):
301 # find all python files in directory 303 # find all python files in directory
302 list = [] 304 lst = []
303 # get extension for python source files 305 # get extension for python source files
304 if '_py_ext' not in globals(): 306 if '_py_ext' not in globals():
305 global _py_ext 307 global _py_ext
306 _py_ext = importlib.machinery.SOURCE_SUFFIXES 308 _py_ext = importlib.machinery.SOURCE_SUFFIXES
307 for root, dirs, files in os.walk(name): 309 for root, dirs, files in os.walk(name):
308 # don't recurse into CVS directories 310 # don't recurse into CVS directories
309 if 'CVS' in dirs: 311 if 'CVS' in dirs:
310 dirs.remove('CVS') 312 dirs.remove('CVS')
311 # add all *.py files to list 313 # add all *.py files to list
312 list.extend( 314 lst.extend(
313 [os.path.join(root, file) for file in files 315 [os.path.join(root, file) for file in files
314 if os.path.splitext(file)[1] == _py_ext] 316 if os.path.splitext(file)[1] == _py_ext]
315 ) 317 )
316 return list 318 return lst
317 elif os.path.exists(name): 319 elif os.path.exists(name):
318 # a single file 320 # a single file
319 return [name] 321 return [name]
320 322
321 return [] 323 return []
324
322 325
323 class TokenEater: 326 class TokenEater:
324 def __init__(self, options): 327 def __init__(self, options):
325 self.__options = options 328 self.__options = options
326 self.__messages = {} 329 self.__messages = {}
396 print(_( 399 print(_(
397 '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"' 400 '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"'
398 ) % { 401 ) % {
399 'token': tstring, 402 'token': tstring,
400 'file': self.__curfile, 403 'file': self.__curfile,
401 'lineno': self.__lineno 404 'lineno': self.__lineno,
402 }, file=sys.stderr) 405 }, file=sys.stderr)
403 self.__state = self.__waiting 406 self.__state = self.__waiting
404 407
405 def __addentry(self, msg, lineno=None, isdocstring=0): 408 def __addentry(self, msg, lineno=None, isdocstring=0):
406 if lineno is None: 409 if lineno is None:
407 lineno = self.__lineno 410 lineno = self.__lineno
408 if not msg in self.__options.toexclude: 411 if msg not in self.__options.toexclude:
409 entry = (self.__curfile, lineno) 412 entry = (self.__curfile, lineno)
410 self.__messages.setdefault(msg, {})[entry] = isdocstring 413 self.__messages.setdefault(msg, {})[entry] = isdocstring
411 414
412 def set_filename(self, filename): 415 def set_filename(self, filename):
413 self.__curfile = filename 416 self.__curfile = filename
504 excludefilename = '' 507 excludefilename = ''
505 docstrings = 0 508 docstrings = 0
506 nodocstrings = {} 509 nodocstrings = {}
507 510
508 options = Options() 511 options = Options()
509 locations = {'gnu' : options.GNU, 512 locations = {'gnu': options.GNU,
510 'solaris' : options.SOLARIS, 513 'solaris': options.SOLARIS,
511 } 514 }
512 515
513 # parse options 516 # parse options
514 for opt, arg in opts: 517 for opt, arg in opts:
515 if opt in ('-h', '--help'): 518 if opt in ('-h', '--help'):
627 eater.write(fp) 630 eater.write(fp)
628 finally: 631 finally:
629 if closep: 632 if closep:
630 fp.close() 633 fp.close()
631 634
635
632 if __name__ == '__main__': 636 if __name__ == '__main__':
633 main() 637 main()
634 # some more test strings 638 # some more test strings
635 _(u'a unicode string') 639 _(u'a unicode string')
636 # this one creates a warning 640 # this one creates a warning

Roundup Issue Tracker: http://roundup-tracker.org/