diff options
author | Timothy Crosley <timothy.crosley@gmail.com> | 2019-03-01 23:57:52 -0800 |
---|---|---|
committer | Timothy Crosley <timothy.crosley@gmail.com> | 2019-03-01 23:57:52 -0800 |
commit | 30b1e9f57b3fd5f09327a0094f6ed793f1c9b3a3 (patch) | |
tree | 247f57130c1968b64385df16f98c677368312be1 | |
parent | f0badf18389935b0275660f8f3ef9899dc4c4f49 (diff) | |
parent | a7992050c0721139c7dd40abd7f7d746576abd12 (diff) | |
download | isort-30b1e9f57b3fd5f09327a0094f6ed793f1c9b3a3.tar.gz |
Merge in latest from master
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | isort/__init__.py | 2 | ||||
-rw-r--r-- | isort/finders.py | 20 | ||||
-rw-r--r-- | isort/settings.py | 8 | ||||
-rwxr-xr-x | setup.py | 2 | ||||
-rw-r--r-- | test_isort.py | 97 | ||||
-rw-r--r-- | tox.ini | 2 |
7 files changed, 86 insertions, 48 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e72551a6..6635a5af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ Internal: Planned: - profile support for common project types (black, django, google, etc) +### 4.3.9 - Feburary 25, 2019 - hot fix release +- Fixed a bug that led to an incompatibility with black: #831 + ### 4.3.8 - Feburary 25, 2019 - hot fix release - Fixed a bug that led to the recursive option not always been available from the command line. diff --git a/isort/__init__.py b/isort/__init__.py index 3553b811..63034de6 100644 --- a/isort/__init__.py +++ b/isort/__init__.py @@ -22,4 +22,4 @@ OTHER DEALINGS IN THE SOFTWARE. from . import settings # noqa: F401 from .isort import SortImports # noqa: F401 -__version__ = "4.3.8" +__version__ = "4.3.9" diff --git a/isort/finders.py b/isort/finders.py index e21ef447..05abb585 100644 --- a/isort/finders.py +++ b/isort/finders.py @@ -34,6 +34,11 @@ try: except ImportError: Pipfile = None +try: + from functools import lru_cache +except ImportError: + from backports.functools_lru_cache import lru_cache + KNOWN_SECTION_MAPPING = { 'STDLIB': 'STANDARD_LIBRARY', @@ -268,6 +273,13 @@ class RequirementsFinder(ReqsBaseFinder): def _get_files_from_dir(self, path: str) -> Iterator[str]: """Return paths to requirements files from passed dir. """ + return RequirementsFinder._get_files_from_dir_cached(path) + + @classmethod + @lru_cache(maxsize=16) + def _get_files_from_dir_cached(cls, path): + result = [] + for fname in os.listdir(path): if 'requirements' not in fname: continue @@ -276,16 +288,16 @@ class RequirementsFinder(ReqsBaseFinder): # *requirements*/*.{txt,in} if os.path.isdir(full_path): for subfile_name in os.listdir(path): - for ext in self.exts: + for ext in cls.exts: if subfile_name.endswith(ext): - yield os.path.join(path, subfile_name) + result.append(os.path.join(path, subfile_name)) continue # *requirements*.{txt,in} if os.path.isfile(full_path): - for ext in self.exts: + for ext in cls.exts: if fname.endswith(ext): - yield full_path + result.append(full_path) break def _get_names(self, path: str) -> Iterator[str]: diff --git a/isort/settings.py b/isort/settings.py index c1d17802..1fbd8cb6 100644 --- a/isort/settings.py +++ b/isort/settings.py @@ -28,7 +28,6 @@ import fnmatch import os import posixpath import re -import stat import warnings from distutils.util import strtobool from functools import lru_cache @@ -337,7 +336,10 @@ def should_skip( path: str = '/' ) -> bool: """Returns True if the file should be skipped based on the passed in settings.""" - normalized_path = posixpath.join(path.replace('\\', '/'), filename) + os_path = os.path.join(path, filename) + normalized_path = os_path.replace('\\', '/') + if normalized_path[1:2] == ':': + normalized_path = normalized_path[2:] if config['safety_excludes'] and safety_exclude_re.search(normalized_path): return True @@ -356,7 +358,7 @@ def should_skip( if fnmatch.fnmatch(filename, glob): return True - if stat.S_ISFIFO(os.stat(normalized_path).st_mode): + if not (os.path.isfile(os_path) or os.path.isdir(os_path) or os.path.islink(os_path)): return True return False @@ -6,7 +6,7 @@ with open('README.rst') as f: readme = f.read() setup(name='isort', - version='4.3.8', + version='4.3.9', description='A Python utility / library to sort Python imports.', long_description=readme, author='Timothy Crosley', diff --git a/test_isort.py b/test_isort.py index b35d6cdd..4a919fff 100644 --- a/test_isort.py +++ b/test_isort.py @@ -23,6 +23,7 @@ OTHER DEALINGS IN THE SOFTWARE. from tempfile import NamedTemporaryFile import os import os.path +import posixpath import sys import sysconfig @@ -51,7 +52,6 @@ skip = build,.tox,venv balanced_wrapping = true not_skip = __init__.py """ - SHORT_IMPORT = "from third_party import lib1, lib2, lib3, lib4" SINGLE_FROM_IMPORT = "from third_party import lib1" SINGLE_LINE_LONG_IMPORT = "from third_party import lib1, lib2, lib3, lib4, lib5, lib5ab" @@ -565,7 +565,7 @@ def test_skip_with_file_name(): test_input = ("import django\n" "import myproject\n") - sort_imports = SortImports(file_path='/baz.py', file_contents=test_input, known_third_party=['django'], + sort_imports = SortImports(file_path='/baz.py', file_contents=test_input, settings_path=os.getcwd(), skip=['baz.py']) assert sort_imports.skipped assert sort_imports.output is None @@ -1721,7 +1721,7 @@ def test_other_file_encodings(tmpdir): tmp_fname = tmpdir.join('test_{0}.py'.format(encoding)) file_contents = "# coding: {0}\n\ns = u'ã'\n".format(encoding) tmp_fname.write_binary(file_contents.encode(encoding)) - assert SortImports(file_path=str(tmp_fname)).output == file_contents + assert SortImports(file_path=str(tmp_fname), settings_path=os.getcwd()).output == file_contents def test_comment_at_top_of_file(): @@ -2516,32 +2516,49 @@ def test_to_ensure_tabs_dont_become_space_issue_665(): def test_new_lines_are_preserved(): - with NamedTemporaryFile('w', suffix='py') as rn_newline: - with open(rn_newline.name, 'w', newline='') as rn_newline_input: + with NamedTemporaryFile('w', suffix='py', delete=False) as rn_newline: + pass + + try: + with io.open(rn_newline.name, mode='w', newline='') as rn_newline_input: rn_newline_input.write('import sys\r\nimport os\r\n') - rn_newline_input.flush() - SortImports(rn_newline.name) - with open(rn_newline.name, newline='') as rn_newline_file: - rn_newline_contents = rn_newline_file.read() - assert rn_newline_contents == 'import os\r\nimport sys\r\n' - - with NamedTemporaryFile('w', suffix='py') as r_newline: - with open(r_newline.name, 'w', newline='') as r_newline_input: + + SortImports(rn_newline.name, settings_path=os.getcwd()) + with io.open(rn_newline.name) as new_line_file: + print(new_line_file.read()) + with io.open(rn_newline.name, newline='') as rn_newline_file: + rn_newline_contents = rn_newline_file.read() + assert rn_newline_contents == 'import os\r\nimport sys\r\n' + finally: + os.remove(rn_newline.name) + + with NamedTemporaryFile('w', suffix='py', delete=False) as r_newline: + pass + + try: + with io.open(r_newline.name, mode='w', newline='') as r_newline_input: r_newline_input.write('import sys\rimport os\r') - r_newline_input.flush() - SortImports(r_newline.name) - with open(r_newline.name, newline='') as r_newline_file: - r_newline_contents = r_newline_file.read() - assert r_newline_contents == 'import os\rimport sys\r' - - with NamedTemporaryFile('w', suffix='py') as n_newline: - with open(n_newline.name, 'w', newline='') as n_newline_input: + + SortImports(r_newline.name, settings_path=os.getcwd()) + with io.open(r_newline.name, newline='') as r_newline_file: + r_newline_contents = r_newline_file.read() + assert r_newline_contents == 'import os\rimport sys\r' + finally: + os.remove(r_newline.name) + + with NamedTemporaryFile('w', suffix='py', delete=False) as n_newline: + pass + + try: + with io.open(n_newline.name, mode='w', newline='') as n_newline_input: n_newline_input.write('import sys\nimport os\n') - n_newline_input.flush() - SortImports(n_newline.name) - with open(n_newline.name, newline='') as n_newline_file: - n_newline_contents = n_newline_file.read() - assert n_newline_contents == 'import os\nimport sys\n' + + SortImports(n_newline.name, settings_path=os.getcwd()) + with io.open(n_newline.name, newline='') as n_newline_file: + n_newline_contents = n_newline_file.read() + assert n_newline_contents == 'import os\nimport sys\n' + finally: + os.remove(n_newline.name) @pytest.mark.skipif(not finders.RequirementsFinder.enabled, reason='RequirementsFinder not enabled (too old version of pip?)') @@ -2665,11 +2682,11 @@ def test_path_finder(monkeypatch): third_party_prefix = next(path for path in finder.paths if "site-packages" in path) ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") or ".so" imaginary_paths = set([ - os.path.join(finder.stdlib_lib_prefix, "example_1.py"), - os.path.join(third_party_prefix, "example_2.py"), - os.path.join(third_party_prefix, "example_3.so"), - os.path.join(third_party_prefix, "example_4" + ext_suffix), - os.path.join(os.getcwd(), "example_5.py"), + posixpath.join(finder.stdlib_lib_prefix, "example_1.py"), + posixpath.join(third_party_prefix, "example_2.py"), + posixpath.join(third_party_prefix, "example_3.so"), + posixpath.join(third_party_prefix, "example_4" + ext_suffix), + posixpath.join(os.getcwd(), "example_5.py"), ]) monkeypatch.setattr("isort.finders.exists_case_sensitive", lambda p: p in imaginary_paths) assert finder.find("example_1") == finder.sections.STDLIB @@ -2693,17 +2710,18 @@ def test_command_line(tmpdir, capfd, multiprocess): from isort.main import main tmpdir.join("file1.py").write("import re\nimport os\n\nimport contextlib\n\n\nimport isort") tmpdir.join("file2.py").write("import collections\nimport time\n\nimport abc\n\n\nimport isort") - arguments = ["-rc", str(tmpdir)] + arguments = ["-rc", str(tmpdir), '--settings-path', os.getcwd()] if multiprocess: arguments.extend(['--jobs', '2']) main(arguments) assert tmpdir.join("file1.py").read() == "import contextlib\nimport os\nimport re\n\nimport isort\n" assert tmpdir.join("file2.py").read() == "import abc\nimport collections\nimport time\n\nimport isort\n" - out, err = capfd.readouterr() - assert not err - # it informs us about fixing the files: - assert str(tmpdir.join("file1.py")) in out - assert str(tmpdir.join("file2.py")) in out + if not sys.platform.startswith('win'): + out, err = capfd.readouterr() + assert not err + # it informs us about fixing the files: + assert str(tmpdir.join("file1.py")) in out + assert str(tmpdir.join("file2.py")) in out @pytest.mark.parametrize('enabled', (False, True)) @@ -2713,12 +2731,15 @@ def test_safety_excludes(tmpdir, enabled): tmpdir.mkdir("lib").mkdir("python3.7").join("importantsystemlibrary.py").write("# ...") config = dict(settings.default.copy(), safety_excludes=enabled) skipped = [] + codes = [str(tmpdir)], + main.iter_source_code(codes, config, skipped) file_names = set(os.path.relpath(f, str(tmpdir)) for f in main.iter_source_code([str(tmpdir)], config, skipped)) if enabled: assert file_names == {'victim.py'} assert len(skipped) == 2 else: - assert file_names == {'.tox/verysafe.py', 'lib/python3.7/importantsystemlibrary.py', 'victim.py'} + assert file_names == {os.sep.join(('.tox', 'verysafe.py')), + os.sep.join(('lib', 'python3.7', 'importantsystemlibrary.py')), 'victim.py'} assert not skipped @@ -13,7 +13,7 @@ extras = pipfile pyproject requirements -commands = py.test test_isort.py {posargs} +commands = py.test -vv -s test_isort.py {posargs} [testenv:isort-check] basepython = python3 |