Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / tools / telemetry / catapult_base / refactor / annotated_symbol / import_statement.py
blobe598f5aa9a22b2ae3c5ddfe5a37c6adfcd4c46f1
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import itertools
6 import keyword
7 import symbol
8 import token
10 from catapult_base.refactor.annotated_symbol import base_symbol
11 from catapult_base.refactor import snippet
14 __all__ = [
15 'AsName',
16 'DottedName',
17 'Import',
18 'ImportFrom',
19 'ImportName',
23 class DottedName(base_symbol.AnnotatedSymbol):
24 @classmethod
25 def Annotate(cls, symbol_type, children):
26 if symbol_type != symbol.dotted_name:
27 return None
28 return cls(symbol_type, children)
30 @property
31 def value(self):
32 return ''.join(token_snippet.value for token_snippet in self._children)
34 @value.setter
35 def value(self, value):
36 value_parts = value.split('.')
37 for value_part in value_parts:
38 if keyword.iskeyword(value_part):
39 raise ValueError('%s is a reserved keyword.' % value_part)
41 # If we have too many children, cut the list down to size.
42 self._children = self._children[:len(value_parts)*2-1]
44 # Update child nodes.
45 for child, value_part in itertools.izip_longest(
46 self._children[::2], value_parts):
47 if child:
48 # Modify existing children. This helps preserve comments and spaces.
49 child.value = value_part
50 else:
51 # Add children as needed.
52 self._children.append(snippet.TokenSnippet.Create(token.DOT, '.'))
53 self._children.append(
54 snippet.TokenSnippet.Create(token.NAME, value_part))
57 class AsName(base_symbol.AnnotatedSymbol):
58 @classmethod
59 def Annotate(cls, symbol_type, children):
60 if (symbol_type != symbol.dotted_as_name and
61 symbol_type != symbol.import_as_name):
62 return None
63 return cls(symbol_type, children)
65 @property
66 def name(self):
67 return self.children[0].value
69 @name.setter
70 def name(self, value):
71 self.children[0].value = value
73 @property
74 def alias(self):
75 if len(self.children) < 3:
76 return None
77 return self.children[2].value
79 @alias.setter
80 def alias(self, value):
81 if keyword.iskeyword(value):
82 raise ValueError('%s is a reserved keyword.' % value)
84 if value:
85 if len(self.children) < 3:
86 # If we currently have no alias, add one.
87 self.children.append(
88 snippet.TokenSnippet.Create(token.NAME, 'as', (0, 1)))
89 self.children.append(
90 snippet.TokenSnippet.Create(token.NAME, value, (0, 1)))
91 else:
92 # We already have an alias. Just update the value.
93 self.children[2].value = value
94 else:
95 # Removing the alias. Strip the "as foo".
96 self.children = [self.children[0]]
99 class Import(base_symbol.AnnotatedSymbol):
100 """An import statement.
102 Example:
103 import a.b.c as d
104 from a.b import c as d
106 In these examples,
107 path == 'a.b.c'
108 alias == 'd'
109 root == 'a.b' (only for "from" imports)
110 module == 'c' (only for "from" imports)
111 name (read-only) == the name used by references to the module, which is the
112 alias if there is one, the full module path in "full" imports, and the
113 module name in "from" imports.
115 @property
116 def has_from(self):
117 """Returns True iff the import statment is of the form "from x import y"."""
118 raise NotImplementedError()
120 @property
121 def values(self):
122 raise NotImplementedError()
124 @property
125 def paths(self):
126 raise NotImplementedError()
128 @property
129 def aliases(self):
130 raise NotImplementedError()
132 @property
133 def path(self):
134 """The full dotted path of the module."""
135 raise NotImplementedError()
137 @path.setter
138 def path(self, value):
139 raise NotImplementedError()
141 @property
142 def alias(self):
143 """The alias, if the module is renamed with "as". None otherwise."""
144 raise NotImplementedError()
146 @alias.setter
147 def alias(self, value):
148 raise NotImplementedError()
150 @property
151 def name(self):
152 """The name used to reference this import's module."""
153 raise NotImplementedError()
156 class ImportName(Import):
157 @classmethod
158 def Annotate(cls, symbol_type, children):
159 if symbol_type != symbol.import_stmt:
160 return None
161 if children[0].type != symbol.import_name:
162 return None
163 assert len(children) == 1
164 return cls(symbol_type, children[0].children)
166 @property
167 def has_from(self):
168 return False
170 @property
171 def values(self):
172 dotted_as_names = self.children[1]
173 return tuple((dotted_as_name.name, dotted_as_name.alias)
174 for dotted_as_name in dotted_as_names.children[::2])
176 @property
177 def paths(self):
178 return tuple(path for path, _ in self.values)
180 @property
181 def aliases(self):
182 return tuple(alias for _, alias in self.values)
184 @property
185 def _dotted_as_name(self):
186 dotted_as_names = self.children[1]
187 if len(dotted_as_names.children) != 1:
188 raise NotImplementedError(
189 'This method only works if the statement has one import.')
190 return dotted_as_names.children[0]
192 @property
193 def path(self):
194 return self._dotted_as_name.name
196 @path.setter
197 def path(self, value): # pylint: disable=arguments-differ
198 self._dotted_as_name.name = value
200 @property
201 def alias(self):
202 return self._dotted_as_name.alias
204 @alias.setter
205 def alias(self, value): # pylint: disable=arguments-differ
206 self._dotted_as_name.alias = value
208 @property
209 def name(self):
210 if self.alias:
211 return self.alias
212 else:
213 return self.path
216 class ImportFrom(Import):
217 @classmethod
218 def Annotate(cls, symbol_type, children):
219 if symbol_type != symbol.import_stmt:
220 return None
221 if children[0].type != symbol.import_from:
222 return None
223 assert len(children) == 1
224 return cls(symbol_type, children[0].children)
226 @property
227 def has_from(self):
228 return True
230 @property
231 def values(self):
232 try:
233 import_as_names = self.FindChild(symbol.import_as_names)
234 except ValueError:
235 return (('*', None),)
237 return tuple((import_as_name.name, import_as_name.alias)
238 for import_as_name in import_as_names.children[::2])
240 @property
241 def paths(self):
242 module = self.module
243 return tuple('.'.join((module, name)) for name, _ in self.values)
245 @property
246 def aliases(self):
247 return tuple(alias for _, alias in self.values)
249 @property
250 def root(self):
251 return self.FindChild(symbol.dotted_name).value
253 @root.setter
254 def root(self, value):
255 self.FindChild(symbol.dotted_name).value = value
257 @property
258 def _import_as_name(self):
259 try:
260 import_as_names = self.FindChild(symbol.import_as_names)
261 except ValueError:
262 return None
264 if len(import_as_names.children) != 1:
265 raise NotImplementedError(
266 'This method only works if the statement has one import.')
268 return import_as_names.children[0]
270 @property
271 def module(self):
272 import_as_name = self._import_as_name
273 if import_as_name:
274 return import_as_name.name
275 else:
276 return '*'
278 @module.setter
279 def module(self, value):
280 if keyword.iskeyword(value):
281 raise ValueError('%s is a reserved keyword.' % value)
283 import_as_name = self._import_as_name
284 if value == '*':
285 # TODO: Implement this.
286 raise NotImplementedError()
287 else:
288 if import_as_name:
289 import_as_name.name = value
290 else:
291 # TODO: Implement this.
292 raise NotImplementedError()
294 @property
295 def path(self):
296 return '.'.join((self.root, self.module))
298 @path.setter
299 def path(self, value): # pylint: disable=arguments-differ
300 self.root, _, self.module = value.rpartition('.')
302 @property
303 def alias(self):
304 import_as_name = self._import_as_name
305 if import_as_name:
306 return import_as_name.alias
307 else:
308 return None
310 @alias.setter
311 def alias(self, value): # pylint: disable=arguments-differ
312 import_as_name = self._import_as_name
313 if not import_as_name:
314 raise NotImplementedError('Cannot change alias for "import *".')
315 import_as_name.alias = value
317 @property
318 def name(self):
319 if self.alias:
320 return self.alias
321 else:
322 return self.module