| Index: tools/telemetry/catapult_base/refactor/annotated_symbol/import_statement.py
|
| diff --git a/tools/telemetry/catapult_base/refactor/annotated_symbol/import_statement.py b/tools/telemetry/catapult_base/refactor/annotated_symbol/import_statement.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e598f5aa9a22b2ae3c5ddfe5a37c6adfcd4c46f1
|
| --- /dev/null
|
| +++ b/tools/telemetry/catapult_base/refactor/annotated_symbol/import_statement.py
|
| @@ -0,0 +1,322 @@
|
| +# Copyright 2015 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import itertools
|
| +import keyword
|
| +import symbol
|
| +import token
|
| +
|
| +from catapult_base.refactor.annotated_symbol import base_symbol
|
| +from catapult_base.refactor import snippet
|
| +
|
| +
|
| +__all__ = [
|
| + 'AsName',
|
| + 'DottedName',
|
| + 'Import',
|
| + 'ImportFrom',
|
| + 'ImportName',
|
| +]
|
| +
|
| +
|
| +class DottedName(base_symbol.AnnotatedSymbol):
|
| + @classmethod
|
| + def Annotate(cls, symbol_type, children):
|
| + if symbol_type != symbol.dotted_name:
|
| + return None
|
| + return cls(symbol_type, children)
|
| +
|
| + @property
|
| + def value(self):
|
| + return ''.join(token_snippet.value for token_snippet in self._children)
|
| +
|
| + @value.setter
|
| + def value(self, value):
|
| + value_parts = value.split('.')
|
| + for value_part in value_parts:
|
| + if keyword.iskeyword(value_part):
|
| + raise ValueError('%s is a reserved keyword.' % value_part)
|
| +
|
| + # If we have too many children, cut the list down to size.
|
| + self._children = self._children[:len(value_parts)*2-1]
|
| +
|
| + # Update child nodes.
|
| + for child, value_part in itertools.izip_longest(
|
| + self._children[::2], value_parts):
|
| + if child:
|
| + # Modify existing children. This helps preserve comments and spaces.
|
| + child.value = value_part
|
| + else:
|
| + # Add children as needed.
|
| + self._children.append(snippet.TokenSnippet.Create(token.DOT, '.'))
|
| + self._children.append(
|
| + snippet.TokenSnippet.Create(token.NAME, value_part))
|
| +
|
| +
|
| +class AsName(base_symbol.AnnotatedSymbol):
|
| + @classmethod
|
| + def Annotate(cls, symbol_type, children):
|
| + if (symbol_type != symbol.dotted_as_name and
|
| + symbol_type != symbol.import_as_name):
|
| + return None
|
| + return cls(symbol_type, children)
|
| +
|
| + @property
|
| + def name(self):
|
| + return self.children[0].value
|
| +
|
| + @name.setter
|
| + def name(self, value):
|
| + self.children[0].value = value
|
| +
|
| + @property
|
| + def alias(self):
|
| + if len(self.children) < 3:
|
| + return None
|
| + return self.children[2].value
|
| +
|
| + @alias.setter
|
| + def alias(self, value):
|
| + if keyword.iskeyword(value):
|
| + raise ValueError('%s is a reserved keyword.' % value)
|
| +
|
| + if value:
|
| + if len(self.children) < 3:
|
| + # If we currently have no alias, add one.
|
| + self.children.append(
|
| + snippet.TokenSnippet.Create(token.NAME, 'as', (0, 1)))
|
| + self.children.append(
|
| + snippet.TokenSnippet.Create(token.NAME, value, (0, 1)))
|
| + else:
|
| + # We already have an alias. Just update the value.
|
| + self.children[2].value = value
|
| + else:
|
| + # Removing the alias. Strip the "as foo".
|
| + self.children = [self.children[0]]
|
| +
|
| +
|
| +class Import(base_symbol.AnnotatedSymbol):
|
| + """An import statement.
|
| +
|
| + Example:
|
| + import a.b.c as d
|
| + from a.b import c as d
|
| +
|
| + In these examples,
|
| + path == 'a.b.c'
|
| + alias == 'd'
|
| + root == 'a.b' (only for "from" imports)
|
| + module == 'c' (only for "from" imports)
|
| + name (read-only) == the name used by references to the module, which is the
|
| + alias if there is one, the full module path in "full" imports, and the
|
| + module name in "from" imports.
|
| + """
|
| + @property
|
| + def has_from(self):
|
| + """Returns True iff the import statment is of the form "from x import y"."""
|
| + raise NotImplementedError()
|
| +
|
| + @property
|
| + def values(self):
|
| + raise NotImplementedError()
|
| +
|
| + @property
|
| + def paths(self):
|
| + raise NotImplementedError()
|
| +
|
| + @property
|
| + def aliases(self):
|
| + raise NotImplementedError()
|
| +
|
| + @property
|
| + def path(self):
|
| + """The full dotted path of the module."""
|
| + raise NotImplementedError()
|
| +
|
| + @path.setter
|
| + def path(self, value):
|
| + raise NotImplementedError()
|
| +
|
| + @property
|
| + def alias(self):
|
| + """The alias, if the module is renamed with "as". None otherwise."""
|
| + raise NotImplementedError()
|
| +
|
| + @alias.setter
|
| + def alias(self, value):
|
| + raise NotImplementedError()
|
| +
|
| + @property
|
| + def name(self):
|
| + """The name used to reference this import's module."""
|
| + raise NotImplementedError()
|
| +
|
| +
|
| +class ImportName(Import):
|
| + @classmethod
|
| + def Annotate(cls, symbol_type, children):
|
| + if symbol_type != symbol.import_stmt:
|
| + return None
|
| + if children[0].type != symbol.import_name:
|
| + return None
|
| + assert len(children) == 1
|
| + return cls(symbol_type, children[0].children)
|
| +
|
| + @property
|
| + def has_from(self):
|
| + return False
|
| +
|
| + @property
|
| + def values(self):
|
| + dotted_as_names = self.children[1]
|
| + return tuple((dotted_as_name.name, dotted_as_name.alias)
|
| + for dotted_as_name in dotted_as_names.children[::2])
|
| +
|
| + @property
|
| + def paths(self):
|
| + return tuple(path for path, _ in self.values)
|
| +
|
| + @property
|
| + def aliases(self):
|
| + return tuple(alias for _, alias in self.values)
|
| +
|
| + @property
|
| + def _dotted_as_name(self):
|
| + dotted_as_names = self.children[1]
|
| + if len(dotted_as_names.children) != 1:
|
| + raise NotImplementedError(
|
| + 'This method only works if the statement has one import.')
|
| + return dotted_as_names.children[0]
|
| +
|
| + @property
|
| + def path(self):
|
| + return self._dotted_as_name.name
|
| +
|
| + @path.setter
|
| + def path(self, value): # pylint: disable=arguments-differ
|
| + self._dotted_as_name.name = value
|
| +
|
| + @property
|
| + def alias(self):
|
| + return self._dotted_as_name.alias
|
| +
|
| + @alias.setter
|
| + def alias(self, value): # pylint: disable=arguments-differ
|
| + self._dotted_as_name.alias = value
|
| +
|
| + @property
|
| + def name(self):
|
| + if self.alias:
|
| + return self.alias
|
| + else:
|
| + return self.path
|
| +
|
| +
|
| +class ImportFrom(Import):
|
| + @classmethod
|
| + def Annotate(cls, symbol_type, children):
|
| + if symbol_type != symbol.import_stmt:
|
| + return None
|
| + if children[0].type != symbol.import_from:
|
| + return None
|
| + assert len(children) == 1
|
| + return cls(symbol_type, children[0].children)
|
| +
|
| + @property
|
| + def has_from(self):
|
| + return True
|
| +
|
| + @property
|
| + def values(self):
|
| + try:
|
| + import_as_names = self.FindChild(symbol.import_as_names)
|
| + except ValueError:
|
| + return (('*', None),)
|
| +
|
| + return tuple((import_as_name.name, import_as_name.alias)
|
| + for import_as_name in import_as_names.children[::2])
|
| +
|
| + @property
|
| + def paths(self):
|
| + module = self.module
|
| + return tuple('.'.join((module, name)) for name, _ in self.values)
|
| +
|
| + @property
|
| + def aliases(self):
|
| + return tuple(alias for _, alias in self.values)
|
| +
|
| + @property
|
| + def root(self):
|
| + return self.FindChild(symbol.dotted_name).value
|
| +
|
| + @root.setter
|
| + def root(self, value):
|
| + self.FindChild(symbol.dotted_name).value = value
|
| +
|
| + @property
|
| + def _import_as_name(self):
|
| + try:
|
| + import_as_names = self.FindChild(symbol.import_as_names)
|
| + except ValueError:
|
| + return None
|
| +
|
| + if len(import_as_names.children) != 1:
|
| + raise NotImplementedError(
|
| + 'This method only works if the statement has one import.')
|
| +
|
| + return import_as_names.children[0]
|
| +
|
| + @property
|
| + def module(self):
|
| + import_as_name = self._import_as_name
|
| + if import_as_name:
|
| + return import_as_name.name
|
| + else:
|
| + return '*'
|
| +
|
| + @module.setter
|
| + def module(self, value):
|
| + if keyword.iskeyword(value):
|
| + raise ValueError('%s is a reserved keyword.' % value)
|
| +
|
| + import_as_name = self._import_as_name
|
| + if value == '*':
|
| + # TODO: Implement this.
|
| + raise NotImplementedError()
|
| + else:
|
| + if import_as_name:
|
| + import_as_name.name = value
|
| + else:
|
| + # TODO: Implement this.
|
| + raise NotImplementedError()
|
| +
|
| + @property
|
| + def path(self):
|
| + return '.'.join((self.root, self.module))
|
| +
|
| + @path.setter
|
| + def path(self, value): # pylint: disable=arguments-differ
|
| + self.root, _, self.module = value.rpartition('.')
|
| +
|
| + @property
|
| + def alias(self):
|
| + import_as_name = self._import_as_name
|
| + if import_as_name:
|
| + return import_as_name.alias
|
| + else:
|
| + return None
|
| +
|
| + @alias.setter
|
| + def alias(self, value): # pylint: disable=arguments-differ
|
| + import_as_name = self._import_as_name
|
| + if not import_as_name:
|
| + raise NotImplementedError('Cannot change alias for "import *".')
|
| + import_as_name.alias = value
|
| +
|
| + @property
|
| + def name(self):
|
| + if self.alias:
|
| + return self.alias
|
| + else:
|
| + return self.module
|
|
|