lyz-code / autoimport Goto Github PK
View Code? Open in Web Editor NEWAutoimport automatically fixes wrong import statements.
Home Page: https://lyz-code.github.io/autoimport
License: GNU General Public License v3.0
Autoimport automatically fixes wrong import statements.
Home Page: https://lyz-code.github.io/autoimport
License: GNU General Public License v3.0
Hi! Thank you so much for creating this! I was wondering if there are any plans to create a vscode integration.
It would be nice if autoimport was clever enough to import at least the objects that are part of the program/library being developed.
Add an entry in _find_package
similar to _find_package_in_typing
that deduces the package that is developed and find any missing objects there.
We could search on the installed packages:
import pkg_resources
installed_packages = pkg_resources.working_set
installed_packages_list = sorted(["%s==%s" % (i.key, i.version)
for i in installed_packages])
print(installed_packages_list)
For any that matches any of the contents of the current working directory.
Then we can recursively use dir()
to find the objects of the package and subpackages
Make autoimport search for the object in all the available packages.
Add an entry in _find_package
similar to _find_package_in_typing
that deduces the package that is developed and find any missing objects there.
We could search all the packages and use dir()
at least on the first level. But we'll need to import all, I'm not sure the performance of that.
Given an import that contains unused function, autoimport exits abnormally.
Given the following code,
from sympy import *
from sympy.parsing.sympy_parser import (parse_expr, standard_transformations, implicit_multiplication_application)
from math import factorial
def fact(n):
return factorial(n)
def evaluate_expression(expression):
# replace "!" with the function call to "fact"
expression = expression.replace('!', ').fact(')
# add an opening parenthesis before each occurrence of "fact"
expression = expression.replace('fact', '(fact')
# replace "√" with the function call to "sqrt"
expression = expression.replace('√', 'sqrt(') + ')'
# add an closing parenthesis after each occurrence of "sqrt"
expression = expression.replace('sqrt', 'sqrt')
# replace "log10" with the function call to "log"
expression = expression.replace('log10', 'log(') + ')'
# add an closing parenthesis after each occurrence of "log"
expression = expression.replace('log', 'log')
# parse the expression to sympy and evaluate
expr = parse_expr(expression, local_dict=namespace, transformations=transformations)
return expr.evalf()
import unittest
class TestEvaluateExpression(unittest.TestCase):
def test_simple_expression(self):
expression = "1+2"
result = evaluate_expression(expression)
self.assertEqual(result, 3)
def test_nested_parentheses(self):
expression = "(((1+2)*3)^2)"
result = evaluate_expression(expression)
self.assertEqual(result, 81)
def test_exponentiation(self):
expression = "2^3"
result = evaluate_expression(expression)
self.assertEqual(result, 8)
def test_modulus(self):
expression = "10%3"
result = evaluate_expression(expression)
self.assertEqual(result, 1)
def test_factorial(self):
expression = "5!"
result = evaluate_expression(expression)
self.assertEqual(result, 120)
def test_square_root(self):
expression = "√16"
result = evaluate_expression(expression)
self.assertEqual(result, 4)
def test_logarithm(self):
expression = "log10(100)"
result = evaluate_expression(expression)
self.assertEqual(result, 2)
def test_complex_expression(self):
expression = "(((1+2)*3)^2%5)!√4log10(100)"
result = evaluate_expression(expression)
self.assertEqual(result, 24)
And we use fix_code to fix it, the autoimport exits with the following traceback:
Traceback (most recent call last):
File "D:\xxx\fix_code_test.py", line 74, in
print(fix_code(code))
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\services.py", line 73, in fix_code
return SourceCode(original_source_code, config=config).fix()
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 67, in fix
self._fix_flake_import_errors()
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 308, in _fix_flake_import_errors
self._remove_unused_imports(import_name)
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 478, in _remove_unused_imports
imports.remove(object_name)
ValueError: list.remove(x): x not in list
The _remove_unused_imports function in model.py (lines 441-505) failed to consider the scenario where multiple function names are enclosed in parentheses. Accordingly, given an import like "from module import (func1, func2)", line 476 in _remove_unused_imports will simply separate "(func1, func2)" into "(func1" and "func2)" without removing the parentheses, which trigges an exception of "ValueError: list.remove(x): x not in list" when executing line 478 in _remove_unused_imports.
Define how to use autoimport automatically with vim.
Probably by creating an ale fixer.
It would be nice if calling autoimport <directory>
(on the command line) would process the python files under that directory.
I find myself typing this at the command line sometimes:
$ for f in `ls *.py`; do autoimport $f; done
This would be consistent with other tools:
mypy <directory>
flake8 <directory>
black <directory>
isort <directory>
# etc...
While testing with a file that only has imports, I noticed that autoimport crashes with the exception IndexError: list index out of range
.
% autoimport - <<<'import os'
Traceback (most recent call last):
File "/tmp/aaaa/venv/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1137, in __call__
return self.main(*args, **kwargs)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1062, in main
rv = self.invoke(ctx)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 763, in invoke
return __callback(*args, **kwargs)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/entrypoints/cli.py", line 19, in cli
fixed_code = services.fix_files(files)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/services.py", line 27, in fix_files
fixed_source = fix_code(source)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/services.py", line 67, in fix_code
return SourceCode(original_source_code).fix()
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 47, in __init__
self._split_code(source_code)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 78, in _split_code
self._extract_typing_statements(source_code_lines)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 155, in _extract_typing_statements
r"^if TYPE_CHECKING:$", source_lines[typing_start_line]
IndexError: list index out of range
Stack trace:
% autoimport - <<<'import os'
Traceback (most recent call last):
File "/tmp/aaaa/venv/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1137, in __call__
return self.main(*args, **kwargs)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1062, in main
rv = self.invoke(ctx)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 763, in invoke
return __callback(*args, **kwargs)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/entrypoints/cli.py", line 19, in cli
fixed_code = services.fix_files(files)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/services.py", line 27, in fix_files
fixed_source = fix_code(source)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/services.py", line 67, in fix_code
return SourceCode(original_source_code).fix()
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 47, in __init__
self._split_code(source_code)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 78, in _split_code
self._extract_typing_statements(source_code_lines)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 155, in _extract_typing_statements
r"^if TYPE_CHECKING:$", source_lines[typing_start_line]
IndexError: list index out of range
Should print an empty string. There are other cases too, for example:
% cat sample.py
import os # noqa: F401
import sys
% autoimport sample.py
Traceback (most recent call last):
File "/tmp/aaaa/venv/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1137, in __call__
return self.main(*args, **kwargs)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1062, in main
rv = self.invoke(ctx)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/click/core.py", line 763, in invoke
return __callback(*args, **kwargs)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/entrypoints/cli.py", line 19, in cli
fixed_code = services.fix_files(files)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/services.py", line 27, in fix_files
fixed_source = fix_code(source)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/services.py", line 67, in fix_code
return SourceCode(original_source_code).fix()
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 47, in __init__
self._split_code(source_code)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 78, in _split_code
self._extract_typing_statements(source_code_lines)
File "/private/tmp/aaaa/venv/lib/python3.9/site-packages/autoimport/model.py", line 155, in _extract_typing_statements
r"^if TYPE_CHECKING:$", source_lines[typing_start_line]
IndexError: list index out of range
In that case the output should've been import os
.
% autoimport --version
autoimport version: 0.7.3
python version: 3.9.6 (default, Jun 29 2021, 05:25:02) [Clang 12.0.5 (clang-1205.0.22.9)]
platform: macOS-11.5.2-x86_64-i386-64bit
% python -c "import autoimport.version; print(autoimport.version.version_info())"
autoimport version: 0.7.3
python version: 3.9.6 (default, Jun 29 2021, 05:25:02) [Clang 12.0.5 (clang-1205.0.22.9)]
platform: macOS-11.5.2-x86_64-i386-64bit
If I run autoimport on a file and the file is not changed, the modification time of the file should not be changed either.
For example:
$ echo "print(123)" > foo.py
$ cat foo.py
print(123)
$ date -r foo.py
Thu Jan 20 17:37:42 CST 2022
$ autoimport foo.py
$ cat foo.py
print(123)
$ # ^ foo.py was not changed
$ date -r foo.py
Thu Jan 20 17:37:51 CST 2022
$ # ^ file modification time has changed!
autoimport
did not modify foo.py
, but the modification time was changed.
Perhaps autoimport could check whether the file would be modified, and only touch the file if a nonzero diff would occur.
I use makefiles and other similar tools which keep track of file modification time. If autoimport does not change the file's contents, modification of the file modification time triggers a false-positive make/build cycle.
Hello,
Unfortunately I have a bug to report. I'm getting a false-positive import with certain typing.Literal
usage.
before running autoimport:
from typing import Literal as L
var: L["* time"] = "* time"
after running autoimport:
from typing import Literal as L
import time
var: L["* time"] = "* time"
Importing the library time
is not correct.
This bug came up when using the nptyping
library, which encourages liberal use of Literal
.
$ python -c "import autoimport.version; print(autoimport.version.version_info())"
autoimport version: 1.2.2
python version: 3.10.4 | packaged by conda-forge | (main, Mar 24 2022, 17:39:04) [GCC 10.3.0]
platform: Linux-5.13.0-35-generic-x86_64-with-glibc2.31
I think autoimport should output the entire script even if it cannot resolve missing libraries. From what I can see, it doesn't output anything despite #131.
#! /usr/bin/env python
plt.style.use('ggplot')
cat example.py | autoimport -
It doesn't return the unmodified script.
I believe it should return the unmodified script.
╰─ → $ python -c "import autoimport.version; print(autoimport.version.version_info())"
autoimport version: 1.2.2
python version: 3.9.12 (main, Jun 1 2022, 11:38:51) [GCC 7.5.0]
platform: Linux-5.18.3-051803-generic-x86_64-with-glibc2.35
autoimport sometimes throws ValueError
when the import to remove appears twice
Create the following python file:
# tmp.py
import my_module.m
from my_module import _tm
Invoke autoimport:
$ autoimport tmp.py
Traceback (most recent call last):
File "/home/rig1/miniconda3/envs/utils/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
return self.main(*args, **kwargs)
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/autoimport/entrypoints/cli.py", line 84, in cli
fixed_code = services.fix_files(flattened_files, config)
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/autoimport/services.py", line 29, in fix_files
fixed_source = fix_code(source, config)
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/autoimport/services.py", line 73, in fix_code
return SourceCode(original_source_code, config=config).fix()
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/autoimport/model.py", line 68, in fix
self._fix_flake_import_errors()
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/autoimport/model.py", line 288, in _fix_flake_import_errors
self._remove_unused_imports(import_name)
File "/home/rig1/miniconda3/envs/utils/lib/python3.10/site-packages/autoimport/model.py", line 454, in _remove_unused_imports
imports.remove(object_name)
ValueError: list.remove(x): x not in list
Strangely, this bug seems dependent on the exact names of the imports. For example, if I do from my_module import _t
instead of from my_module import _tm
, no ValueError
occurs.
$ python -c "import autoimport.version; print(autoimport.version.version_info())"
------------------------------------------------------------------
autoimport: 1.2.3
Python: 3.10.5
Platform: Linux-5.15.0-48-generic-x86_64-with-glibc2.35
------------------------------------------------------------------
https://pypi.org/project/xdg/:
xdg has been renamed to xdg-base-dirs due to an import collision with PyXDG. Therefore the xdg package is deprecated. Install xdg-base-dirs instead.
tl;dr: you'd need to change this
Line 34 in f0ac03d
(and that
Line 382 in f0ac03d
and then this
to xdg_base_dirs
(and the one reference ofc 😅)
Import lines that also contain a semicolon separator will be incorrectly formatted.
Execute autoimport
on this file:
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hi(self):
import pdb;pdb.set_trace()
return f"Hello, my name is {self.name}"
Will result in this output:
import pdb;pdb.set_trace()
return f"Hello, my name is {self.name}"
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hi(self):
This is because it thinks this is a multiline import statement (due to the (
) character
The expected output should be:
import pdb
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hi(self):
pdb.set_trace()
return f"Hello, my name is {self.name}"
david ~ 1 $ autoimport --version
autoimport version: 1.0.0
python version: 3.8.7 (default, Jan 3 2021, 20:50:30) [GCC 10.2.0]
platform: Linux-5.10.89-1-MANJARO-x86_64-with-glibc2.2.5
See title
echo from subprocess import run as run > test.py
autoimport test.py
Traceback (most recent call last):
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/click/core.py", line 1128, in __call__
return self.main(*args, **kwargs)
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/click/core.py", line 1053, in main
rv = self.invoke(ctx)
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/click/core.py", line 1395, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/click/core.py", line 754, in invoke
return __callback(*args, **kwargs)
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/autoimport/entrypoints/cli.py", line 19, in cli
fixed_code = services.fix_files(files)
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/autoimport/services.py", line 27, in fix_files
fixed_source = fix_code(source)
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/autoimport/services.py", line 67, in fix_code
return SourceCode(original_source_code).fix()
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/autoimport/model.py", line 59, in fix
self._fix_flake_import_errors()
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/autoimport/model.py", line 254, in _fix_flake_import_errors
self._remove_unused_imports(import_name)
File "/home/sam/.cache/pypoetry/virtualenvs/charmonium.determ-hash-sYmCxUo--py3.9/lib/python3.9/site-packages/autoimport/model.py", line 405, in _remove_unused_imports
imports.remove(object_name)
ValueError: list.remove(x): x not in list
I did some basic debugging. The pattern on L397 does not expect as z
part of the statement. On L404, imports = ['x as z']
. L405 attempts to remove z
from this list.
No crash
autoimport 0.7.5
When an unimported symbol occurs multiple times, duplicate import statements may be produced.
demo.py
def f(x):
return numpy.sin(x) + numpy.cos(x) + numpy.tan(x)
autoimport demo.py
.The file will contain a duplicate import of numpy
.
import numpy
import numpy
import numpy
def f(x):
return numpy.sin(x) + numpy.cos(x) + numpy.tan(x)
The module should be imported only once.
import numpy
def f(x):
return numpy.sin(x) + numpy.cos(x) + numpy.tan(x)
>>> python -c "import autoimport.version; print(autoimport.version.version_info())"
autoimport version: 0.7.0
python version: 3.9.5 (default, May 18 2021, 19:34:48) [GCC 7.3.0]
platform: Linux-4.12.14-lp151.28.91-default-x86_64-with-glibc2.26
Currently, when autoimport FILENAME.py
does not find a suitable
completion, the program just crashes.
Instead in such as case, that symbol should be skipped and informative
messages should be given.
Consider this exmaple file:
## -- demo.py
def f(x):
return sin(x) + cos(x)
Instead, it would be desirable to obtain an output message along the lines of
>>> autoimport demo.py
demo.py:2: No such module: 'cos'
demo.py:2: No such module: 'sin'
and otherwise have autoimport
continue its work.
For such a file, autoimport demo.py
crashes:
>>> autoimport demo.py 2>&1 | head -5
Traceback (most recent call last):
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 736, in __str__
return self._str
AttributeError: _str
The current behavior of autoimport
allows to import objects from
modules by explicitly specifying them, e.g.
## -- demo2.py
def f(x):
return sin(x) + cos(x)
from numpy import sin, cos
which allows for more convenient workflows than contantly jumping back
to the import statements by using autoimport
's "move imports to
top" functionality.
>>> autoimport demo2.py && cat demo2.py
from numpy import sin, cos
def f(x):
return sin(x) + cos(x)
However, it fails if any of the missing imports are not given
explicitly, e.g.
## -- demo3.py
def f(x):
return sin(x) + cos(x)
from numpy import sin
>>> autoimport demo3.py 2>&1 | tail -5
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 738, in __str__
self._str = self._format_parsed_parts(self._drv, self._root,
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 718, in _format_parsed_parts
return drv + root + cls._flavour.join(parts[1:])
RecursionError: maximum recursion depth exceeded while calling a Python object
## -- demo.py
def f(x):
return sin(x) + cos(x)
>>> autoimport demo.py
Traceback (most recent call last):
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 736, in __str__
return self._str
AttributeError: _str
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/USERNAME/anaconda3/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/click/core.py", line 1137, in __call__
return self.main(*args, **kwargs)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/click/core.py", line 1062, in main
rv = self.invoke(ctx)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/click/core.py", line 763, in invoke
return __callback(*args, **kwargs)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/entrypoints/cli.py", line 19, in cli
fixed_code = services.fix_files(files)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/services.py", line 27, in fix_files
fixed_source = fix_code(source)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/services.py", line 67, in fix_code
return SourceCode(original_source_code).fix()
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/model.py", line 59, in fix
self._fix_flake_import_errors()
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/model.py", line 248, in _fix_flake_import_errors
self._add_package(object_name)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/model.py", line 260, in _add_package
import_string = self._find_package(object_name)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/model.py", line 287, in _find_package
package = getattr(self, check)(name)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/autoimport/model.py", line 303, in _find_package_in_our_project
project_package = os.path.basename(here()).replace("-", "_")
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/pyprojroot/pyprojroot.py", line 44, in here
project_path = py_project_root(Path(".").cwd(), project_files)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/pyprojroot/pyprojroot.py", line 18, in py_project_root
return py_project_root(path.parent, project_files)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/pyprojroot/pyprojroot.py", line 18, in py_project_root
return py_project_root(path.parent, project_files)
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/pyprojroot/pyprojroot.py", line 18, in py_project_root
return py_project_root(path.parent, project_files)
[Previous line repeated 971 more times]
File "/home/USERNAME/anaconda3/lib/python3.9/site-packages/pyprojroot/pyprojroot.py", line 15, in py_project_root
found = list(path.glob(file))
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 1167, in glob
for p in selector.select_from(self):
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 533, in _select_from
if (is_dir if self.dironly else exists)(path):
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 1414, in exists
self.stat()
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 1222, in stat
return self._accessor.stat(self)
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 743, in __fspath__
return str(self)
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 738, in __str__
self._str = self._format_parsed_parts(self._drv, self._root,
File "/home/USERNAME/anaconda3/lib/python3.9/pathlib.py", line 718, in _format_parsed_parts
return drv + root + cls._flavour.join(parts[1:])
RecursionError: maximum recursion depth exceeded while calling a Python object
>>> python -c "import autoimport.version; print(autoimport.version.version_info())"
autoimport version: 0.7.1
python version: 3.9.5 (default, May 18 2021, 19:34:48) [GCC 7.3.0]
platform: Linux-4.12.14-lp151.28.91-default-x86_64-with-glibc2.26
autoimport
was installed by:
>>> pip3 install git+https://github.com/lyz-code/autoimport.git@master
Collecting git+https://github.com/lyz-code/autoimport.git@master
Cloning https://github.com/lyz-code/autoimport.git (to revision master) to ./pip-req-build-q12jz4nv
Running command git clone -q https://github.com/lyz-code/autoimport.git /tmp/pip-req-build-q12jz4nv
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
Preparing wheel metadata: started
Preparing wheel metadata: finished with status 'done'
Requirement already satisfied: Click in /home/USERNAME/anaconda3/lib/python3.9/site-packages (from autoimport==0.7.1) (8.0.1)
Requirement already satisfied: autoflake in /home/USERNAME/anaconda3/lib/python3.9/site-packages (from autoimport==0.7.1) (1.4)
Requirement already satisfied: sh in /home/USERNAME/anaconda3/lib/python3.9/site-packages (from autoimport==0.7.1) (1.14.2)
Requirement already satisfied: pyprojroot in /home/USERNAME/anaconda3/lib/python3.9/site-packages (from autoimport==0.7.1) (0.2.0)
Requirement already satisfied: pyflakes>=1.1.0 in /home/USERNAME/anaconda3/lib/python3.9/site-packages (from autoflake->autoimport==0.7.1) (2.2.0)
Given a piece of code containing at least one unused multiline import statement, autoimport exits abnormally.
Given the following code:
from sympy import *
def compute_expression(expression: str) -> float:
expression = expression.replace('^', '**')
assignments, calculation = expression.split(';')[:-1], expression.split(';')[-1]
symbols_table = {}
for assignment in assignments:
variable, value = assignment.split('=')
symbols_table[variable.strip()] = float(value.strip())
for variable, value in symbols_table.items():
calculation = calculation.replace(variable, str(value))
result = eval(calculation)
return result
import unittest
from sympy import *
class TestComputeExpression(unittest.TestCase):
def test_single_operation(self):
expression = "x = 8; y = 4; z = 2; w = 3; x + y"
result = compute_expression(expression)
self.assertEqual(result, 12.0)
def test_multiple_operations(self):
expression = "x = 8; y = 4; z = 2; w = 3; x / (y + z) * w - z ^ w"
result = compute_expression(expression)
self.assertEqual(result, -1.0)
def test_parentheses(self):
expression = "x = 8; y = 4; z = 2; w = 3; (x + y) * z"
result = compute_expression(expression)
self.assertEqual(result, 24.0)
def test_exponentiation(self):
expression = "x = 8; y = 4; z = 2; w = 3; x ^ y"
result = compute_expression(expression)
self.assertEqual(result, 4096.0)
def test_variable_assignment(self):
expression = "x = 8; y = 4; z = 2; w = 3; x + y; x = 10; x + y"
result = compute_expression(expression)
self.assertEqual(result, 14.0)
And we use autoimport.fix_code(code_str) to fix it, autoimport exits with the following traceback:
Traceback (most recent call last):
File "D:\XXX\fix_code_test.py", line 54, in
print(fix_code(code))
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\services.py", line 73, in fix_code
return SourceCode(original_source_code, config=config).fix()
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 67, in fix
self._fix_flake_import_errors()
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 308, in _fix_flake_import_errors
self._remove_unused_imports(import_name)
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 455, in _remove_unused_imports
if re.match(
File "D:\anaconda3\envs\my_env\lib\re.py", line 190, in match
return _compile(pattern, flags).match(string)
File "D:\anaconda3\envs\my_env\lib\re.py", line 303, in _compile
p = sre_compile.compile(pattern, flags)
File "D:\anaconda3\envs\my_env\lib\sre_compile.py", line 788, in compile
p = sre_parse.parse(p, flags)
File "D:\anaconda3\envs\my_env\lib\sre_parse.py", line 955, in parse
p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
File "D:\anaconda3\envs\my_env\lib\sre_parse.py", line 444, in _parse_sub
itemsappend(_parse(source, state, verbose, nested + 1,
File "D:\anaconda3\envs\my_env\lib\sre_parse.py", line 672, in _parse
raise source.error("multiple repeat",
re.error: multiple repeat at position 31
It seems that the _remove_unused_imports function in model.py (lines 441 to 505) failed to consider the scenario where object_name is not a regular identifier but can be a "*" , which can leads to an abnormal regular expression in lines 456 and 457, which then leads to a multiple repeat exception when using re.match to match lines in the code.
It would be useful to support local conventions (such as import datetime as dt
) and names from local modules (from mymodule.mypackage.somewhere import SomeName
).
Doing this requires a config; a most simple config for this would be a py
file with example imports.
Example implementation: #170
For further consideration: an extra tool for gathering all imports from files, to build such config, to cleanup, tune, and use it.
Can be seen as an alternative to #39
Python CLI tools typically give the ability to be invoked via python3 -m <NAME>
. This is useful when multiple python versions are installed, and one want so pick up a specific version. isort
, flake8
, black
and others all support this functionality. autoimport
does not:
~$ python3 -m autoimport
/usr/local/bin/python3: No module named autoimport.__main__; 'autoimport' is a package and cannot be directly executed
This can be easily achieved by adding a __main__.py
file in the same directory as __init__.py
. Within __main__.py
it should be sufficient to just do (not tested):
from .entrypoints.cli import cli
cli()
Running autoimport on a file with unix line ending (LR) in Windows convert it into Windows line endings (CRLF).
Line ending converted to OS line endings.
Line endings should be preserved.
When used on a python script, autoimport
breaks the shebang and the file-variables line used by Emacs (which must come immediately after the shebang).
Create a script file test.py
with contents
#!/usr/bin/env python3
# -*- coding: latin-1 -*-
"""docstring"""
print(os.path.exists("."))
and run autoimport test.py
.
The file will now contain
import os
#!/usr/bin/env python3
# -*- coding: latin-1 -*-
"""docstring"""
print(os.path.exists("."))
Not only does this break the shebang, module docstring and file variables, it is also potentially dangerous, because import
is an existing executable associated with ImageMagick.
There are many possible ways changing the position of the imports might break a python file, some of which might depend on the tooling used by the developer.
Imports should therefore be positioned
autoimport version: 0.5.0
python version: 3.8.5 (default, Sep 4 2020, 07:30:14) [GCC 7.3.0]
platform: Linux-4.12.14-lp151.28.52-default-x86_64-with-glibc2.10
following instructions here https://lyz-code.github.io/autoimport/contributing/#pull-requests
all steps work fine until getting to the git commit
stage. this fails with the following error:
[WARNING] The 'rev' field of repo 'https://github.com/ambv/black' appears to be a mutable reference (moving tag / branch). Mutable references are never updated after first install and are not supported. See https://pre-commit.com/#using-the-latest-version-for-a-repository for more details. Hint: `pre-commit autoupdate` often fixes this.
[WARNING] The 'rev' field of repo 'https://github.com/life4/flakehell/' appears to be a mutable reference (moving tag / branch). Mutable references are never updated after first install and are not supported. See https://pre-commit.com/#using-the-latest-version-for-a-repository for more details. Hint: `pre-commit autoupdate` often fixes this.
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Initializing environment for https://github.com/ambv/black.
An unexpected error has occurred: CalledProcessError: command: ('/Library/Developer/CommandLineTools/usr/libexec/git-core/git', 'checkout', 'master')
return code: 1
expected return code: 0
stdout: (none)
stderr:
error: pathspec 'master' did not match any file(s) known to git
Check the log at /Users/.../.cache/pre-commit/pre-commit.log
i believe this is due to the fact that black
repo has no master
branch (been renamed to main
). however i think there are larger issues here, note the pre-commit
warnings at the top of the trace.
also, one of the pre-commit
hooks is flakehell which has been archived. there is a fork but perhaps it would be best to use a different tool here?
follow the steps in the contributing guide and then try to commit some changes
the error happens
i'm able to commit changes
autoimport version: 0.7.3
python version: 3.7.4 (default, Sep 15 2021, 11:54:44) [Clang 12.0.0 (clang-1200.0.32.29)]
platform: Darwin-19.6.0-x86_64-i386-64bit
When autoimport removes the last import from a multi-line parenthetical import statement, the result gives a SyntaxError
.
from foo import (
bar,
baz,
)
autoimport
from foo import (
)
SyntaxError
.Autoimport should produce valid python code. The from foo import (\n)
should be removed.
>>> print(autoimport.version.version_info())
autoimport version: 1.0.0
python version: 3.9.9 | packaged by conda-forge | (main, Dec 20 2021, 02:40:17) [GCC 9.4.0]
platform: Linux-5.4.0-91-generic-x86_64-with-glibc2.27
autoimport
crashes when there are multiple imports from the same module and one of the imports is marked with a # noqa
comment.
Here is a file that causes a crash:
# tmp.py
from typing import Any # noqa
from typing import TypeVar
Here is the output from autoimport
:
$ autoimport tmp.py
Traceback (most recent call last):
File "/home/jasha10/miniconda3/envs/pysc/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 1128, in __call__
return self.main(*args, **kwargs)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 1053, in main
rv = self.invoke(ctx)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 1395, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 754, in invoke
return __callback(*args, **kwargs)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/entrypoints/cli.py", line 21, in cli
fixed_code = services.fix_files(files, config)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/services.py", line 29, in fix_files
fixed_source = fix_code(source, config)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/services.py", line 69, in fix_code
return SourceCode(original_source_code, config=config).fix()
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/model.py", line 62, in fix
self._fix_flake_import_errors()
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/model.py", line 257, in _fix_flake_import_errors
self._remove_unused_imports(import_name)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/model.py", line 411, in _remove_unused_imports
imports.remove(object_name)
ValueError: list.remove(x): x not in list
Ideally, the noqa line(s) should not be touched, and the other line(s) should be processed as usual.
$ autoimport --version
autoimport version: 0.8.0
python version: 3.9.7 | packaged by conda-forge | (default, Sep 29 2021, 19:23:11) [GCC 9.4.0]
platform: Linux-5.4.0-87-generic-x86_64-with-glibc2.27
When developing a package I prefer to use relative imports over absolute ones to avoid loop dependencies. Right now autoimport only uses absolute imports, so I need to remove the absolute reference and convert it to relative.
It's not easy to solve, as we can't take into account the relative position of the file we're fixing regarding the rest of the project, as some of the tools that use autoimport (ALE for vim integration), copies the file to a temporal directory and applies the fixer there.
So we would need to:
Make autoimport manage the commonly used imports.
Add an entry in _find_package
similar to _find_package_in_typing
that has a dictionary of object and import string.
For example:
from _pytest.logging import LogCaptureFixture
def test_baz(caplog: LogCaptureFixture):
func_under_test()
for record in caplog.records:
assert record.levelname != "CRITICAL"
assert "wally" not in caplog.text
We could have the dictionary {'LogCaptureFixture': 'from _pytest.logging import LogCaptureFixture'}
.
If you are developing a package and install it with pip install -e .
, whenever you make a change that breaks the package, autoimport is not going to be able to load the objects as it is not able lo import them.
We want to be able to import the package objects even if the package is broken
autoimport
does not properly handle top-level use of if TYPE_CHECKING: ...
Run autoimport
on the following file:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
foo = "bar"
The output looks like this:
if TYPE_CHECKING:
foo = "bar"
Why did the from typing ...
import disappear?
Run autoimport
on the following file:
if TYPE_CHECKING:
foo = "bar"
The output looks like this:
from typing import TYPE_CHECKING
Why did the if TYPE_CHECKING: ...
block disappear?
Run autoimport
on the following file:
from typing import TYPE_CHECKING
The output is empty:
Repeatedly running autoimport
on the file from Case 1 causes the file's contents to completely disappear.
autoimport
should not remove the if TYPE_CHECKING: ...
block or the related import from typing ...
.
$ python -c "import autoimport.version; print(autoimport.version.version_info())"
------------------------------------------------------------------
autoimport: 1.3.1
Python: 3.9.12
Platform: Linux-5.15.0-52-generic-x86_64-with-glibc2.31
------------------------------------------------------------------
Cannot run autoimport on a UTF-8 file with cyrillic characters on Windows.
> autoimport <any_file_with_non_ascii>.py
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:\Users\user\Projects\MyProject\.venv\Scripts\autoimport.exe\__main__.py", line 7, in <module>
File "C:\Users\user\Projects\MyProject\.venv\lib\site-packages\click\core.py", line 1157, in __call__
return self.main(*args, **kwargs)
File "C:\Users\user\Projects\MyProject\.venv\lib\site-packages\click\core.py", line 1078, in main
rv = self.invoke(ctx)
File "C:\Users\user\Projects\MyProject\.venv\lib\site-packages\click\core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "C:\Users\user\Projects\MyProject\.venv\lib\site-packages\click\core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "C:\Users\user\Projects\MyProject\.venv\lib\site-packages\autoimport\entrypoints\cli.py", line 94, in cli
fixed_code = services.fix_files(flattened_files, config)
File "C:\Users\user\Projects\MyProject\.venv\lib\site-packages\autoimport\services.py", line 28, in fix_files
source = file_wrapper.read()
File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\encodings\cp1251.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 29668: character maps to <undefined>
Just works and fixes the file.
Windows 11
Python 3.9
autoimport==1.3.3
I made a workaround for myself by adding encoding='utf-8'
at
files.append(click.File("r+", encoding='utf-8').convert(py_file, None, None))
and at
return click.File("r+", encoding='utf-8').convert(value, param, ctx)
But it would be better to have a special encoding parameter at the command line arguments and/or in the pyproject.toml
configuration file.
The idea of have a list of "common statements" in the pyproject file seems ok for small project, but it's unmaintainable for large scale ones.
For instance, I have a project with several subpackages defining different classes (sqlalchemy models) and I would like to be able to autoimport them without needing to declare them explicitly.
The point is I have plenty other modules where I already imported those classes and I would like just
So, I guess it could be possible to walk sibling modules (or beyond) and try to find there the any missing object is being imported, in a sake of "automatic" common statements.
If this idea fits in the project I could try to implement it.
I wasn't sure if this is a bug or a feature, but whenever I run autoimport
a blank line is inserted above the import statements.
If this is a feature, it would be great to have a config option to turn it off. If it's a bug, should be as simple as removing whatever is inserting it, I'd be happy to open a PR depending on what needs to be done.
I'm running this from the command line via a vim command: :!autoimport %
I'd like to request the ability to extend the common_statements
dict.
One idea is to allow user configuration (via e.g. pyproject.toml
or .autoimport.ini
or CLI arguments), so that the user can add their own common statements
As an example, I find myself typing from numpy import typing as npt
quite a bit. It would be nice to automate this with autoimport.
Thanks!
I'd like that autoimport
can figure out its opts, akin to pytest
s addopts
With that, some more documentation examples would be welcome
PS: I am aware of the maintenance mode. Just wanted to add the idea to the wall.
I've stumbled upon a bug that comes up when using the TYPE_CHECKING
guard together with a star import.
Here's a minimal reproducible example:
# repro.py
from typing import TYPE_CHECKING
from module_1 import *
if TYPE_CHECKING:
import module_2
$ autoimport repro.py
Traceback (most recent call last):
File "/home/homestar/tmp/.direnv/python-3.11.3/bin/autoimport", line 8, in <module>
sys.exit(cli())
^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/autoimport/entrypoints/cli.py", line 94, in cli
fixed_code = services.fix_files(flattened_files, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/autoimport/services.py", line 29, in fix_files
fixed_source = fix_code(source, config)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/autoimport/services.py", line 73, in fix_code
return SourceCode(original_source_code, config=config).fix()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/autoimport/model.py", line 67, in fix
self._fix_flake_import_errors()
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/autoimport/model.py", line 308, in _fix_flake_import_errors
self._remove_unused_imports(import_name)
File "/home/homestar/tmp/.direnv/python-3.11.3/lib/python3.11/site-packages/autoimport/model.py", line 455, in _remove_unused_imports
if re.match(
^^^^^^^^^
File "/home/homestar/.pyenv/versions/3.11.3/lib/python3.11/re/__init__.py", line 166, in match
return _compile(pattern, flags).match(string)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/.pyenv/versions/3.11.3/lib/python3.11/re/__init__.py", line 294, in _compile
p = _compiler.compile(pattern, flags)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/.pyenv/versions/3.11.3/lib/python3.11/re/_compiler.py", line 743, in compile
p = _parser.parse(p, flags)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/.pyenv/versions/3.11.3/lib/python3.11/re/_parser.py", line 980, in parse
p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/.pyenv/versions/3.11.3/lib/python3.11/re/_parser.py", line 455, in _parse_sub
itemsappend(_parse(source, state, verbose, nested + 1,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/homestar/.pyenv/versions/3.11.3/lib/python3.11/re/_parser.py", line 685, in _parse
raise source.error("multiple repeat",
re.error: multiple repeat at position 37
It seems to be an issue with one of Autoimport's regex patterns. The error only occurs if both the star import and the (Edit: see my comment below)if TYPE_CHECKING
block are present.
------------------------------------------------------------------
autoimport: 1.3.3
Python: 3.11.3
Platform: Linux-5.15.0-75-generic-x86_64-with-glibc2.31
------------------------------------------------------------------
Hello,
Autoimport crashes on an empty file.
Here is a minimal example:
$ touch empty.py
$ autoimport empty.py
Traceback (most recent call last):
File "/home/jasha10/miniconda3/envs/pysc/bin/autoimport", line 8, in <module>
sys.exit(cli())
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 1137, in __call__
return self.main(*args, **kwargs)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 1062, in main
rv = self.invoke(ctx)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/click/core.py", line 763, in invoke
return __callback(*args, **kwargs)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/entrypoints/cli.py", line 19, in cli
fixed_code = services.fix_files(files)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/services.py", line 27, in fix_files
fixed_source = fix_code(source)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/services.py", line 67, in fix_code
return SourceCode(original_source_code).fix()
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/model.py", line 47, in __init__
self._split_code(source_code)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/model.py", line 78, in _split_code
self._extract_typing_statements(source_code_lines)
File "/home/jasha10/miniconda3/envs/pysc/lib/python3.9/site-packages/autoimport/model.py", line 154, in _extract_typing_statements
if re.match(r"^if TYPE_CHECKING:$", source_lines[typing_start_line]):
IndexError: list index out of range
Autoimport version 0.7.2
CPython version 3.9.6
Error happens on unused import ending wirh #noqa: autoimport
.
from os import getcwd # noqa: autoimport
autoimport test.py
Got ValueError: list.remove(x): x not in list
in terminal.
Just ignore the noqa
line.
python -c "import autoimport.version; print(autoimport.version.version_info())"
autoimport version: 0.7.4
python version: 3.8.10 (default, Sep 28 2021, 16:10:42) [GCC 9.3.0]
platform: Linux-5.8.0-53-generic-x86_64-with-glibc2.29
One of the most useful use case for auto import is when using PyQt/PySide classes. This poses several problems
Pre-generate the symbol list in the modules. This should be manually run by the user. Since python modules can have side effect, importing any/all modules in the PYTHONPATH could be dangerous. Module priority could be defined by using configuration file in the project directory.
Hi all, right now I'm not using this project and don't have the time to maintain it, I plan to start using it again in the future so I'll probably restore the maintenance mode. This means:
Install
and Update
CI pipelines).If you want to see the project thrive please evaluate becoming a maintainer and help me answering issues, pull requests and develop the program.
This announcement is not meant to prevent you from opening issues! Even though I'm not maintaining the project right now, it's always good to do requests. Maybe others in the community can help you :).
If you need to get my attention you can reach me here
from foo import bar
class C(bar.C):
def method(self, param):
from foo.some_very_long_name_of_a_module.another_submodule.wait_for_it import (
yet_another_long_name
)
yet_another_long_name(param)
Run autoimport
on that file.
from foo import bar
from foo.some_very_long_name_of_a_module.another_submodule.wait_for_it import (
yet_another_long_name
)
class C(bar.C):
def method(self, param):
yet_another_long_name(param)
Syntax is not broken. Import moved correctly (or not moved, see #249)
autoimport 1.3.3
By the way, neither make version
nor python -c "import autoimport.version; print(autoimport.version.version_info())"
do work with pipx, I used pipx list
, which is a bit rigid.
Hi all, right now I only find time to maintain autoimport
this means:
If you want to see the project thrive please evaluate becoming a maintainer and help me answering issues, pull requests and develop the program.
This announcement is not meant to prevent you from opening issues! Even though we're in maintenance mode it's always good to do requests, maybe other autoimport
users want to implement it :)
I'm a Cyber Security researcher and developer of PackjGuard [1] to address open-source software supply chain attacks.
During my research, I found that this repo is vulnerable to attack due to deleted dependency from the public PyPI registry.
Specifically, file https://github.com/lyz-code/autoimport/blob/b421368d64027a0d253ae247da8ce08659f5277c/pyproject.toml
lists projroot
as one of the dependencies. However, it has been deleted from public PyPI. As such, an external bad actor can claim that name and register a malicious package, which will be then installed with pip install
command, resulting in arbitrary remote code execution.
Not only your apps/services using https://github.com/lyz-code/autoimport
repo code are vulnerable to this attack, but the users of your open-source Github repo could also fall victim.
You could read more about such attacks here: https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610
Please manually register a placeholder projroot
package on PyPI immediately or remove projroot
dependency from https://github.com/lyz-code/autoimport/blob/b421368d64027a0d253ae247da8ce08659f5277c/pyproject.toml
to fix this vulnerability.
To automatically fix such issues in future, please install PackjGuard Github app [1].
Thanks!
There is currently no way to tell both black and autoimport to ignore formatting a line.
This can be an issue when using black along with autoimport but wanting both formatters to ignore a debugger line.
The # noqa: autoimport
is not recognised by black, so the current implementations does not suffice.
Black uses # fmt: skip
as an instruction to not format a line.
We can utilise this same marker to ensure neither autoimport or black format a given line.
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/Users/yoland/Library/Python/3.10/lib/python/site-packages/autoimport/__main__.py", line 3, in <module>
from autoimport.entrypoints.cli import cli
File "/Users/yoland/Library/Python/3.10/lib/python/site-packages/autoimport/entrypoints/cli.py", line 10, in <module>
from maison.config import ProjectConfig
File "/Users/yoland/Library/Python/3.10/lib/python/site-packages/maison/__init__.py", line 2, in <module>
from .config import ProjectConfig
File "/Users/yoland/Library/Python/3.10/lib/python/site-packages/maison/config.py", line 12, in <module>
from maison.schema import ConfigSchema
File "/Users/yoland/Library/Python/3.10/lib/python/site-packages/maison/schema.py", line 2, in <module>
from pydantic import BaseModel
ImportError: dlopen(/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pydantic/__init__.cpython-310-darwin.so, 0x0002): tried: '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pydantic/__init__.cpython-310-darwin.so' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64')), '/System/Volumes/Preboot/Cryptexes/OS/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pydantic/__init__.cpython-310-darwin.so' (no such file), '/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pydantic/__init__.cpython-310-darwin.so' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64'))
Since __init__.py
files tend to have "unused" imports, autoimport will happily remove them.
This is fine if the script is run from somewhere where we can easily filter out the __init__.py
(like in a Makefile), but becomes unwieldy when run through "fix-on-save" in your editor.
autoflake
has solved the same problem with a --ignore-init-module-imports
flag, perhaps we could add the same to autoimport?
Edit: should've opened this as a feature request, sry.
I work on a project which has many function-local imports because top imports would cause import cycles. But I can't use autoimport because it insists on moving them to the top (and also produces invalid syntax in this case, but that's another story).
Make "move-import-to-top" feature optional, so it can be disabled, and still keep the "remove-unused-imports" feature.
autoimport removes extra blank lines after imports, even when it’s required for PEP 8 compliance (e.g. when imports are directly followed by a class
or a def
). And also I like doing lines_after_imports = 2
in isort for consistency anyway.
While you may say I can just run another auto-formatter afterwards to fix the issue, this actually makes it impossible to use autoimport as a pre-commit hook, as on the next run autoimport will remove the blank line again, and pre-commit requires all hooks to succeed.
import random
def foo():
print(random.random())
autoimport foo.py
The file gets rewritten to this:
import random
def foo():
print(random.random())
The file should remain untouched.
autoimport version: 1.2.2
python version: 3.10.4 (main, Apr 4 2022, 14:54:08) [GCC 10.2.1 20210110]
platform: Linux-5.10.0-16-amd64-x86_64-with-glibc2.31
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.