pyflyby 1.9.0__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.0/lib/python/pyflyby.egg-info → pyflyby-1.9.2}/PKG-INFO +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_autoimp.py +20 -7
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_cmdline.py +4 -4
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.2/bin}/pyflyby/_file.py +31 -17
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.2/bin}/pyflyby/_importclns.py +2 -2
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_imports2s.py +15 -11
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_importstmt.py +27 -20
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.2/bin}/pyflyby/_modules.py +13 -11
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.2/bin}/pyflyby/_parse.py +36 -12
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.2/bin}/pyflyby/_py.py +18 -10
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_util.py +20 -42
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.2/bin}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/tidy-imports +0 -4
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_autoimp.py +20 -7
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_cmdline.py +4 -4
- {pyflyby-1.9.0/bin → pyflyby-1.9.2/lib/python}/pyflyby/_file.py +31 -17
- {pyflyby-1.9.0/bin → pyflyby-1.9.2/lib/python}/pyflyby/_importclns.py +2 -2
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_imports2s.py +15 -11
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_importstmt.py +27 -20
- {pyflyby-1.9.0/bin → pyflyby-1.9.2/lib/python}/pyflyby/_modules.py +13 -11
- {pyflyby-1.9.0/bin → pyflyby-1.9.2/lib/python}/pyflyby/_parse.py +36 -12
- {pyflyby-1.9.0/bin → pyflyby-1.9.2/lib/python}/pyflyby/_py.py +18 -10
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_util.py +20 -42
- {pyflyby-1.9.0/bin → pyflyby-1.9.2/lib/python}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.2/lib/python/pyflyby.egg-info}/PKG-INFO +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_imports2s.py +35 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_importstmt.py +10 -10
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_interactive.py +3 -4
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_modules.py +31 -17
- {pyflyby-1.9.0 → pyflyby-1.9.2}/.pyflyby +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/LICENSE.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/MANIFEST.in +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/README.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/autoipython +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/autopython +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/collect-exports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/collect-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/create-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/find-import +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/list-bad-xrefs +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/prune-broken-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_format.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/_log.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/pyflyby-diff +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/reformat-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/replace-star-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/bin/transform-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/LICENSE.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/Makefile +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/TODO.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/api.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/autoimp.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/cmdline.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/comms.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/dbg.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/file.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/flags.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/format.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/idents.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/importclns.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/importdb.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/imports2s.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/importstmt.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/interactive.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/livepatch.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/log.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/modules.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/parse.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/py.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/api/util.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/autoipython.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/cli.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/collect_exports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/collect_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/find_import.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/prune_broken_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/py.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/pyflyby_diff.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/reformat_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/replace_star_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/tidy_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/cli/transform_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/conf.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/index.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/make.bat +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/doc/testing.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/etc/pyflyby/common.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/etc/pyflyby/std.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/emacs/pyflyby.el +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_format.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/_log.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/SOURCES.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/dependency_links.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/entry_points.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/requires.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/lib/python/pyflyby.egg-info/top_level.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/setup.cfg +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/setup.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_0testconfig.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_autoimp.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_cmdline.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_docxref.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_file.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_flags.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_format.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_idents.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_importclns.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_jupyterlab_pyflyby.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_livepatch.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_parse.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_py.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/test_util.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/tests_sorts.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tests/xrefs.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.2}/tox.ini +0 -0
|
@@ -22,7 +22,7 @@ from pyflyby._importdb import ImportDB
|
|
|
22
22
|
from pyflyby._importstmt import Import
|
|
23
23
|
from pyflyby._log import logger
|
|
24
24
|
from pyflyby._modules import ModuleHandle
|
|
25
|
-
from pyflyby._parse import PythonBlock, infer_compile_mode
|
|
25
|
+
from pyflyby._parse import PythonBlock, infer_compile_mode, _is_ast_str
|
|
26
26
|
|
|
27
27
|
if sys.version_info >= (3, 12):
|
|
28
28
|
ATTRIBUTE_NAME = "value"
|
|
@@ -34,6 +34,11 @@ if sys.version_info > (3, 11):
|
|
|
34
34
|
else:
|
|
35
35
|
LOAD_SHIFT = 0
|
|
36
36
|
|
|
37
|
+
if sys.version_info > (3, 11):
|
|
38
|
+
LOAD_SHIFT = 1
|
|
39
|
+
else:
|
|
40
|
+
LOAD_SHIFT = 0
|
|
41
|
+
|
|
37
42
|
NoneType = type(None)
|
|
38
43
|
EllipsisType = type(Ellipsis)
|
|
39
44
|
|
|
@@ -580,7 +585,7 @@ class _MissingImportFinder(object):
|
|
|
580
585
|
if not isinstance(node.value, ast.List):
|
|
581
586
|
logger.warning("Don't know how to handle __all__ as (%s)" % node.value)
|
|
582
587
|
return
|
|
583
|
-
if not all(
|
|
588
|
+
if not all(_is_ast_str(e) for e in node.value.elts):
|
|
584
589
|
logger.warning("Don't know how to handle __all__ with list elements other than str")
|
|
585
590
|
return
|
|
586
591
|
for e in node.value.elts:
|
|
@@ -588,7 +593,11 @@ class _MissingImportFinder(object):
|
|
|
588
593
|
|
|
589
594
|
def visit_ClassDef(self, node):
|
|
590
595
|
logger.debug("visit_ClassDef(%r)", node)
|
|
591
|
-
|
|
596
|
+
if sys.version_info > (3,12):
|
|
597
|
+
# we don't visit type_params, so autoimport won't work yet for type annotations
|
|
598
|
+
assert node._fields == ('name', 'bases', 'keywords', 'body', 'decorator_list', 'type_params'), node._fields
|
|
599
|
+
else:
|
|
600
|
+
assert node._fields == ('name', 'bases', 'keywords', 'body', 'decorator_list'), node._fields
|
|
592
601
|
self.visit(node.bases)
|
|
593
602
|
self.visit(node.decorator_list)
|
|
594
603
|
# The class's name is only visible to others (not to the body to the
|
|
@@ -600,11 +609,11 @@ class _MissingImportFinder(object):
|
|
|
600
609
|
if self._in_class_def == 0:
|
|
601
610
|
self.scopestack._class_delayed[node.name] = None
|
|
602
611
|
with self._NewScopeCtx(new_class_scope=True):
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
self._visit_Store(node.name)
|
|
612
|
+
self._in_class_def += 1
|
|
613
|
+
self._visit_Store(node.name)
|
|
606
614
|
self.visit(node.body)
|
|
607
615
|
self._in_class_def -= 1
|
|
616
|
+
assert self._in_class_def >= 0
|
|
608
617
|
self._remove_from_missing_imports(node.name)
|
|
609
618
|
self._visit_Store(node.name)
|
|
610
619
|
|
|
@@ -619,7 +628,11 @@ class _MissingImportFinder(object):
|
|
|
619
628
|
# scope.
|
|
620
629
|
# - Store the name in the current scope (but not visibly to
|
|
621
630
|
# args/decorator_list).
|
|
622
|
-
|
|
631
|
+
if sys.version_info > (3, 12):
|
|
632
|
+
# we don't visit type_params, so autoimport won't work yet for type annotations
|
|
633
|
+
assert node._fields == ('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), node._fields
|
|
634
|
+
else:
|
|
635
|
+
assert node._fields == ('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment'), node._fields
|
|
623
636
|
with self._NewScopeCtx(include_class_scopes=True):
|
|
624
637
|
self.visit(node.decorator_list)
|
|
625
638
|
self.visit(node.args)
|
|
@@ -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.
|
|
@@ -215,8 +215,8 @@ class ImportSet(object):
|
|
|
215
215
|
"""
|
|
216
216
|
:return:
|
|
217
217
|
(mapping from name to __future__ imports,
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
mapping from name to non-'from' imports,
|
|
219
|
+
mapping from name to 'from' imports)
|
|
220
220
|
"""
|
|
221
221
|
ftr_imports = defaultdict(set)
|
|
222
222
|
pkg_imports = defaultdict(set)
|
|
@@ -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
|
|
|
@@ -15,17 +15,16 @@ from pyflyby._parse import PythonStatement
|
|
|
15
15
|
from pyflyby._util import (Inf, cached_attribute, cmp,
|
|
16
16
|
longest_common_prefix)
|
|
17
17
|
|
|
18
|
-
from black import format_str, FileMode as Mode
|
|
19
|
-
from black.files import find_pyproject_toml, parse_pyproject_toml
|
|
20
|
-
from black.mode import TargetVersion
|
|
21
18
|
|
|
19
|
+
from typing import Dict, Tuple, Optional
|
|
22
20
|
|
|
23
|
-
def read_black_config():
|
|
24
|
-
"""Read the black configuration from ``pyproject.toml``
|
|
25
21
|
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
def read_black_config() -> Dict:
|
|
24
|
+
"""Read the black configuration from ``pyproject.toml``"""
|
|
25
|
+
from black.files import find_pyproject_toml, parse_pyproject_toml
|
|
26
|
+
|
|
27
|
+
pyproject_path = find_pyproject_toml((".",))
|
|
29
28
|
|
|
30
29
|
raw_config = parse_pyproject_toml(pyproject_path) if pyproject_path else {}
|
|
31
30
|
|
|
@@ -348,24 +347,31 @@ class Import(object):
|
|
|
348
347
|
return NotImplemented
|
|
349
348
|
return self._data < other._data
|
|
350
349
|
|
|
351
|
-
def _validate_alias(arg):
|
|
350
|
+
def _validate_alias(arg) -> Tuple[str, Optional[str]]:
|
|
352
351
|
"""
|
|
353
352
|
Ensure each alias is a tuple (str, None|str), and return it.
|
|
354
353
|
|
|
355
354
|
"""
|
|
356
355
|
assert isinstance(arg, tuple)
|
|
357
|
-
|
|
356
|
+
# Pyright does not seem to be able to infer the length from a
|
|
357
|
+
# the unpacking.
|
|
358
|
+
assert len(arg) == 2
|
|
359
|
+
a0, a1 = arg
|
|
358
360
|
assert isinstance(a0, str)
|
|
359
361
|
assert isinstance(a1, (str, type(None)))
|
|
360
362
|
return arg
|
|
361
363
|
|
|
362
364
|
@total_ordering
|
|
363
|
-
class ImportStatement
|
|
365
|
+
class ImportStatement:
|
|
364
366
|
"""
|
|
365
367
|
Token-level representation of an import statement containing multiple
|
|
366
368
|
imports from a single module. Corresponds to an ``ast.ImportFrom`` or
|
|
367
369
|
``ast.Import``.
|
|
368
370
|
"""
|
|
371
|
+
|
|
372
|
+
aliases : Tuple[Tuple[str, Optional[str]],...]
|
|
373
|
+
fromname : Optional[str]
|
|
374
|
+
|
|
369
375
|
def __new__(cls, arg):
|
|
370
376
|
if isinstance(arg, cls):
|
|
371
377
|
return arg
|
|
@@ -381,10 +387,10 @@ class ImportStatement(object):
|
|
|
381
387
|
raise TypeError
|
|
382
388
|
|
|
383
389
|
@classmethod
|
|
384
|
-
def from_parts(cls, fromname, aliases):
|
|
385
|
-
assert isinstance(aliases,
|
|
390
|
+
def from_parts(cls, fromname:Optional[str], aliases:Tuple[Tuple[str, Optional[str]],...]):
|
|
391
|
+
assert isinstance(aliases, tuple)
|
|
386
392
|
assert len(aliases) > 0
|
|
387
|
-
|
|
393
|
+
|
|
388
394
|
self = object.__new__(cls)
|
|
389
395
|
self.fromname = fromname
|
|
390
396
|
self.aliases = tuple(_validate_alias(a) for a in aliases)
|
|
@@ -440,7 +446,7 @@ class ImportStatement(object):
|
|
|
440
446
|
raise NonImportStatementError(
|
|
441
447
|
'Expected ImportStatement, got {node}'.format(node=node)
|
|
442
448
|
)
|
|
443
|
-
aliases =
|
|
449
|
+
aliases = tuple( (alias.name, alias.asname) for alias in node.names )
|
|
444
450
|
return cls.from_parts(fromname, aliases)
|
|
445
451
|
|
|
446
452
|
@classmethod
|
|
@@ -463,7 +469,7 @@ class ImportStatement(object):
|
|
|
463
469
|
raise ValueError(
|
|
464
470
|
"Inconsistent module names %r" % (sorted(module_names),))
|
|
465
471
|
fromname = list(module_names)[0]
|
|
466
|
-
aliases =
|
|
472
|
+
aliases = tuple(imp.split[1:] for imp in imports)
|
|
467
473
|
return cls.from_parts(fromname, aliases)
|
|
468
474
|
|
|
469
475
|
@cached_attribute
|
|
@@ -529,12 +535,15 @@ class ImportStatement(object):
|
|
|
529
535
|
return res
|
|
530
536
|
|
|
531
537
|
@staticmethod
|
|
532
|
-
def run_black(src_contents: str, params) -> str:
|
|
538
|
+
def run_black(src_contents: str, params:FormatParams) -> str:
|
|
533
539
|
"""Run the black formatter for the Python source code given as a string
|
|
534
540
|
|
|
535
541
|
This is adapted from https://github.com/akaihola/darker
|
|
536
542
|
|
|
537
543
|
"""
|
|
544
|
+
from black import format_str, FileMode
|
|
545
|
+
from black.mode import TargetVersion
|
|
546
|
+
|
|
538
547
|
black_config = read_black_config()
|
|
539
548
|
mode = dict()
|
|
540
549
|
if "line_length" in black_config:
|
|
@@ -568,14 +577,12 @@ class ImportStatement(object):
|
|
|
568
577
|
# ``--skip-string-normalization``, but the parameter for
|
|
569
578
|
# ``black.Mode`` needs to be the opposite boolean of
|
|
570
579
|
# ``skip-string-normalization``, hence the inverse boolean
|
|
571
|
-
mode["string_normalization"] = not black_config[
|
|
572
|
-
"skip_string_normalization"
|
|
573
|
-
]
|
|
580
|
+
mode["string_normalization"] = not black_config["skip_string_normalization"]
|
|
574
581
|
|
|
575
582
|
# The custom handling of empty and all-whitespace files below will be unnecessary if
|
|
576
583
|
# https://github.com/psf/black/pull/2484 lands in Black.
|
|
577
584
|
contents_for_black = src_contents
|
|
578
|
-
return format_str(contents_for_black, mode=
|
|
585
|
+
return format_str(contents_for_black, mode=FileMode(**mode))
|
|
579
586
|
|
|
580
587
|
@property
|
|
581
588
|
def _data(self):
|
|
@@ -125,6 +125,8 @@ class ModuleHandle(object):
|
|
|
125
125
|
A handle to a module.
|
|
126
126
|
"""
|
|
127
127
|
|
|
128
|
+
name: DottedIdentifier
|
|
129
|
+
|
|
128
130
|
def __new__(cls, arg):
|
|
129
131
|
if isinstance(arg, cls):
|
|
130
132
|
return arg
|
|
@@ -206,14 +208,8 @@ class ModuleHandle(object):
|
|
|
206
208
|
if self.parent and not self.parent.exists:
|
|
207
209
|
return False
|
|
208
210
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
try:
|
|
212
|
-
import importlib.util
|
|
213
|
-
find = importlib.util.find_spec
|
|
214
|
-
except ImportError:
|
|
215
|
-
import pkgutil
|
|
216
|
-
find = pkgutil.find_loader
|
|
211
|
+
import importlib.util
|
|
212
|
+
find = importlib.util.find_spec
|
|
217
213
|
|
|
218
214
|
try:
|
|
219
215
|
pkg = find(name)
|
|
@@ -241,6 +237,7 @@ class ModuleHandle(object):
|
|
|
241
237
|
# module, which may be undesirable.
|
|
242
238
|
import pkgutil
|
|
243
239
|
try:
|
|
240
|
+
#TODO: deprecated and will be removed in 3.14
|
|
244
241
|
loader = pkgutil.get_loader(str(self.name))
|
|
245
242
|
except ImportError:
|
|
246
243
|
return None
|
|
@@ -303,7 +300,7 @@ class ModuleHandle(object):
|
|
|
303
300
|
Enumerate the importable submodules of this module.
|
|
304
301
|
|
|
305
302
|
>>> ModuleHandle("email").submodules # doctest:+ELLIPSIS
|
|
306
|
-
(..., 'email.encoders', ..., 'email.mime', ...)
|
|
303
|
+
(..., ModuleHandle('email.encoders'), ..., ModuleHandle('email.mime'), ...)
|
|
307
304
|
|
|
308
305
|
:rtype:
|
|
309
306
|
``tuple`` of `ModuleHandle` s
|
|
@@ -366,6 +363,7 @@ class ModuleHandle(object):
|
|
|
366
363
|
|
|
367
364
|
# If __all__ is defined, try to use it
|
|
368
365
|
all_is_good = False # pun intended
|
|
366
|
+
all_members = []
|
|
369
367
|
if "__all__" in members:
|
|
370
368
|
# Iterate through the nodes and reconstruct the
|
|
371
369
|
# value of __all__
|
|
@@ -418,7 +416,7 @@ class ModuleHandle(object):
|
|
|
418
416
|
members = [n for n in members if not n.startswith("_")]
|
|
419
417
|
|
|
420
418
|
# Filter out artificially added "deep" members.
|
|
421
|
-
members = [(n, None) for n in members if "." not in n]
|
|
419
|
+
members = tuple([(n, None) for n in members if "." not in n])
|
|
422
420
|
if not members:
|
|
423
421
|
return None
|
|
424
422
|
return ImportSet(
|
|
@@ -482,7 +480,11 @@ class ModuleHandle(object):
|
|
|
482
480
|
result = module.module
|
|
483
481
|
except Exception as e:
|
|
484
482
|
raise ImportError(e)
|
|
485
|
-
|
|
483
|
+
# TODO: as far as I can tell the code here is never reached, or haven't
|
|
484
|
+
# been in quite some time as the line below was invalid on Python 3 since 2011
|
|
485
|
+
# zip(...)[...] fails as zip is not indexable.
|
|
486
|
+
# the only place that seem to be using this method is XrefScanner.
|
|
487
|
+
for part, prefix in list(zip(identifier, prefixes(identifier)))[1:]:
|
|
486
488
|
try:
|
|
487
489
|
result = getattr(result, str(part))
|
|
488
490
|
except Exception:
|