Show More
@@ -0,0 +1,63 b'' | |||
|
1 | """Fixer that changes bytes % whatever to a function that actually formats | |
|
2 | it.""" | |
|
3 | ||
|
4 | from lib2to3 import fixer_base | |
|
5 | from lib2to3.fixer_util import is_tuple, Call, Comma, Name, touch_import | |
|
6 | ||
|
7 | # XXX: Implementing a blacklist in 2to3 turned out to be more troublesome than | |
|
8 | # blacklisting some modules inside the fixers. So, this is what I came with. | |
|
9 | ||
|
10 | blacklist = ['mercurial/demandimport.py', | |
|
11 | 'mercurial/py3kcompat.py', | |
|
12 | 'mercurial/i18n.py', | |
|
13 | ] | |
|
14 | ||
|
15 | def isnumberremainder(formatstr, data): | |
|
16 | try: | |
|
17 | if data.value.isdigit(): | |
|
18 | return True | |
|
19 | except AttributeError: | |
|
20 | return False | |
|
21 | ||
|
22 | class FixBytesmod(fixer_base.BaseFix): | |
|
23 | # XXX: There's one case (I suppose) I can't handle: when a remainder | |
|
24 | # operation like foo % bar is performed, I can't really know what the | |
|
25 | # contents of foo and bar are. I believe the best approach is to "correct" | |
|
26 | # the to-be-converted code and let bytesformatter handle that case in | |
|
27 | # runtime. | |
|
28 | PATTERN = ''' | |
|
29 | term< formatstr=STRING '%' data=STRING > | | |
|
30 | term< formatstr=STRING '%' data=atom > | | |
|
31 | term< formatstr=NAME '%' data=any > | | |
|
32 | term< formatstr=any '%' data=any > | |
|
33 | ''' | |
|
34 | ||
|
35 | def transform(self, node, results): | |
|
36 | if self.filename in blacklist: | |
|
37 | return | |
|
38 | elif self.filename == 'mercurial/util.py': | |
|
39 | touch_import('.', 'py3kcompat', node=node) | |
|
40 | ||
|
41 | formatstr = results['formatstr'].clone() | |
|
42 | data = results['data'].clone() | |
|
43 | formatstr.prefix = '' # remove spaces from start | |
|
44 | ||
|
45 | if isnumberremainder(formatstr, data): | |
|
46 | return | |
|
47 | ||
|
48 | # We have two possibilities: | |
|
49 | # 1- An identifier or name is passed, it is going to be a leaf, thus, we | |
|
50 | # just need to copy its value as an argument to the formatter; | |
|
51 | # 2- A tuple is explicitly passed. In this case, we're gonna explode it | |
|
52 | # to pass to the formatter | |
|
53 | # TODO: Check for normal strings. They don't need to be translated | |
|
54 | ||
|
55 | if is_tuple(data): | |
|
56 | args = [formatstr, Comma().clone()] + \ | |
|
57 | [c.clone() for c in data.children[:]] | |
|
58 | else: | |
|
59 | args = [formatstr, Comma().clone(), data] | |
|
60 | ||
|
61 | call = Call(Name('bytesformatter', prefix = ' '), args) | |
|
62 | return call | |
|
63 |
General Comments 0
You need to be logged in to leave comments.
Login now