]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | """Fixer for operator functions.\r |
2 | \r | |
3 | operator.isCallable(obj) -> hasattr(obj, '__call__')\r | |
4 | operator.sequenceIncludes(obj) -> operator.contains(obj)\r | |
5 | operator.isSequenceType(obj) -> isinstance(obj, collections.Sequence)\r | |
6 | operator.isMappingType(obj) -> isinstance(obj, collections.Mapping)\r | |
7 | operator.isNumberType(obj) -> isinstance(obj, numbers.Number)\r | |
8 | operator.repeat(obj, n) -> operator.mul(obj, n)\r | |
9 | operator.irepeat(obj, n) -> operator.imul(obj, n)\r | |
10 | """\r | |
11 | \r | |
12 | # Local imports\r | |
13 | from lib2to3 import fixer_base\r | |
14 | from lib2to3.fixer_util import Call, Name, String, touch_import\r | |
15 | \r | |
16 | \r | |
17 | def invocation(s):\r | |
18 | def dec(f):\r | |
19 | f.invocation = s\r | |
20 | return f\r | |
21 | return dec\r | |
22 | \r | |
23 | \r | |
24 | class FixOperator(fixer_base.BaseFix):\r | |
25 | BM_compatible = True\r | |
26 | order = "pre"\r | |
27 | \r | |
28 | methods = """\r | |
29 | method=('isCallable'|'sequenceIncludes'\r | |
30 | |'isSequenceType'|'isMappingType'|'isNumberType'\r | |
31 | |'repeat'|'irepeat')\r | |
32 | """\r | |
33 | obj = "'(' obj=any ')'"\r | |
34 | PATTERN = """\r | |
35 | power< module='operator'\r | |
36 | trailer< '.' %(methods)s > trailer< %(obj)s > >\r | |
37 | |\r | |
38 | power< %(methods)s trailer< %(obj)s > >\r | |
39 | """ % dict(methods=methods, obj=obj)\r | |
40 | \r | |
41 | def transform(self, node, results):\r | |
42 | method = self._check_method(node, results)\r | |
43 | if method is not None:\r | |
44 | return method(node, results)\r | |
45 | \r | |
46 | @invocation("operator.contains(%s)")\r | |
47 | def _sequenceIncludes(self, node, results):\r | |
48 | return self._handle_rename(node, results, u"contains")\r | |
49 | \r | |
50 | @invocation("hasattr(%s, '__call__')")\r | |
51 | def _isCallable(self, node, results):\r | |
52 | obj = results["obj"]\r | |
53 | args = [obj.clone(), String(u", "), String(u"'__call__'")]\r | |
54 | return Call(Name(u"hasattr"), args, prefix=node.prefix)\r | |
55 | \r | |
56 | @invocation("operator.mul(%s)")\r | |
57 | def _repeat(self, node, results):\r | |
58 | return self._handle_rename(node, results, u"mul")\r | |
59 | \r | |
60 | @invocation("operator.imul(%s)")\r | |
61 | def _irepeat(self, node, results):\r | |
62 | return self._handle_rename(node, results, u"imul")\r | |
63 | \r | |
64 | @invocation("isinstance(%s, collections.Sequence)")\r | |
65 | def _isSequenceType(self, node, results):\r | |
66 | return self._handle_type2abc(node, results, u"collections", u"Sequence")\r | |
67 | \r | |
68 | @invocation("isinstance(%s, collections.Mapping)")\r | |
69 | def _isMappingType(self, node, results):\r | |
70 | return self._handle_type2abc(node, results, u"collections", u"Mapping")\r | |
71 | \r | |
72 | @invocation("isinstance(%s, numbers.Number)")\r | |
73 | def _isNumberType(self, node, results):\r | |
74 | return self._handle_type2abc(node, results, u"numbers", u"Number")\r | |
75 | \r | |
76 | def _handle_rename(self, node, results, name):\r | |
77 | method = results["method"][0]\r | |
78 | method.value = name\r | |
79 | method.changed()\r | |
80 | \r | |
81 | def _handle_type2abc(self, node, results, module, abc):\r | |
82 | touch_import(None, module, node)\r | |
83 | obj = results["obj"]\r | |
84 | args = [obj.clone(), String(u", " + u".".join([module, abc]))]\r | |
85 | return Call(Name(u"isinstance"), args, prefix=node.prefix)\r | |
86 | \r | |
87 | def _check_method(self, node, results):\r | |
88 | method = getattr(self, "_" + results["method"][0].value.encode("ascii"))\r | |
89 | if callable(method):\r | |
90 | if "module" in results:\r | |
91 | return method\r | |
92 | else:\r | |
93 | sub = (unicode(results["obj"]),)\r | |
94 | invocation_str = unicode(method.invocation) % sub\r | |
95 | self.warning(node, u"You should use '%s' here." % invocation_str)\r | |
96 | return None\r |