Skip to content

Commit 6ed0cd3

Browse files
#1363: Improve warning handling around 5.0.0 upgrade, include error codes
1 parent da0058f commit 6ed0cd3

File tree

3 files changed

+129
-111
lines changed

3 files changed

+129
-111
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ Changelog
33

44
NOTE: isort follows the [semver](https://semver.org/) versioning standard.
55

6+
### 5.3.1 TBD
7+
- Improve upgrade warnings to be less noisy and point to error codes for easy interoperability with Visual Studio Code (see: #1363).
8+
69
### 5.3.0 Aug 4, 2020
710
- Implemented ability to treat all or select comments as code (issue #1357)
811
- Implemented ability to use different configs for different file extensions (issue #1162)

isort/main.py

Lines changed: 92 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ def iter_source_code(paths: Iterable[str], config: Config, skipped: List[str]) -
121121

122122
resolved_path = full_path.resolve()
123123
if resolved_path in visited_dirs: # pragma: no cover
124-
warn(f"Likely recursive symlink detected to {resolved_path}")
124+
if not config.quiet:
125+
warn(f"Likely recursive symlink detected to {resolved_path}")
125126
dirnames.remove(dirname)
126127
else:
127128
visited_dirs.add(resolved_path)
@@ -723,20 +724,16 @@ def _build_arg_parser() -> argparse.ArgumentParser:
723724

724725
def parse_args(argv: Optional[Sequence[str]] = None) -> Dict[str, Any]:
725726
argv = sys.argv[1:] if argv is None else list(argv)
727+
remapped_deprecated_args = []
726728
for index, arg in enumerate(argv):
727729
if arg in DEPRECATED_SINGLE_DASH_ARGS:
728-
warn(
729-
f"\n\nThe following deprecated single dash CLI flags was used: {arg}!\n"
730-
f"It is being auto translated to -{arg} to maintain backward compatibility.\n"
731-
f"This behavior will be REMOVED in the 6.x.x release and is not guaranteed across"
732-
f" 5.x.x releases.\n\n"
733-
"Please see the 5.0.0 upgrade guide:\n"
734-
"\thttps://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/\n"
735-
)
730+
remapped_deprecated_args.append(arg)
736731
argv[index] = f"-{arg}"
737732

738733
parser = _build_arg_parser()
739734
arguments = {key: value for key, value in vars(parser.parse_args(argv)).items() if value}
735+
if remapped_deprecated_args:
736+
arguments["remapped_deprecated_args"] = remapped_deprecated_args
740737
if "dont_order_by_type" in arguments:
741738
arguments["order_by_type"] = False
742739
multi_line_output = arguments.get("multi_line_output", None)
@@ -790,15 +787,6 @@ def main(argv: Optional[Sequence[str]] = None, stdin: Optional[TextIOWrapper] =
790787
sys.exit("Error: arguments passed in without any paths or content.")
791788
else:
792789
return
793-
elif file_names == ["-"] and not show_config:
794-
arguments.setdefault("settings_path", os.getcwd())
795-
api.sort_stream(
796-
input_stream=sys.stdin if stdin is None else stdin,
797-
output_stream=sys.stdout,
798-
**arguments,
799-
)
800-
return
801-
802790
if "settings_path" not in arguments:
803791
arguments["settings_path"] = (
804792
os.path.abspath(file_names[0] if file_names else ".") or os.getcwd()
@@ -813,13 +801,8 @@ def main(argv: Optional[Sequence[str]] = None, stdin: Optional[TextIOWrapper] =
813801
show_diff = config_dict.pop("show_diff", False)
814802
write_to_stdout = config_dict.pop("write_to_stdout", False)
815803
deprecated_flags = config_dict.pop("deprecated_flags", False)
816-
817-
if deprecated_flags: # pragma: no cover
818-
warn(
819-
f"\n\nThe following deprecated CLI flags were used: {', '.join(deprecated_flags)}!\n"
820-
"Please see the 5.0.0 upgrade guide:\n"
821-
"\thttps://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/\n"
822-
)
804+
remapped_deprecated_args = config_dict.pop("remapped_deprecated_args", False)
805+
wrong_sorted_files = False
823806

824807
if "src_paths" in config_dict:
825808
config_dict["src_paths"] = {
@@ -830,74 +813,98 @@ def main(argv: Optional[Sequence[str]] = None, stdin: Optional[TextIOWrapper] =
830813
if show_config:
831814
print(json.dumps(config.__dict__, indent=4, separators=(",", ": "), default=_preconvert))
832815
return
833-
834-
wrong_sorted_files = False
835-
skipped: List[str] = []
836-
837-
if config.filter_files:
838-
filtered_files = []
839-
for file_name in file_names:
840-
if config.is_skipped(Path(file_name)):
841-
skipped.append(file_name)
842-
else:
843-
filtered_files.append(file_name)
844-
file_names = filtered_files
845-
846-
file_names = iter_source_code(file_names, config, skipped)
847-
num_skipped = 0
848-
if config.verbose:
849-
print(ASCII_ART)
850-
851-
if jobs:
852-
import multiprocessing
853-
854-
executor = multiprocessing.Pool(jobs)
855-
attempt_iterator = executor.imap(
856-
functools.partial(
857-
sort_imports,
858-
config=config,
859-
check=check,
860-
ask_to_apply=ask_to_apply,
861-
write_to_stdout=write_to_stdout,
862-
),
863-
file_names,
816+
elif file_names == ["-"]:
817+
arguments.setdefault("settings_path", os.getcwd())
818+
api.sort_stream(
819+
input_stream=sys.stdin if stdin is None else stdin,
820+
output_stream=sys.stdout,
821+
**arguments,
864822
)
865823
else:
866-
# https://github.com/python/typeshed/pull/2814
867-
attempt_iterator = (
868-
sort_imports( # type: ignore
869-
file_name,
870-
config=config,
871-
check=check,
872-
ask_to_apply=ask_to_apply,
873-
show_diff=show_diff,
874-
write_to_stdout=write_to_stdout,
824+
skipped: List[str] = []
825+
826+
if config.filter_files:
827+
filtered_files = []
828+
for file_name in file_names:
829+
if config.is_skipped(Path(file_name)):
830+
skipped.append(file_name)
831+
else:
832+
filtered_files.append(file_name)
833+
file_names = filtered_files
834+
835+
file_names = iter_source_code(file_names, config, skipped)
836+
num_skipped = 0
837+
if config.verbose:
838+
print(ASCII_ART)
839+
840+
if jobs:
841+
import multiprocessing
842+
843+
executor = multiprocessing.Pool(jobs)
844+
attempt_iterator = executor.imap(
845+
functools.partial(
846+
sort_imports,
847+
config=config,
848+
check=check,
849+
ask_to_apply=ask_to_apply,
850+
write_to_stdout=write_to_stdout,
851+
),
852+
file_names,
875853
)
876-
for file_name in file_names
877-
)
854+
else:
855+
# https://github.com/python/typeshed/pull/2814
856+
attempt_iterator = (
857+
sort_imports( # type: ignore
858+
file_name,
859+
config=config,
860+
check=check,
861+
ask_to_apply=ask_to_apply,
862+
show_diff=show_diff,
863+
write_to_stdout=write_to_stdout,
864+
)
865+
for file_name in file_names
866+
)
867+
868+
for sort_attempt in attempt_iterator:
869+
if not sort_attempt:
870+
continue # pragma: no cover - shouldn't happen, satisfies type constraint
871+
incorrectly_sorted = sort_attempt.incorrectly_sorted
872+
if arguments.get("check", False) and incorrectly_sorted:
873+
wrong_sorted_files = True
874+
if sort_attempt.skipped:
875+
num_skipped += (
876+
1 # pragma: no cover - shouldn't happen, due to skip in iter_source_code
877+
)
878878

879-
for sort_attempt in attempt_iterator:
880-
if not sort_attempt:
881-
continue # pragma: no cover - shouldn't happen, satisfies type constraint
882-
incorrectly_sorted = sort_attempt.incorrectly_sorted
883-
if arguments.get("check", False) and incorrectly_sorted:
884-
wrong_sorted_files = True
885-
if sort_attempt.skipped:
886-
num_skipped += 1 # pragma: no cover - shouldn't happen, due to skip in iter_source_code
879+
num_skipped += len(skipped)
880+
if num_skipped and not arguments.get("quiet", False):
881+
if config.verbose:
882+
for was_skipped in skipped:
883+
warn(
884+
f"{was_skipped} was skipped as it's listed in 'skip' setting"
885+
" or matches a glob in 'skip_glob' setting"
886+
)
887+
print(f"Skipped {num_skipped} files")
888+
889+
if not config.quiet and (remapped_deprecated_args or deprecated_flags): # pragma: no cover
890+
if remapped_deprecated_args:
891+
warn(
892+
"W0502: The following deprecated single dash CLI flags were used and translated: "
893+
f"{', '.join(remapped_deprecated_args)}!"
894+
)
895+
if deprecated_flags:
896+
warn(
897+
"W0501: The following deprecated CLI flags were used and ignored: "
898+
f"{', '.join(deprecated_flags)}!"
899+
)
900+
warn(
901+
"W0500: Please see the 5.0.0 Upgrade guide: "
902+
"https://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/"
903+
)
887904

888905
if wrong_sorted_files:
889906
sys.exit(1)
890907

891-
num_skipped += len(skipped)
892-
if num_skipped and not arguments.get("quiet", False):
893-
if config.verbose:
894-
for was_skipped in skipped:
895-
warn(
896-
f"{was_skipped} was skipped as it's listed in 'skip' setting"
897-
" or matches a glob in 'skip_glob' setting"
898-
)
899-
print(f"Skipped {num_skipped} files")
900-
901908

902909
if __name__ == "__main__":
903910
main()

isort/settings.py

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@
4444
"tox.ini",
4545
".editorconfig",
4646
)
47+
DEFAULT_SKIP: FrozenSet[str] = frozenset(
48+
{
49+
".venv",
50+
"venv",
51+
".tox",
52+
".eggs",
53+
".git",
54+
".hg",
55+
".mypy_cache",
56+
".nox",
57+
"_build",
58+
"buck-out",
59+
"build",
60+
"dist",
61+
".pants.d",
62+
"node_modules",
63+
}
64+
)
4765

4866
CONFIG_SECTIONS: Dict[str, Tuple[str, ...]] = {
4967
".isort.cfg": ("settings", "isort"),
@@ -94,24 +112,7 @@ class _Config:
94112

95113
py_version: str = "3"
96114
force_to_top: FrozenSet[str] = frozenset()
97-
skip: FrozenSet[str] = frozenset(
98-
{
99-
".venv",
100-
"venv",
101-
".tox",
102-
".eggs",
103-
".git",
104-
".hg",
105-
".mypy_cache",
106-
".nox",
107-
"_build",
108-
"buck-out",
109-
"build",
110-
"dist",
111-
".pants.d",
112-
"node_modules",
113-
}
114-
)
115+
skip: FrozenSet[str] = DEFAULT_SKIP
115116
skip_glob: FrozenSet[str] = frozenset()
116117
skip_gitignore: bool = False
117118
line_length: int = 79
@@ -322,7 +323,7 @@ def __init__(
322323
combined_config.pop(key)
323324
if maps_to_section in KNOWN_SECTION_MAPPING:
324325
section_name = f"known_{KNOWN_SECTION_MAPPING[maps_to_section].lower()}"
325-
if section_name in combined_config:
326+
if section_name in combined_config and not self.quiet:
326327
warn(
327328
f"Can't set both {key} and {section_name} in the same config file.\n"
328329
f"Default to {section_name} if unsure."
@@ -334,7 +335,10 @@ def __init__(
334335
combined_config[section_name] = frozenset(value)
335336
else:
336337
known_other[import_heading] = frozenset(value)
337-
if maps_to_section not in combined_config.get("sections", ()):
338+
if (
339+
maps_to_section not in combined_config.get("sections", ())
340+
and not self.quiet
341+
):
338342
warn(
339343
f"`{key}` setting is defined, but {maps_to_section} is not"
340344
" included in `sections` config option:"
@@ -395,14 +399,18 @@ def __init__(
395399
combined_config.pop("sources", None)
396400
combined_config.pop("runtime_src_paths", None)
397401

398-
for deprecated_option in DEPRECATED_SETTINGS:
399-
if deprecated_option in combined_config:
402+
deprecated_options_used = [
403+
option for option in combined_config if option in DEPRECATED_SETTINGS
404+
]
405+
if deprecated_options_used:
406+
for deprecated_option in deprecated_options_used:
407+
combined_config.pop(deprecated_option)
408+
if not self.quiet:
400409
warn(
401-
f"\n\nThe following deprecated settings was used: {deprecated_option}!\n"
402-
"Please see the 5.0.0 upgrade guide:\n"
403-
"\thttps://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/\n"
410+
"W503: Deprecated config options were used: "
411+
f"{', '.join(deprecated_options_used)}."
412+
"Please see the 5.0.0 upgrade guide: bit.ly/isortv5."
404413
)
405-
combined_config.pop(deprecated_option)
406414

407415
if known_other:
408416
combined_config["known_other"] = known_other

0 commit comments

Comments
 (0)