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.

Files changed (40) hide show
  1. pyflyby/__init__.py +1 -0
  2. pyflyby/_autoimp.py +51 -5
  3. pyflyby/_cmdline.py +6 -3
  4. pyflyby/_dynimp.py +152 -0
  5. pyflyby/_file.py +37 -20
  6. pyflyby/_importclns.py +30 -14
  7. pyflyby/_importdb.py +133 -45
  8. pyflyby/_interactive.py +22 -145
  9. pyflyby/_parse.py +9 -1
  10. pyflyby/_py.py +2 -2
  11. pyflyby/_version.py +1 -1
  12. {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/METADATA +32 -1
  13. pyflyby-1.9.5.dist-info/RECORD +55 -0
  14. {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/WHEEL +1 -1
  15. pyflyby-1.9.4.dist-info/RECORD +0 -54
  16. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/canonical.py +0 -0
  17. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/common.py +0 -0
  18. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/forget.py +0 -0
  19. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/mandatory.py +0 -0
  20. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/numpy.py +0 -0
  21. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/etc/pyflyby/std.py +0 -0
  22. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/libexec/pyflyby/colordiff +0 -0
  23. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/libexec/pyflyby/diff-colorize +0 -0
  24. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/doc/pyflyby/LICENSE.txt +0 -0
  25. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/doc/pyflyby/TODO.txt +0 -0
  26. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/doc/pyflyby/testing.txt +0 -0
  27. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/data/share/emacs/site-lisp/pyflyby.el +0 -0
  28. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/collect-exports +0 -0
  29. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/collect-imports +0 -0
  30. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/find-import +0 -0
  31. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/list-bad-xrefs +0 -0
  32. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/prune-broken-imports +0 -0
  33. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/pyflyby-diff +0 -0
  34. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/reformat-imports +0 -0
  35. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/replace-star-imports +0 -0
  36. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/tidy-imports +0 -0
  37. {pyflyby-1.9.4.data → pyflyby-1.9.5.data}/scripts/transform-imports +0 -0
  38. {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/LICENSE.txt +0 -0
  39. {pyflyby-1.9.4.dist-info → pyflyby-1.9.5.dist-info}/entry_points.txt +0 -0
  40. {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 pyflyby._file import Filename, expand_py_files_from_args, UnsafeFilenameError
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
- from typing import Dict, Any
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
- pathnames = [Filename(fn) for fn in pathnames]
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 = Filename(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 = Filename(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(object):
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 cls._default_cache:
212
- if logger.debug_enabled:
213
- allpyfiles = set()
214
- for tup in cls._default_cache:
215
- if tup[0] != 2:
216
- continue
217
- for tup2 in tup[1:]:
218
- for f in tup2:
219
- assert isinstance(f, Filename)
220
- if f.ext == '.py':
221
- allpyfiles.add(f)
222
- nfiles = len(allpyfiles)
223
- logger.debug("ImportDB: Clearing default cache of %d files",
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 target_filenames in a number of steps.
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
- target_filename = Filename(target_filename or ".")
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
- return cls._default_cache[cache_keys[-1]]
267
- except KeyError:
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 "SUPPORT DEPRECATED BEHAVIOR":
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
- default_path, target_dirname)
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
- filenames = [Filename(f) for f in filenames]
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 "SUPPORT DEPRECATED BEHAVIOR":
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(object):
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(object):
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 = Filename(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
@@ -4,4 +4,4 @@
4
4
  # http://creativecommons.org/publicdomain/zero/1.0/
5
5
 
6
6
 
7
- __version__ = "1.9.4"
7
+ __version__ = "1.9.5"