pyflyby 1.9.1__tar.gz → 1.9.2__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.

Files changed (149) hide show
  1. {pyflyby-1.9.1/lib/python/pyflyby.egg-info → pyflyby-1.9.2}/PKG-INFO +1 -1
  2. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_autoimp.py +3 -3
  3. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_cmdline.py +4 -4
  4. {pyflyby-1.9.1/lib/python → pyflyby-1.9.2/bin}/pyflyby/_file.py +31 -17
  5. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_imports2s.py +15 -11
  6. {pyflyby-1.9.1/lib/python → pyflyby-1.9.2/bin}/pyflyby/_parse.py +32 -11
  7. {pyflyby-1.9.1/lib/python → pyflyby-1.9.2/bin}/pyflyby/_version.py +1 -1
  8. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/tidy-imports +0 -4
  9. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_autoimp.py +3 -3
  10. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_cmdline.py +4 -4
  11. {pyflyby-1.9.1/bin → pyflyby-1.9.2/lib/python}/pyflyby/_file.py +31 -17
  12. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_imports2s.py +15 -11
  13. {pyflyby-1.9.1/bin → pyflyby-1.9.2/lib/python}/pyflyby/_parse.py +32 -11
  14. {pyflyby-1.9.1/bin → pyflyby-1.9.2/lib/python}/pyflyby/_version.py +1 -1
  15. {pyflyby-1.9.1 → pyflyby-1.9.2/lib/python/pyflyby.egg-info}/PKG-INFO +1 -1
  16. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_imports2s.py +35 -0
  17. {pyflyby-1.9.1 → pyflyby-1.9.2}/.pyflyby +0 -0
  18. {pyflyby-1.9.1 → pyflyby-1.9.2}/LICENSE.txt +0 -0
  19. {pyflyby-1.9.1 → pyflyby-1.9.2}/MANIFEST.in +0 -0
  20. {pyflyby-1.9.1 → pyflyby-1.9.2}/README.rst +0 -0
  21. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/autoipython +0 -0
  22. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/autopython +0 -0
  23. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/collect-exports +0 -0
  24. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/collect-imports +0 -0
  25. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/create-imports +0 -0
  26. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/find-import +0 -0
  27. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/list-bad-xrefs +0 -0
  28. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/prune-broken-imports +0 -0
  29. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/py +0 -0
  30. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/__init__.py +0 -0
  31. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/__main__.py +0 -0
  32. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_comms.py +0 -0
  33. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_dbg.py +0 -0
  34. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_docxref.py +0 -0
  35. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_flags.py +0 -0
  36. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_format.py +0 -0
  37. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_idents.py +0 -0
  38. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_importclns.py +0 -0
  39. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_importdb.py +0 -0
  40. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_importstmt.py +0 -0
  41. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_interactive.py +0 -0
  42. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_livepatch.py +0 -0
  43. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_log.py +0 -0
  44. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_modules.py +0 -0
  45. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_py.py +0 -0
  46. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_util.py +0 -0
  47. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/autoimport.py +0 -0
  48. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/importdb.py +0 -0
  49. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby-diff +0 -0
  50. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/reformat-imports +0 -0
  51. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/replace-star-imports +0 -0
  52. {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/transform-imports +0 -0
  53. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/LICENSE.txt +0 -0
  54. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/Makefile +0 -0
  55. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/TODO.txt +0 -0
  56. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/__init__.py +0 -0
  57. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/api.rst +0 -0
  58. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/autoimp.rst +0 -0
  59. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/cmdline.rst +0 -0
  60. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/comms.rst +0 -0
  61. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/dbg.rst +0 -0
  62. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/file.rst +0 -0
  63. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/flags.rst +0 -0
  64. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/format.rst +0 -0
  65. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/idents.rst +0 -0
  66. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/importclns.rst +0 -0
  67. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/importdb.rst +0 -0
  68. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/imports2s.rst +0 -0
  69. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/importstmt.rst +0 -0
  70. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/interactive.rst +0 -0
  71. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/livepatch.rst +0 -0
  72. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/log.rst +0 -0
  73. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/modules.rst +0 -0
  74. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/parse.rst +0 -0
  75. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/py.rst +0 -0
  76. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/util.rst +0 -0
  77. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/autoipython.rst +0 -0
  78. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/cli.rst +0 -0
  79. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/collect_exports.rst +0 -0
  80. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/collect_imports.rst +0 -0
  81. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/find_import.rst +0 -0
  82. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/prune_broken_imports.rst +0 -0
  83. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/py.rst +0 -0
  84. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/pyflyby_diff.rst +0 -0
  85. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/reformat_imports.rst +0 -0
  86. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/replace_star_imports.rst +0 -0
  87. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/tidy_imports.rst +0 -0
  88. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/transform_imports.rst +0 -0
  89. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/conf.py +0 -0
  90. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/index.rst +0 -0
  91. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/make.bat +0 -0
  92. {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/testing.txt +0 -0
  93. {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/canonical.py +0 -0
  94. {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/common.py +0 -0
  95. {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/forget.py +0 -0
  96. {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/mandatory.py +0 -0
  97. {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/numpy.py +0 -0
  98. {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/std.py +0 -0
  99. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/emacs/pyflyby.el +0 -0
  100. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/__init__.py +0 -0
  101. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/__main__.py +0 -0
  102. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_comms.py +0 -0
  103. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_dbg.py +0 -0
  104. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_docxref.py +0 -0
  105. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_flags.py +0 -0
  106. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_format.py +0 -0
  107. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_idents.py +0 -0
  108. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_importclns.py +0 -0
  109. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_importdb.py +0 -0
  110. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_importstmt.py +0 -0
  111. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_interactive.py +0 -0
  112. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_livepatch.py +0 -0
  113. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_log.py +0 -0
  114. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_modules.py +0 -0
  115. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_py.py +0 -0
  116. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_util.py +0 -0
  117. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/autoimport.py +0 -0
  118. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/importdb.py +0 -0
  119. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/SOURCES.txt +0 -0
  120. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/dependency_links.txt +0 -0
  121. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/entry_points.txt +0 -0
  122. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/requires.txt +0 -0
  123. {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/top_level.txt +0 -0
  124. {pyflyby-1.9.1 → pyflyby-1.9.2}/libexec/pyflyby/colordiff +0 -0
  125. {pyflyby-1.9.1 → pyflyby-1.9.2}/libexec/pyflyby/diff-colorize +0 -0
  126. {pyflyby-1.9.1 → pyflyby-1.9.2}/setup.cfg +0 -0
  127. {pyflyby-1.9.1 → pyflyby-1.9.2}/setup.py +0 -0
  128. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/__init__.py +0 -0
  129. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_0testconfig.py +0 -0
  130. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_autoimp.py +0 -0
  131. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_cmdline.py +0 -0
  132. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_docxref.py +0 -0
  133. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_file.py +0 -0
  134. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_flags.py +0 -0
  135. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_format.py +0 -0
  136. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_idents.py +0 -0
  137. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_importclns.py +0 -0
  138. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_importdb.py +0 -0
  139. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_importstmt.py +0 -0
  140. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_interactive.py +0 -0
  141. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_jupyterlab_pyflyby.py +0 -0
  142. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_livepatch.py +0 -0
  143. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_modules.py +0 -0
  144. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_parse.py +0 -0
  145. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_py.py +0 -0
  146. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_util.py +0 -0
  147. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/tests_sorts.py +0 -0
  148. {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/xrefs.py +0 -0
  149. {pyflyby-1.9.1 → pyflyby-1.9.2}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyflyby
3
- Version: 1.9.1
3
+ Version: 1.9.2
4
4
  Summary: pyflyby - Python development productivity tools, in particular automatic import management
5
5
  Home-page: https://pypi.org/project/pyflyby/
6
6
  Author: Karl Chen
@@ -609,11 +609,11 @@ class _MissingImportFinder(object):
609
609
  if self._in_class_def == 0:
610
610
  self.scopestack._class_delayed[node.name] = None
611
611
  with self._NewScopeCtx(new_class_scope=True):
612
- if not self._in_class_def:
613
- self._in_class_def += 1
614
- self._visit_Store(node.name)
612
+ self._in_class_def += 1
613
+ self._visit_Store(node.name)
615
614
  self.visit(node.body)
616
615
  self._in_class_def -= 1
616
+ assert self._in_class_def >= 0
617
617
  self._remove_from_missing_imports(node.name)
618
618
  self._visit_Store(node.name)
619
619
 
@@ -7,11 +7,11 @@
7
7
  import optparse
8
8
  import os
9
9
  import signal
10
- from six import reraise
11
- from six.moves import input
10
+ from builtins import input
12
11
  import sys
13
12
  from textwrap import dedent
14
13
  import traceback
14
+ from typing import List
15
15
 
16
16
 
17
17
  from pyflyby._file import (FileText, Filename, atomic_write_file,
@@ -376,7 +376,7 @@ class Modifier(object):
376
376
  f.close()
377
377
 
378
378
 
379
- def process_actions(filenames, actions, modify_function,
379
+ def process_actions(filenames:List[str], actions, modify_function,
380
380
  reraise_exceptions=()):
381
381
  errors = []
382
382
  def on_error_filename_arg(arg):
@@ -408,7 +408,7 @@ def process_actions(filenames, actions, modify_function,
408
408
  # Exception takes more than one argument
409
409
  pass
410
410
  if logger.debug_enabled:
411
- reraise(type_e, e, tb)
411
+ raise
412
412
  traceback.print_exception(type(e), e, tb)
413
413
  finally:
414
414
  tb = None # avoid refcycles involving tb
@@ -4,13 +4,14 @@
4
4
 
5
5
 
6
6
 
7
- from functools import total_ordering
7
+ from functools import total_ordering, cached_property
8
8
  import io
9
9
  import os
10
10
  import re
11
11
  import sys
12
+ from typing import Optional, Tuple
12
13
 
13
- from pyflyby._util import cached_attribute, cmp, memoize
14
+ from pyflyby._util import cmp, memoize
14
15
 
15
16
 
16
17
  class UnsafeFilenameError(ValueError):
@@ -28,6 +29,8 @@ class Filename(object):
28
29
  Filename('/etc/passwd')
29
30
 
30
31
  """
32
+ _filename: str
33
+
31
34
  def __new__(cls, arg):
32
35
  if isinstance(arg, cls):
33
36
  return arg
@@ -85,7 +88,7 @@ class Filename(object):
85
88
  return NotImplemented
86
89
  return cmp(self._filename, o._filename)
87
90
 
88
- @cached_attribute
91
+ @cached_property
89
92
  def ext(self):
90
93
  """
91
94
  Returns the extension of this filename, including the dot.
@@ -99,15 +102,15 @@ class Filename(object):
99
102
  return None
100
103
  return dot + rhs
101
104
 
102
- @cached_attribute
105
+ @cached_property
103
106
  def base(self):
104
107
  return os.path.basename(self._filename)
105
108
 
106
- @cached_attribute
109
+ @cached_property
107
110
  def dir(self):
108
111
  return type(self)(os.path.dirname(self._filename))
109
112
 
110
- @cached_attribute
113
+ @cached_property
111
114
  def real(self):
112
115
  return type(self)(os.path.realpath(self._filename))
113
116
 
@@ -230,6 +233,9 @@ class FilePos(object):
230
233
  Both lineno and colno are 1-indexed.
231
234
  """
232
235
 
236
+ lineno: int
237
+ colno: int
238
+
233
239
  def __new__(cls, *args):
234
240
  if len(args) == 0:
235
241
  return cls._ONE_ONE
@@ -265,7 +271,7 @@ class FilePos(object):
265
271
  raise TypeError("Expected (int,int); got %r" % (args,))
266
272
 
267
273
  @classmethod
268
- def _from_lc(cls, lineno, colno):
274
+ def _from_lc(cls, lineno:int, colno:int):
269
275
  self = object.__new__(cls)
270
276
  self.lineno = lineno
271
277
  self.colno = colno
@@ -338,6 +344,10 @@ class FileText:
338
344
  Represents a contiguous sequence of lines from a file.
339
345
  """
340
346
 
347
+ filename: Optional[Filename]
348
+ startpos: FilePos
349
+ _lines: Optional[Tuple[str, ...]] = None
350
+
341
351
  def __new__(cls, arg, filename=None, startpos=None):
342
352
  """
343
353
  Return a new ``FileText`` instance.
@@ -371,7 +381,7 @@ class FileText:
371
381
  return FileText(arg.__text__(), filename=filename, startpos=startpos)
372
382
  elif isinstance(arg, str):
373
383
  self = object.__new__(cls)
374
- self.joined = arg
384
+ self._lines = tuple(arg.split('\n'))
375
385
  else:
376
386
  raise TypeError("%s: unexpected %s"
377
387
  % (cls.__name__, type(arg).__name__))
@@ -383,19 +393,21 @@ class FileText:
383
393
  return self
384
394
 
385
395
  @classmethod
386
- def _from_lines(cls, lines, filename, startpos):
396
+ def _from_lines(cls, lines, filename: Optional[Filename], startpos: FilePos):
387
397
  assert type(lines) is tuple
388
398
  assert len(lines) > 0
389
399
  assert isinstance(lines[0], str)
390
400
  assert not lines[-1].endswith("\n")
401
+ assert isinstance(startpos, FilePos), repr(startpos)
402
+ assert isinstance(filename, (Filename, type(None))), repr(filename)
391
403
  self = object.__new__(cls)
392
- self.lines = lines
404
+ self._lines = tuple(lines)
393
405
  self.filename = filename
394
406
  self.startpos = startpos
395
407
  return self
396
408
 
397
- @cached_attribute
398
- def lines(self):
409
+ @cached_property
410
+ def lines(self) -> Tuple[str, ...]:
399
411
  r"""
400
412
  Lines that have been split by newline.
401
413
 
@@ -408,16 +420,19 @@ class FileText:
408
420
  :rtype:
409
421
  ``tuple`` of ``str``
410
422
  """
423
+ if self._lines is not None:
424
+ return self._lines
411
425
  # Used if only initialized with 'joined'.
412
426
  # We use str.split() instead of str.splitlines() because the latter
413
427
  # doesn't distinguish between strings that end in newline or not
414
428
  # (or requires extra work to process if we use splitlines(True)).
415
429
  return tuple(self.joined.split('\n'))
416
430
 
417
- @cached_attribute
418
- def joined(self): # used if only initialized with 'lines'
431
+ @cached_property
432
+ def joined(self) -> str:
419
433
  return '\n'.join(self.lines)
420
434
 
435
+
421
436
  @classmethod
422
437
  def from_filename(cls, filename):
423
438
  return cls.from_lines(Filename(filename))
@@ -435,13 +450,12 @@ class FileText:
435
450
  return self
436
451
  else:
437
452
  result = object.__new__(type(self))
438
- result.lines = self.lines
439
- result.joined = self.joined
453
+ result._lines = self._lines
440
454
  result.filename = filename
441
455
  result.startpos = startpos
442
456
  return result
443
457
 
444
- @cached_attribute
458
+ @cached_property
445
459
  def endpos(self):
446
460
  """
447
461
  The position after the last character in the text.
@@ -3,7 +3,6 @@
3
3
  # License: MIT http://opensource.org/licenses/MIT
4
4
  from collections import defaultdict
5
5
 
6
- import isort
7
6
  from pyflyby._autoimp import scan_for_import_issues
8
7
  from pyflyby._file import FileText, Filename
9
8
  from pyflyby._flags import CompilerFlags
@@ -14,10 +13,12 @@ from pyflyby._log import logger
14
13
  from pyflyby._parse import PythonBlock
15
14
  from pyflyby._util import ImportPathCtx, Inf, NullCtx, memoize
16
15
  import re
17
- from six import exec_
18
16
 
19
17
 
20
18
  class SourceToSourceTransformationBase(object):
19
+
20
+ input: PythonBlock
21
+
21
22
  def __new__(cls, arg):
22
23
  if isinstance(arg, cls):
23
24
  return arg
@@ -52,11 +53,15 @@ class SourceToSourceTransformationBase(object):
52
53
 
53
54
 
54
55
  class SourceToSourceTransformation(SourceToSourceTransformationBase):
56
+
57
+ _output: PythonBlock
58
+
55
59
  def preprocess(self):
56
- self.output = self.input
60
+ assert isinstance(self.input, PythonBlock), self.input
61
+ self._output = self.input
57
62
 
58
63
  def pretty_print(self, params=None):
59
- return self.output.text
64
+ return self._output.text
60
65
 
61
66
 
62
67
  class SourceToSourceImportBlockTransformation(SourceToSourceTransformationBase):
@@ -195,12 +200,10 @@ class SourceToSourceFileImportsTransformation(SourceToSourceTransformationBase):
195
200
  # insert in the middle.
196
201
  self.blocks[:1] = (
197
202
  [SourceToSourceTransformation(
198
- PythonBlock.concatenate(statements[:idx],
199
- assume_contiguous=True))] +
203
+ PythonBlock.concatenate(statements[:idx]))] +
200
204
  blocks +
201
205
  [SourceToSourceTransformation(
202
- PythonBlock.concatenate(statements[idx:],
203
- assume_contiguous=True))])
206
+ PythonBlock.concatenate(statements[idx:]))])
204
207
  break
205
208
  else:
206
209
  # First block is entirely comments, so just insert after it.
@@ -214,7 +217,7 @@ class SourceToSourceFileImportsTransformation(SourceToSourceTransformationBase):
214
217
  """
215
218
  block = SourceToSourceImportBlockTransformation("")
216
219
  sepblock = SourceToSourceTransformation("")
217
- sepblock.output = PythonBlock("\n")
220
+ sepblock._output = PythonBlock("\n")
218
221
  self.insert_new_blocks_after_comments([block, sepblock])
219
222
  self.import_blocks.insert(0, block)
220
223
  return block
@@ -433,7 +436,7 @@ def remove_broken_imports(codeblock, params=None):
433
436
  for imp in list(block.importset.imports):
434
437
  ns = {}
435
438
  try:
436
- exec_(imp.pretty_print(), ns)
439
+ exec(imp.pretty_print(), ns)
437
440
  except Exception as e:
438
441
  logger.info("%s: Could not import %r; removing it: %s: %s",
439
442
  filename, imp.fullname, type(e).__name__, e)
@@ -540,6 +543,7 @@ def sort_imports(codeblock):
540
543
  :param codeblock:
541
544
  :return: codeblock
542
545
  """
546
+ import isort
543
547
  sorted_imports = isort.code(
544
548
  str(codeblock),
545
549
  # To sort all the import in lexicographic order
@@ -644,7 +648,7 @@ def transform_imports(codeblock, transformations, params=None):
644
648
  output_imports = [ transform_import(imp) for imp in input_imports ]
645
649
  block.importset = ImportSet(output_imports, ignore_shadowed=True)
646
650
  else:
647
- block.output = transform_block(block.input)
651
+ block._output = transform_block(block.input)
648
652
  return transformer.output(params=params)
649
653
 
650
654
 
@@ -1,7 +1,7 @@
1
1
  # pyflyby/_parse.py.
2
2
  # Copyright (C) 2011, 2012, 2013, 2014, 2015, 2018 Karl Chen.
3
3
  # License: MIT http://opensource.org/licenses/MIT
4
-
4
+ from __future__ import annotations
5
5
 
6
6
 
7
7
  import ast
@@ -13,6 +13,8 @@ import re
13
13
  import sys
14
14
  from textwrap import dedent
15
15
  import types
16
+ from typing import Optional
17
+ import warnings
16
18
 
17
19
  from pyflyby._file import FilePos, FileText, Filename
18
20
  from pyflyby._flags import CompilerFlags
@@ -22,6 +24,8 @@ from pyflyby._util import cached_attribute, cmp
22
24
 
23
25
  from ast import TypeIgnore, AsyncFunctionDef
24
26
 
27
+ _sentinel = object()
28
+
25
29
 
26
30
  def _is_comment_or_blank(line):
27
31
  """
@@ -741,7 +745,7 @@ class _DummyAst_Node(object):
741
745
  pass
742
746
 
743
747
 
744
- class PythonStatement(object):
748
+ class PythonStatement:
745
749
  r"""
746
750
  Representation of a top-level Python statement or consecutive
747
751
  comments/blank lines.
@@ -753,7 +757,9 @@ class PythonStatement(object):
753
757
  top-level AST node.
754
758
  """
755
759
 
756
- def __new__(cls, arg, filename=None, startpos=None, flags=None):
760
+ block: PythonBlock
761
+
762
+ def __new__(cls, arg:PythonStatement, filename=None, startpos=None, flags=None):
757
763
  if isinstance(arg, cls):
758
764
  if filename is startpos is flags is None:
759
765
  return arg
@@ -773,7 +779,8 @@ class PythonStatement(object):
773
779
  raise TypeError("PythonStatement: unexpected %s" % (type(arg).__name__,))
774
780
 
775
781
  @classmethod
776
- def _construct_from_block(cls, block):
782
+ def _construct_from_block(cls, block:PythonBlock):
783
+ assert isinstance(block, PythonBlock), repr(block)
777
784
  # Only to be used by PythonBlock.
778
785
  assert isinstance(block, PythonBlock)
779
786
  self = object.__new__(cls)
@@ -781,7 +788,7 @@ class PythonStatement(object):
781
788
  return self
782
789
 
783
790
  @property
784
- def text(self):
791
+ def text(self) -> FileText:
785
792
  """
786
793
  :rtype:
787
794
  `FileText`
@@ -789,7 +796,7 @@ class PythonStatement(object):
789
796
  return self.block.text
790
797
 
791
798
  @property
792
- def filename(self):
799
+ def filename(self) -> Optional[str]:
793
800
  """
794
801
  :rtype:
795
802
  `Filename`
@@ -828,9 +835,17 @@ class PythonStatement(object):
828
835
  return ast_nodes[0]
829
836
  raise AssertionError("More than one AST node in block")
830
837
 
838
+ @property
839
+ def is_blank(self):
840
+ return self.ast_node is None and self.text.joined.strip() == ''
841
+
842
+ @property
843
+ def is_comment(self):
844
+ return self.ast_node is None and self.text.joined.strip() != ''
845
+
831
846
  @property
832
847
  def is_comment_or_blank(self):
833
- return self.ast_node is None
848
+ return self.is_comment or self.is_blank
834
849
 
835
850
  @property
836
851
  def is_comment_or_blank_or_string_literal(self):
@@ -898,7 +913,7 @@ class PythonStatement(object):
898
913
 
899
914
 
900
915
  @total_ordering
901
- class PythonBlock(object):
916
+ class PythonBlock:
902
917
  r"""
903
918
  Representation of a sequence of consecutive top-level
904
919
  `PythonStatement` (s).
@@ -920,6 +935,8 @@ class PythonBlock(object):
920
935
 
921
936
  """
922
937
 
938
+ text: FileText
939
+
923
940
  def __new__(cls, arg, filename=None, startpos=None, flags=None,
924
941
  auto_flags=None):
925
942
  if isinstance(arg, PythonStatement):
@@ -935,7 +952,7 @@ class PythonBlock(object):
935
952
  return cls.from_text(
936
953
  arg, filename=filename, startpos=startpos,
937
954
  flags=flags, auto_flags=auto_flags)
938
- raise TypeError("%s: unexpected %s"
955
+ raise TypeError("%r: unexpected %r"
939
956
  % (cls.__name__, type(arg).__name__,))
940
957
 
941
958
  @classmethod
@@ -991,17 +1008,21 @@ class PythonBlock(object):
991
1008
  return self
992
1009
 
993
1010
  @classmethod
994
- def concatenate(cls, blocks, assume_contiguous=False):
1011
+ def concatenate(cls, blocks, assume_contiguous=_sentinel):
995
1012
  """
996
1013
  Concatenate a bunch of blocks into one block.
997
1014
 
998
1015
  :type blocks:
999
1016
  sequence of `PythonBlock` s and/or `PythonStatement` s
1000
1017
  :param assume_contiguous:
1018
+ Deprecated, always True
1001
1019
  Whether to assume, without checking, that the input blocks were
1002
1020
  originally all contiguous. This must be set to True to indicate the
1003
1021
  caller understands the assumption; False is not implemented.
1004
1022
  """
1023
+ if assume_contiguous is not _sentinel:
1024
+ warnings.warn('`assume_continuous` is deprecated and considered always `True`')
1025
+ assume_contiguous = True
1005
1026
  if not assume_contiguous:
1006
1027
  raise NotImplementedError
1007
1028
  blocks = [PythonBlock(b) for b in blocks]
@@ -1246,7 +1267,7 @@ class PythonBlock(object):
1246
1267
  cls = type(self)
1247
1268
  for pred, stmts in groupby(self.statements, predicate):
1248
1269
  blocks = [s.block for s in stmts]
1249
- yield pred, cls.concatenate(blocks, assume_contiguous=True)
1270
+ yield pred, cls.concatenate(blocks)
1250
1271
 
1251
1272
  def string_literals(self):
1252
1273
  r"""
@@ -5,4 +5,4 @@
5
5
 
6
6
 
7
7
 
8
- __version__ = '1.9.1'
8
+ __version__ = '1.9.2'
@@ -21,9 +21,6 @@ Only top-level import statements are touched.
21
21
  # License: MIT http://opensource.org/licenses/MIT
22
22
 
23
23
 
24
- from distutils.spawn import find_executable
25
- import subprocess
26
- import sys
27
24
  import os
28
25
 
29
26
  from pyflyby._cmdline import hfmt, parse_args, process_actions
@@ -31,7 +28,6 @@ from pyflyby._imports2s import (canonicalize_imports,
31
28
  fix_unused_and_missing_imports,
32
29
  replace_star_imports,
33
30
  transform_imports, sort_imports)
34
- from pyflyby._log import logger
35
31
 
36
32
  import toml
37
33
  TOML_AVAIL = True
@@ -609,11 +609,11 @@ class _MissingImportFinder(object):
609
609
  if self._in_class_def == 0:
610
610
  self.scopestack._class_delayed[node.name] = None
611
611
  with self._NewScopeCtx(new_class_scope=True):
612
- if not self._in_class_def:
613
- self._in_class_def += 1
614
- self._visit_Store(node.name)
612
+ self._in_class_def += 1
613
+ self._visit_Store(node.name)
615
614
  self.visit(node.body)
616
615
  self._in_class_def -= 1
616
+ assert self._in_class_def >= 0
617
617
  self._remove_from_missing_imports(node.name)
618
618
  self._visit_Store(node.name)
619
619
 
@@ -7,11 +7,11 @@
7
7
  import optparse
8
8
  import os
9
9
  import signal
10
- from six import reraise
11
- from six.moves import input
10
+ from builtins import input
12
11
  import sys
13
12
  from textwrap import dedent
14
13
  import traceback
14
+ from typing import List
15
15
 
16
16
 
17
17
  from pyflyby._file import (FileText, Filename, atomic_write_file,
@@ -376,7 +376,7 @@ class Modifier(object):
376
376
  f.close()
377
377
 
378
378
 
379
- def process_actions(filenames, actions, modify_function,
379
+ def process_actions(filenames:List[str], actions, modify_function,
380
380
  reraise_exceptions=()):
381
381
  errors = []
382
382
  def on_error_filename_arg(arg):
@@ -408,7 +408,7 @@ def process_actions(filenames, actions, modify_function,
408
408
  # Exception takes more than one argument
409
409
  pass
410
410
  if logger.debug_enabled:
411
- reraise(type_e, e, tb)
411
+ raise
412
412
  traceback.print_exception(type(e), e, tb)
413
413
  finally:
414
414
  tb = None # avoid refcycles involving tb
@@ -4,13 +4,14 @@
4
4
 
5
5
 
6
6
 
7
- from functools import total_ordering
7
+ from functools import total_ordering, cached_property
8
8
  import io
9
9
  import os
10
10
  import re
11
11
  import sys
12
+ from typing import Optional, Tuple
12
13
 
13
- from pyflyby._util import cached_attribute, cmp, memoize
14
+ from pyflyby._util import cmp, memoize
14
15
 
15
16
 
16
17
  class UnsafeFilenameError(ValueError):
@@ -28,6 +29,8 @@ class Filename(object):
28
29
  Filename('/etc/passwd')
29
30
 
30
31
  """
32
+ _filename: str
33
+
31
34
  def __new__(cls, arg):
32
35
  if isinstance(arg, cls):
33
36
  return arg
@@ -85,7 +88,7 @@ class Filename(object):
85
88
  return NotImplemented
86
89
  return cmp(self._filename, o._filename)
87
90
 
88
- @cached_attribute
91
+ @cached_property
89
92
  def ext(self):
90
93
  """
91
94
  Returns the extension of this filename, including the dot.
@@ -99,15 +102,15 @@ class Filename(object):
99
102
  return None
100
103
  return dot + rhs
101
104
 
102
- @cached_attribute
105
+ @cached_property
103
106
  def base(self):
104
107
  return os.path.basename(self._filename)
105
108
 
106
- @cached_attribute
109
+ @cached_property
107
110
  def dir(self):
108
111
  return type(self)(os.path.dirname(self._filename))
109
112
 
110
- @cached_attribute
113
+ @cached_property
111
114
  def real(self):
112
115
  return type(self)(os.path.realpath(self._filename))
113
116
 
@@ -230,6 +233,9 @@ class FilePos(object):
230
233
  Both lineno and colno are 1-indexed.
231
234
  """
232
235
 
236
+ lineno: int
237
+ colno: int
238
+
233
239
  def __new__(cls, *args):
234
240
  if len(args) == 0:
235
241
  return cls._ONE_ONE
@@ -265,7 +271,7 @@ class FilePos(object):
265
271
  raise TypeError("Expected (int,int); got %r" % (args,))
266
272
 
267
273
  @classmethod
268
- def _from_lc(cls, lineno, colno):
274
+ def _from_lc(cls, lineno:int, colno:int):
269
275
  self = object.__new__(cls)
270
276
  self.lineno = lineno
271
277
  self.colno = colno
@@ -338,6 +344,10 @@ class FileText:
338
344
  Represents a contiguous sequence of lines from a file.
339
345
  """
340
346
 
347
+ filename: Optional[Filename]
348
+ startpos: FilePos
349
+ _lines: Optional[Tuple[str, ...]] = None
350
+
341
351
  def __new__(cls, arg, filename=None, startpos=None):
342
352
  """
343
353
  Return a new ``FileText`` instance.
@@ -371,7 +381,7 @@ class FileText:
371
381
  return FileText(arg.__text__(), filename=filename, startpos=startpos)
372
382
  elif isinstance(arg, str):
373
383
  self = object.__new__(cls)
374
- self.joined = arg
384
+ self._lines = tuple(arg.split('\n'))
375
385
  else:
376
386
  raise TypeError("%s: unexpected %s"
377
387
  % (cls.__name__, type(arg).__name__))
@@ -383,19 +393,21 @@ class FileText:
383
393
  return self
384
394
 
385
395
  @classmethod
386
- def _from_lines(cls, lines, filename, startpos):
396
+ def _from_lines(cls, lines, filename: Optional[Filename], startpos: FilePos):
387
397
  assert type(lines) is tuple
388
398
  assert len(lines) > 0
389
399
  assert isinstance(lines[0], str)
390
400
  assert not lines[-1].endswith("\n")
401
+ assert isinstance(startpos, FilePos), repr(startpos)
402
+ assert isinstance(filename, (Filename, type(None))), repr(filename)
391
403
  self = object.__new__(cls)
392
- self.lines = lines
404
+ self._lines = tuple(lines)
393
405
  self.filename = filename
394
406
  self.startpos = startpos
395
407
  return self
396
408
 
397
- @cached_attribute
398
- def lines(self):
409
+ @cached_property
410
+ def lines(self) -> Tuple[str, ...]:
399
411
  r"""
400
412
  Lines that have been split by newline.
401
413
 
@@ -408,16 +420,19 @@ class FileText:
408
420
  :rtype:
409
421
  ``tuple`` of ``str``
410
422
  """
423
+ if self._lines is not None:
424
+ return self._lines
411
425
  # Used if only initialized with 'joined'.
412
426
  # We use str.split() instead of str.splitlines() because the latter
413
427
  # doesn't distinguish between strings that end in newline or not
414
428
  # (or requires extra work to process if we use splitlines(True)).
415
429
  return tuple(self.joined.split('\n'))
416
430
 
417
- @cached_attribute
418
- def joined(self): # used if only initialized with 'lines'
431
+ @cached_property
432
+ def joined(self) -> str:
419
433
  return '\n'.join(self.lines)
420
434
 
435
+
421
436
  @classmethod
422
437
  def from_filename(cls, filename):
423
438
  return cls.from_lines(Filename(filename))
@@ -435,13 +450,12 @@ class FileText:
435
450
  return self
436
451
  else:
437
452
  result = object.__new__(type(self))
438
- result.lines = self.lines
439
- result.joined = self.joined
453
+ result._lines = self._lines
440
454
  result.filename = filename
441
455
  result.startpos = startpos
442
456
  return result
443
457
 
444
- @cached_attribute
458
+ @cached_property
445
459
  def endpos(self):
446
460
  """
447
461
  The position after the last character in the text.