Mercurial > p > roundup > code
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 |
