pyflyby 1.9.4__py3-none-any.whl → 1.9.5__py3-none-any.whl
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/__init__.py +1 -0
- pyflyby/_autoimp.py +51 -5
- pyflyby/_cmdline.py +6 -3
- pyflyby/_dynimp.py +152 -0
- pyflyby/_file.py +37 -20
- pyflyby/_importclns.py +30 -14
- pyflyby/_importdb.py +133 -45
- pyflyby/_interactive.py +22 -145
- pyflyby/_parse.py +9 -1
- pyflyby/_py.py +2 -2
- pyflyby/_version.py +1 -1
- {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/METADATA +32 -1
- pyflyby-1.9.5.dist-info/RECORD +55 -0
- {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/WHEEL +1 -1
- pyflyby-1.9.4.dist-info/RECORD +0 -54
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/common.py +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/std.py +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/doc/pyflyby/LICENSE.txt +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/doc/pyflyby/TODO.txt +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/doc/pyflyby/testing.txt +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/emacs/site-lisp/pyflyby.el +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/collect-exports +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/collect-imports +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/find-import +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/list-bad-xrefs +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/prune-broken-imports +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/pyflyby-diff +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/reformat-imports +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/replace-star-imports +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/tidy-imports +0 -0
- {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/transform-imports +0 -0
- {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/LICENSE.txt +0 -0
- {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/entry_points.txt +0 -0
- {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/top_level.txt +0 -0
pyflyby/_importdb.py
CHANGED
|
@@ -7,8 +7,15 @@
|
|
|
7
7
|
from collections import defaultdict
|
|
8
8
|
import os
|
|
9
9
|
import re
|
|
10
|
+
import sys
|
|
11
|
+
import warnings
|
|
10
12
|
|
|
11
|
-
from
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from typing import Any, Dict, List, Tuple, Union
|
|
16
|
+
|
|
17
|
+
from pyflyby._file import (Filename, UnsafeFilenameError,
|
|
18
|
+
expand_py_files_from_args)
|
|
12
19
|
from pyflyby._idents import dotted_prefixes
|
|
13
20
|
from pyflyby._importclns import ImportMap, ImportSet
|
|
14
21
|
from pyflyby._importstmt import Import, ImportStatement
|
|
@@ -16,8 +23,12 @@ from pyflyby._log import logger
|
|
|
16
23
|
from pyflyby._parse import PythonBlock
|
|
17
24
|
from pyflyby._util import cached_attribute, memoize, stable_unique
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
if sys.version_info <= (3, 12):
|
|
27
|
+
from typing_extensions import Self
|
|
28
|
+
else:
|
|
29
|
+
from typing import Self
|
|
20
30
|
|
|
31
|
+
SUPPORT_DEPRECATED_BEHAVIOR = True
|
|
21
32
|
|
|
22
33
|
@memoize
|
|
23
34
|
def _find_etc_dirs():
|
|
@@ -83,8 +94,11 @@ def _get_python_path(env_var_name, default_path, target_dirname):
|
|
|
83
94
|
.format(env_var_name=env_var_name, p=p))
|
|
84
95
|
pathnames = [os.path.expanduser(p) for p in pathnames]
|
|
85
96
|
pathnames = _expand_tripledots(pathnames, target_dirname)
|
|
86
|
-
|
|
97
|
+
for fn in pathnames:
|
|
98
|
+
assert isinstance(fn, Filename)
|
|
87
99
|
pathnames = stable_unique(pathnames)
|
|
100
|
+
for p in pathnames:
|
|
101
|
+
assert isinstance(p, Filename)
|
|
88
102
|
pathnames = expand_py_files_from_args(pathnames)
|
|
89
103
|
if not pathnames:
|
|
90
104
|
logger.warning(
|
|
@@ -96,8 +110,8 @@ def _get_python_path(env_var_name, default_path, target_dirname):
|
|
|
96
110
|
# TODO: stop memoizing here after using StatCache. Actually just inline into
|
|
97
111
|
# _ancestors_on_same_partition
|
|
98
112
|
@memoize
|
|
99
|
-
def _get_st_dev(filename):
|
|
100
|
-
filename
|
|
113
|
+
def _get_st_dev(filename: Filename):
|
|
114
|
+
assert isinstance(filename, Filename)
|
|
101
115
|
try:
|
|
102
116
|
return os.stat(str(filename)).st_dev
|
|
103
117
|
except OSError:
|
|
@@ -152,7 +166,7 @@ def _expand_tripledots(pathnames, target_dirname):
|
|
|
152
166
|
:rtype:
|
|
153
167
|
``list`` of `Filename`
|
|
154
168
|
"""
|
|
155
|
-
target_dirname
|
|
169
|
+
assert isinstance(target_dirname, Filename)
|
|
156
170
|
if not isinstance(pathnames, (tuple, list)):
|
|
157
171
|
pathnames = [pathnames]
|
|
158
172
|
result = []
|
|
@@ -171,7 +185,7 @@ def _expand_tripledots(pathnames, target_dirname):
|
|
|
171
185
|
return result
|
|
172
186
|
|
|
173
187
|
|
|
174
|
-
class ImportDB
|
|
188
|
+
class ImportDB:
|
|
175
189
|
"""
|
|
176
190
|
A database of known, mandatory, canonical imports.
|
|
177
191
|
|
|
@@ -186,6 +200,13 @@ class ImportDB(object):
|
|
|
186
200
|
canonical_imports.
|
|
187
201
|
"""
|
|
188
202
|
|
|
203
|
+
forget_imports : ImportSet
|
|
204
|
+
known_imports : ImportSet
|
|
205
|
+
mandatory_imports: ImportSet
|
|
206
|
+
canonical_imports: ImportMap
|
|
207
|
+
|
|
208
|
+
_default_cache: Dict[Any, Any] = {}
|
|
209
|
+
|
|
189
210
|
def __new__(cls, *args):
|
|
190
211
|
if len(args) != 1:
|
|
191
212
|
raise TypeError
|
|
@@ -196,8 +217,8 @@ class ImportDB(object):
|
|
|
196
217
|
return cls._from_data(arg, [], [], [])
|
|
197
218
|
return cls._from_args(arg) # PythonBlock, Filename, etc
|
|
198
219
|
|
|
220
|
+
|
|
199
221
|
|
|
200
|
-
_default_cache: Dict[Any, Any] = {}
|
|
201
222
|
|
|
202
223
|
@classmethod
|
|
203
224
|
def clear_default_cache(cls):
|
|
@@ -208,24 +229,22 @@ class ImportDB(object):
|
|
|
208
229
|
cached results. Existing ImportDB instances are not affected by this
|
|
209
230
|
call.
|
|
210
231
|
"""
|
|
211
|
-
if
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
for
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
nfiles)
|
|
225
|
-
cls._default_cache.clear()
|
|
232
|
+
if logger.debug_enabled:
|
|
233
|
+
allpyfiles = set()
|
|
234
|
+
for tup in cls._default_cache:
|
|
235
|
+
if tup[0] != 2:
|
|
236
|
+
continue
|
|
237
|
+
for tup2 in tup[1:]:
|
|
238
|
+
for f in tup2:
|
|
239
|
+
assert isinstance(f, Filename)
|
|
240
|
+
if f.ext == ".py":
|
|
241
|
+
allpyfiles.add(f)
|
|
242
|
+
nfiles = len(allpyfiles)
|
|
243
|
+
logger.debug("ImportDB: Clearing default cache of %d files", nfiles)
|
|
244
|
+
cls._default_cache.clear()
|
|
226
245
|
|
|
227
246
|
@classmethod
|
|
228
|
-
def get_default(cls, target_filename):
|
|
247
|
+
def get_default(cls, target_filename: Union[Filename, str], /):
|
|
229
248
|
"""
|
|
230
249
|
Return the default import library for the given target filename.
|
|
231
250
|
|
|
@@ -242,7 +261,7 @@ class ImportDB(object):
|
|
|
242
261
|
:rtype:
|
|
243
262
|
`ImportDB`
|
|
244
263
|
"""
|
|
245
|
-
# We're going to canonicalize
|
|
264
|
+
# We're going to canonicalize target_filename in a number of steps.
|
|
246
265
|
# At each step, see if we've seen the input so far. We do the cache
|
|
247
266
|
# checking incrementally since the steps involve syscalls. Since this
|
|
248
267
|
# is going to potentially be executed inside the IPython interactive
|
|
@@ -250,22 +269,56 @@ class ImportDB(object):
|
|
|
250
269
|
# TODO: Consider refreshing periodically. Check if files have
|
|
251
270
|
# been touched, and if so, return new data. Check file timestamps at
|
|
252
271
|
# most once every 60 seconds.
|
|
253
|
-
cache_keys = []
|
|
254
|
-
|
|
272
|
+
cache_keys:List[Tuple[Any,...]] = []
|
|
273
|
+
if target_filename is None:
|
|
274
|
+
target_filename = "."
|
|
275
|
+
|
|
276
|
+
if isinstance(target_filename, Filename):
|
|
277
|
+
target_filename = str(target_filename)
|
|
278
|
+
|
|
279
|
+
assert isinstance(target_filename, str), (
|
|
280
|
+
target_filename,
|
|
281
|
+
type(target_filename),
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
target_path = Path(target_filename).resolve()
|
|
285
|
+
|
|
286
|
+
parents: List[Path]
|
|
287
|
+
if not target_path.is_dir():
|
|
288
|
+
parents = [target_path]
|
|
289
|
+
else:
|
|
290
|
+
parents = []
|
|
291
|
+
|
|
292
|
+
# filter safe parents
|
|
293
|
+
safe_parent = None
|
|
294
|
+
for p in parents + list(target_path.parents):
|
|
295
|
+
try:
|
|
296
|
+
safe_parent = Filename(str(p))
|
|
297
|
+
break
|
|
298
|
+
except UnsafeFilenameError:
|
|
299
|
+
pass
|
|
300
|
+
if safe_parent is None:
|
|
301
|
+
raise ValueError("No know path are safe")
|
|
302
|
+
|
|
303
|
+
target_dirname = safe_parent
|
|
304
|
+
|
|
255
305
|
if target_filename.startswith("/dev"):
|
|
256
|
-
target_filename = Filename(".")
|
|
257
|
-
target_dirname = target_filename
|
|
258
|
-
# TODO: with StatCache
|
|
259
|
-
while True:
|
|
260
|
-
cache_keys.append((1,
|
|
261
|
-
target_dirname,
|
|
262
|
-
os.getenv("PYFLYBY_PATH"),
|
|
263
|
-
os.getenv("PYFLYBY_KNOWN_IMPORTS_PATH"),
|
|
264
|
-
os.getenv("PYFLYBY_MANDATORY_IMPORTS_PATH")))
|
|
265
306
|
try:
|
|
266
|
-
|
|
267
|
-
except
|
|
307
|
+
target_dirname = Filename(".")
|
|
308
|
+
except UnsafeFilenameError:
|
|
268
309
|
pass
|
|
310
|
+
# TODO: with StatCache
|
|
311
|
+
while True:
|
|
312
|
+
key = (
|
|
313
|
+
1,
|
|
314
|
+
target_dirname,
|
|
315
|
+
os.getenv("PYFLYBY_PATH"),
|
|
316
|
+
os.getenv("PYFLYBY_KNOWN_IMPORTS_PATH"),
|
|
317
|
+
os.getenv("PYFLYBY_MANDATORY_IMPORTS_PATH"),
|
|
318
|
+
)
|
|
319
|
+
cache_keys.append(key)
|
|
320
|
+
if key in cls._default_cache:
|
|
321
|
+
return cls._default_cache[key]
|
|
269
322
|
if target_dirname.isdir:
|
|
270
323
|
break
|
|
271
324
|
target_dirname = target_dirname.dir
|
|
@@ -293,7 +346,7 @@ class ImportDB(object):
|
|
|
293
346
|
filenames = _get_python_path("PYFLYBY_PATH", DEFAULT_PYFLYBY_PATH,
|
|
294
347
|
target_dirname)
|
|
295
348
|
mandatory_imports_filenames = ()
|
|
296
|
-
if
|
|
349
|
+
if SUPPORT_DEPRECATED_BEHAVIOR:
|
|
297
350
|
PYFLYBY_PATH = _get_env_var("PYFLYBY_PATH", DEFAULT_PYFLYBY_PATH)
|
|
298
351
|
# If the old deprecated environment variables are set, then heed
|
|
299
352
|
# them.
|
|
@@ -320,7 +373,15 @@ class ImportDB(object):
|
|
|
320
373
|
default_path = PYFLYBY_PATH
|
|
321
374
|
# Expand $PYFLYBY_KNOWN_IMPORTS_PATH.
|
|
322
375
|
filenames = _get_python_path(
|
|
323
|
-
"PYFLYBY_KNOWN_IMPORTS_PATH", default_path, target_dirname
|
|
376
|
+
"PYFLYBY_KNOWN_IMPORTS_PATH", default_path, target_dirname
|
|
377
|
+
)
|
|
378
|
+
warnings.warn(
|
|
379
|
+
"The environment variable PYFLYBY_KNOWN_IMPORTS_PATH was"
|
|
380
|
+
" deprecated since 2014. But never emitted a warning,"
|
|
381
|
+
" please use PYFLYBY_PATH or open an issue"
|
|
382
|
+
" if you are still requiring PYFLYBY_KNOWN_IMPORTS_PATH",
|
|
383
|
+
DeprecationWarning,
|
|
384
|
+
)
|
|
324
385
|
logger.debug(
|
|
325
386
|
"The environment variable PYFLYBY_KNOWN_IMPORTS_PATH is deprecated. "
|
|
326
387
|
"Use PYFLYBY_PATH.")
|
|
@@ -333,8 +394,15 @@ class ImportDB(object):
|
|
|
333
394
|
os.path.join(d,"mandatory_imports") for d in PYFLYBY_PATH]
|
|
334
395
|
# Expand $PYFLYBY_MANDATORY_IMPORTS_PATH.
|
|
335
396
|
mandatory_imports_filenames = _get_python_path(
|
|
336
|
-
"PYFLYBY_MANDATORY_IMPORTS_PATH",
|
|
337
|
-
|
|
397
|
+
"PYFLYBY_MANDATORY_IMPORTS_PATH", default_path, target_dirname
|
|
398
|
+
)
|
|
399
|
+
warnings.warn(
|
|
400
|
+
"The environment variable PYFLYBY_MANDATORY_IMPORTS_PATH was"
|
|
401
|
+
" deprecated since 2014 but never emitted a warning."
|
|
402
|
+
" Use PYFLYBY_PATH and write __mandatory_imports__=['...']"
|
|
403
|
+
" in your files.",
|
|
404
|
+
DeprecationWarning,
|
|
405
|
+
)
|
|
338
406
|
logger.debug(
|
|
339
407
|
"The environment variable PYFLYBY_MANDATORY_IMPORTS_PATH is deprecated. "
|
|
340
408
|
"Use PYFLYBY_PATH and write __mandatory_imports__=['...'] in your files.")
|
|
@@ -366,6 +434,16 @@ class ImportDB(object):
|
|
|
366
434
|
self.canonical_imports = ImportMap(canonical_imports).without_imports(forget_imports)
|
|
367
435
|
return self
|
|
368
436
|
|
|
437
|
+
def __or__(self, other:'Self') -> 'Self':
|
|
438
|
+
assert isinstance(other, ImportDB)
|
|
439
|
+
return self._from_data(
|
|
440
|
+
known_imports = self.known_imports | other.known_imports,
|
|
441
|
+
mandatory_imports = self.mandatory_imports | other.mandatory_imports,
|
|
442
|
+
canonical_imports = self.canonical_imports | other.canonical_imports,
|
|
443
|
+
forget_imports = self.forget_imports | other.forget_imports
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
|
|
369
447
|
@classmethod
|
|
370
448
|
def _from_args(cls, args):
|
|
371
449
|
# TODO: support merging input ImportDBs. For now we support
|
|
@@ -469,13 +547,23 @@ class ImportDB(object):
|
|
|
469
547
|
:rtype:
|
|
470
548
|
`ImportDB`
|
|
471
549
|
"""
|
|
550
|
+
if _mandatory_filenames_deprecated:
|
|
551
|
+
warnings.warn(
|
|
552
|
+
"_mandatory_filenames_deprecated has been deprecated in Pyflyby"
|
|
553
|
+
" 1.9.4 and will removed in future versions",
|
|
554
|
+
DeprecationWarning,
|
|
555
|
+
stacklevel=1,
|
|
556
|
+
)
|
|
472
557
|
if not isinstance(filenames, (tuple, list)):
|
|
558
|
+
# TODO DeprecationWarning July 2024,
|
|
559
|
+
# this is internal deprecate not passing a list;
|
|
473
560
|
filenames = [filenames]
|
|
474
|
-
|
|
561
|
+
for f in filenames:
|
|
562
|
+
assert isinstance(f, Filename)
|
|
475
563
|
logger.debug("ImportDB: loading [%s], mandatory=[%s]",
|
|
476
564
|
', '.join(map(str, filenames)),
|
|
477
565
|
', '.join(map(str, _mandatory_filenames_deprecated)))
|
|
478
|
-
if
|
|
566
|
+
if SUPPORT_DEPRECATED_BEHAVIOR:
|
|
479
567
|
# Before 2014-10, pyflyby read the following:
|
|
480
568
|
# * known_imports from $PYFLYBY_PATH/known_imports/**/*.py or
|
|
481
569
|
# $PYFLYBY_KNOWN_IMPORTS_PATH/**/*.py,
|
|
@@ -531,7 +619,7 @@ class ImportDB(object):
|
|
|
531
619
|
return ImportMap(arg)
|
|
532
620
|
|
|
533
621
|
@cached_attribute
|
|
534
|
-
def by_fullname_or_import_as(self):
|
|
622
|
+
def by_fullname_or_import_as(self) -> Dict[str, Tuple[Import, ...]]:
|
|
535
623
|
"""
|
|
536
624
|
Map from ``fullname`` and ``import_as`` to `Import` s.
|
|
537
625
|
|
pyflyby/_interactive.py
CHANGED
|
@@ -15,11 +15,14 @@ import re
|
|
|
15
15
|
import subprocess
|
|
16
16
|
import sys
|
|
17
17
|
|
|
18
|
+
from typing import List, Any, Dict
|
|
19
|
+
|
|
18
20
|
|
|
19
21
|
from pyflyby._autoimp import (LoadSymbolError, ScopeStack, auto_eval,
|
|
20
22
|
auto_import,
|
|
21
23
|
clear_failed_imports_cache,
|
|
22
24
|
load_symbol)
|
|
25
|
+
from pyflyby._dynimp import inject as inject_dynamic_import
|
|
23
26
|
from pyflyby._comms import (initialize_comms, remove_comms,
|
|
24
27
|
send_comm_message, MISSING_IMPORTS)
|
|
25
28
|
from pyflyby._file import Filename, atomic_write_file, read_file
|
|
@@ -1368,20 +1371,30 @@ def UpdateIPythonStdioCtx():
|
|
|
1368
1371
|
|
|
1369
1372
|
|
|
1370
1373
|
|
|
1371
|
-
class _EnableState
|
|
1374
|
+
class _EnableState:
|
|
1372
1375
|
DISABLING = "DISABLING"
|
|
1373
1376
|
DISABLED = "DISABLED"
|
|
1374
1377
|
ENABLING = "ENABLING"
|
|
1375
1378
|
ENABLED = "ENABLED"
|
|
1376
1379
|
|
|
1377
1380
|
|
|
1378
|
-
class AutoImporter
|
|
1381
|
+
class AutoImporter:
|
|
1379
1382
|
"""
|
|
1380
1383
|
Auto importer enable state.
|
|
1381
1384
|
|
|
1382
1385
|
The state is attached to an IPython "application".
|
|
1383
1386
|
"""
|
|
1384
1387
|
|
|
1388
|
+
db: ImportDB
|
|
1389
|
+
app: Any
|
|
1390
|
+
_state: _EnableState
|
|
1391
|
+
_disablers: List[Any]
|
|
1392
|
+
|
|
1393
|
+
_errored: bool
|
|
1394
|
+
_ip: Any
|
|
1395
|
+
_ast_transformer: Any
|
|
1396
|
+
_autoimported_this_cell: Dict[Any, Any]
|
|
1397
|
+
|
|
1385
1398
|
def __new__(cls, arg=Ellipsis):
|
|
1386
1399
|
"""
|
|
1387
1400
|
Get the AutoImporter for the given app, or create and assign one.
|
|
@@ -1418,7 +1431,7 @@ class AutoImporter(object):
|
|
|
1418
1431
|
raise TypeError("AutoImporter(): unexpected %s" % (clsname,))
|
|
1419
1432
|
|
|
1420
1433
|
@classmethod
|
|
1421
|
-
def _from_app(cls, app):
|
|
1434
|
+
def _from_app(cls, app) -> 'AutoImporter':
|
|
1422
1435
|
subapp = getattr(app, "subapp", None)
|
|
1423
1436
|
if subapp is not None:
|
|
1424
1437
|
app = subapp
|
|
@@ -1432,6 +1445,7 @@ class AutoImporter(object):
|
|
|
1432
1445
|
# Create a new instance and assign to the app.
|
|
1433
1446
|
self = cls._construct(app)
|
|
1434
1447
|
app.auto_importer = self
|
|
1448
|
+
self.db = ImportDB("")
|
|
1435
1449
|
return self
|
|
1436
1450
|
|
|
1437
1451
|
@classmethod
|
|
@@ -1517,7 +1531,6 @@ class AutoImporter(object):
|
|
|
1517
1531
|
self.app = app
|
|
1518
1532
|
logger.debug("app = %r", app)
|
|
1519
1533
|
ok = True
|
|
1520
|
-
ok &= self._enable_ipython_bugfixes()
|
|
1521
1534
|
ok &= self._enable_initializer_hooks(app)
|
|
1522
1535
|
ok &= self._enable_kernel_manager_hook(app)
|
|
1523
1536
|
ok &= self._enable_shell_hooks(app)
|
|
@@ -1681,67 +1694,6 @@ class AutoImporter(object):
|
|
|
1681
1694
|
finally:
|
|
1682
1695
|
format_kernel_cmd_with_autoimport.unadvise()
|
|
1683
1696
|
return True
|
|
1684
|
-
try:
|
|
1685
|
-
# Tested with IPython 1.0, 1.2, 2.0, 2.1, 2.2, 2.3, 2.4, 3.0, 3.1,
|
|
1686
|
-
# 3.2.
|
|
1687
|
-
from IPython.kernel.manager import KernelManager as IPythonKernelManager
|
|
1688
|
-
except ImportError:
|
|
1689
|
-
pass
|
|
1690
|
-
else:
|
|
1691
|
-
@self._advise(kernel_manager.start_kernel)
|
|
1692
|
-
def start_kernel_with_autoimport_ipython(*args, **kwargs):
|
|
1693
|
-
logger.debug("start_kernel()")
|
|
1694
|
-
# Advise format_kernel_cmd(), which is the function that
|
|
1695
|
-
# computes the command line for a subprocess to run a new
|
|
1696
|
-
# kernel. Note that we advise the method on the class, rather
|
|
1697
|
-
# than this instance of kernel_manager, because start_kernel()
|
|
1698
|
-
# actually creates a *new* KernelInstance for this.
|
|
1699
|
-
@advise(IPythonKernelManager.format_kernel_cmd)
|
|
1700
|
-
def format_kernel_cmd_with_autoimport(*args, **kwargs):
|
|
1701
|
-
result = __original__(*args, **kwargs)
|
|
1702
|
-
logger.debug("intercepting format_kernel_cmd(): orig = %r", result)
|
|
1703
|
-
if result[1:3] in [
|
|
1704
|
-
# IPython 3.x
|
|
1705
|
-
['-m', 'IPython.kernel'],
|
|
1706
|
-
# IPython 1.x, 2.x
|
|
1707
|
-
['-c', 'from IPython.kernel.zmq.kernelapp import main; main()'],
|
|
1708
|
-
]:
|
|
1709
|
-
result[1:3] = new_cmd
|
|
1710
|
-
logger.debug("intercepting format_kernel_cmd(): new = %r", result)
|
|
1711
|
-
return result
|
|
1712
|
-
else:
|
|
1713
|
-
logger.debug("intercepting format_kernel_cmd(): unexpected output; not modifying it")
|
|
1714
|
-
return result
|
|
1715
|
-
try:
|
|
1716
|
-
return __original__(*args, **kwargs)
|
|
1717
|
-
finally:
|
|
1718
|
-
format_kernel_cmd_with_autoimport.unadvise()
|
|
1719
|
-
return True
|
|
1720
|
-
# Tested with IPython 0.12, 0.13
|
|
1721
|
-
try:
|
|
1722
|
-
import IPython.zmq.ipkernel
|
|
1723
|
-
except ImportError:
|
|
1724
|
-
pass
|
|
1725
|
-
else:
|
|
1726
|
-
@self._advise(kernel_manager.start_kernel)
|
|
1727
|
-
def start_kernel_with_autoimport013(*args, **kwargs):
|
|
1728
|
-
logger.debug("start_kernel()")
|
|
1729
|
-
@advise((IPython.zmq.ipkernel, 'base_launch_kernel'))
|
|
1730
|
-
def base_launch_kernel_with_autoimport(cmd, *args, **kwargs):
|
|
1731
|
-
logger.debug("base_launch_kernel()")
|
|
1732
|
-
expected_cmd = 'from IPython.zmq.ipkernel import main; main()'
|
|
1733
|
-
if cmd != expected_cmd:
|
|
1734
|
-
logger.debug("unexpected command, not modifying it: %r", cmd)
|
|
1735
|
-
else:
|
|
1736
|
-
cmd = (
|
|
1737
|
-
'from pyflyby._interactive import start_ipython_kernel_with_autoimporter; '
|
|
1738
|
-
'start_ipython_kernel_with_autoimporter()')
|
|
1739
|
-
return __original__(cmd, *args, **kwargs)
|
|
1740
|
-
try:
|
|
1741
|
-
return __original__(*args, **kwargs)
|
|
1742
|
-
finally:
|
|
1743
|
-
base_launch_kernel_with_autoimport.unadvise()
|
|
1744
|
-
return True
|
|
1745
1697
|
logger.debug("Couldn't enable start_kernel hook")
|
|
1746
1698
|
return False
|
|
1747
1699
|
|
|
@@ -1886,14 +1838,6 @@ class AutoImporter(object):
|
|
|
1886
1838
|
self.reset_state_new_cell()
|
|
1887
1839
|
return __original__()
|
|
1888
1840
|
return True
|
|
1889
|
-
elif hasattr(ip, "resetbuffer"):
|
|
1890
|
-
# Tested with IPython 0.10.
|
|
1891
|
-
@self._advise(ip.resetbuffer)
|
|
1892
|
-
def resetbuffer_and_autoimporter_state():
|
|
1893
|
-
logger.debug("resetbuffer_and_autoimporter_state")
|
|
1894
|
-
self.reset_state_new_cell()
|
|
1895
|
-
return __original__()
|
|
1896
|
-
return True
|
|
1897
1841
|
else:
|
|
1898
1842
|
logger.debug("Couldn't enable reset hook")
|
|
1899
1843
|
return False
|
|
@@ -2045,15 +1989,6 @@ class AutoImporter(object):
|
|
|
2045
1989
|
__original__, compile=self.compile_with_autoimport)
|
|
2046
1990
|
return wrapped(*args, **kwargs)
|
|
2047
1991
|
return True
|
|
2048
|
-
elif hasattr(ip, 'magic_time'):
|
|
2049
|
-
# Tested with IPython 0.10, 0.11, 0.12
|
|
2050
|
-
@self._advise(ip.magic_time)
|
|
2051
|
-
def magic_time_with_autoimport(*args, **kwargs):
|
|
2052
|
-
logger.debug("time_with_autoimport()")
|
|
2053
|
-
wrapped = FunctionWithGlobals(
|
|
2054
|
-
__original__, compile=self.compile_with_autoimport)
|
|
2055
|
-
return wrapped(*args, **kwargs)
|
|
2056
|
-
return True
|
|
2057
1992
|
else:
|
|
2058
1993
|
logger.debug("Couldn't enable time hook")
|
|
2059
1994
|
return False
|
|
@@ -2079,15 +2014,6 @@ class AutoImporter(object):
|
|
|
2079
2014
|
__original__, compile=self.compile_with_autoimport)
|
|
2080
2015
|
return wrapped(*args, **kwargs)
|
|
2081
2016
|
return True
|
|
2082
|
-
elif hasattr(ip, 'magic_timeit'):
|
|
2083
|
-
# Tested with IPython 0.10, 0.11, 0.12
|
|
2084
|
-
@self._advise(ip.magic_timeit)
|
|
2085
|
-
def magic_timeit_with_autoimport(*args, **kwargs):
|
|
2086
|
-
logger.debug("timeit_with_autoimport()")
|
|
2087
|
-
wrapped = FunctionWithGlobals(
|
|
2088
|
-
__original__, compile=self.compile_with_autoimport)
|
|
2089
|
-
return wrapped(*args, **kwargs)
|
|
2090
|
-
return True
|
|
2091
2017
|
else:
|
|
2092
2018
|
logger.debug("Couldn't enable timeit hook")
|
|
2093
2019
|
return False
|
|
@@ -2126,24 +2052,6 @@ class AutoImporter(object):
|
|
|
2126
2052
|
__original__, profile=ProfileFactory_with_autoimport())
|
|
2127
2053
|
return wrapped(*args, **kwargs)
|
|
2128
2054
|
return True
|
|
2129
|
-
elif hasattr(ip, "magic_prun"):
|
|
2130
|
-
# Tested with IPython 0.10, 0.11, 0.12.
|
|
2131
|
-
class ProfileFactory_with_autoimport(object):
|
|
2132
|
-
def Profile(self_, *args):
|
|
2133
|
-
import profile
|
|
2134
|
-
p = profile.Profile()
|
|
2135
|
-
@advise(p.runctx)
|
|
2136
|
-
def runctx_with_autoimport(cmd, globals, locals):
|
|
2137
|
-
self.auto_import(cmd, [globals, locals])
|
|
2138
|
-
return __original__(cmd, globals, locals)
|
|
2139
|
-
return p
|
|
2140
|
-
@self._advise(ip.magic_prun)
|
|
2141
|
-
def magic_prun_with_autoimport(*args, **kwargs):
|
|
2142
|
-
logger.debug("magic_prun_with_autoimport()")
|
|
2143
|
-
wrapped = FunctionWithGlobals(
|
|
2144
|
-
__original__, profile=ProfileFactory_with_autoimport())
|
|
2145
|
-
return wrapped(*args, **kwargs)
|
|
2146
|
-
return True
|
|
2147
2055
|
else:
|
|
2148
2056
|
logger.debug("Couldn't enable prun hook")
|
|
2149
2057
|
return False
|
|
@@ -2335,41 +2243,6 @@ class AutoImporter(object):
|
|
|
2335
2243
|
# python-2.x); we patch it here.
|
|
2336
2244
|
return True
|
|
2337
2245
|
|
|
2338
|
-
def _enable_ipython_bugfixes(self):
|
|
2339
|
-
"""
|
|
2340
|
-
Enable some advice that's actually just fixing bugs in IPython.
|
|
2341
|
-
"""
|
|
2342
|
-
ok = True
|
|
2343
|
-
ok &= self._enable_ipython_bugfixes_LevelFormatter()
|
|
2344
|
-
return ok
|
|
2345
|
-
|
|
2346
|
-
def _enable_ipython_bugfixes_LevelFormatter(self):
|
|
2347
|
-
# New versions of IPython complain if you import 'IPython.config'.
|
|
2348
|
-
# Old versions of IPython already have it imported.
|
|
2349
|
-
if 'IPython.config' not in sys.modules:
|
|
2350
|
-
return True
|
|
2351
|
-
try:
|
|
2352
|
-
from IPython.config.application import LevelFormatter
|
|
2353
|
-
except ImportError:
|
|
2354
|
-
return True
|
|
2355
|
-
if (not issubclass(LevelFormatter, object) and
|
|
2356
|
-
"super" in LevelFormatter.format.__func__.__code__.co_names and
|
|
2357
|
-
"logging" not in LevelFormatter.format.__func__.__code__.co_names):
|
|
2358
|
-
# In IPython 1.0, LevelFormatter uses super(), which assumes
|
|
2359
|
-
# that logging.Formatter is a subclass of object. However,
|
|
2360
|
-
# this is only true in Python 2.7+, not in Python 2.6. So
|
|
2361
|
-
# Python 2.6 + IPython 1.0 causes problems. IPython 1.2
|
|
2362
|
-
# already includes this fix.
|
|
2363
|
-
from logging import Formatter
|
|
2364
|
-
@self._advise(LevelFormatter.format)
|
|
2365
|
-
def format_patched(self, record):
|
|
2366
|
-
if record.levelno >= self.highlevel_limit:
|
|
2367
|
-
record.highlevel = self.highlevel_format % record.__dict__
|
|
2368
|
-
else:
|
|
2369
|
-
record.highlevel = ""
|
|
2370
|
-
return Formatter.format(self, record)
|
|
2371
|
-
return True
|
|
2372
|
-
|
|
2373
2246
|
def disable(self):
|
|
2374
2247
|
"""
|
|
2375
2248
|
Turn off auto-importer in the current IPython session.
|
|
@@ -2464,7 +2337,8 @@ class AutoImporter(object):
|
|
|
2464
2337
|
send_comm_message(MISSING_IMPORTS, {"missing_imports": str(imp)})
|
|
2465
2338
|
|
|
2466
2339
|
return self._safe_call(
|
|
2467
|
-
auto_import, arg, namespaces,
|
|
2340
|
+
auto_import, arg=arg, namespaces=namespaces,
|
|
2341
|
+
extra_db=self.db,
|
|
2468
2342
|
autoimported=self._autoimported_this_cell,
|
|
2469
2343
|
raise_on_error=raise_on_error, on_error=on_error,
|
|
2470
2344
|
post_import_hook=post_import_hook)
|
|
@@ -2567,6 +2441,8 @@ def load_ipython_extension(arg=Ellipsis):
|
|
|
2567
2441
|
os.path.dirname(__file__))
|
|
2568
2442
|
# Turn on the auto-importer.
|
|
2569
2443
|
auto_importer = AutoImporter(arg)
|
|
2444
|
+
if arg is not Ellipsis:
|
|
2445
|
+
arg._auto_importer = auto_importer
|
|
2570
2446
|
auto_importer.enable(even_if_previously_errored=True)
|
|
2571
2447
|
# Clear ImportDB cache.
|
|
2572
2448
|
ImportDB.clear_default_cache()
|
|
@@ -2584,6 +2460,7 @@ def load_ipython_extension(arg=Ellipsis):
|
|
|
2584
2460
|
enable_signal_handler_debugger()
|
|
2585
2461
|
enable_sigterm_handler(on_existing_handler='keep_existing')
|
|
2586
2462
|
add_debug_functions_to_builtins()
|
|
2463
|
+
inject_dynamic_import()
|
|
2587
2464
|
initialize_comms()
|
|
2588
2465
|
|
|
2589
2466
|
|
pyflyby/_parse.py
CHANGED
|
@@ -23,10 +23,13 @@ import types
|
|
|
23
23
|
from typing import Any, List, Optional, Tuple, Union, cast
|
|
24
24
|
import warnings
|
|
25
25
|
|
|
26
|
+
|
|
26
27
|
_sentinel = object()
|
|
27
28
|
|
|
28
29
|
if sys.version_info < (3, 10):
|
|
29
30
|
|
|
31
|
+
NoneType = type(None)
|
|
32
|
+
|
|
30
33
|
class MatchAs:
|
|
31
34
|
name: str
|
|
32
35
|
pattern: ast.AST
|
|
@@ -36,6 +39,7 @@ if sys.version_info < (3, 10):
|
|
|
36
39
|
patterns: List[MatchAs]
|
|
37
40
|
|
|
38
41
|
else:
|
|
42
|
+
from types import NoneType
|
|
39
43
|
from ast import MatchAs, MatchMapping
|
|
40
44
|
|
|
41
45
|
|
|
@@ -208,6 +212,7 @@ def _iter_child_nodes_in_order_internal_1(node):
|
|
|
208
212
|
yield node.name,
|
|
209
213
|
elif isinstance(node, MatchMapping):
|
|
210
214
|
for k, p in zip(node.keys, node.patterns):
|
|
215
|
+
pass
|
|
211
216
|
yield k, p
|
|
212
217
|
else:
|
|
213
218
|
# Default behavior.
|
|
@@ -962,6 +967,9 @@ class PythonBlock:
|
|
|
962
967
|
:rtype:
|
|
963
968
|
`PythonBlock`
|
|
964
969
|
"""
|
|
970
|
+
if isinstance(filename, str):
|
|
971
|
+
filename = Filename(filename)
|
|
972
|
+
assert isinstance(filename, (Filename, NoneType)), filename
|
|
965
973
|
text = FileText(text, filename=filename, startpos=startpos)
|
|
966
974
|
self = object.__new__(cls)
|
|
967
975
|
self.text = text
|
|
@@ -973,7 +981,7 @@ class PythonBlock:
|
|
|
973
981
|
def __construct_from_annotated_ast(cls, annotated_ast_nodes, text:FileText, flags):
|
|
974
982
|
# Constructor for internal use by _split_by_statement() or
|
|
975
983
|
# concatenate().
|
|
976
|
-
ast_node = AnnotatedModule(annotated_ast_nodes)
|
|
984
|
+
ast_node = AnnotatedModule(annotated_ast_nodes, type_ignores=[])
|
|
977
985
|
ast_node.text = text
|
|
978
986
|
ast_node.flags = flags
|
|
979
987
|
if not hasattr(ast_node, "source_flags"):
|
pyflyby/_py.py
CHANGED
|
@@ -343,11 +343,11 @@ $ py IPython shell
|
|
|
343
343
|
# TODO: add --profile, --runsnake
|
|
344
344
|
|
|
345
345
|
import ast
|
|
346
|
+
import builtins
|
|
346
347
|
from contextlib import contextmanager
|
|
347
348
|
import inspect
|
|
348
349
|
import os
|
|
349
350
|
import re
|
|
350
|
-
import builtins
|
|
351
351
|
import sys
|
|
352
352
|
import types
|
|
353
353
|
from types import FunctionType, MethodType
|
|
@@ -1303,7 +1303,7 @@ def _has_python_shebang(filename):
|
|
|
1303
1303
|
Note that this test is only needed for scripts found via which(), since
|
|
1304
1304
|
otherwise the shebang is not necessary.
|
|
1305
1305
|
"""
|
|
1306
|
-
filename
|
|
1306
|
+
assert isinstance(filename, Filename)
|
|
1307
1307
|
with open(str(filename), 'rb') as f:
|
|
1308
1308
|
line = f.readline(1024)
|
|
1309
1309
|
return line.startswith(b"#!") and b"python" in line
|
pyflyby/_version.py
CHANGED