pyflyby 1.9.0__tar.gz → 1.9.1__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.1}/PKG-INFO +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_autoimp.py +17 -4
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.1/bin}/pyflyby/_importclns.py +2 -2
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_importstmt.py +27 -20
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.1/bin}/pyflyby/_modules.py +13 -11
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.1/bin}/pyflyby/_parse.py +4 -1
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.1/bin}/pyflyby/_py.py +18 -10
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_util.py +20 -42
- {pyflyby-1.9.0/lib/python → pyflyby-1.9.1/bin}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_autoimp.py +17 -4
- {pyflyby-1.9.0/bin → pyflyby-1.9.1/lib/python}/pyflyby/_importclns.py +2 -2
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_importstmt.py +27 -20
- {pyflyby-1.9.0/bin → pyflyby-1.9.1/lib/python}/pyflyby/_modules.py +13 -11
- {pyflyby-1.9.0/bin → pyflyby-1.9.1/lib/python}/pyflyby/_parse.py +4 -1
- {pyflyby-1.9.0/bin → pyflyby-1.9.1/lib/python}/pyflyby/_py.py +18 -10
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_util.py +20 -42
- {pyflyby-1.9.0/bin → pyflyby-1.9.1/lib/python}/pyflyby/_version.py +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.1/lib/python/pyflyby.egg-info}/PKG-INFO +1 -1
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_importstmt.py +10 -10
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_interactive.py +3 -4
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_modules.py +31 -17
- {pyflyby-1.9.0 → pyflyby-1.9.1}/.pyflyby +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/LICENSE.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/MANIFEST.in +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/README.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/autoipython +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/autopython +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/collect-exports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/collect-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/create-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/find-import +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/list-bad-xrefs +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/prune-broken-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_cmdline.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_file.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_format.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_imports2s.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/_log.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/pyflyby-diff +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/reformat-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/replace-star-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/tidy-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/bin/transform-imports +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/LICENSE.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/Makefile +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/TODO.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/api.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/autoimp.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/cmdline.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/comms.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/dbg.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/file.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/flags.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/format.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/idents.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/importclns.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/importdb.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/imports2s.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/importstmt.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/interactive.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/livepatch.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/log.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/modules.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/parse.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/py.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/api/util.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/autoipython.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/cli.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/collect_exports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/collect_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/find_import.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/prune_broken_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/py.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/pyflyby_diff.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/reformat_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/replace_star_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/tidy_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/cli/transform_imports.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/conf.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/index.rst +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/make.bat +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/doc/testing.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/etc/pyflyby/common.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/etc/pyflyby/std.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/emacs/pyflyby.el +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/__main__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_cmdline.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_comms.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_dbg.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_docxref.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_file.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_flags.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_format.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_idents.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_imports2s.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_interactive.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/_log.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/autoimport.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby/importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby.egg-info/SOURCES.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby.egg-info/dependency_links.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby.egg-info/entry_points.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby.egg-info/requires.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/lib/python/pyflyby.egg-info/top_level.txt +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/setup.cfg +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/setup.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/__init__.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_0testconfig.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_autoimp.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_cmdline.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_docxref.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_file.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_flags.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_format.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_idents.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_importclns.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_importdb.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_imports2s.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_jupyterlab_pyflyby.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_livepatch.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_parse.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_py.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/test_util.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/tests_sorts.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/tests/xrefs.py +0 -0
- {pyflyby-1.9.0 → pyflyby-1.9.1}/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
|
|
@@ -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)
|
|
@@ -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)
|
|
@@ -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:
|
|
@@ -260,7 +260,10 @@ def _test_parse_string_literal(text, flags):
|
|
|
260
260
|
body = module_node.body
|
|
261
261
|
if not _is_ast_str_or_byte(body):
|
|
262
262
|
return None
|
|
263
|
-
|
|
263
|
+
if sys.version_info < (3 ,9):
|
|
264
|
+
return body.s
|
|
265
|
+
else:
|
|
266
|
+
return body.value
|
|
264
267
|
|
|
265
268
|
|
|
266
269
|
AstNodeContext = namedtuple("AstNodeContext", "parent field index")
|
|
@@ -275,6 +275,7 @@ Examples
|
|
|
275
275
|
|
|
276
276
|
|
|
277
277
|
from functools import total_ordering
|
|
278
|
+
from typing import Any
|
|
278
279
|
|
|
279
280
|
from pyflyby._util import cmp
|
|
280
281
|
|
|
@@ -377,7 +378,7 @@ FLAGS = CompilerFlags(["absolute_import", "with_statement", "division",
|
|
|
377
378
|
"print_function"])
|
|
378
379
|
|
|
379
380
|
|
|
380
|
-
def _get_argspec(arg
|
|
381
|
+
def _get_argspec(arg:Any) -> inspect.FullArgSpec:
|
|
381
382
|
from inspect import getfullargspec as getargspec, FullArgSpec as ArgSpec
|
|
382
383
|
if isinstance(arg, FunctionType):
|
|
383
384
|
return getargspec(arg)
|
|
@@ -394,8 +395,6 @@ def _get_argspec(arg, _recurse=False):
|
|
|
394
395
|
else:
|
|
395
396
|
argspec = _get_argspec(arg.__init__)
|
|
396
397
|
return ArgSpec(argspec.args[1:], *argspec[1:])
|
|
397
|
-
elif _recurse and hasattr(arg, '__call__'):
|
|
398
|
-
return _get_argspec(arg.__call__, _recurse=False)
|
|
399
398
|
elif callable(arg):
|
|
400
399
|
# Unknown, probably a built-in method.
|
|
401
400
|
return ArgSpec([], "args", "kwargs", None, [], None, {})
|
|
@@ -458,8 +457,16 @@ def _requires_parens_as_function(function_name:str):
|
|
|
458
457
|
return True
|
|
459
458
|
|
|
460
459
|
|
|
461
|
-
def _format_call_spec(function_name,
|
|
462
|
-
|
|
460
|
+
def _format_call_spec(function_name:str, obj:Any)-> str:
|
|
461
|
+
# using signature() is not strictly identical
|
|
462
|
+
# as it might look at __text_signature__ and/or respect possitional only
|
|
463
|
+
# forward slash:
|
|
464
|
+
# >>> def foo(a, /, b)
|
|
465
|
+
# whcih formatargspec did not do.
|
|
466
|
+
# argspec = _get_argspec(obj)
|
|
467
|
+
# old_callspect = inspect.formatargspec(*argspec)
|
|
468
|
+
# assert old_callspect == callspec , f"{old_callspect} !={callspec}"
|
|
469
|
+
callspec = str(inspect.signature(obj))
|
|
463
470
|
if _requires_parens_as_function(function_name):
|
|
464
471
|
return "(%s)%s" % (function_name, callspec)
|
|
465
472
|
else:
|
|
@@ -483,11 +490,13 @@ except ImportError:
|
|
|
483
490
|
return "'" + s.replace("'", "'\"'\"'") + "'"
|
|
484
491
|
|
|
485
492
|
|
|
486
|
-
def _build_function_usage_string(function_name,
|
|
493
|
+
def _build_function_usage_string(function_name:str, obj:Any, prefix:str):
|
|
494
|
+
argspec = _get_argspec(obj)
|
|
495
|
+
|
|
487
496
|
usage = []
|
|
488
497
|
# TODO: colorize
|
|
489
498
|
usage.append("Python signature:")
|
|
490
|
-
usage.append(" >"+">> " + _format_call_spec(function_name,
|
|
499
|
+
usage.append(" >"+">> " + _format_call_spec(function_name, obj))
|
|
491
500
|
usage.append("")
|
|
492
501
|
usage.append("Command-line signature:")
|
|
493
502
|
keywords = argspec.varkw
|
|
@@ -902,11 +911,10 @@ def _get_help(expr, verbosity=1):
|
|
|
902
911
|
# TODO: colorize headers
|
|
903
912
|
result = ""
|
|
904
913
|
obj = expr.value
|
|
905
|
-
name = str(expr.source)
|
|
914
|
+
name:str = str(expr.source)
|
|
906
915
|
if callable(obj):
|
|
907
|
-
argspec = _get_argspec(obj)
|
|
908
916
|
prefix = os.path.basename(sys.orig_argv[0]) + " "
|
|
909
|
-
result += _build_function_usage_string(name,
|
|
917
|
+
result += _build_function_usage_string(name, obj, prefix)
|
|
910
918
|
if verbosity == 0:
|
|
911
919
|
include_filename = False
|
|
912
920
|
include_doc = False
|
|
@@ -7,60 +7,38 @@
|
|
|
7
7
|
from contextlib import contextmanager
|
|
8
8
|
import inspect
|
|
9
9
|
import os
|
|
10
|
-
from six import reraise
|
|
11
10
|
import sys
|
|
12
11
|
import types
|
|
13
12
|
|
|
13
|
+
# There used to be a custom caching_attribute implementation
|
|
14
|
+
# this now uses functools's cached_property which is understood by
|
|
15
|
+
# various static analysis tools.
|
|
16
|
+
from functools import cached_property as cached_attribute # noqa: F401
|
|
17
|
+
|
|
14
18
|
# Python 2/3 compatibility
|
|
15
19
|
DictProxyType = type(object.__dict__)
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
if sys.version_info > (3,9):
|
|
22
|
+
from functools import cache as memoize
|
|
23
|
+
else:
|
|
24
|
+
def memoize(function):
|
|
25
|
+
cache = {}
|
|
26
|
+
def wrapped_fn(*args, **kwargs):
|
|
27
|
+
cache_key = (args, tuple(sorted(kwargs.items())))
|
|
28
|
+
try:
|
|
29
|
+
return cache[cache_key]
|
|
30
|
+
except KeyError:
|
|
31
|
+
result = function(*args, **kwargs)
|
|
32
|
+
cache[cache_key] = result
|
|
33
|
+
return result
|
|
34
|
+
wrapped_fn.cache = cache
|
|
35
|
+
return wrapped_fn
|
|
30
36
|
|
|
31
37
|
|
|
32
38
|
class WrappedAttributeError(Exception):
|
|
33
39
|
pass
|
|
34
40
|
|
|
35
41
|
|
|
36
|
-
class cached_attribute(object):
|
|
37
|
-
"""Computes attribute value and caches it in instance.
|
|
38
|
-
|
|
39
|
-
Example::
|
|
40
|
-
|
|
41
|
-
class MyClass(object):
|
|
42
|
-
@cached_attribute
|
|
43
|
-
def myMethod(self):
|
|
44
|
-
# ...
|
|
45
|
-
|
|
46
|
-
Use "del inst.myMethod" to clear cache."""
|
|
47
|
-
# http://code.activestate.com/recipes/276643/
|
|
48
|
-
|
|
49
|
-
def __init__(self, method, name=None):
|
|
50
|
-
self.method = method
|
|
51
|
-
self.name = name or method.__name__
|
|
52
|
-
|
|
53
|
-
def __get__(self, inst, cls):
|
|
54
|
-
if inst is None:
|
|
55
|
-
return self
|
|
56
|
-
try:
|
|
57
|
-
result = self.method(inst)
|
|
58
|
-
except AttributeError as e:
|
|
59
|
-
reraise(WrappedAttributeError, WrappedAttributeError(str(e)), sys.exc_info()[2])
|
|
60
|
-
setattr(inst, self.name, result)
|
|
61
|
-
return result
|
|
62
|
-
|
|
63
|
-
|
|
64
42
|
def stable_unique(items):
|
|
65
43
|
"""
|
|
66
44
|
Return a copy of ``items`` without duplicates. The order of other items is
|
|
@@ -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
|
|
@@ -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)
|
|
@@ -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)
|
|
@@ -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):
|