| OLD | NEW |
| 1 # copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
| 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
| 3 # | 3 # |
| 4 # This file is part of astroid. | 4 # This file is part of astroid. |
| 5 # | 5 # |
| 6 # astroid is free software: you can redistribute it and/or modify it | 6 # astroid is free software: you can redistribute it and/or modify it |
| 7 # under the terms of the GNU Lesser General Public License as published by the | 7 # under the terms of the GNU Lesser General Public License as published by the |
| 8 # Free Software Foundation, either version 2.1 of the License, or (at your | 8 # Free Software Foundation, either version 2.1 of the License, or (at your |
| 9 # option) any later version. | 9 # option) any later version. |
| 10 # | 10 # |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 from _ast import PyCF_ONLY_AST | 37 from _ast import PyCF_ONLY_AST |
| 38 def parse(string): | 38 def parse(string): |
| 39 return compile(string, "<string>", 'exec', PyCF_ONLY_AST) | 39 return compile(string, "<string>", 'exec', PyCF_ONLY_AST) |
| 40 | 40 |
| 41 if sys.version_info >= (3, 0): | 41 if sys.version_info >= (3, 0): |
| 42 from tokenize import detect_encoding | 42 from tokenize import detect_encoding |
| 43 | 43 |
| 44 def open_source_file(filename): | 44 def open_source_file(filename): |
| 45 with open(filename, 'rb') as byte_stream: | 45 with open(filename, 'rb') as byte_stream: |
| 46 encoding = detect_encoding(byte_stream.readline)[0] | 46 encoding = detect_encoding(byte_stream.readline)[0] |
| 47 stream = open(filename, 'rU', encoding=encoding) | 47 stream = open(filename, 'r', newline=None, encoding=encoding) |
| 48 try: | 48 try: |
| 49 data = stream.read() | 49 data = stream.read() |
| 50 except UnicodeError: # wrong encodingg | 50 except UnicodeError: # wrong encodingg |
| 51 # detect_encoding returns utf-8 if no encoding specified | 51 # detect_encoding returns utf-8 if no encoding specified |
| 52 msg = 'Wrong (%s) or no encoding specified' % encoding | 52 msg = 'Wrong (%s) or no encoding specified' % encoding |
| 53 raise AstroidBuildingException(msg) | 53 raise AstroidBuildingException(msg) |
| 54 return stream, encoding, data | 54 return stream, encoding, data |
| 55 | 55 |
| 56 else: | 56 else: |
| 57 import re | 57 import re |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 # nodes | 108 # nodes |
| 109 node = self._manager.transform(node) | 109 node = self._manager.transform(node) |
| 110 return node | 110 return node |
| 111 | 111 |
| 112 def file_build(self, path, modname=None): | 112 def file_build(self, path, modname=None): |
| 113 """build astroid from a source code file (i.e. from an ast) | 113 """build astroid from a source code file (i.e. from an ast) |
| 114 | 114 |
| 115 path is expected to be a python source file | 115 path is expected to be a python source file |
| 116 """ | 116 """ |
| 117 try: | 117 try: |
| 118 _, encoding, data = open_source_file(path) | 118 stream, encoding, data = open_source_file(path) |
| 119 except IOError, exc: | 119 except IOError as exc: |
| 120 msg = 'Unable to load file %r (%s)' % (path, exc) | 120 msg = 'Unable to load file %r (%s)' % (path, exc) |
| 121 raise AstroidBuildingException(msg) | 121 raise AstroidBuildingException(msg) |
| 122 except SyntaxError, exc: # py3k encoding specification error | 122 except SyntaxError as exc: # py3k encoding specification error |
| 123 raise AstroidBuildingException(exc) | 123 raise AstroidBuildingException(exc) |
| 124 except LookupError, exc: # unknown encoding | 124 except LookupError as exc: # unknown encoding |
| 125 raise AstroidBuildingException(exc) | 125 raise AstroidBuildingException(exc) |
| 126 # get module name if necessary | 126 with stream: |
| 127 if modname is None: | 127 # get module name if necessary |
| 128 try: | 128 if modname is None: |
| 129 modname = '.'.join(modpath_from_file(path)) | 129 try: |
| 130 except ImportError: | 130 modname = '.'.join(modpath_from_file(path)) |
| 131 modname = splitext(basename(path))[0] | 131 except ImportError: |
| 132 # build astroid representation | 132 modname = splitext(basename(path))[0] |
| 133 module = self._data_build(data, modname, path) | 133 # build astroid representation |
| 134 return self._post_build(module, encoding) | 134 module = self._data_build(data, modname, path) |
| 135 return self._post_build(module, encoding) |
| 135 | 136 |
| 136 def string_build(self, data, modname='', path=None): | 137 def string_build(self, data, modname='', path=None): |
| 137 """build astroid from source code string and return rebuilded astroid""" | 138 """build astroid from source code string and return rebuilded astroid""" |
| 138 module = self._data_build(data, modname, path) | 139 module = self._data_build(data, modname, path) |
| 139 module.file_bytes = data.encode('utf-8') | 140 module.file_bytes = data.encode('utf-8') |
| 140 return self._post_build(module, 'utf-8') | 141 return self._post_build(module, 'utf-8') |
| 141 | 142 |
| 142 def _post_build(self, module, encoding): | 143 def _post_build(self, module, encoding): |
| 143 """handles encoding and delayed nodes | 144 """handles encoding and delayed nodes |
| 144 after a module has been built | 145 after a module has been built |
| 145 """ | 146 """ |
| 146 module.file_encoding = encoding | 147 module.file_encoding = encoding |
| 147 self._manager.cache_module(module) | 148 self._manager.cache_module(module) |
| 148 # post tree building steps after we stored the module in the cache: | 149 # post tree building steps after we stored the module in the cache: |
| 149 for from_node in module._from_nodes: | 150 for from_node in module._from_nodes: |
| 150 if from_node.modname == '__future__': | 151 if from_node.modname == '__future__': |
| 151 for symbol, _ in from_node.names: | 152 for symbol, _ in from_node.names: |
| 152 module.future_imports.add(symbol) | 153 module.future_imports.add(symbol) |
| 153 self.add_from_names_to_locals(from_node) | 154 self.add_from_names_to_locals(from_node) |
| 154 # handle delayed assattr nodes | 155 # handle delayed assattr nodes |
| 155 for delayed in module._delayed_assattr: | 156 for delayed in module._delayed_assattr: |
| 156 self.delayed_assattr(delayed) | 157 self.delayed_assattr(delayed) |
| 157 return module | 158 return module |
| 158 | 159 |
| 159 def _data_build(self, data, modname, path): | 160 def _data_build(self, data, modname, path): |
| 160 """build tree node from data and add some informations""" | 161 """build tree node from data and add some informations""" |
| 161 # this method could be wrapped with a pickle/cache function | 162 # this method could be wrapped with a pickle/cache function |
| 162 node = parse(data + '\n') | 163 try: |
| 164 node = parse(data + '\n') |
| 165 except TypeError as exc: |
| 166 raise AstroidBuildingException(exc) |
| 163 if path is not None: | 167 if path is not None: |
| 164 node_file = abspath(path) | 168 node_file = abspath(path) |
| 165 else: | 169 else: |
| 166 node_file = '<?>' | 170 node_file = '<?>' |
| 167 if modname.endswith('.__init__'): | 171 if modname.endswith('.__init__'): |
| 168 modname = modname[:-9] | 172 modname = modname[:-9] |
| 169 package = True | 173 package = True |
| 170 else: | 174 else: |
| 171 package = path and path.find('__init__.py') > -1 or False | 175 package = path and path.find('__init__.py') > -1 or False |
| 172 rebuilder = TreeRebuilder(self._manager) | 176 rebuilder = TreeRebuilder(self._manager) |
| 173 module = rebuilder.visit_module(node, modname, package) | 177 module = rebuilder.visit_module(node, modname, node_file, package) |
| 174 module.file = module.path = node_file | |
| 175 module._from_nodes = rebuilder._from_nodes | 178 module._from_nodes = rebuilder._from_nodes |
| 176 module._delayed_assattr = rebuilder._delayed_assattr | 179 module._delayed_assattr = rebuilder._delayed_assattr |
| 177 return module | 180 return module |
| 178 | 181 |
| 179 def add_from_names_to_locals(self, node): | 182 def add_from_names_to_locals(self, node): |
| 180 """store imported names to the locals; | 183 """store imported names to the locals; |
| 181 resort the locals if coming from a delayed node | 184 resort the locals if coming from a delayed node |
| 182 """ | 185 """ |
| 183 | 186 |
| 184 _key_func = lambda node: node.fromlineno | 187 _key_func = lambda node: node.fromlineno |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 continue | 231 continue |
| 229 # get assign in __init__ first XXX useful ? | 232 # get assign in __init__ first XXX useful ? |
| 230 if frame.name == '__init__' and values and not \ | 233 if frame.name == '__init__' and values and not \ |
| 231 values[0].frame().name == '__init__': | 234 values[0].frame().name == '__init__': |
| 232 values.insert(0, node) | 235 values.insert(0, node) |
| 233 else: | 236 else: |
| 234 values.append(node) | 237 values.append(node) |
| 235 except InferenceError: | 238 except InferenceError: |
| 236 pass | 239 pass |
| 237 | 240 |
| OLD | NEW |