Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate pyupgrade to Python >=3.9 + related changes (follow-up to #192) #195

Merged
merged 1 commit into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ repos:
rev: v3.18.0
hooks:
- id: pyupgrade
args: ['--py38-plus']
args: ['--py39-plus']

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
Expand Down
28 changes: 14 additions & 14 deletions git_delete_merged_branches/_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from functools import partial, reduce
from operator import and_
from subprocess import CalledProcessError
from typing import List, Optional, Set, Tuple
from typing import Optional

from ._git import CheckoutFailed, MergeBaseFailed, PullFailed
from ._metadata import APP
Expand Down Expand Up @@ -75,7 +75,7 @@ def __init__(self, git, messenger, confirmation, selector, effort_level):
self._effort_using_squashed_copies = effort_level >= 3

def _interactively_edit_list(self, description, valid_names, old_names, format,
min_selection_count) -> Set[str]:
min_selection_count) -> set[str]:
if len(valid_names) < min_selection_count:
raise _TooFewOptionsAvailable

Expand All @@ -101,7 +101,7 @@ def _interactively_edit_list(self, description, valid_names, old_names, format,

return new_names

def _configure_required_branches(self, git_config) -> Set[str]:
def _configure_required_branches(self, git_config) -> set[str]:
try:
return self._interactively_edit_list(
'[1/3] For a branch to be considered'
Expand All @@ -114,7 +114,7 @@ def _configure_required_branches(self, git_config) -> Set[str]:
except _TooFewOptionsAvailable:
raise _GitRepositoryWithoutBranches

def _configure_excluded_branches(self, git_config, new_required_branches: Set[str]):
def _configure_excluded_branches(self, git_config, new_required_branches: set[str]):
valid_names = sorted(set(self._git.find_all_branch_names()) - new_required_branches)
self._interactively_edit_list(
'[2/3] Which of these branches (if any)'
Expand Down Expand Up @@ -177,7 +177,7 @@ def find_enabled_remotes(cls, git_config):
return cls._filter_git_config(git_config, cls._PATTERN_REMOTE_ENABLED)

def _find_branches_merged_using_git_branch_merged(self, required_target_branches,
remote_name: Optional[str]) -> Set[str]:
remote_name: Optional[str]) -> set[str]:
if remote_name is None:
find_branches_that_were_merged_into = self._git.find_merged_local_branches_for
else:
Expand Down Expand Up @@ -218,7 +218,7 @@ def _has_been_squash_merged_into(self, target_branch, topic_branch) -> bool:
return defacto_merged_into_target

def _find_branches_merged_using_git_cherry(self, required_target_branches,
candidate_branches) -> Set[str]:
candidate_branches) -> set[str]:
assert required_target_branches

if not candidate_branches:
Expand Down Expand Up @@ -268,8 +268,8 @@ def _find_branches_merged_using_git_cherry(self, required_target_branches,
return branches_merged_to_all_required_targets

def _find_branches_merged_to_all_targets_for_single_remote(
self, required_target_branches, excluded_branches: Set[str],
remote_name: Optional[str]) -> Tuple[Set[str], Set[str]]:
self, required_target_branches, excluded_branches: set[str],
remote_name: Optional[str]) -> tuple[set[str], set[str]]:
if remote_name is not None:
excluded_branches = {
f'{remote_name}/{branch_name}'
Expand Down Expand Up @@ -299,7 +299,7 @@ def _find_branches_merged_to_all_targets_for_single_remote(

return (truly_merged_branches, defacto_merged_branches)

def _report_branches_as_deleted(self, branch_names: Set[str], remote_name: str = None):
def _report_branches_as_deleted(self, branch_names: set[str], remote_name: str = None):
branch_type = 'local' if (remote_name is None) else 'remote'
info_text = f'{len(branch_names)} {branch_type} branch(es) deleted.'
self._messenger.tell_info(info_text)
Expand Down Expand Up @@ -344,7 +344,7 @@ def _delete_local_merged_branches_for(self, required_target_branches, excluded_b
self._report_branches_as_deleted(truly_merged | defacto_merged)

def _delete_remote_merged_branches_for(self, required_target_branches, excluded_branches,
remote_name, all_branch_refs: Set[str]):
remote_name, all_branch_refs: set[str]):
if not all((f'{remote_name}/{branch_name}' in all_branch_refs)
for branch_name in required_target_branches):
self._messenger.tell_info(f'Skipped remote {remote_name!r} '
Expand Down Expand Up @@ -465,8 +465,8 @@ def delete_merged_branches(self, required_target_branches, excluded_branches, en
self._delete_remote_merged_branches_for(required_target_branches, excluded_branches,
remote_name, all_branch_refs)

def determine_excluded_branches(self, git_config: dict, excluded_branches: List[str],
included_branches_patterns: List[str]) -> Set[str]:
def determine_excluded_branches(self, git_config: dict, excluded_branches: list[str],
included_branches_patterns: list[str]) -> set[str]:
existing_branches = set(self._git.find_all_branch_names())
if excluded_branches:
excluded_branches_set = set(excluded_branches)
Expand Down Expand Up @@ -495,7 +495,7 @@ def determine_excluded_branches(self, git_config: dict, excluded_branches: List[
return excluded_branches_set

def determine_required_target_branches(self, git_config: dict,
required_target_branches: List[str]):
required_target_branches: list[str]):
existing_branches = set(self._git.find_local_branches())
if required_target_branches:
required_target_branches_set = set(required_target_branches)
Expand All @@ -511,7 +511,7 @@ def determine_required_target_branches(self, git_config: dict,

return required_target_branches_set

def determine_enabled_remotes(self, git_config: dict, enabled_remotes: List[str]):
def determine_enabled_remotes(self, git_config: dict, enabled_remotes: list[str]):
existing_remotes = set(self._git.find_remotes())
if enabled_remotes:
enabled_remotes_set = set(enabled_remotes)
Expand Down
22 changes: 11 additions & 11 deletions git_delete_merged_branches/_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import subprocess
from collections import OrderedDict
from typing import List, Optional, Set
from typing import Optional

from ._metadata import APP

Expand Down Expand Up @@ -71,7 +71,7 @@ def _subprocess_check_call(self, argv, is_write, env=None):
env=env)

@classmethod
def _output_bytes_to_lines(cls, output_bytes) -> List[str]:
def _output_bytes_to_lines(cls, output_bytes) -> list[str]:
text = output_bytes.decode(cls._GIT_ENCODING).rstrip()
if not text: # protect against this: ''.split('\n') -> ['']
return []
Expand Down Expand Up @@ -103,7 +103,7 @@ def find_remotes(self):
output_bytes = self._subprocess_check_output(argv, is_write=False)
return self._output_bytes_to_lines(output_bytes)

def _find_branches(self, extra_argv=None, strip_left: int = 2) -> List[str]:
def _find_branches(self, extra_argv=None, strip_left: int = 2) -> list[str]:
# strip_left==1 strips leading "refs/"
# strip_left==2 strips leading "refs/heads/" and "refs/remotes/"
argv = [
Expand All @@ -119,13 +119,13 @@ def _find_branches(self, extra_argv=None, strip_left: int = 2) -> List[str]:
line for line in lines if not line.endswith('/HEAD') and 'HEAD detached at' not in line
]

def find_local_branches(self) -> List[str]:
def find_local_branches(self) -> list[str]:
return self._find_branches()

def find_all_branch_refs(self) -> List[str]:
def find_all_branch_refs(self) -> list[str]:
return self._find_branches(['--all'])

def find_all_branch_names(self) -> Set[str]:
def find_all_branch_names(self) -> set[str]:
branch_names = set()
for line in self._find_branches(['--all'], strip_left=1):
heads_or_remotes, *remainder = line.split('/')
Expand All @@ -138,7 +138,7 @@ def find_all_branch_names(self) -> Set[str]:
branch_names.add(branch_name)
return branch_names

def find_remote_branches_at(self, remote_name) -> List[str]:
def find_remote_branches_at(self, remote_name) -> list[str]:
assert remote_name
extra_argv = ['--remote', '--list', f'{remote_name}/*']
return self._find_branches(extra_argv)
Expand All @@ -157,15 +157,15 @@ def find_current_branch(self) -> Optional[str]:
return None # detached head
return reference[len(expected_prefix):]

def find_working_tree_branches(self) -> List[Optional[str]]:
def find_working_tree_branches(self) -> list[Optional[str]]:
argv = [self._GIT, 'worktree', 'list', '--porcelain'] # requires Git >=2.7.0
output_bytes = self._subprocess_check_output(argv, is_write=False)
lines = self._output_bytes_to_lines(output_bytes)

detached_line_prefix = 'detached'
branch_line_prefix = 'branch '
branch_prefix = 'refs/heads/'
branch_names: List[Optional[str]] = []
branch_names: list[Optional[str]] = []

for line in lines:
if line.startswith(detached_line_prefix):
Expand Down Expand Up @@ -262,7 +262,7 @@ def pull_ff_only(self) -> None:
raise PullFailed
raise

def _has_changes(self, extra_argv: Optional[List[str]] = None) -> bool:
def _has_changes(self, extra_argv: Optional[list[str]] = None) -> bool:
argv = [self._GIT, 'diff', '--exit-code', '--quiet']
if extra_argv:
argv += extra_argv
Expand All @@ -283,7 +283,7 @@ def has_uncommitted_changes(self) -> bool:
return True
return self.has_staged_changes()

def cherry(self, target_branch, topic_branch) -> List[str]:
def cherry(self, target_branch, topic_branch) -> list[str]:
argv = [self._GIT, 'cherry', target_branch, topic_branch]
output_bytes = self._subprocess_check_output(argv, is_write=False)
return self._output_bytes_to_lines(output_bytes)
Expand Down
16 changes: 8 additions & 8 deletions git_delete_merged_branches/_multiselect.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from abc import ABC
from dataclasses import dataclass
from typing import Any, List, Optional, Tuple
from typing import Any, Optional

from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
Expand Down Expand Up @@ -67,7 +67,7 @@ class _NonItemRenderProcessor(Processor):
A Prompt Toolkit input processor for Buffer that formats lines for display to the user.
"""

def __init__(self, prompt: '_MultiSelectPrompt', lines: List):
def __init__(self, prompt: '_MultiSelectPrompt', lines: list):
self._prompt = prompt
self._lines = lines

Expand Down Expand Up @@ -186,7 +186,7 @@ def __init__(self,
self._item_selection_pane: Optional[_HeightTrackingScrollablePane] = None
self._buffer: Optional[Buffer] = None
self._document: Optional[Document] = None
self._accepted_selection: List[Any] = None
self._accepted_selection: list[Any] = None

def _move_cursor_one_page_vertically(self, upwards: bool):
render_cursor_line = (self._item_selection_pane.content.render_info.cursor_position.y
Expand Down Expand Up @@ -301,14 +301,14 @@ def _create_key_bindings(self):

return key_bindings

def _create_text_display_window_for(self, lines: List[_LineBase]) -> Window:
def _create_text_display_window_for(self, lines: list[_LineBase]) -> Window:
document = Document(text='\n'.join(line.text for line in lines))
buffer = Buffer(read_only=True, document=document)
buffer_control = BufferControl(
buffer=buffer, input_processors=[_NonItemRenderProcessor(prompt=self, lines=lines)])
return Window(buffer_control, wrap_lines=True, height=Dimension(min=len(lines)))

def _create_layout(self) -> Tuple[Layout, _HeightTrackingScrollablePane]:
def _create_layout(self) -> tuple[Layout, _HeightTrackingScrollablePane]:
header = self._create_text_display_window_for(self._header_lines)
footer = self._create_text_display_window_for(self._footer_lines)

Expand Down Expand Up @@ -338,7 +338,7 @@ def _create_layout(self) -> Tuple[Layout, _HeightTrackingScrollablePane]:
def _collect_selected_values(self):
return [item.value for item in self.item_lines if item.selected]

def get_selected_values(self) -> List[Any]:
def get_selected_values(self) -> list[Any]:
self._document = Document(text='\n'.join(line.text for line in self.item_lines))
self._buffer = _LineJumpingBuffer(read_only=True, document=self._document)
layout, self._item_selection_pane = self._create_layout()
Expand All @@ -350,8 +350,8 @@ def get_selected_values(self) -> List[Any]:
return self._accepted_selection


def multiselect(messenger: Messenger, options: List[str], initial_selection: List[int], title: str,
help: str, min_selection_count: int, colorize: bool) -> List[str]:
def multiselect(messenger: Messenger, options: list[str], initial_selection: list[int], title: str,
help: str, min_selection_count: int, colorize: bool) -> list[str]:
assert len(options) >= min_selection_count

menu = _MultiSelectPrompt(
Expand Down