summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml10
-rw-r--r--CHANGELOG.md5
-rw-r--r--README.rst2
-rw-r--r--appveyor.yml2
-rw-r--r--isort/__init__.py3
-rw-r--r--isort/__main__.py2
-rw-r--r--isort/finders.py21
-rw-r--r--isort/hooks.py2
-rw-r--r--isort/isort.py10
-rw-r--r--isort/main.py2
-rw-r--r--isort/pie_slice.py129
-rw-r--r--isort/settings.py27
-rw-r--r--setup.cfg3
-rwxr-xr-xsetup.py10
-rw-r--r--test_isort.py46
-rw-r--r--tox.ini3
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
diff --git a/README.rst b/README.rst
index 6c4db34e..2c5ad6f1 100644
--- a/README.rst
+++ b/README.rst
@@ -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):
diff --git a/setup.cfg b/setup.cfg
index 96518d7c..c39295eb 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,3 @@
-[bdist_wheel]
-universal = 1
-
[flake8]
max-line-length = 160
ignore =
diff --git a/setup.py b/setup.py
index cb501f1a..afdf77b2 100755
--- a/setup.py
+++ b/setup.py
@@ -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'])
diff --git a/tox.ini b/tox.ini
index 0e5b1db9..cb36b189 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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]