22
22
23
23
from babel import __version__ as VERSION
24
24
from babel import Locale , localedata
25
- from babel ._compat import StringIO , string_types
25
+ from babel ._compat import StringIO , string_types , text_type
26
26
from babel .core import UnknownLocaleError
27
27
from babel .messages .catalog import Catalog
28
28
from babel .messages .extract import DEFAULT_KEYWORDS , DEFAULT_MAPPING , check_and_call_extract_file , extract_from_dir
39
39
from configparser import RawConfigParser
40
40
41
41
42
+ def listify_value (arg , split = None ):
43
+ """
44
+ Make a list out of an argument.
45
+
46
+ Values from `distutils` argument parsing are always single strings;
47
+ values from `optparse` parsing may be lists of strings that may need
48
+ to be further split.
49
+
50
+ No matter the input, this function returns a flat list of whitespace-trimmed
51
+ strings, with `None` values filtered out.
52
+
53
+ >>> listify_value("foo bar")
54
+ ['foo', 'bar']
55
+ >>> listify_value(["foo bar"])
56
+ ['foo', 'bar']
57
+ >>> listify_value([["foo"], "bar"])
58
+ ['foo', 'bar']
59
+ >>> listify_value([["foo"], ["bar", None, "foo"]])
60
+ ['foo', 'bar', 'foo']
61
+ >>> listify_value("foo, bar, quux", ",")
62
+ ['foo', 'bar', 'quux']
63
+
64
+ :param arg: A string or a list of strings
65
+ :param split: The argument to pass to `str.split()`.
66
+ :return:
67
+ """
68
+ out = []
69
+
70
+ if not isinstance (arg , (list , tuple )):
71
+ arg = [arg ]
72
+
73
+ for val in arg :
74
+ if val is None :
75
+ continue
76
+ if isinstance (val , (list , tuple )):
77
+ out .extend (listify_value (val , split = split ))
78
+ continue
79
+ out .extend (s .strip () for s in text_type (val ).split (split ))
80
+ assert all (isinstance (val , string_types ) for val in out )
81
+ return out
82
+
83
+
42
84
class Command (_Command ):
43
85
# This class is a small shim between Distutils commands and
44
86
# optparse option parsing in the frontend command line.
@@ -47,8 +89,21 @@ class Command(_Command):
47
89
as_args = None
48
90
49
91
#: Options which allow multiple values.
92
+ #: This is used by the `optparse` transmogrification code.
50
93
multiple_value_options = ()
51
94
95
+ #: Options which are booleans.
96
+ #: This is used by the `optparse` transmogrification code.
97
+ # (This is actually used by distutils code too, but is never
98
+ # declared in the base class.)
99
+ boolean_options = ()
100
+
101
+ #: Option aliases, to retain standalone command compatibility.
102
+ #: Distutils does not support option aliases, but optparse does.
103
+ #: This maps the distutils argument name to an iterable of aliases
104
+ #: that are usable with optparse.
105
+ option_aliases = {}
106
+
52
107
#: Log object. To allow replacement in the script command line runner.
53
108
log = distutils_log
54
109
@@ -110,6 +165,7 @@ def initialize_options(self):
110
165
self .statistics = False
111
166
112
167
def finalize_options (self ):
168
+ self .domain = listify_value (self .domain )
113
169
if not self .input_file and not self .directory :
114
170
raise DistutilsOptionError ('you must specify either the input file '
115
171
'or the base directory' )
@@ -118,9 +174,7 @@ def finalize_options(self):
118
174
'or the base directory' )
119
175
120
176
def run (self ):
121
- domains = self .domain .split ()
122
-
123
- for domain in domains :
177
+ for domain in self .domain :
124
178
self ._run_domain (domain )
125
179
126
180
def _run_domain (self , domain ):
@@ -174,12 +228,12 @@ def _run_domain(self, domain):
174
228
if len (catalog ):
175
229
percentage = translated * 100 // len (catalog )
176
230
self .log .info (
177
- '%d of %d messages (%d%%) translated in %r ' ,
231
+ '%d of %d messages (%d%%) translated in %s ' ,
178
232
translated , len (catalog ), percentage , po_file
179
233
)
180
234
181
235
if catalog .fuzzy and not self .use_fuzzy :
182
- self .log .info ('catalog %r is marked as fuzzy, skipping' , po_file )
236
+ self .log .info ('catalog %s is marked as fuzzy, skipping' , po_file )
183
237
continue
184
238
185
239
for message , errors in catalog .check ():
@@ -188,7 +242,7 @@ def _run_domain(self, domain):
188
242
'error: %s:%d: %s' , po_file , message .lineno , error
189
243
)
190
244
191
- self .log .info ('compiling catalog %r to %r ' , po_file , mo_file )
245
+ self .log .info ('compiling catalog %s to %s ' , po_file , mo_file )
192
246
193
247
outfile = open (mo_file , 'wb' )
194
248
try :
@@ -249,7 +303,7 @@ class extract_messages(Command):
249
303
('add-comments=' , 'c' ,
250
304
'place comment block with TAG (or those preceding keyword lines) in '
251
305
'output file. Separate multiple TAGs with commas(,)' ), # TODO: Support repetition of this argument
252
- ('strip-comments' , None ,
306
+ ('strip-comments' , 's' ,
253
307
'strip the comment TAGs from the comments.' ),
254
308
('input-paths=' , None ,
255
309
'files or directories that should be scanned for messages. Separate multiple '
@@ -263,6 +317,12 @@ class extract_messages(Command):
263
317
]
264
318
as_args = 'input-paths'
265
319
multiple_value_options = ('add-comments' , 'keywords' )
320
+ option_aliases = {
321
+ 'keywords' : ('--keyword' ,),
322
+ 'mapping-file' : ('--mapping' ,),
323
+ 'output-file' : ('--output' ,),
324
+ 'strip-comments' : ('--strip-comment-tags' ,),
325
+ }
266
326
267
327
def initialize_options (self ):
268
328
self .charset = 'utf-8'
@@ -299,8 +359,7 @@ def finalize_options(self):
299
359
else :
300
360
keywords = DEFAULT_KEYWORDS .copy ()
301
361
302
- for kwarg in (self .keywords or ()):
303
- keywords .update (parse_keywords (kwarg .split ()))
362
+ keywords .update (parse_keywords (listify_value (self .keywords )))
304
363
305
364
self .keywords = keywords
306
365
@@ -325,11 +384,13 @@ def finalize_options(self):
325
384
if self .input_paths :
326
385
if isinstance (self .input_paths , string_types ):
327
386
self .input_paths = re .split (',\s*' , self .input_paths )
328
- else :
387
+ elif self . distribution is not None :
329
388
self .input_paths = dict .fromkeys ([
330
389
k .split ('.' , 1 )[0 ]
331
390
for k in (self .distribution .packages or ())
332
391
]).keys ()
392
+ else :
393
+ self .input_paths = []
333
394
334
395
if not self .input_paths :
335
396
raise DistutilsOptionError ("no input files or directories specified" )
@@ -338,11 +399,7 @@ def finalize_options(self):
338
399
if not os .path .exists (path ):
339
400
raise DistutilsOptionError ("Input path: %s does not exist" % path )
340
401
341
- if self .add_comments :
342
- if isinstance (self .add_comments , string_types ):
343
- self .add_comments = self .add_comments .split (',' )
344
- else :
345
- self .add_comments = []
402
+ self .add_comments = listify_value (self .add_comments or (), "," )
346
403
347
404
if self .distribution :
348
405
if not self .project :
@@ -531,7 +588,7 @@ def finalize_options(self):
531
588
532
589
def run (self ):
533
590
self .log .info (
534
- 'creating catalog %r based on %r ' , self .output_file , self .input_file
591
+ 'creating catalog %s based on %s ' , self .output_file , self .input_file
535
592
)
536
593
537
594
infile = open (self .input_file , 'rb' )
@@ -662,7 +719,7 @@ def run(self):
662
719
raise DistutilsOptionError ('no message catalogs found' )
663
720
664
721
for locale , filename in po_files :
665
- self .log .info ('updating catalog %r based on %r ' , filename , self .input_file )
722
+ self .log .info ('updating catalog %s based on %s ' , filename , self .input_file )
666
723
infile = open (filename , 'rb' )
667
724
try :
668
725
catalog = read_po (infile , locale = locale , domain = domain )
@@ -825,6 +882,7 @@ def _configure_command(self, cmdname, argv):
825
882
strs = ["--%s" % name ]
826
883
if short :
827
884
strs .append ("-%s" % short )
885
+ strs .extend (cmdclass .option_aliases .get (name , ()))
828
886
if name == as_args :
829
887
parser .usage += "<%s>" % name
830
888
elif name in cmdclass .boolean_options :
0 commit comments