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.
- {pyflyby-1.9.1/lib/python/pyflyby.egg-info → pyflyby-1.9.2}/PKG-INFO +1 -1
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_autoimp.py +3 -3
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_cmdline.py +4 -4
- {pyflyby-1.9.1/lib/python → pyflyby-1.9.2/bin}/pyflyby/_file.py +31 -17
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_imports2s.py +15 -11
- {pyflyby-1.9.1/lib/python → pyflyby-1.9.2/bin}/pyflyby/_parse.py +32 -11
- {pyflyby-1.9.1/lib/python → pyflyby-1.9.2/bin}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/tidy-imports +0 -4
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_autoimp.py +3 -3
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_cmdline.py +4 -4
- {pyflyby-1.9.1/bin → pyflyby-1.9.2/lib/python}/pyflyby/_file.py +31 -17
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_imports2s.py +15 -11
- {pyflyby-1.9.1/bin → pyflyby-1.9.2/lib/python}/pyflyby/_parse.py +32 -11
- {pyflyby-1.9.1/bin → pyflyby-1.9.2/lib/python}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.1 → pyflyby-1.9.2/lib/python/pyflyby.egg-info}/PKG-INFO +1 -1
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_imports2s.py +35 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/.pyflyby +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/LICENSE.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/MANIFEST.in +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/README.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/autoipython +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/autopython +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/collect-exports +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/collect-imports +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/create-imports +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/find-import +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/list-bad-xrefs +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/prune-broken-imports +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_format.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_importclns.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_log.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_modules.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_py.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/_util.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/pyflyby-diff +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/reformat-imports +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/replace-star-imports +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/bin/transform-imports +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/LICENSE.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/Makefile +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/TODO.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/__init__.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/api.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/autoimp.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/cmdline.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/comms.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/dbg.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/file.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/flags.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/format.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/idents.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/importclns.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/importdb.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/imports2s.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/importstmt.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/interactive.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/livepatch.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/log.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/modules.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/parse.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/py.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/api/util.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/autoipython.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/cli.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/collect_exports.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/collect_imports.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/find_import.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/prune_broken_imports.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/py.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/pyflyby_diff.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/reformat_imports.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/replace_star_imports.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/tidy_imports.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/cli/transform_imports.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/conf.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/index.rst +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/make.bat +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/doc/testing.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/common.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/etc/pyflyby/std.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/emacs/pyflyby.el +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_format.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_importclns.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_log.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_modules.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_py.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/_util.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/SOURCES.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/dependency_links.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/entry_points.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/requires.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/top_level.txt +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/setup.cfg +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/setup.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/__init__.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_0testconfig.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_autoimp.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_cmdline.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_docxref.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_file.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_flags.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_format.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_idents.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_importclns.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_importdb.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_importstmt.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_interactive.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_jupyterlab_pyflyby.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_livepatch.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_modules.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_parse.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_py.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/test_util.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/tests_sorts.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tests/xrefs.py +0 -0
- {pyflyby-1.9.1 → pyflyby-1.9.2}/tox.ini +0 -0
|
@@ -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
|
-
|
|
613
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
105
|
+
@cached_property
|
|
103
106
|
def base(self):
|
|
104
107
|
return os.path.basename(self._filename)
|
|
105
108
|
|
|
106
|
-
@
|
|
109
|
+
@cached_property
|
|
107
110
|
def dir(self):
|
|
108
111
|
return type(self)(os.path.dirname(self._filename))
|
|
109
112
|
|
|
110
|
-
@
|
|
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.
|
|
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.
|
|
404
|
+
self._lines = tuple(lines)
|
|
393
405
|
self.filename = filename
|
|
394
406
|
self.startpos = startpos
|
|
395
407
|
return self
|
|
396
408
|
|
|
397
|
-
@
|
|
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
|
-
@
|
|
418
|
-
def joined(self)
|
|
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.
|
|
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
|
-
@
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
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("%
|
|
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=
|
|
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
|
|
1270
|
+
yield pred, cls.concatenate(blocks)
|
|
1250
1271
|
|
|
1251
1272
|
def string_literals(self):
|
|
1252
1273
|
r"""
|
|
@@ -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
|
-
|
|
613
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
105
|
+
@cached_property
|
|
103
106
|
def base(self):
|
|
104
107
|
return os.path.basename(self._filename)
|
|
105
108
|
|
|
106
|
-
@
|
|
109
|
+
@cached_property
|
|
107
110
|
def dir(self):
|
|
108
111
|
return type(self)(os.path.dirname(self._filename))
|
|
109
112
|
|
|
110
|
-
@
|
|
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.
|
|
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.
|
|
404
|
+
self._lines = tuple(lines)
|
|
393
405
|
self.filename = filename
|
|
394
406
|
self.startpos = startpos
|
|
395
407
|
return self
|
|
396
408
|
|
|
397
|
-
@
|
|
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
|
-
@
|
|
418
|
-
def joined(self)
|
|
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.
|
|
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
|
-
@
|
|
458
|
+
@cached_property
|
|
445
459
|
def endpos(self):
|
|
446
460
|
"""
|
|
447
461
|
The position after the last character in the text.
|