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 |