diff options
-rw-r--r-- | .travis.yml | 10 | ||||
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | README.rst | 2 | ||||
-rw-r--r-- | appveyor.yml | 2 | ||||
-rw-r--r-- | isort/__init__.py | 3 | ||||
-rw-r--r-- | isort/__main__.py | 2 | ||||
-rw-r--r-- | isort/finders.py | 21 | ||||
-rw-r--r-- | isort/hooks.py | 2 | ||||
-rw-r--r-- | isort/isort.py | 10 | ||||
-rw-r--r-- | isort/main.py | 2 | ||||
-rw-r--r-- | isort/pie_slice.py | 129 | ||||
-rw-r--r-- | isort/settings.py | 27 | ||||
-rw-r--r-- | setup.cfg | 3 | ||||
-rwxr-xr-x | setup.py | 10 | ||||
-rw-r--r-- | test_isort.py | 46 | ||||
-rw-r--r-- | tox.ini | 3 |
16 files changed, 44 insertions, 233 deletions
diff --git a/.travis.yml b/.travis.yml index a4815179..e1205586 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ language: python cache: pip matrix: include: - - env: TOXENV=isort-check - - env: TOXENV=lint - - python: 2.7 - env: TOXENV=py27 + - python: 3.7 + env: TOXENV=isort-check + - python: 3.7 + env: TOXENV=lint - python: 3.4 env: TOXENV=py34 - python: 3.5 @@ -16,8 +16,6 @@ matrix: env: TOXENV=py36 - python: 3.7 env: TOXENV=py37 - - python: pypy2.7-6.0 - env: TOXENV=pypy - python: pypy3.5-6.0 env: TOXENV=pypy3 install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fef20fb..ed7984a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ Changelog ========= +### UNRELEASED +- **Breaking changes:** + - isort now requires Python 3.4+ to run but continues to support formating + Python 2 code. + ### 4.3.4 - Feburary 12, 2018 - hotfix release - Fixed issue #671: isort is corrupting CRLF files @@ -29,7 +29,7 @@ isort your python imports for you so you don't have to. isort is a Python utility / library to sort imports alphabetically, and automatically separated into sections. It provides a command line utility, Python library and `plugins for various editors <https://github.com/timothycrosley/isort/wiki/isort-Plugins>`_ to quickly sort all your imports. -It currently cleanly supports Python 2.7 and 3.4+ without any dependencies. +It requires Python 3.4+ to run but supports formatting Python 2 code too. .. image:: https://raw.github.com/timothycrosley/isort/develop/example.gif :alt: Example Usage diff --git a/appveyor.yml b/appveyor.yml index 11c69a45..636ce96f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,4 +9,4 @@ install: - pip install tox test_script: - - tox -e isort-check,py27,py34,py35,py36,py37 + - tox -e isort-check,py34,py35,py36,py37 diff --git a/isort/__init__.py b/isort/__init__.py index 4f1adaa0..881077e2 100644 --- a/isort/__init__.py +++ b/isort/__init__.py @@ -19,9 +19,6 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFT OTHER DEALINGS IN THE SOFTWARE. """ - -from __future__ import absolute_import, division, print_function, unicode_literals - from . import settings # noqa: F401 from .isort import SortImports # noqa: F401 diff --git a/isort/__main__.py b/isort/__main__.py index 186c98e8..94b1d057 100644 --- a/isort/__main__.py +++ b/isort/__main__.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import - from isort.main import main main() diff --git a/isort/finders.py b/isort/finders.py index 54259afd..66ae7ee4 100644 --- a/isort/finders.py +++ b/isort/finders.py @@ -1,7 +1,5 @@ """Finders try to find right section for passed module name """ -from __future__ import absolute_import, division, print_function, unicode_literals - import inspect import os import os.path @@ -11,7 +9,6 @@ import sysconfig from fnmatch import fnmatch from glob import glob -from .pie_slice import PY2 from .utils import chdir, exists_case_sensitive try: @@ -70,7 +67,7 @@ class LocalFinder(BaseFinder): class KnownPatternFinder(BaseFinder): def __init__(self, config, sections): - super(KnownPatternFinder, self).__init__(config, sections) + super().__init__(config, sections) self.known_patterns = [] for placement in reversed(self.sections): @@ -86,16 +83,6 @@ class KnownPatternFinder(BaseFinder): regexp = '^' + known_pattern.replace('*', '.*').replace('?', '.?') + '$' self.known_patterns.append((re.compile(regexp), placement)) - @staticmethod - def _is_package(path): - """ - Evaluates if path is a python package - """ - if PY2: - return os.path.exists(os.path.join(path, '__init__.py')) - else: - return os.path.isdir(path) - def _parse_known_pattern(self, pattern): """ Expand pattern if identified as a directory and return found sub packages @@ -104,7 +91,7 @@ class KnownPatternFinder(BaseFinder): patterns = [ filename for filename in os.listdir(pattern) - if self._is_package(os.path.join(pattern, filename)) + if os.path.isdir(os.path.join(pattern, filename)) ] else: patterns = [pattern] @@ -123,7 +110,7 @@ class KnownPatternFinder(BaseFinder): class PathFinder(BaseFinder): def __init__(self, config, sections): - super(PathFinder, self).__init__(config, sections) + super().__init__(config, sections) # Use a copy of sys.path to avoid any unintended modifications # to it - e.g. `+=` used below will change paths in place and @@ -168,7 +155,7 @@ class PathFinder(BaseFinder): class ReqsBaseFinder(BaseFinder): def __init__(self, config, sections, path='.'): - super(ReqsBaseFinder, self).__init__(config, sections) + super().__init__(config, sections) self.path = path if self.enabled: self.mapping = self._load_mapping() diff --git a/isort/hooks.py b/isort/hooks.py index 15b6d408..1073de94 100644 --- a/isort/hooks.py +++ b/isort/hooks.py @@ -45,7 +45,7 @@ def get_lines(command): :returns: list of whitespace-stripped lines output by command """ stdout = get_output(command) - return [line.strip().decode('utf-8') for line in stdout.splitlines()] + return [line.strip().decode() for line in stdout.splitlines()] def git_hook(strict=False): diff --git a/isort/isort.py b/isort/isort.py index 9c7ed8cf..65f6a131 100644 --- a/isort/isort.py +++ b/isort/isort.py @@ -24,10 +24,7 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFT OTHER DEALINGS IN THE SOFTWARE. """ -from __future__ import absolute_import, division, print_function, unicode_literals - import copy -import io import itertools import os import re @@ -39,7 +36,6 @@ from difflib import unified_diff from . import settings from .finders import FindersManager from .natural import nsorted -from .pie_slice import input class SortImports(object): @@ -102,7 +98,7 @@ class SortImports(object): elif not file_contents: self.file_path = file_path self.file_encoding = coding_check(file_path) - with io.open(file_path, encoding=self.file_encoding, newline='') as file_to_import_sort: + with open(file_path, encoding=self.file_encoding, newline='') as file_to_import_sort: file_contents = file_to_import_sort.read() if file_contents is None or ("isort:" + "skip_file") in file_contents: @@ -197,7 +193,7 @@ class SortImports(object): return if answer in ('quit', 'q'): sys.exit(1) - with io.open(self.file_path, encoding=self.file_encoding, mode='w', newline='') as output_file: + with open(self.file_path, 'w', encoding=self.file_encoding, newline='') as output_file: print("Fixing {0}".format(self.file_path)) output_file.write(self.output) @@ -969,7 +965,7 @@ def coding_check(fname, default='utf-8'): pattern = re.compile(br'coding[:=]\s*([-\w.]+)') coding = default - with io.open(fname, 'rb') as f: + with open(fname, 'rb') as f: for line_number, line in enumerate(f, 1): groups = re.findall(pattern, line) if groups: diff --git a/isort/main.py b/isort/main.py index a584c226..41fa1fcc 100644 --- a/isort/main.py +++ b/isort/main.py @@ -17,8 +17,6 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFT OTHER DEALINGS IN THE SOFTWARE. ''' -from __future__ import absolute_import, division, print_function, unicode_literals - import argparse import functools import glob diff --git a/isort/pie_slice.py b/isort/pie_slice.py deleted file mode 100644 index 2209cb4e..00000000 --- a/isort/pie_slice.py +++ /dev/null @@ -1,129 +0,0 @@ -"""pie_slice/overrides.py. - -Overrides Python syntax to conform to the Python3 version as much as possible using a '*' import - -Copyright (C) 2013 Timothy Edmund Crosley - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and -to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -""" -from __future__ import absolute_import - -import collections -import sys - -__version__ = "1.1.0" - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -VERSION = sys.version_info - -__all__ = ['PY2', 'PY3', 'lru_cache'] - - -if PY3: - input = input -else: - input = raw_input # noqa: F821 - - -if sys.version_info < (3, 2): - try: - from threading import Lock - except ImportError: - from dummy_threading import Lock - - from functools import wraps - - _CacheInfo = collections.namedtuple("CacheInfo", "hits misses maxsize currsize") - - def lru_cache(maxsize=100): - """Least-recently-used cache decorator. - Taking from: https://github.com/MiCHiLU/python-functools32/blob/master/functools32/functools32.py - with slight modifications. - If *maxsize* is set to None, the LRU features are disabled and the cache - can grow without bound. - Arguments to the cached function must be hashable. - View the cache statistics named tuple (hits, misses, maxsize, currsize) with - f.cache_info(). Clear the cache and statistics with f.cache_clear(). - Access the underlying function with f.__wrapped__. - See: https://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used - - """ - def decorating_function(user_function, tuple=tuple, sorted=sorted, len=len, KeyError=KeyError): - hits, misses = [0], [0] - kwd_mark = (object(),) # separates positional and keyword args - lock = Lock() - - if maxsize is None: - CACHE = {} - - @wraps(user_function) - def wrapper(*args, **kwds): - key = args - if kwds: - key += kwd_mark + tuple(sorted(kwds.items())) - try: - result = CACHE[key] - hits[0] += 1 - return result - except KeyError: - pass - result = user_function(*args, **kwds) - CACHE[key] = result - misses[0] += 1 - return result - else: - CACHE = collections.OrderedDict() - - @wraps(user_function) - def wrapper(*args, **kwds): - key = args - if kwds: - key += kwd_mark + tuple(sorted(kwds.items())) - with lock: - cached = CACHE.get(key, None) - if cached: - del CACHE[key] - CACHE[key] = cached - hits[0] += 1 - return cached - result = user_function(*args, **kwds) - with lock: - CACHE[key] = result # record recent use of this key - misses[0] += 1 - while len(CACHE) > maxsize: - CACHE.popitem(last=False) - return result - - def cache_info(): - """Report CACHE statistics.""" - with lock: - return _CacheInfo(hits[0], misses[0], maxsize, len(CACHE)) - - def cache_clear(): - """Clear the CACHE and CACHE statistics.""" - with lock: - CACHE.clear() - hits[0] = misses[0] = 0 - - wrapper.cache_info = cache_info - wrapper.cache_clear = cache_clear - return wrapper - - return decorating_function - -else: - from functools import lru_cache diff --git a/isort/settings.py b/isort/settings.py index cb047158..0fb7c744 100644 --- a/isort/settings.py +++ b/isort/settings.py @@ -22,24 +22,15 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFT OTHER DEALINGS IN THE SOFTWARE. """ -from __future__ import absolute_import, division, print_function, unicode_literals - +import configparser import fnmatch -import io import os -import re import posixpath -import sys +import re import warnings from collections import namedtuple from distutils.util import strtobool - -from .pie_slice import lru_cache - -try: - import configparser -except ImportError: - import ConfigParser as configparser +from functools import lru_cache try: import toml @@ -171,7 +162,7 @@ def _update_settings_with_config(path, name, default, sections, computed_setting tries = 0 current_directory = path while current_directory and tries < MAX_CONFIG_SEARCH_DEPTH: - potential_path = os.path.join(current_directory, str(name)) + potential_path = os.path.join(current_directory, name) if os.path.exists(potential_path): editor_config_file = potential_path break @@ -258,7 +249,7 @@ def _abspaths(cwd, values): def _get_config_data(file_path, sections): settings = {} - with io.open(file_path) as config_file: + with open(file_path) as config_file: if file_path.endswith('.toml'): if toml: config = toml.load(config_file) @@ -283,12 +274,8 @@ def _get_config_data(file_path, sections): break last_position = config_file.tell() - if sys.version_info >= (3, 2): - config = configparser.ConfigParser() - config.read_file(config_file) - else: - config = configparser.SafeConfigParser() - config.readfp(config_file) + config = configparser.ConfigParser() + config.read_file(config_file) for section in sections: if config.has_section(section): @@ -1,6 +1,3 @@ -[bdist_wheel] -universal = 1 - [flake8] max-line-length = 160 ignore = @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from setuptools import setup @@ -26,22 +26,20 @@ setup(name='isort', 'pyproject': ['toml'], 'requirements': ['pip', 'pipreqs'], }, - install_requires=['futures; python_version < "3.2"'], - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", - keywords='Refactor, Python, Python2, Python3, Refactoring, Imports, Sort, Clean', + python_requires=">=3.4", + keywords='Refactor, Python, Python3, Refactoring, Imports, Sort, Clean', classifiers=['Development Status :: 6 - Mature', 'Intended Audience :: Developers', 'Natural Language :: English', 'Environment :: Console', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries', diff --git a/test_isort.py b/test_isort.py index ca826a5a..c45a6ca2 100644 --- a/test_isort.py +++ b/test_isort.py @@ -1,4 +1,3 @@ -# coding: utf-8 """test_isort.py. Tests all major functionality of the isort library @@ -21,10 +20,7 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFT OTHER DEALINGS IN THE SOFTWARE. """ -from __future__ import absolute_import, division, print_function, unicode_literals - from tempfile import NamedTemporaryFile -import io import os import sys @@ -34,7 +30,6 @@ from isort import finders, main, settings from isort.isort import SortImports from isort.utils import exists_case_sensitive from isort.main import is_python_file -from isort.pie_slice import PY2 from isort.settings import WrapModes try: @@ -843,21 +838,12 @@ def test_known_pattern_path_expansion(): default_section='THIRDPARTY', known_first_party=['./', 'this'] ).output - if PY2: - assert test_output == ("import os\n" - "import sys\n" - "\n" - "from kate_plugin import isort_plugin\n" - "\n" - "import isort.settings\n" - "import this\n") - else: - assert test_output == ("import os\n" - "import sys\n" - "\n" - "import isort.settings\n" - "import this\n" - "from kate_plugin import isort_plugin\n") + assert test_output == ("import os\n" + "import sys\n" + "\n" + "import isort.settings\n" + "import this\n" + "from kate_plugin import isort_plugin\n") def test_force_single_line_imports(): @@ -2502,29 +2488,29 @@ 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 io.open(rn_newline.name, mode='w', newline='') as rn_newline_input: + with open(rn_newline.name, '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 io.open(rn_newline.name, newline='') as rn_newline_file: + 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 io.open(r_newline.name, mode='w', newline='') as r_newline_input: + with open(r_newline.name, 'w', newline='') as r_newline_input: r_newline_input.write('import sys\rimport os\r') r_newline_input.flush() SortImports(r_newline.name) - with io.open(r_newline.name, newline='') as r_newline_file: + 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 io.open(n_newline.name, mode='w', newline='') as n_newline_input: + with open(n_newline.name, 'w', newline='') as n_newline_input: n_newline_input.write('import sys\nimport os\n') n_newline_input.flush() SortImports(n_newline.name) - with io.open(n_newline.name, newline='') as n_newline_file: + 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' @@ -2609,14 +2595,6 @@ def test_pipfile_finder(tmpdir): pipfile.remove() -@pytest.mark.skipif(sys.version_info[0] == 2, reason="Requires Python 3") -def test_monkey_patched_urllib(): - with pytest.raises(ImportError): - # Previous versions of isort monkey patched urllib which caused unusual - # importing for other projects. - from urllib import quote # noqa: F401 - - def test_argument_parsing(): from isort.main import parse_args args = parse_args(['-dt', '-t', 'foo', '--skip=bar', 'baz.py']) @@ -3,7 +3,7 @@ minversion = 2.4 envlist = isort-check, lint, - py{27,34,35,36,37,py,py3} + py{34,35,36,37,py3} [testenv] deps = @@ -15,6 +15,7 @@ extras = commands = py.test test_isort.py {posargs} [testenv:isort-check] +basepython = python3 commands = python setup.py isort [testenv:lint] |