pyflyby 1.9.8__tar.gz → 1.9.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyflyby might be problematic. Click here for more details.
- {pyflyby-1.9.8/lib/python/pyflyby.egg-info → pyflyby-1.9.9}/PKG-INFO +1 -1
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_autoimp.py +56 -24
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_dbg.py +8 -0
- {pyflyby-1.9.8/lib/python → pyflyby-1.9.9/bin}/pyflyby/_dynimp.py +3 -2
- {pyflyby-1.9.8/lib/python → pyflyby-1.9.9/bin}/pyflyby/_importdb.py +3 -1
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_imports2s.py +10 -9
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_interactive.py +7 -196
- {pyflyby-1.9.8/lib/python → pyflyby-1.9.9/bin}/pyflyby/_parse.py +0 -76
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_saveframe.py +1 -1
- {pyflyby-1.9.8/lib/python → pyflyby-1.9.9/bin}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/saveframe +2 -2
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_autoimp.py +56 -24
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_dbg.py +8 -0
- {pyflyby-1.9.8/bin → pyflyby-1.9.9/lib/python}/pyflyby/_dynimp.py +3 -2
- {pyflyby-1.9.8/bin → pyflyby-1.9.9/lib/python}/pyflyby/_importdb.py +3 -1
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_imports2s.py +10 -9
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_interactive.py +7 -196
- {pyflyby-1.9.8/bin → pyflyby-1.9.9/lib/python}/pyflyby/_parse.py +0 -76
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_saveframe.py +1 -1
- {pyflyby-1.9.8/bin → pyflyby-1.9.9/lib/python}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.8 → pyflyby-1.9.9/lib/python/pyflyby.egg-info}/PKG-INFO +1 -1
- {pyflyby-1.9.8 → pyflyby-1.9.9}/.pyflyby +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/LICENSE.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/MANIFEST.in +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/README.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/autoipython +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/autopython +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/collect-exports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/collect-imports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/create-imports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/find-import +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/list-bad-xrefs +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/prune-broken-imports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_cmdline.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_file.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_format.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_import_sorting.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_importclns.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_log.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_modules.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_py.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/_util.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/pyflyby-diff +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/reformat-imports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/replace-star-imports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/tidy-imports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/bin/transform-imports +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/LICENSE.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/Makefile +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/TODO.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/__init__.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/api.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/autoimp.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/cmdline.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/comms.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/dbg.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/file.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/flags.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/format.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/idents.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/importclns.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/importdb.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/imports2s.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/importstmt.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/interactive.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/livepatch.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/log.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/modules.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/parse.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/py.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/api/util.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/autoipython.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/cli.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/collect_exports.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/collect_imports.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/find_import.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/prune_broken_imports.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/py.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/pyflyby_diff.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/reformat_imports.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/replace_star_imports.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/tidy_imports.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/cli/transform_imports.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/conf.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/index.rst +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/make.bat +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/doc/testing.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/etc/pyflyby/common.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/etc/pyflyby/std.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/emacs/pyflyby.el +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_cmdline.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_file.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_format.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_import_sorting.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_importclns.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_log.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_modules.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_py.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/_util.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby.egg-info/SOURCES.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby.egg-info/dependency_links.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby.egg-info/entry_points.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby.egg-info/requires.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/lib/python/pyflyby.egg-info/top_level.txt +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/pyproject.toml +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/setup.cfg +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/setup.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/__init__.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_0testconfig.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_autoimp.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_cmdline.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_docxref.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_file.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_flags.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_format.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_idents.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_importclns.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_importdb.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_imports2s.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_importstmt.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_interactive.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_jupyterlab_pyflyby.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_livepatch.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_modules.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_parse.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_py.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_saveframe.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/test_util.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/tests_sorts.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tests/xrefs.py +0 -0
- {pyflyby-1.9.8 → pyflyby-1.9.9}/tox.ini +0 -0
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations, print_function
|
|
8
|
+
|
|
7
9
|
import ast
|
|
8
10
|
import builtins
|
|
9
11
|
from collections.abc import Sequence
|
|
@@ -18,13 +20,14 @@ from pyflyby._importdb import ImportDB
|
|
|
18
20
|
from pyflyby._importstmt import Import
|
|
19
21
|
from pyflyby._log import logger
|
|
20
22
|
from pyflyby._modules import ModuleHandle
|
|
21
|
-
from pyflyby._parse import (PythonBlock, _is_ast_str,
|
|
22
|
-
infer_compile_mode
|
|
23
|
+
from pyflyby._parse import (MatchAs, PythonBlock, _is_ast_str,
|
|
24
|
+
infer_compile_mode)
|
|
23
25
|
|
|
24
26
|
from six import reraise
|
|
25
27
|
import sys
|
|
26
28
|
import types
|
|
27
|
-
from typing import Any,
|
|
29
|
+
from typing import (Any, Dict, List, Optional, Set, Tuple,
|
|
30
|
+
Union)
|
|
28
31
|
|
|
29
32
|
if sys.version_info >= (3, 12):
|
|
30
33
|
ATTRIBUTE_NAME = "value"
|
|
@@ -130,9 +133,13 @@ class ScopeStack(Sequence):
|
|
|
130
133
|
def __len__(self):
|
|
131
134
|
return len(self._tup)
|
|
132
135
|
|
|
133
|
-
def
|
|
134
|
-
self,
|
|
135
|
-
|
|
136
|
+
def _with_new_scope(
|
|
137
|
+
self,
|
|
138
|
+
*,
|
|
139
|
+
include_class_scopes: bool,
|
|
140
|
+
new_class_scope: bool,
|
|
141
|
+
unhide_classdef: bool,
|
|
142
|
+
) -> ScopeStack:
|
|
136
143
|
"""
|
|
137
144
|
Return a new ``ScopeStack`` with an additional empty scope.
|
|
138
145
|
|
|
@@ -148,8 +155,8 @@ class ScopeStack(Sequence):
|
|
|
148
155
|
if include_class_scopes:
|
|
149
156
|
scopes = tuple(self)
|
|
150
157
|
else:
|
|
151
|
-
scopes = tuple(s for s in self
|
|
152
|
-
|
|
158
|
+
scopes = tuple(s for s in self if not isinstance(s, _ClassScope))
|
|
159
|
+
new_scope: Union[_ClassScope, Dict[str, Any]]
|
|
153
160
|
if new_class_scope:
|
|
154
161
|
new_scope = _ClassScope()
|
|
155
162
|
else:
|
|
@@ -199,7 +206,7 @@ class ScopeStack(Sequence):
|
|
|
199
206
|
return (d, self[-1])
|
|
200
207
|
|
|
201
208
|
|
|
202
|
-
def has_star_import(self):
|
|
209
|
+
def has_star_import(self) -> bool:
|
|
203
210
|
"""
|
|
204
211
|
Return whether there are any star-imports in this ScopeStack.
|
|
205
212
|
Only relevant in AST-based static analysis mode.
|
|
@@ -355,9 +362,10 @@ class _UseChecker:
|
|
|
355
362
|
self.name = name
|
|
356
363
|
self.source = source # generally an Import
|
|
357
364
|
self.lineno = lineno
|
|
365
|
+
logger.debug("Create _UseChecker : %r", self)
|
|
358
366
|
|
|
359
367
|
def __repr__(self):
|
|
360
|
-
return f"<{type(self).__name__}: name:{self.name} source:{self.source!r} lineno:{self.lineno} used:{self.used}>"
|
|
368
|
+
return f"<{type(self).__name__}: name:{self.name!r} source:{self.source!r} lineno:{self.lineno} used:{self.used}>"
|
|
361
369
|
|
|
362
370
|
|
|
363
371
|
class _MissingImportFinder:
|
|
@@ -397,13 +405,13 @@ class _MissingImportFinder:
|
|
|
397
405
|
# Create a stack of namespaces. The caller should pass in a list that
|
|
398
406
|
# includes the globals dictionary. ScopeStack() will make sure this
|
|
399
407
|
# includes builtins.
|
|
400
|
-
|
|
408
|
+
_scopestack = ScopeStack(scopestack)
|
|
401
409
|
|
|
402
410
|
# Add an empty namespace to the stack. This facilitates adding stuff
|
|
403
411
|
# to scopestack[-1] without ever modifying user globals.
|
|
404
|
-
scopestack =
|
|
405
|
-
|
|
406
|
-
|
|
412
|
+
self.scopestack = _scopestack._with_new_scope(
|
|
413
|
+
include_class_scopes=False, new_class_scope=False, unhide_classdef=False
|
|
414
|
+
)
|
|
407
415
|
|
|
408
416
|
# Create data structure to hold the result.
|
|
409
417
|
# missing_imports is a list of (lineno, DottedIdentifier) tuples.
|
|
@@ -450,6 +458,7 @@ class _MissingImportFinder:
|
|
|
450
458
|
# references in doctests to be noted as missing-imports. For now we
|
|
451
459
|
# just let the code accumulate into self.missing_imports and ignore
|
|
452
460
|
# the result.
|
|
461
|
+
logger.debug("unused: %r", self.unused_imports)
|
|
453
462
|
missing_imports = sorted(self.missing_imports)
|
|
454
463
|
if self.parse_docstrings and self.unused_imports is not None:
|
|
455
464
|
doctest_blocks = codeblock.get_doctests()
|
|
@@ -467,10 +476,8 @@ class _MissingImportFinder:
|
|
|
467
476
|
# Currently we don't support the 'global' keyword anyway so
|
|
468
477
|
# this doesn't matter yet, and it's uncommon to use 'global'
|
|
469
478
|
# in a doctest, so this is low priority to fix.
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
self._scan_node(block.ast_node)
|
|
473
|
-
self.scopestack = oldstack
|
|
479
|
+
with self._NewScopeCtx(check_unused_imports=False):
|
|
480
|
+
self._scan_node(block.ast_node)
|
|
474
481
|
# Find literal brace identifiers like "... `Foo` ...".
|
|
475
482
|
# TODO: Do this inline: (1) faster; (2) can use proper scope of vars
|
|
476
483
|
# Once we do that, use _check_load() with new args
|
|
@@ -553,17 +560,36 @@ class _MissingImportFinder:
|
|
|
553
560
|
|
|
554
561
|
|
|
555
562
|
@contextlib.contextmanager
|
|
556
|
-
def _NewScopeCtx(
|
|
563
|
+
def _NewScopeCtx(
|
|
564
|
+
self,
|
|
565
|
+
include_class_scopes=False,
|
|
566
|
+
new_class_scope=False,
|
|
567
|
+
unhide_classdef=False,
|
|
568
|
+
check_unused_imports=True,
|
|
569
|
+
):
|
|
557
570
|
"""
|
|
558
571
|
Context manager that temporarily pushes a new empty namespace onto the
|
|
559
572
|
stack of namespaces.
|
|
560
573
|
"""
|
|
561
574
|
prev_scopestack = self.scopestack
|
|
562
|
-
new_scopestack = prev_scopestack.
|
|
575
|
+
new_scopestack = prev_scopestack._with_new_scope(
|
|
576
|
+
include_class_scopes=include_class_scopes,
|
|
577
|
+
new_class_scope=new_class_scope,
|
|
578
|
+
unhide_classdef=unhide_classdef,
|
|
579
|
+
)
|
|
563
580
|
self.scopestack = new_scopestack
|
|
564
581
|
try:
|
|
565
582
|
yield
|
|
566
583
|
finally:
|
|
584
|
+
logger.debug("throwing last scope from scopestack: %r", new_scopestack[-1])
|
|
585
|
+
for name, use_checker in new_scopestack[-1].items():
|
|
586
|
+
if use_checker and use_checker.used == False and check_unused_imports:
|
|
587
|
+
logger.debug(
|
|
588
|
+
"unused checker %r scopestack_depth %r",
|
|
589
|
+
use_checker,
|
|
590
|
+
len(self.scopestack),
|
|
591
|
+
)
|
|
592
|
+
self.unused_imports.append((use_checker.lineno, use_checker.source))
|
|
567
593
|
assert self.scopestack is new_scopestack
|
|
568
594
|
self.scopestack = prev_scopestack
|
|
569
595
|
|
|
@@ -693,7 +719,7 @@ class _MissingImportFinder:
|
|
|
693
719
|
self.visit(node.body)
|
|
694
720
|
self._in_FunctionDef = old_in_FunctionDef
|
|
695
721
|
|
|
696
|
-
def _visit_typecomment(self, typecomment):
|
|
722
|
+
def _visit_typecomment(self, typecomment: str) -> None:
|
|
697
723
|
"""
|
|
698
724
|
Warning, when a type comment the node is a string, not an ast node.
|
|
699
725
|
We also get two types of type comments:
|
|
@@ -716,6 +742,7 @@ class _MissingImportFinder:
|
|
|
716
742
|
"""
|
|
717
743
|
if typecomment is None:
|
|
718
744
|
return
|
|
745
|
+
node: Union[ast.Module, ast.FunctionType]
|
|
719
746
|
if '->' in typecomment:
|
|
720
747
|
node = ast.parse(typecomment, mode='func_type')
|
|
721
748
|
else:
|
|
@@ -723,7 +750,7 @@ class _MissingImportFinder:
|
|
|
723
750
|
|
|
724
751
|
self.visit(node)
|
|
725
752
|
|
|
726
|
-
def visit_arguments(self, node):
|
|
753
|
+
def visit_arguments(self, node) -> None:
|
|
727
754
|
assert node._fields == ('posonlyargs', 'args', 'vararg', 'kwonlyargs', 'kw_defaults', 'kwarg', 'defaults'), node._fields
|
|
728
755
|
# Argument/parameter list. Note that the defaults should be
|
|
729
756
|
# considered "Load"s from the upper scope, and the argument names are
|
|
@@ -754,7 +781,7 @@ class _MissingImportFinder:
|
|
|
754
781
|
else:
|
|
755
782
|
self._visit_Store(node.kwarg)
|
|
756
783
|
|
|
757
|
-
def visit_ExceptHandler(self, node):
|
|
784
|
+
def visit_ExceptHandler(self, node) -> None:
|
|
758
785
|
assert node._fields == ('type', 'name', 'body')
|
|
759
786
|
if node.type:
|
|
760
787
|
self.visit(node.type)
|
|
@@ -948,7 +975,12 @@ class _MissingImportFinder:
|
|
|
948
975
|
value = _UseChecker(name, imp, self._lineno)
|
|
949
976
|
self._visit_Store(name, value)
|
|
950
977
|
|
|
951
|
-
def _visit_Store(self, fullname:str, value=None):
|
|
978
|
+
def _visit_Store(self, fullname: str, value: Optional[_UseChecker] = None):
|
|
979
|
+
"""
|
|
980
|
+
Visit a Store action, check for unused import
|
|
981
|
+
and add current value to the last scope.
|
|
982
|
+
"""
|
|
983
|
+
assert isinstance(value, (_UseChecker, type(None)))
|
|
952
984
|
logger.debug("_visit_Store(%r)", fullname)
|
|
953
985
|
if fullname is None:
|
|
954
986
|
return
|
|
@@ -316,6 +316,14 @@ def _debug_exception(*exc_info, **kwargs):
|
|
|
316
316
|
# will cause print_verbose_tb to include a line with just a colon.
|
|
317
317
|
# TODO: avoid that line.
|
|
318
318
|
exc_info = ("", "", exc_info)
|
|
319
|
+
if exc_info[1]:
|
|
320
|
+
# Explicitly set sys.last_value / sys.last_exc to ensure they are available
|
|
321
|
+
# in the debugger. One use case is that this allows users to call
|
|
322
|
+
# pyflyby.saveframe() within the debugger.
|
|
323
|
+
if sys.version_info < (3, 12):
|
|
324
|
+
sys.last_value = exc_info[1]
|
|
325
|
+
else:
|
|
326
|
+
sys.last_exc = exc_info[1]
|
|
319
327
|
|
|
320
328
|
with _DebuggerCtx(tty=tty) as pdb:
|
|
321
329
|
if debugger_attached:
|
|
@@ -49,6 +49,7 @@ from pyflyby._importclns import ImportSet, Import
|
|
|
49
49
|
|
|
50
50
|
module_dict = {}
|
|
51
51
|
|
|
52
|
+
PYFLYBY_LAZY_LOAD_PREFIX = "from pyflyby_autoimport_"
|
|
52
53
|
|
|
53
54
|
def add_import(names: str, code: str, *, strict: bool = True):
|
|
54
55
|
"""
|
|
@@ -110,8 +111,8 @@ def _add_import(ip, names: str, code: str) -> None:
|
|
|
110
111
|
private version of add_import
|
|
111
112
|
"""
|
|
112
113
|
assert ip is not None
|
|
113
|
-
mang =
|
|
114
|
-
a: FrozenSet[Import] = ImportSet(f"
|
|
114
|
+
mang = PYFLYBY_LAZY_LOAD_PREFIX + names.replace(",", "_").replace(" ", "_")
|
|
115
|
+
a: FrozenSet[Import] = ImportSet(f"{mang} import {names}")._importset
|
|
115
116
|
b: FrozenSet[Import] = ip._auto_importer.db.known_imports._importset
|
|
116
117
|
s_import: FrozenSet[Import] = a | b
|
|
117
118
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
# Copyright (C) 2011, 2012, 2013, 2014, 2015 Karl Chen.
|
|
3
3
|
# License: MIT http://opensource.org/licenses/MIT
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
from collections import defaultdict
|
|
@@ -417,7 +419,7 @@ class ImportDB:
|
|
|
417
419
|
return result
|
|
418
420
|
|
|
419
421
|
@classmethod
|
|
420
|
-
def interpret_arg(cls, arg, target_filename):
|
|
422
|
+
def interpret_arg(cls, arg, target_filename) -> ImportDB:
|
|
421
423
|
if arg is None:
|
|
422
424
|
return cls.get_default(target_filename)
|
|
423
425
|
else:
|
|
@@ -13,12 +13,12 @@ from pyflyby._parse import PythonBlock
|
|
|
13
13
|
from pyflyby._util import ImportPathCtx, Inf, NullCtx, memoize
|
|
14
14
|
import re
|
|
15
15
|
|
|
16
|
-
from typing import Union
|
|
16
|
+
from typing import Union, Optional, Literal
|
|
17
17
|
|
|
18
18
|
from textwrap import indent
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
class SourceToSourceTransformationBase
|
|
21
|
+
class SourceToSourceTransformationBase:
|
|
22
22
|
|
|
23
23
|
input: PythonBlock
|
|
24
24
|
|
|
@@ -121,7 +121,7 @@ class SourceToSourceFileImportsTransformation(SourceToSourceTransformationBase):
|
|
|
121
121
|
result = [block.pretty_print(params=params) for block in self.blocks]
|
|
122
122
|
return FileText.concatenate(result)
|
|
123
123
|
|
|
124
|
-
def find_import_block_by_lineno(self, lineno):
|
|
124
|
+
def find_import_block_by_lineno(self, lineno: int):
|
|
125
125
|
"""
|
|
126
126
|
Find the import block containing the given line number.
|
|
127
127
|
|
|
@@ -312,11 +312,11 @@ def ImportPathForRelativeImportsCtx(codeblock):
|
|
|
312
312
|
|
|
313
313
|
|
|
314
314
|
def fix_unused_and_missing_imports(
|
|
315
|
-
codeblock: Union[PythonBlock, str],
|
|
316
|
-
add_missing=True,
|
|
317
|
-
remove_unused="AUTOMATIC",
|
|
318
|
-
add_mandatory=True,
|
|
319
|
-
db=None,
|
|
315
|
+
codeblock: Union[PythonBlock, str, Filename],
|
|
316
|
+
add_missing: bool = True,
|
|
317
|
+
remove_unused: Union[Literal["AUTOMATIC"], bool] = "AUTOMATIC",
|
|
318
|
+
add_mandatory: bool = True,
|
|
319
|
+
db: Optional[ImportDB] = None,
|
|
320
320
|
params=None,
|
|
321
321
|
) -> PythonBlock:
|
|
322
322
|
r"""
|
|
@@ -345,6 +345,7 @@ def fix_unused_and_missing_imports(
|
|
|
345
345
|
:rtype:
|
|
346
346
|
`PythonBlock`
|
|
347
347
|
"""
|
|
348
|
+
_codeblock: PythonBlock
|
|
348
349
|
if isinstance(codeblock, Filename):
|
|
349
350
|
_codeblock = PythonBlock(codeblock)
|
|
350
351
|
if not isinstance(codeblock, PythonBlock):
|
|
@@ -393,7 +394,7 @@ def fix_unused_and_missing_imports(
|
|
|
393
394
|
logger.error(
|
|
394
395
|
"%s: couldn't remove import %r", filename, imp,)
|
|
395
396
|
except LineNumberNotFoundError as e:
|
|
396
|
-
logger.
|
|
397
|
+
logger.debug(
|
|
397
398
|
"%s: unused import %r on line %d not global",
|
|
398
399
|
filename, str(imp), e.args[0])
|
|
399
400
|
else:
|
|
@@ -22,7 +22,8 @@ from pyflyby._autoimp import (LoadSymbolError, ScopeStack, auto_eval,
|
|
|
22
22
|
auto_import,
|
|
23
23
|
clear_failed_imports_cache,
|
|
24
24
|
load_symbol)
|
|
25
|
-
from pyflyby._dynimp import inject as inject_dynamic_import
|
|
25
|
+
from pyflyby._dynimp import (inject as inject_dynamic_import,
|
|
26
|
+
PYFLYBY_LAZY_LOAD_PREFIX)
|
|
26
27
|
from pyflyby._comms import (initialize_comms, remove_comms,
|
|
27
28
|
send_comm_message, MISSING_IMPORTS)
|
|
28
29
|
from pyflyby._file import Filename, atomic_write_file, read_file
|
|
@@ -35,7 +36,6 @@ from pyflyby._util import (AdviceCtx, Aspect, CwdCtx,
|
|
|
35
36
|
FunctionWithGlobals, NullCtx, advise,
|
|
36
37
|
indent)
|
|
37
38
|
|
|
38
|
-
|
|
39
39
|
if False:
|
|
40
40
|
__original__ = None # for pyflakes
|
|
41
41
|
|
|
@@ -85,9 +85,6 @@ def _get_or_create_ipython_terminal_app():
|
|
|
85
85
|
pass
|
|
86
86
|
else:
|
|
87
87
|
return TerminalIPythonApp.instance()
|
|
88
|
-
# The following has been tested on IPython 0.10.
|
|
89
|
-
if hasattr(IPython, "ipapi"):
|
|
90
|
-
return _IPython010TerminalApplication.instance()
|
|
91
88
|
raise RuntimeError(
|
|
92
89
|
"Couldn't get TerminalIPythonApp class. "
|
|
93
90
|
"Is your IPython version too old (or too new)? "
|
|
@@ -122,51 +119,6 @@ def _app_is_initialized(app):
|
|
|
122
119
|
|
|
123
120
|
|
|
124
121
|
|
|
125
|
-
class _IPython010TerminalApplication(object):
|
|
126
|
-
"""
|
|
127
|
-
Shim class that mimics IPython 0.11+ application classes, for use in
|
|
128
|
-
IPython 0.10.
|
|
129
|
-
"""
|
|
130
|
-
|
|
131
|
-
# IPython.ipapi.launch_instance() => IPython.Shell.start() creates an
|
|
132
|
-
# instance of "IPShell". IPShell has an attribute named "IP" which is an
|
|
133
|
-
# "InteractiveShell".
|
|
134
|
-
|
|
135
|
-
_instance = None
|
|
136
|
-
|
|
137
|
-
@classmethod
|
|
138
|
-
def instance(cls):
|
|
139
|
-
if cls._instance is not None:
|
|
140
|
-
self = cls._instance
|
|
141
|
-
self.init_shell()
|
|
142
|
-
return self
|
|
143
|
-
import IPython
|
|
144
|
-
if not hasattr(IPython, "ipapi"):
|
|
145
|
-
raise RuntimeError("Inappropriate version of IPython %r"
|
|
146
|
-
% (IPython.__version__,))
|
|
147
|
-
self = cls._instance = cls()
|
|
148
|
-
self.init_shell()
|
|
149
|
-
return self
|
|
150
|
-
|
|
151
|
-
def init_shell(self):
|
|
152
|
-
import IPython
|
|
153
|
-
ipapi = IPython.ipapi.get() # IPApi instance
|
|
154
|
-
if ipapi is not None:
|
|
155
|
-
self.shell = ipapi.IP # InteractiveShell instance
|
|
156
|
-
else:
|
|
157
|
-
self.shell = None
|
|
158
|
-
|
|
159
|
-
def initialize(self, argv=None):
|
|
160
|
-
import IPython
|
|
161
|
-
logger.debug("Creating IPython 0.10 session")
|
|
162
|
-
self._session = IPython.ipapi.make_session() # IPShell instance
|
|
163
|
-
self.init_shell()
|
|
164
|
-
assert self._session is not None
|
|
165
|
-
|
|
166
|
-
def start(self):
|
|
167
|
-
self._session.mainloop()
|
|
168
|
-
|
|
169
|
-
|
|
170
122
|
|
|
171
123
|
class _DummyIPythonEmbeddedApp(object):
|
|
172
124
|
"""
|
|
@@ -412,30 +364,7 @@ def install_in_ipython_config_file():
|
|
|
412
364
|
else:
|
|
413
365
|
_install_in_ipython_config_file_40()
|
|
414
366
|
return
|
|
415
|
-
|
|
416
|
-
# 2.2, 2.3, 2.4, 3.0, 3.1, 3.2, 4.0.
|
|
417
|
-
try:
|
|
418
|
-
IPython.core.profiledir.ProfileDir.startup_dir
|
|
419
|
-
except AttributeError:
|
|
420
|
-
pass
|
|
421
|
-
else:
|
|
422
|
-
_install_in_ipython_config_file_012()
|
|
423
|
-
return
|
|
424
|
-
# The following has been tested on IPython 0.11.
|
|
425
|
-
try:
|
|
426
|
-
IPython.core.profiledir.ProfileDir
|
|
427
|
-
except AttributeError:
|
|
428
|
-
pass
|
|
429
|
-
else:
|
|
430
|
-
_install_in_ipython_config_file_011()
|
|
431
|
-
return
|
|
432
|
-
try:
|
|
433
|
-
IPython.genutils.get_ipython_dir
|
|
434
|
-
except AttributeError:
|
|
435
|
-
pass
|
|
436
|
-
else:
|
|
437
|
-
_install_in_ipython_config_file_010()
|
|
438
|
-
return
|
|
367
|
+
|
|
439
368
|
raise RuntimeError(
|
|
440
369
|
"Couldn't install pyflyby autoimporter in IPython. "
|
|
441
370
|
"Is your IPython version too old (or too new)? "
|
|
@@ -555,96 +484,10 @@ def _install_in_ipython_config_file_40():
|
|
|
555
484
|
logger.info("[DONE] Removed old file %s (moved to %s)", old_fn, trash_fn)
|
|
556
485
|
|
|
557
486
|
|
|
558
|
-
def _install_in_ipython_config_file_012():
|
|
559
|
-
"""
|
|
560
|
-
Implementation of `install_in_ipython_config_file` for IPython 0.12+.
|
|
561
|
-
Tested with IPython 0.12, 0.13, 1.0, 1.2, 2.0, 2.1, 2.2, 2.3, 2.4, 3.0,
|
|
562
|
-
3.1, 3.2, 4.0.
|
|
563
|
-
"""
|
|
564
|
-
import IPython
|
|
565
|
-
ipython_dir = Filename(IPython.utils.path.get_ipython_dir())
|
|
566
|
-
if not ipython_dir.isdir:
|
|
567
|
-
raise RuntimeError(
|
|
568
|
-
"Couldn't find IPython config dir. Tried %s" % (ipython_dir,))
|
|
569
|
-
startup_dir = ipython_dir / "profile_default" / "startup"
|
|
570
|
-
if not startup_dir.isdir:
|
|
571
|
-
raise RuntimeError(
|
|
572
|
-
"Couldn't find IPython startup dir. Tried %s" % (startup_dir,))
|
|
573
|
-
fn = startup_dir / "50-pyflyby.py"
|
|
574
|
-
if fn.exists:
|
|
575
|
-
logger.info("Doing nothing, because %s already exists", fn)
|
|
576
|
-
return
|
|
577
|
-
argv = sys.argv[:]
|
|
578
|
-
argv[0] = os.path.realpath(argv[0])
|
|
579
|
-
argv = ' '.join(argv)
|
|
580
|
-
header = (
|
|
581
|
-
"# File: {fn}\n"
|
|
582
|
-
"#\n"
|
|
583
|
-
"# Generated by {argv}\n"
|
|
584
|
-
"#\n"
|
|
585
|
-
"# This file causes IPython to enable the Pyflyby Auto Importer.\n"
|
|
586
|
-
"#\n"
|
|
587
|
-
"# To uninstall, just delete this file.\n"
|
|
588
|
-
"#\n"
|
|
589
|
-
).format(**locals())
|
|
590
|
-
contents = header + _generate_enabler_code()
|
|
591
|
-
logger.info("Installing pyflyby auto importer in your IPython startup")
|
|
592
|
-
logger.info("Writing to %s:\n%s", fn, contents)
|
|
593
|
-
atomic_write_file(fn, contents)
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
def _install_in_ipython_config_file_011():
|
|
597
|
-
"""
|
|
598
|
-
Implementation of `install_in_ipython_config_file` for IPython 0.11.
|
|
599
|
-
"""
|
|
600
|
-
import IPython
|
|
601
|
-
ipython_dir = Filename(IPython.utils.path.get_ipython_dir())
|
|
602
|
-
fn = ipython_dir / "profile_default" / "ipython_config.py"
|
|
603
|
-
if not fn.exists:
|
|
604
|
-
raise RuntimeError(
|
|
605
|
-
"Couldn't find IPython startup file. Tried %s" % (fn,))
|
|
606
|
-
old_contents = read_file(fn).joined
|
|
607
|
-
if re.search(r"^ *(pyflyby[.])?enable_auto_importer[(][)]", old_contents, re.M):
|
|
608
|
-
logger.info("Doing nothing, because already installed in %s", fn)
|
|
609
|
-
return
|
|
610
|
-
header = (
|
|
611
|
-
"\n"
|
|
612
|
-
"\n"
|
|
613
|
-
"#\n"
|
|
614
|
-
"# Enable the Pyflyby Auto Importer.\n"
|
|
615
|
-
)
|
|
616
|
-
new_contents = header + _generate_enabler_code()
|
|
617
|
-
contents = old_contents.rstrip() + new_contents
|
|
618
|
-
logger.info("Installing pyflyby auto importer in your IPython startup")
|
|
619
|
-
logger.info("Appending to %s:\n%s", fn, new_contents)
|
|
620
|
-
atomic_write_file(fn, contents)
|
|
621
487
|
|
|
622
488
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
Implementation of `install_in_ipython_config_file` for IPython 0.10.
|
|
626
|
-
"""
|
|
627
|
-
import IPython
|
|
628
|
-
ipython_dir = Filename(IPython.genutils.get_ipython_dir())
|
|
629
|
-
fn = ipython_dir / "ipy_user_conf.py"
|
|
630
|
-
if not fn.exists:
|
|
631
|
-
raise RuntimeError(
|
|
632
|
-
"Couldn't find IPython config file. Tried %s" % (fn,))
|
|
633
|
-
old_contents = read_file(fn).joined
|
|
634
|
-
if re.search(r"^ *(pyflyby[.])?enable_auto_importer[(][)]", old_contents, re.M):
|
|
635
|
-
logger.info("Doing nothing, because already installed in %s", fn)
|
|
636
|
-
return
|
|
637
|
-
header = (
|
|
638
|
-
"\n"
|
|
639
|
-
"\n"
|
|
640
|
-
"#\n"
|
|
641
|
-
"# Enable the Pyflyby Auto Importer.\n"
|
|
642
|
-
)
|
|
643
|
-
new_contents = header + _generate_enabler_code()
|
|
644
|
-
contents = old_contents.rstrip() + new_contents
|
|
645
|
-
logger.info("Installing pyflyby auto importer in your IPython startup")
|
|
646
|
-
logger.info("Appending to %s:\n%s", fn, new_contents)
|
|
647
|
-
atomic_write_file(fn, contents)
|
|
489
|
+
|
|
490
|
+
|
|
648
491
|
|
|
649
492
|
|
|
650
493
|
def _ipython_in_multiline(ip):
|
|
@@ -722,37 +565,6 @@ def InterceptPrintsDuringPromptCtx(ip):
|
|
|
722
565
|
else:
|
|
723
566
|
return ip.separate_in + ip.prompt_in1.format(ip.execution_count)
|
|
724
567
|
get_prompt = get_prompt_rlipython
|
|
725
|
-
elif hasattr(ip, "prompt_manager"):
|
|
726
|
-
# IPython >= 0.12 (known to work including up to 1.2, 2.1)
|
|
727
|
-
prompt_manager = ip.prompt_manager
|
|
728
|
-
def get_prompt_ipython_012():
|
|
729
|
-
pdb_instance = _get_pdb_if_is_in_pdb()
|
|
730
|
-
if pdb_instance is not None:
|
|
731
|
-
return pdb_instance.prompt
|
|
732
|
-
elif _ipython_in_multiline(ip):
|
|
733
|
-
return prompt_manager.render("in2")
|
|
734
|
-
else:
|
|
735
|
-
return ip.separate_in + prompt_manager.render("in")
|
|
736
|
-
get_prompt = get_prompt_ipython_012
|
|
737
|
-
elif hasattr(ip.hooks, "generate_prompt"):
|
|
738
|
-
# IPython 0.10, 0.11
|
|
739
|
-
generate_prompt = ip.hooks.generate_prompt
|
|
740
|
-
def get_prompt_ipython_010():
|
|
741
|
-
pdb_instance = _get_pdb_if_is_in_pdb()
|
|
742
|
-
if pdb_instance is not None:
|
|
743
|
-
return pdb_instance.prompt
|
|
744
|
-
elif _ipython_in_multiline(ip):
|
|
745
|
-
return generate_prompt(True)
|
|
746
|
-
else:
|
|
747
|
-
if hasattr(ip, "outputcache"):
|
|
748
|
-
# IPython 0.10 (but not 0.11+):
|
|
749
|
-
# Decrement the prompt_count since it otherwise
|
|
750
|
-
# auto-increments. (It's hard to avoid the
|
|
751
|
-
# auto-increment as it happens as a side effect of
|
|
752
|
-
# __str__!)
|
|
753
|
-
ip.outputcache.prompt_count -= 1
|
|
754
|
-
return generate_prompt(False)
|
|
755
|
-
get_prompt = get_prompt_ipython_010
|
|
756
568
|
else:
|
|
757
569
|
# Too old or too new IPython version?
|
|
758
570
|
return NullCtx()
|
|
@@ -818,8 +630,6 @@ def _get_ipython_app():
|
|
|
818
630
|
# No active IPython app/shell.
|
|
819
631
|
raise NoActiveIPythonAppError("No active IPython application")
|
|
820
632
|
# The following has been tested on IPython 0.10.
|
|
821
|
-
if hasattr(IPython, "ipapi"):
|
|
822
|
-
return _IPython010TerminalApplication.instance()
|
|
823
633
|
raise NoActiveIPythonAppError(
|
|
824
634
|
"Could not figure out how to get active IPython application for IPython version %s"
|
|
825
635
|
% (IPython.__version__,))
|
|
@@ -2341,7 +2151,8 @@ class AutoImporter:
|
|
|
2341
2151
|
namespaces = get_global_namespaces(self._ip)
|
|
2342
2152
|
|
|
2343
2153
|
def post_import_hook(imp):
|
|
2344
|
-
|
|
2154
|
+
if not str(imp).startswith(PYFLYBY_LAZY_LOAD_PREFIX):
|
|
2155
|
+
send_comm_message(MISSING_IMPORTS, {"missing_imports": str(imp)})
|
|
2345
2156
|
|
|
2346
2157
|
return self._safe_call(
|
|
2347
2158
|
auto_import, arg=arg, namespaces=namespaces,
|
|
@@ -346,9 +346,6 @@ def _annotate_ast_nodes(ast_node: ast.AST) -> AnnotatedAst:
|
|
|
346
346
|
flags = aast_node.flags
|
|
347
347
|
startpos = text.startpos
|
|
348
348
|
_annotate_ast_startpos(aast_node, None, startpos, text, flags)
|
|
349
|
-
# Not used for now:
|
|
350
|
-
# ast_node.context = AstNodeContext(None, None, None)
|
|
351
|
-
# _annotate_ast_context(ast_node)
|
|
352
349
|
return aast_node
|
|
353
350
|
|
|
354
351
|
|
|
@@ -526,29 +523,6 @@ def _annotate_ast_startpos(
|
|
|
526
523
|
raise ValueError("Couldn't find exact position of %s" % (ast.dump(ast_node)))
|
|
527
524
|
|
|
528
525
|
|
|
529
|
-
def _annotate_ast_context(ast_node):
|
|
530
|
-
"""
|
|
531
|
-
Recursively annotate ``context`` on ast nodes, setting ``context`` to
|
|
532
|
-
a `AstNodeContext` named tuple with values
|
|
533
|
-
``(parent, field, index)``.
|
|
534
|
-
Each aast_node satisfies ``parent.<field>[<index>] is ast_node``.
|
|
535
|
-
|
|
536
|
-
For non-list fields, the index part is ``None``.
|
|
537
|
-
"""
|
|
538
|
-
assert isinstance(ast_node, ast.AST)
|
|
539
|
-
for field_name, field_value in ast.iter_fields(ast_node):
|
|
540
|
-
if isinstance(field_value, ast.AST):
|
|
541
|
-
child_node = field_value
|
|
542
|
-
child_node.context = AstNodeContext(ast_node, field_name, None)
|
|
543
|
-
_annotate_ast_context(child_node)
|
|
544
|
-
elif isinstance(field_value, list):
|
|
545
|
-
for i, item in enumerate(field_value):
|
|
546
|
-
if isinstance(item, ast.AST):
|
|
547
|
-
child_node = item
|
|
548
|
-
child_node.context = AstNodeContext(ast_node, field_name, i)
|
|
549
|
-
_annotate_ast_context(child_node)
|
|
550
|
-
|
|
551
|
-
|
|
552
526
|
def _split_code_lines(ast_nodes, text):
|
|
553
527
|
"""
|
|
554
528
|
Split the given ``ast_nodes`` and corresponding ``text`` by code/noncode
|
|
@@ -632,51 +606,6 @@ def _split_code_lines(ast_nodes, text):
|
|
|
632
606
|
yield ([], text[endpos:next_startpos])
|
|
633
607
|
|
|
634
608
|
|
|
635
|
-
def _ast_node_is_in_docstring_position(ast_node):
|
|
636
|
-
"""
|
|
637
|
-
Given a ``Str`` AST node, return whether its position within the AST makes
|
|
638
|
-
it eligible as a docstring.
|
|
639
|
-
|
|
640
|
-
The main way a ``Str`` can be a docstring is if it is a standalone string
|
|
641
|
-
at the beginning of a ``Module``, ``FunctionDef``, ``AsyncFucntionDef``
|
|
642
|
-
or ``ClassDef``.
|
|
643
|
-
|
|
644
|
-
We also support variable docstrings per Epydoc:
|
|
645
|
-
|
|
646
|
-
- If a variable assignment statement is immediately followed by a bare
|
|
647
|
-
string literal, then that assignment is treated as a docstring for
|
|
648
|
-
that variable.
|
|
649
|
-
|
|
650
|
-
:type ast_node:
|
|
651
|
-
``ast.Str``
|
|
652
|
-
:param ast_node:
|
|
653
|
-
AST node that has been annotated by ``_annotate_ast_nodes``.
|
|
654
|
-
:rtype:
|
|
655
|
-
``bool``
|
|
656
|
-
:return:
|
|
657
|
-
Whether this string ast node is in docstring position.
|
|
658
|
-
"""
|
|
659
|
-
if not _is_ast_str_or_byte(ast_node):
|
|
660
|
-
raise TypeError
|
|
661
|
-
expr_node = ast_node.context.parent
|
|
662
|
-
if not isinstance(expr_node, ast.Expr):
|
|
663
|
-
return False
|
|
664
|
-
assert ast_node.context.field == 'value'
|
|
665
|
-
assert ast_node.context.index is None
|
|
666
|
-
expr_ctx = expr_node.context
|
|
667
|
-
if expr_ctx.field != 'body':
|
|
668
|
-
return False
|
|
669
|
-
parent_node = expr_ctx.parent
|
|
670
|
-
if not isinstance(parent_node, (ast.FunctionDef, ast.ClassDef, ast.Module, AsyncFunctionDef)):
|
|
671
|
-
return False
|
|
672
|
-
if expr_ctx.index == 0:
|
|
673
|
-
return True
|
|
674
|
-
prev_sibling_node = parent_node.body[expr_ctx.index-1]
|
|
675
|
-
if isinstance(prev_sibling_node, ast.Assign):
|
|
676
|
-
return True
|
|
677
|
-
return False
|
|
678
|
-
|
|
679
|
-
|
|
680
609
|
def infer_compile_mode(arg:ast.AST) -> Literal['exec','eval','single']:
|
|
681
610
|
"""
|
|
682
611
|
Infer the mode needed to compile ``arg``.
|
|
@@ -1334,11 +1263,6 @@ class PythonBlock:
|
|
|
1334
1263
|
# - This function yields multiple docstrings (even per ast node)
|
|
1335
1264
|
# - This function doesn't raise TypeError on other AST types
|
|
1336
1265
|
# - This function doesn't cleandoc
|
|
1337
|
-
# A previous implementation did
|
|
1338
|
-
# [n for n in self.string_literals()
|
|
1339
|
-
# if _ast_node_is_in_docstring_position(n)]
|
|
1340
|
-
# However, the method we now use is more straightforward, and doesn't
|
|
1341
|
-
# require first annotating each node with context information.
|
|
1342
1266
|
docstring_containers = (ast.FunctionDef, ast.ClassDef, ast.Module, AsyncFunctionDef)
|
|
1343
1267
|
for node in _walk_ast_nodes_in_order(self.annotated_ast_node):
|
|
1344
1268
|
if not isinstance(node, docstring_containers):
|