Mercurial > babel > old > babel-test
annotate babel/util.py @ 508:dbb70d75718a stable-0.9.x
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
author | fschwarz |
---|---|
date | Fri, 04 Mar 2011 14:16:15 +0000 |
parents | b29ff192b610 |
children |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
3 # Copyright (C) 2007 Edgewall Software | |
4 # All rights reserved. | |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
8 # are also available at http://babel.edgewall.org/wiki/License. | |
9 # | |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
12 # history and logs, available at http://babel.edgewall.org/log/. | |
13 | |
14 """Various utility classes and functions.""" | |
15 | |
164
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
16 import codecs |
30 | 17 from datetime import timedelta, tzinfo |
1 | 18 import os |
19 import re | |
227 | 20 try: |
507
b29ff192b610
Python 2.3 compatibility: backporting r456 and r457 to 0.9 branch (see #233)
fschwarz
parents:
369
diff
changeset
|
21 set = set |
227 | 22 except NameError: |
23 from sets import Set as set | |
316 | 24 import textwrap |
95
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
25 import time |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
26 from itertools import izip, imap |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
27 missing = object() |
1 | 28 |
316 | 29 __all__ = ['distinct', 'pathmatch', 'relpath', 'wraptext', 'odict', 'UTC', |
30 'LOCALTZ'] | |
1 | 31 __docformat__ = 'restructuredtext en' |
32 | |
369 | 33 |
227 | 34 def distinct(iterable): |
35 """Yield all items in an iterable collection that are distinct. | |
36 | |
37 Unlike when using sets for a similar effect, the original ordering of the | |
38 items in the collection is preserved by this function. | |
39 | |
40 >>> print list(distinct([1, 2, 1, 3, 4, 4])) | |
41 [1, 2, 3, 4] | |
42 >>> print list(distinct('foobar')) | |
43 ['f', 'o', 'b', 'a', 'r'] | |
44 | |
45 :param iterable: the iterable collection providing the data | |
46 :return: the distinct items in the collection | |
47 :rtype: ``iterator`` | |
48 """ | |
49 seen = set() | |
50 for item in iter(iterable): | |
51 if item not in seen: | |
52 yield item | |
53 seen.add(item) | |
54 | |
164
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
55 # Regexp to match python magic encoding line |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
56 PYTHON_MAGIC_COMMENT_re = re.compile( |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
57 r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)', re.VERBOSE) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
58 def parse_encoding(fp): |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
59 """Deduce the encoding of a source file from magic comment. |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
60 |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
61 It does this in the same way as the `Python interpreter`__ |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
62 |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
63 .. __: http://docs.python.org/ref/encodings.html |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
64 |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
65 The ``fp`` argument should be a seekable file object. |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
66 |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
67 (From Jeff Dairiki) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
68 """ |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
69 pos = fp.tell() |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
70 fp.seek(0) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
71 try: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
72 line1 = fp.readline() |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
73 has_bom = line1.startswith(codecs.BOM_UTF8) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
74 if has_bom: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
75 line1 = line1[len(codecs.BOM_UTF8):] |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
76 |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
77 m = PYTHON_MAGIC_COMMENT_re.match(line1) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
78 if not m: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
79 try: |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
80 import parser |
164
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
81 parser.suite(line1) |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
82 except (ImportError, SyntaxError): |
164
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
83 # Either it's a real syntax error, in which case the source is |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
84 # not valid python source, or line2 is a continuation of line1, |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
85 # in which case we don't want to scan line2 for a magic |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
86 # comment. |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
87 pass |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
88 else: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
89 line2 = fp.readline() |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
90 m = PYTHON_MAGIC_COMMENT_re.match(line2) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
91 |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
92 if has_bom: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
93 if m: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
94 raise SyntaxError( |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
95 "python refuses to compile code with both a UTF8 " |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
96 "byte-order-mark and a magic encoding comment") |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
97 return 'utf_8' |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
98 elif m: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
99 return m.group(1) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
100 else: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
101 return None |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
102 finally: |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
103 fp.seek(pos) |
84a9e5f97658
made the python extractor detect source file encodings from the magic encoding
pjenvey
parents:
163
diff
changeset
|
104 |
44 | 105 def pathmatch(pattern, filename): |
106 """Extended pathname pattern matching. | |
1 | 107 |
44 | 108 This function is similar to what is provided by the ``fnmatch`` module in |
109 the Python standard library, but: | |
110 | |
111 * can match complete (relative or absolute) path names, and not just file | |
112 names, and | |
113 * also supports a convenience pattern ("**") to match files at any | |
114 directory level. | |
115 | |
116 Examples: | |
117 | |
118 >>> pathmatch('**.py', 'bar.py') | |
119 True | |
120 >>> pathmatch('**.py', 'foo/bar/baz.py') | |
121 True | |
122 >>> pathmatch('**.py', 'templates/index.html') | |
123 False | |
47
76381d4b3635
Support passing extraction method mapping and options from the frontends (see #4). No distutils/setuptools keyword supported yet, but the rest seems to be working okay.
cmlenz
parents:
44
diff
changeset
|
124 |
44 | 125 >>> pathmatch('**/templates/*.html', 'templates/index.html') |
126 True | |
127 >>> pathmatch('**/templates/*.html', 'templates/foo/bar.html') | |
128 False | |
1 | 129 |
130 :param pattern: the glob pattern | |
44 | 131 :param filename: the path name of the file to match against |
132 :return: `True` if the path name matches the pattern, `False` otherwise | |
133 :rtype: `bool` | |
1 | 134 """ |
135 symbols = { | |
136 '?': '[^/]', | |
137 '?/': '[^/]/', | |
138 '*': '[^/]+', | |
139 '*/': '[^/]+/', | |
140 '**/': '(?:.+/)*?', | |
44 | 141 '**': '(?:.+/)*?[^/]+', |
1 | 142 } |
143 buf = [] | |
144 for idx, part in enumerate(re.split('([?*]+/?)', pattern)): | |
145 if idx % 2: | |
146 buf.append(symbols[part]) | |
147 elif part: | |
148 buf.append(re.escape(part)) | |
134 | 149 match = re.match(''.join(buf) + '$', filename.replace(os.sep, '/')) |
150 return match is not None | |
1 | 151 |
29 | 152 |
316 | 153 class TextWrapper(textwrap.TextWrapper): |
154 wordsep_re = re.compile( | |
155 r'(\s+|' # any whitespace | |
156 r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))' # em-dash | |
157 ) | |
158 | |
159 | |
160 def wraptext(text, width=70, initial_indent='', subsequent_indent=''): | |
161 """Simple wrapper around the ``textwrap.wrap`` function in the standard | |
162 library. This version does not wrap lines on hyphens in words. | |
163 | |
164 :param text: the text to wrap | |
165 :param width: the maximum line width | |
166 :param initial_indent: string that will be prepended to the first line of | |
167 wrapped output | |
168 :param subsequent_indent: string that will be prepended to all lines save | |
169 the first of wrapped output | |
170 :return: a list of lines | |
171 :rtype: `list` | |
172 """ | |
173 wrapper = TextWrapper(width=width, initial_indent=initial_indent, | |
174 subsequent_indent=subsequent_indent, | |
175 break_long_words=False) | |
176 return wrapper.wrap(text) | |
177 | |
178 | |
56
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
179 class odict(dict): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
180 """Ordered dict implementation. |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
181 |
227 | 182 :see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747 |
56
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
183 """ |
62
84d400066b71
The order of extraction methods is now preserved (see #10).
cmlenz
parents:
60
diff
changeset
|
184 def __init__(self, data=None): |
84d400066b71
The order of extraction methods is now preserved (see #10).
cmlenz
parents:
60
diff
changeset
|
185 dict.__init__(self, data or {}) |
163
f2c78a271159
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
134
diff
changeset
|
186 self._keys = dict.keys(self) |
56
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
187 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
188 def __delitem__(self, key): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
189 dict.__delitem__(self, key) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
190 self._keys.remove(key) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
191 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
192 def __setitem__(self, key, item): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
193 dict.__setitem__(self, key, item) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
194 if key not in self._keys: |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
195 self._keys.append(key) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
196 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
197 def __iter__(self): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
198 return iter(self._keys) |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
199 iterkeys = __iter__ |
56
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
200 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
201 def clear(self): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
202 dict.clear(self) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
203 self._keys = [] |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
204 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
205 def copy(self): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
206 d = odict() |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
207 d.update(self) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
208 return d |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
209 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
210 def items(self): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
211 return zip(self._keys, self.values()) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
212 |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
213 def iteritems(self): |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
214 return izip(self._keys, self.itervalues()) |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
215 |
56
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
216 def keys(self): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
217 return self._keys[:] |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
218 |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
219 def pop(self, key, default=missing): |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
220 if default is missing: |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
221 return dict.pop(self, key) |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
222 elif key not in self: |
165
650a6e996ede
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
164
diff
changeset
|
223 return default |
650a6e996ede
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
164
diff
changeset
|
224 self._keys.remove(key) |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
225 return dict.pop(self, key, default) |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
226 |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
227 def popitem(self, key): |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
228 self._keys.remove(key) |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
229 return dict.popitem(key) |
165
650a6e996ede
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
164
diff
changeset
|
230 |
56
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
231 def setdefault(self, key, failobj = None): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
232 dict.setdefault(self, key, failobj) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
233 if key not in self._keys: |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
234 self._keys.append(key) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
235 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
236 def update(self, dict): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
237 for (key, val) in dict.items(): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
238 self[key] = val |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
239 |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
240 def values(self): |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
241 return map(self.get, self._keys) |
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
242 |
346
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
243 def itervalues(self): |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
244 return imap(self.get, self._keys) |
faf0ead3a132
Merged revisions [358:360], [364:370], [373:378], [380:382] from [source:trunk].
cmlenz
parents:
316
diff
changeset
|
245 |
56
27fba894d3ca
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
47
diff
changeset
|
246 |
1 | 247 try: |
248 relpath = os.path.relpath | |
249 except AttributeError: | |
250 def relpath(path, start='.'): | |
29 | 251 """Compute the relative path to one path from another. |
252 | |
130 | 253 >>> relpath('foo/bar.txt', '').replace(os.sep, '/') |
44 | 254 'foo/bar.txt' |
130 | 255 >>> relpath('foo/bar.txt', 'foo').replace(os.sep, '/') |
44 | 256 'bar.txt' |
130 | 257 >>> relpath('foo/bar.txt', 'baz').replace(os.sep, '/') |
44 | 258 '../foo/bar.txt' |
259 | |
29 | 260 :return: the relative path |
261 :rtype: `basestring` | |
262 """ | |
1 | 263 start_list = os.path.abspath(start).split(os.sep) |
264 path_list = os.path.abspath(path).split(os.sep) | |
265 | |
266 # Work out how much of the filepath is shared by start and path. | |
267 i = len(os.path.commonprefix([start_list, path_list])) | |
268 | |
269 rel_list = [os.path.pardir] * (len(start_list) - i) + path_list[i:] | |
270 return os.path.join(*rel_list) | |
29 | 271 |
508
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
272 try: |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
273 from operator import attrgetter, itemgetter |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
274 except ImportError: |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
275 def itemgetter(name): |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
276 def _getitem(obj): |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
277 return obj[name] |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
278 return _getitem |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
279 |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
280 try: |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
281 ''.rsplit |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
282 def rsplit(a_string, sep=None, maxsplit=None): |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
283 return a_string.rsplit(sep, maxsplit) |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
284 except AttributeError: |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
285 def rsplit(a_string, sep=None, maxsplit=None): |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
286 parts = a_string.split(sep) |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
287 if maxsplit is None or len(parts) <= maxsplit: |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
288 return parts |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
289 maxsplit_index = len(parts) - maxsplit |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
290 non_splitted_part = sep.join(parts[:maxsplit_index]) |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
291 splitted = parts[maxsplit_index:] |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
292 return [non_splitted_part] + splitted |
dbb70d75718a
Fix Python 2.3 compatibility for 0.9 branch (closes #233)
fschwarz
parents:
507
diff
changeset
|
293 |
106
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
294 ZERO = timedelta(0) |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
295 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
296 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
297 class FixedOffsetTimezone(tzinfo): |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
298 """Fixed offset in minutes east from UTC.""" |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
299 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
300 def __init__(self, offset, name=None): |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
301 self._offset = timedelta(minutes=offset) |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
302 if name is None: |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
303 name = 'Etc/GMT+%d' % offset |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
304 self.zone = name |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
305 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
306 def __str__(self): |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
307 return self.zone |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
308 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
309 def __repr__(self): |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
310 return '<FixedOffset "%s" %s>' % (self.zone, self._offset) |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
311 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
312 def utcoffset(self, dt): |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
313 return self._offset |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
314 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
315 def tzname(self, dt): |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
316 return self.zone |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
317 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
318 def dst(self, dt): |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
319 return ZERO |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
320 |
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
321 |
29 | 322 try: |
323 from pytz import UTC | |
324 except ImportError: | |
106
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
325 UTC = FixedOffsetTimezone(0, 'UTC') |
29 | 326 """`tzinfo` object for UTC (Universal Time). |
327 | |
328 :type: `tzinfo` | |
329 """ | |
95
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
330 |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
331 STDOFFSET = timedelta(seconds = -time.timezone) |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
332 if time.daylight: |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
333 DSTOFFSET = timedelta(seconds = -time.altzone) |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
334 else: |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
335 DSTOFFSET = STDOFFSET |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
336 |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
337 DSTDIFF = DSTOFFSET - STDOFFSET |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
338 |
106
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
339 |
95
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
340 class LocalTimezone(tzinfo): |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
341 |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
342 def utcoffset(self, dt): |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
343 if self._isdst(dt): |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
344 return DSTOFFSET |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
345 else: |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
346 return STDOFFSET |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
347 |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
348 def dst(self, dt): |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
349 if self._isdst(dt): |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
350 return DSTDIFF |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
351 else: |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
352 return ZERO |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
353 |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
354 def tzname(self, dt): |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
355 return time.tzname[self._isdst(dt)] |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
356 |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
357 def _isdst(self, dt): |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
358 tt = (dt.year, dt.month, dt.day, |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
359 dt.hour, dt.minute, dt.second, |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
360 dt.weekday(), 0, -1) |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
361 stamp = time.mktime(tt) |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
362 tt = time.localtime(stamp) |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
363 return tt.tm_isdst > 0 |
008cd3f7d485
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
62
diff
changeset
|
364 |
106
9b22b36066f6
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
97
diff
changeset
|
365 |
97 | 366 LOCALTZ = LocalTimezone() |
367 """`tzinfo` object for local time-zone. | |
368 | |
369 :type: `tzinfo` | |
370 """ |