summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Edmund Crosley <timothy.crosley@gmail.com>2019-04-30 11:57:17 -0700
committerGitHub <noreply@github.com>2019-04-30 11:57:17 -0700
commit80500b9d031166dc973727d0c689590be2f287e5 (patch)
treefcf855ea82e3e380c08d920be037bd6083205874
parent493c02a1a000fe782cec56f1f43262bacb316381 (diff)
parent48ec46ca927befcd1cc21ddbbdcd03b5b42dcba9 (diff)
downloadisort-80500b9d031166dc973727d0c689590be2f287e5.tar.gz
Merge pull request #936 from mkurnikov/move-to-pathlib-2
Move most of filesystem operations to pathlib
-rw-r--r--isort/compat.py73
-rw-r--r--isort/format.py16
-rw-r--r--isort/isort.py13
-rw-r--r--isort/settings.py10
-rw-r--r--setup.cfg1
5 files changed, 72 insertions, 41 deletions
diff --git a/isort/compat.py b/isort/compat.py
index d3ea4ced..5fa33729 100644
--- a/isort/compat.py
+++ b/isort/compat.py
@@ -2,6 +2,7 @@ import locale
import os
import re
import sys
+from pathlib import Path
from typing import Any, Optional, Tuple
from isort import settings
@@ -9,12 +10,12 @@ from isort.format import ask_whether_to_apply_changes_to_file, show_unified_diff
from isort.isort import _SortImports
-def determine_file_encoding(fname: str, default: str = 'utf-8') -> str:
+def determine_file_encoding(file_path: Path, default: str = 'utf-8') -> str:
# see https://www.python.org/dev/peps/pep-0263/
pattern = re.compile(br'coding[:=]\s*([-\w.]+)')
coding = default
- with open(fname, 'rb') as f:
+ with file_path.open('rb') as f:
for line_number, line in enumerate(f, 1):
groups = re.findall(pattern, line)
if groups:
@@ -26,15 +27,15 @@ def determine_file_encoding(fname: str, default: str = 'utf-8') -> str:
return coding
-def read_file_contents(file_path: str, encoding: str, fallback_encoding: str) -> Tuple[Optional[str], Optional[str]]:
- with open(file_path, encoding=encoding, newline='') as file_to_import_sort:
+def read_file_contents(file_path: Path, encoding: str, fallback_encoding: str) -> Tuple[Optional[str], Optional[str]]:
+ with file_path.open(encoding=encoding, newline='') as file_to_import_sort:
try:
file_contents = file_to_import_sort.read()
return file_contents, encoding
except UnicodeDecodeError:
pass
- with open(file_path, encoding=fallback_encoding, newline='') as file_to_import_sort:
+ with file_path.open(encoding=fallback_encoding, newline='') as file_to_import_sort:
try:
file_contents = file_to_import_sort.read()
return file_contents, fallback_encoding
@@ -42,14 +43,21 @@ def read_file_contents(file_path: str, encoding: str, fallback_encoding: str) ->
return None, None
-def get_settings_path(settings_path: Optional[str], current_file_path: Optional[str]) -> str:
+def resolve(path: Path) -> Path:
+ if sys.version_info[:2] >= (3, 6):
+ return path.resolve()
+ else:
+ return Path(os.path.abspath(str(path)))
+
+
+def get_settings_path(settings_path: Optional[Path], current_file_path: Optional[Path]) -> Path:
if settings_path:
return settings_path
if current_file_path:
- return os.path.dirname(os.path.abspath(current_file_path))
+ return resolve(current_file_path).parent
else:
- return os.getcwd()
+ return Path.cwd()
class SortImports(object):
@@ -69,44 +77,48 @@ class SortImports(object):
check_skip: bool = True,
**setting_overrides: Any
):
+ file_path = None if file_path is None else Path(file_path)
+ settings_path = None if settings_path is None else Path(settings_path)
+
self.config = settings.prepare_config(get_settings_path(settings_path, file_path),
**setting_overrides)
self.output = None
file_encoding = 'utf-8'
- file_name = file_path
- self.file_path = file_path or ""
+ self.file_path = None
if file_path:
- file_path = os.path.abspath(file_path)
+ self.file_path = file_path # raw file path (unresolved) ?
+
+ absolute_file_path = resolve(file_path)
if check_skip:
- if run_path and file_path.startswith(run_path):
- file_name = os.path.relpath(file_path, run_path)
+ if run_path and run_path in absolute_file_path.parents:
+ file_name = os.path.relpath(absolute_file_path, run_path)
else:
- file_name = file_path
+ file_name = str(absolute_file_path)
run_path = ''
if settings.file_should_be_skipped(file_name, self.config, run_path):
self.skipped = True
if self.config['verbose']:
print("WARNING: {0} was skipped as it's listed in 'skip' setting"
- " or matches a glob in 'skip_glob' setting".format(file_path))
+ " or matches a glob in 'skip_glob' setting".format(absolute_file_path))
file_contents = None
if not self.skipped and not file_contents:
- preferred_encoding = determine_file_encoding(file_path)
+ preferred_encoding = determine_file_encoding(absolute_file_path)
# default encoding for open(mode='r') on the system
fallback_encoding = locale.getpreferredencoding(False)
- file_contents, used_encoding = read_file_contents(file_path,
+ file_contents, used_encoding = read_file_contents(absolute_file_path,
encoding=preferred_encoding,
fallback_encoding=fallback_encoding)
if used_encoding is None:
self.skipped = True
if self.config['verbose']:
print("WARNING: {} was skipped as it couldn't be opened with the given "
- "{} encoding or {} fallback encoding".format(file_path,
+ "{} encoding or {} fallback encoding".format(str(absolute_file_path),
file_encoding,
fallback_encoding))
else:
@@ -123,19 +135,20 @@ class SortImports(object):
self.output = self.sorted_imports.output
if self.config['atomic']:
+ logging_file_path = str(self.file_path or '')
try:
out_lines_without_top_comment = self.sorted_imports.get_out_lines_without_top_comment()
- compile(out_lines_without_top_comment, self.file_path, 'exec', 0, 1)
+ compile(out_lines_without_top_comment, logging_file_path, 'exec', 0, 1)
except SyntaxError:
self.output = file_contents
self.incorrectly_sorted = True
try:
in_lines_without_top_comment = self.sorted_imports.get_in_lines_without_top_comment()
- compile(in_lines_without_top_comment, self.file_path, 'exec', 0, 1)
+ compile(in_lines_without_top_comment, logging_file_path, 'exec', 0, 1)
print("ERROR: {0} isort would have introduced syntax errors, please report to the project!".
- format(self.file_path))
+ format(logging_file_path))
except SyntaxError:
- print("ERROR: {0} File contains syntax errors.".format(self.file_path))
+ print("ERROR: {0} File contains syntax errors.".format(logging_file_path))
return
@@ -143,11 +156,12 @@ class SortImports(object):
check_output = self.output
check_against = file_contents
if self.config['ignore_whitespace']:
- check_output = check_output.replace(self.sorted_imports.line_separator, "").replace(" ", "").replace("\x0c", "")
- check_against = check_against.replace(self.sorted_imports.line_separator, "").replace(" ", "").replace("\x0c", "")
+ check_output = self.sorted_imports.remove_whitespaces(check_output)
+ check_against = self.sorted_imports.remove_whitespaces(check_against)
- current_input_sorted_correctly = self.sorted_imports.check_if_input_already_sorted(check_output, check_against,
- current_file_path=self.file_path)
+ current_input_sorted_correctly = (self.sorted_imports
+ .check_if_input_already_sorted(check_output, check_against,
+ logging_file_path=str(self.file_path or '')))
if current_input_sorted_correctly:
return
else:
@@ -160,18 +174,19 @@ class SortImports(object):
elif write_to_stdout:
sys.stdout.write(self.output)
- elif file_name and not check:
+ elif self.file_path and not check:
+ # if file_name resolves to True, file_path never None or ''
if self.output == file_contents:
return
if ask_to_apply:
show_unified_diff(file_input=file_contents, file_output=self.output,
file_path=self.file_path)
- apply_changes = ask_whether_to_apply_changes_to_file(self.file_path)
+ apply_changes = ask_whether_to_apply_changes_to_file(str(self.file_path))
if not apply_changes:
return
- with open(self.file_path, 'w', encoding=file_encoding, newline='') as output_file:
+ with self.file_path.open('w', encoding=file_encoding, newline='') as output_file:
if not self.config['quiet']:
print("Fixing {0}".format(self.file_path))
diff --git a/isort/format.py b/isort/format.py
index 9aa81bea..e008eab0 100644
--- a/isort/format.py
+++ b/isort/format.py
@@ -1,7 +1,8 @@
-import os
import sys
from datetime import datetime
from difflib import unified_diff
+from pathlib import Path
+from typing import Optional
def format_simplified(import_line: str) -> str:
@@ -27,14 +28,17 @@ def format_natural(import_line: str) -> str:
return import_line
-def show_unified_diff(*, file_input: str, file_output: str, file_path: str) -> None:
+def show_unified_diff(*, file_input: str, file_output: str, file_path: Optional[Path]) -> None:
+ file_name = '' if file_path is None else str(file_path)
+ file_mtime = str(datetime.now() if file_path is None
+ else datetime.fromtimestamp(file_path.stat().st_mtime))
+
unified_diff_lines = unified_diff(
file_input.splitlines(keepends=True),
file_output.splitlines(keepends=True),
- fromfile=file_path + ':before',
- tofile=file_path + ':after',
- fromfiledate=str(datetime.fromtimestamp(os.path.getmtime(file_path))
- if file_path else datetime.now()),
+ fromfile=file_name + ':before',
+ tofile=file_name + ':after',
+ fromfiledate=file_mtime,
tofiledate=str(datetime.now())
)
for line in unified_diff_lines:
diff --git a/isort/isort.py b/isort/isort.py
index 880952e0..f000494c 100644
--- a/isort/isort.py
+++ b/isort/isort.py
@@ -98,6 +98,13 @@ class _SortImports(object):
self.out_lines.append("")
self.output = self.line_separator.join(self.out_lines)
+ def remove_whitespaces(self, contents: str) -> str:
+ contents = (contents
+ .replace(self.line_separator, "")
+ .replace(" ", "")
+ .replace("\x0c", ""))
+ return contents
+
def get_out_lines_without_top_comment(self) -> str:
return self._strip_top_comments(self.out_lines, self.line_separator)
@@ -105,13 +112,13 @@ class _SortImports(object):
return self._strip_top_comments(self.in_lines, self.line_separator)
def check_if_input_already_sorted(self, output: str, check_against: str,
- *, current_file_path) -> bool:
+ *, logging_file_path: str) -> bool:
if output.strip() == check_against.strip():
if self.config['verbose']:
- print("SUCCESS: {0} Everything Looks Good!".format(current_file_path))
+ print("SUCCESS: {0} Everything Looks Good!".format(logging_file_path))
return True
- print("ERROR: {0} Imports are incorrectly sorted.".format(current_file_path))
+ print("ERROR: {0} Imports are incorrectly sorted.".format(logging_file_path))
return False
def determine_line_separator(self, file_contents: str) -> str:
diff --git a/isort/settings.py b/isort/settings.py
index e0bf72ac..9ab88f65 100644
--- a/isort/settings.py
+++ b/isort/settings.py
@@ -31,7 +31,8 @@ import re
import warnings
from distutils.util import strtobool
from functools import lru_cache
-from typing import Any, Callable, Dict, Iterable, List, Mapping, MutableMapping
+from pathlib import Path
+from typing import Any, Callable, Dict, Iterable, List, Mapping, MutableMapping, Union
from .utils import difference, union
@@ -172,12 +173,15 @@ default = {'force_to_top': [],
@lru_cache()
-def from_path(path: str) -> Dict[str, Any]:
+def from_path(path: Union[str, Path]) -> Dict[str, Any]:
computed_settings = default.copy()
isort_defaults = ['~/.isort.cfg']
if appdirs:
isort_defaults = [appdirs.user_config_dir('isort.cfg')] + isort_defaults
+ if isinstance(path, Path):
+ path = str(path)
+
_update_settings_with_config(path, '.editorconfig', ['~/.editorconfig'], ('*', '*.py', '**.py'), computed_settings)
_update_settings_with_config(path, 'pyproject.toml', [], ('tool.isort', ), computed_settings)
_update_settings_with_config(path, '.isort.cfg', isort_defaults, ('settings', 'isort'), computed_settings)
@@ -186,7 +190,7 @@ def from_path(path: str) -> Dict[str, Any]:
return computed_settings
-def prepare_config(settings_path: str, **setting_overrides: Any) -> Dict[str, Any]:
+def prepare_config(settings_path: Path, **setting_overrides: Any) -> Dict[str, Any]:
config = from_path(settings_path).copy()
for key, value in setting_overrides.items():
access_key = key.replace('not_', '').lower()
diff --git a/setup.cfg b/setup.cfg
index 9574a5ce..14571a02 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -19,6 +19,7 @@ ignore_missing_imports = True
strict_optional = True
warn_no_return = False
check_untyped_defs = True
+allow_redefinition = True
[mypy-test_isort]
strict_optional = False