Skip to content

Commit 6a1491a

Browse files
committed
Merge pull request #394 from akx/2.3.4
2.3.4
2 parents 3086b0c + 915236c commit 6a1491a

File tree

6 files changed

+179
-39
lines changed

6 files changed

+179
-39
lines changed

CHANGES

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
Babel Changelog
22
===============
33

4+
Version 2.3.4
5+
-------------
6+
7+
(Bugfix release, released on April 22th)
8+
9+
Bugfixes
10+
~~~~~~~~
11+
12+
* CLDR: The lxml library is no longer used for CLDR importing, so it should not cause strange failures either. Thanks to @aronbierbaum for the bug report and @jtwang for the fix. (https://github.com/python-babel/babel/pull/393)
13+
* CLI: Every last single CLI usage regression should now be gone, and both distutils and stand-alone CLIs should work as they have in the past. Thanks to @paxswill and @ajaeger for bug reports. (https://github.com/python-babel/babel/pull/389)
14+
415
Version 2.3.3
516
-------------
617

babel/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
negotiate_locale, parse_locale, get_locale_identifier
2222

2323

24-
__version__ = '2.3.3'
24+
__version__ = '2.3.4'

babel/messages/frontend.py

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from babel import __version__ as VERSION
2424
from babel import Locale, localedata
25-
from babel._compat import StringIO, string_types
25+
from babel._compat import StringIO, string_types, text_type
2626
from babel.core import UnknownLocaleError
2727
from babel.messages.catalog import Catalog
2828
from babel.messages.extract import DEFAULT_KEYWORDS, DEFAULT_MAPPING, check_and_call_extract_file, extract_from_dir
@@ -39,6 +39,48 @@
3939
from configparser import RawConfigParser
4040

4141

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+
4284
class Command(_Command):
4385
# This class is a small shim between Distutils commands and
4486
# optparse option parsing in the frontend command line.
@@ -47,8 +89,21 @@ class Command(_Command):
4789
as_args = None
4890

4991
#: Options which allow multiple values.
92+
#: This is used by the `optparse` transmogrification code.
5093
multiple_value_options = ()
5194

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+
52107
#: Log object. To allow replacement in the script command line runner.
53108
log = distutils_log
54109

@@ -110,6 +165,7 @@ def initialize_options(self):
110165
self.statistics = False
111166

112167
def finalize_options(self):
168+
self.domain = listify_value(self.domain)
113169
if not self.input_file and not self.directory:
114170
raise DistutilsOptionError('you must specify either the input file '
115171
'or the base directory')
@@ -118,9 +174,7 @@ def finalize_options(self):
118174
'or the base directory')
119175

120176
def run(self):
121-
domains = self.domain.split()
122-
123-
for domain in domains:
177+
for domain in self.domain:
124178
self._run_domain(domain)
125179

126180
def _run_domain(self, domain):
@@ -174,12 +228,12 @@ def _run_domain(self, domain):
174228
if len(catalog):
175229
percentage = translated * 100 // len(catalog)
176230
self.log.info(
177-
'%d of %d messages (%d%%) translated in %r',
231+
'%d of %d messages (%d%%) translated in %s',
178232
translated, len(catalog), percentage, po_file
179233
)
180234

181235
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)
183237
continue
184238

185239
for message, errors in catalog.check():
@@ -188,7 +242,7 @@ def _run_domain(self, domain):
188242
'error: %s:%d: %s', po_file, message.lineno, error
189243
)
190244

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)
192246

193247
outfile = open(mo_file, 'wb')
194248
try:
@@ -249,7 +303,7 @@ class extract_messages(Command):
249303
('add-comments=', 'c',
250304
'place comment block with TAG (or those preceding keyword lines) in '
251305
'output file. Separate multiple TAGs with commas(,)'), # TODO: Support repetition of this argument
252-
('strip-comments', None,
306+
('strip-comments', 's',
253307
'strip the comment TAGs from the comments.'),
254308
('input-paths=', None,
255309
'files or directories that should be scanned for messages. Separate multiple '
@@ -263,6 +317,12 @@ class extract_messages(Command):
263317
]
264318
as_args = 'input-paths'
265319
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+
}
266326

267327
def initialize_options(self):
268328
self.charset = 'utf-8'
@@ -299,8 +359,7 @@ def finalize_options(self):
299359
else:
300360
keywords = DEFAULT_KEYWORDS.copy()
301361

302-
for kwarg in (self.keywords or ()):
303-
keywords.update(parse_keywords(kwarg.split()))
362+
keywords.update(parse_keywords(listify_value(self.keywords)))
304363

305364
self.keywords = keywords
306365

@@ -325,11 +384,13 @@ def finalize_options(self):
325384
if self.input_paths:
326385
if isinstance(self.input_paths, string_types):
327386
self.input_paths = re.split(',\s*', self.input_paths)
328-
else:
387+
elif self.distribution is not None:
329388
self.input_paths = dict.fromkeys([
330389
k.split('.', 1)[0]
331390
for k in (self.distribution.packages or ())
332391
]).keys()
392+
else:
393+
self.input_paths = []
333394

334395
if not self.input_paths:
335396
raise DistutilsOptionError("no input files or directories specified")
@@ -338,11 +399,7 @@ def finalize_options(self):
338399
if not os.path.exists(path):
339400
raise DistutilsOptionError("Input path: %s does not exist" % path)
340401

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 (), ",")
346403

347404
if self.distribution:
348405
if not self.project:
@@ -531,7 +588,7 @@ def finalize_options(self):
531588

532589
def run(self):
533590
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
535592
)
536593

537594
infile = open(self.input_file, 'rb')
@@ -662,7 +719,7 @@ def run(self):
662719
raise DistutilsOptionError('no message catalogs found')
663720

664721
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)
666723
infile = open(filename, 'rb')
667724
try:
668725
catalog = read_po(infile, locale=locale, domain=domain)
@@ -825,6 +882,7 @@ def _configure_command(self, cmdname, argv):
825882
strs = ["--%s" % name]
826883
if short:
827884
strs.append("-%s" % short)
885+
strs.extend(cmdclass.option_aliases.get(name, ()))
828886
if name == as_args:
829887
parser.usage += "<%s>" % name
830888
elif name in cmdclass.boolean_options:

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
# The short X.Y version.
5454
version = '2.3'
5555
# The full version, including alpha/beta/rc tags.
56-
release = '2.3.3'
56+
release = '2.3.4'
5757

5858
# The language for content autogenerated by Sphinx. Refer to documentation
5959
# for a list of supported languages.

scripts/import_cldr.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,9 @@
1818
import sys
1919

2020
try:
21-
import lxml.etree as ElementTree
21+
from xml.etree import cElementTree as ElementTree
2222
except ImportError:
23-
try:
24-
from xml.etree import cElementTree as ElementTree
25-
except ImportError:
26-
from xml.etree import ElementTree
23+
from xml.etree import ElementTree
2724

2825
# Make sure we're using Babel source, and not some previously installed version
2926
CHECKOUT_ROOT = os.path.abspath(os.path.join(

0 commit comments

Comments
 (0)