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