diff --git a/personal_python_ast_optimizer/futures.py b/personal_python_ast_optimizer/futures.py index cab2aef..8589d8b 100644 --- a/personal_python_ast_optimizer/futures.py +++ b/personal_python_ast_optimizer/futures.py @@ -1,22 +1,31 @@ -futures_to_mandatory_version: dict[str, tuple[int, int]] = { - "nested_scopes": (2, 2), - "generators": (2, 3), - "with_statement": (2, 6), - "division": (3, 0), - "absolute_import": (3, 0), - "print_function": (3, 0), - "unicode_literals": (3, 0), - "generator_stop": (3, 7), -} +class Futures: + + __slots__ = ("name", "mandatory_version") + + def __init__(self, name: str, mandatory_version: tuple[int, int]) -> None: + self.name: str = name + self.mandatory_version: tuple[int, int] = mandatory_version + + +futures_to_mandatory_version: list[Futures] = [ + Futures("nested_scopes", (2, 2)), + Futures("generators", (2, 3)), + Futures("with_statement", (2, 6)), + Futures("division", (3, 0)), + Futures("absolute_import", (3, 0)), + Futures("print_function", (3, 0)), + Futures("unicode_literals", (3, 0)), + Futures("generator_stop", (3, 7)), +] def get_unneeded_futures(python_version: tuple[int, int]) -> list[str]: """Returns list of __future__ imports that are unneeded in provided python version""" unneeded_futures: list[str] = [ - future - for future, mandatory_version in futures_to_mandatory_version.items() - if python_version >= mandatory_version + future.name + for future in futures_to_mandatory_version + if python_version >= future.mandatory_version ] return unneeded_futures diff --git a/personal_python_ast_optimizer/parser/minifier.py b/personal_python_ast_optimizer/parser/minifier.py index ee430b0..1f2417e 100644 --- a/personal_python_ast_optimizer/parser/minifier.py +++ b/personal_python_ast_optimizer/parser/minifier.py @@ -55,7 +55,7 @@ def _yield_updated_text(self, text_iter: Iterable[str]) -> Iterator[str]: yield text.strip() elif text in comparison_and_conjunctions: yield self._get_space_before_write() + text[1:] - elif text: + elif text != "": yield text def visit_node( @@ -227,24 +227,20 @@ def _write_decorators( self.traverse(deco) def _last_char_is(self, char_to_check: str) -> bool: - return bool(self._source) and self._source[-1][-1:] == char_to_check + return bool(self._source) and self._source[-1][-1] == char_to_check def _get_space_before_write(self) -> str: return ( "" if not self._source - or self._source[-1][-1:] in chars_that_dont_need_whitespace + or self._source[-1][-1] in chars_that_dont_need_whitespace else " " ) def _get_line_splitter(self) -> Literal["", "\n", ";"]: """Get character that starts the next line of code with the shortest possible whitespace. Either a new line, semicolon, or nothing.""" - if ( - len(self._source) > 0 - and self._source[-1] == ":" - and self.can_write_body_in_one_line - ): + if self._source and self._source[-1] == ":" and self.can_write_body_in_one_line: return "" if ( diff --git a/personal_python_ast_optimizer/parser/skipper.py b/personal_python_ast_optimizer/parser/skipper.py index 0bb20e7..c3dac45 100644 --- a/personal_python_ast_optimizer/parser/skipper.py +++ b/personal_python_ast_optimizer/parser/skipper.py @@ -147,9 +147,6 @@ def _combine_imports(body: list) -> None: body[:] = new_body def visit_Module(self, node: ast.Module) -> ast.AST: - if not self._has_code_to_skip(): - return node - if self.token_types_config.skip_dangling_expressions: skip_dangling_expressions(node) @@ -573,14 +570,6 @@ def _use_version_optimization(self, min_version: tuple[int, int]) -> bool: else self.target_python_version >= min_version ) - def _has_code_to_skip(self) -> bool: - return ( - self.target_python_version is not None - or self.optimizations_config.has_code_to_skip() - or self.tokens_config.has_code_to_skip() - or self.token_types_config.has_code_to_skip() - ) - def _should_skip_function_assign(self, node: ast.Assign | ast.AnnAssign) -> bool: return ( isinstance(node.value, ast.Call) diff --git a/personal_python_ast_optimizer/parser/utils.py b/personal_python_ast_optimizer/parser/utils.py index 9fa3e88..cbd7db6 100644 --- a/personal_python_ast_optimizer/parser/utils.py +++ b/personal_python_ast_optimizer/parser/utils.py @@ -6,9 +6,12 @@ def exclude_imports(node: ast.Import | ast.ImportFrom, exlcudes: Iterable[str]) -> None: - node.names = [ - alias for alias in node.names if (alias.asname or alias.name) not in exlcudes - ] + if exlcudes: + node.names = [ + alias + for alias in node.names + if (alias.asname or alias.name) not in exlcudes + ] def filter_imports(node: ast.Import | ast.ImportFrom, filter: Iterable[str]) -> None: @@ -51,18 +54,24 @@ def skip_dangling_expressions( def skip_base_classes( node: ast.ClassDef, classes_to_ignore: Iterable[str] | TokensToSkip ) -> None: - node.bases = [ - base for base in node.bases if getattr(base, "id", "") not in classes_to_ignore - ] + if classes_to_ignore: + node.bases = [ + base + for base in node.bases + if getattr(base, "id", "") not in classes_to_ignore + ] def skip_decorators( node: ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef, decorators_to_ignore: Iterable[str] | TokensToSkip, ) -> None: - node.decorator_list = [ - n for n in node.decorator_list if get_node_name(n) not in decorators_to_ignore - ] + if decorators_to_ignore: + node.decorator_list = [ + n + for n in node.decorator_list + if get_node_name(n) not in decorators_to_ignore + ] def remove_duplicate_slots( diff --git a/version.txt b/version.txt index 26d99a2..ce7f2b4 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -5.2.1 +5.2.2