:param code: The code from where we want to get the __future__ imports (note that it's possible that there's no such entry). :return tuple(str, str): The return is a tuple(future_import, code). If the future import is not available a return such as ('', cod
(code)
| 113 | |
| 114 | |
| 115 | def _separate_future_imports(code): |
| 116 | """ |
| 117 | :param code: |
| 118 | The code from where we want to get the __future__ imports (note that it's possible that |
| 119 | there's no such entry). |
| 120 | |
| 121 | :return tuple(str, str): |
| 122 | The return is a tuple(future_import, code). |
| 123 | |
| 124 | If the future import is not available a return such as ('', code) is given, otherwise, the |
| 125 | future import will end with a ';' (so that it can be put right before the pydevd attach |
| 126 | code). |
| 127 | """ |
| 128 | try: |
| 129 | node = ast.parse(code, "<string>", "exec") |
| 130 | visitor = _LastFutureImportFinder() |
| 131 | visitor.visit(node) |
| 132 | |
| 133 | if visitor.last_future_import_found is None: |
| 134 | return "", code |
| 135 | |
| 136 | node = visitor.last_future_import_found |
| 137 | offset = -1 |
| 138 | if hasattr(node, "end_lineno") and hasattr(node, "end_col_offset"): |
| 139 | # Python 3.8 onwards has these (so, use when possible). |
| 140 | line, col = node.end_lineno, node.end_col_offset |
| 141 | offset = _get_offset_from_line_col(code, line - 1, col) # ast lines are 1-based, make it 0-based. |
| 142 | |
| 143 | else: |
| 144 | # end line/col not available, let's just find the offset and then search |
| 145 | # for the alias from there. |
| 146 | line, col = node.lineno, node.col_offset |
| 147 | offset = _get_offset_from_line_col(code, line - 1, col) # ast lines are 1-based, make it 0-based. |
| 148 | if offset >= 0 and node.names: |
| 149 | from_future_import_name = node.names[-1].name |
| 150 | i = code.find(from_future_import_name, offset) |
| 151 | if i < 0: |
| 152 | offset = -1 |
| 153 | else: |
| 154 | offset = i + len(from_future_import_name) |
| 155 | |
| 156 | if offset >= 0: |
| 157 | for i in range(offset, len(code)): |
| 158 | if code[i] in (" ", "\t", ";", ")", "\n"): |
| 159 | offset += 1 |
| 160 | else: |
| 161 | break |
| 162 | |
| 163 | future_import = code[:offset] |
| 164 | code_remainder = code[offset:] |
| 165 | |
| 166 | # Now, put '\n' lines back into the code remainder (we had to search for |
| 167 | # `\n)`, but in case we just got the `\n`, it should be at the remainder, |
| 168 | # not at the future import. |
| 169 | while future_import.endswith("\n"): |
| 170 | future_import = future_import[:-1] |
| 171 | code_remainder = "\n" + code_remainder |
| 172 |
no test coverage detected