From a293240f40bd4c33285820f41eab6a07d295442d Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Sun, 5 May 2024 09:25:47 +0200 Subject: chore: blacken the file Formatting produced by Black is commonly agreed one, and it simplifies life a lot. Add black to your pre-commit hook. --- import_issues.py | 306 ++++++++++++++++++++++++++++++++----------------------- pyproject.toml | 3 + 2 files changed, 182 insertions(+), 127 deletions(-) create mode 100644 pyproject.toml diff --git a/import_issues.py b/import_issues.py index 666644e..13c06ea 100755 --- a/import_issues.py +++ b/import_issues.py @@ -138,8 +138,10 @@ from typing import Dict, List, Optional ID_RE = re.compile(r'^[0-9]+$') -logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', - level=logging.DEBUG) +logging.basicConfig( + format='%(levelname)s:%(funcName)s:%(message)s', + level=logging.DEBUG, +) log = logging.getLogger() email_count = 0 @@ -155,25 +157,27 @@ def read_id_map_file(file_path: Path) -> Dict[int, str]: line_num = 0 for row in reader: line_num += 1 - assert len(row) == 2 and ID_RE.search(row[0]) and row[1], \ - f"Row {line_num} of {file_path} is not in the form ,: {row!r}" + assert ( + len(row) == 2 and ID_RE.search(row[0]) and row[1] + ), f"Row {line_num} of {file_path} is not in the form ,: {row!r}" new_id = int(row[0]) - assert new_id not in result, \ - f"ID {new_id} appears multiple times in {file_path}." + assert ( + new_id not in result + ), f"ID {new_id} appears multiple times in {file_path}." result[new_id] = row[1] return result def do_mail( - *, - smtp, - smtp_delay: float, - mode: str, - frm: str, - to: str, - body: str, - subject: Optional[str] = None, + *, + smtp, + smtp_delay: float, + mode: str, + frm: str, + to: str, + body: str, + subject: Optional[str] = None, ): global email_count email_count += 1 @@ -217,23 +221,23 @@ def do_mail( def open_ticket( - *, - smtp, - smtp_delay: float, - mode: str, - srht_owner: str, - srht_tracker: str, - frm: str, - title: str, - body: str, - created_by: Optional[str], - created_at: str, - closed_at: Optional[str], - is_closed: bool, - is_confidential: bool, - label_names: List[str], - milestone_name: Optional[str], - gitlab_ticket_url: str, + *, + smtp, + smtp_delay: float, + mode: str, + srht_owner: str, + srht_tracker: str, + frm: str, + title: str, + body: str, + created_by: Optional[str], + created_at: str, + closed_at: Optional[str], + is_closed: bool, + is_confidential: bool, + label_names: List[str], + milestone_name: Optional[str], + gitlab_ticket_url: str, ) -> int: global issue_count @@ -279,14 +283,14 @@ def open_ticket( def file_missing_ticket( - *, - smtp, - smtp_delay: float, - mode: str, - srht_owner: str, - srht_tracker: str, - frm: str, - issue_id: int, + *, + smtp, + smtp_delay: float, + mode: str, + srht_owner: str, + srht_tracker: str, + frm: str, + issue_id: int, ): global issue_count @@ -318,20 +322,20 @@ def file_missing_ticket( def send_comment( - *, - smtp, - smtp_delay: float, - mode: str, - srht_owner: str, - srht_tracker: str, - frm: str, - issue_id: int, - body: str, - author_name: str, - created_at: str, - last_edited_at: str, - is_system: bool, - is_confidential: bool, + *, + smtp, + smtp_delay: float, + mode: str, + srht_owner: str, + srht_tracker: str, + frm: str, + issue_id: int, + body: str, + author_name: str, + created_at: str, + last_edited_at: str, + is_system: bool, + is_confidential: bool, ): lines = [] pheaders = [] @@ -368,16 +372,16 @@ def send_comment( def close_ticket( - *, - smtp, - smtp_delay: float, - mode: str, - srht_owner: str, - srht_tracker: str, - frm: str, - issue_id: int, - closed_at: Optional[str], - is_closed: bool, + *, + smtp, + smtp_delay: float, + mode: str, + srht_owner: str, + srht_tracker: str, + frm: str, + issue_id: int, + closed_at: Optional[str], + is_closed: bool, ): lines = [] @@ -401,39 +405,47 @@ def close_ticket( def run( - *, - smtp, - smtp_delay: float, - mode: str, - srht_owner: str, - srht_tracker: str, - frm: str, - export_dir_path: Path, - gitlab_project_url: str, - labels_file_path: Optional[Path], - skip_unknown_labels: bool, - users_file_path: Optional[Path], - skip_unknown_users: bool, - skip_missing_issues: bool, - create_missing_issues: bool, - include_confidential: bool, - skip_confidential: bool, + *, + smtp, + smtp_delay: float, + mode: str, + srht_owner: str, + srht_tracker: str, + frm: str, + export_dir_path: Path, + gitlab_project_url: str, + labels_file_path: Optional[Path], + skip_unknown_labels: bool, + users_file_path: Optional[Path], + skip_unknown_users: bool, + skip_missing_issues: bool, + create_missing_issues: bool, + include_confidential: bool, + skip_confidential: bool, ): - label_ids_to_names: Optional[Dict[int, str]] = \ - read_id_map_file(labels_file_path) if labels_file_path else None - user_ids_to_names: Optional[Dict[int, str]] = \ + label_ids_to_names: Optional[Dict[int, str]] = ( + read_id_map_file(labels_file_path) + if labels_file_path + else None + ) + user_ids_to_names: Optional[Dict[int, str]] = ( read_id_map_file(users_file_path) if users_file_path else None + ) # TODO Might be able to automatically map note.events.author_id to # note.author.name for a subset of relevant users. milestone_jsons = [] - with open(export_dir_path / 'milestones.ndjson') as milestones_file: + with open( + export_dir_path / 'milestones.ndjson' + ) as milestones_file: for line in milestones_file: milestone_jsons.append(json.loads(line)) milestone_ids_to_titles = {} for milestone_json in milestone_jsons: - milestone_ids_to_titles[milestone_json['iid']] = milestone_json['title'] + milestone_ids_to_titles[milestone_json['iid']] = ( + milestone_json['title'] + ) issue_jsons = [] with open(export_dir_path / 'issues.ndjson') as issues_file: @@ -441,7 +453,9 @@ def run( issue_jsons.append(json.loads(line)) if skip_confidential: - issue_jsons = [x for x in issue_jsons if not x.get('confidential')] + issue_jsons = [ + x for x in issue_jsons if not x.get('confidential') + ] for issue_json in issue_jsons: issue_json['notes'] = [ n @@ -451,8 +465,7 @@ def run( elif not include_confidential: have_confidential_issues = any( - x.get('confidential') - for x in issue_jsons + x.get('confidential') for x in issue_jsons ) have_confidential_notes = any( n.get('confidential') @@ -464,21 +477,27 @@ def run( confidential_types.append('issues') if have_confidential_notes: confidential_types.append('notes') - assert not (have_confidential_issues or have_confidential_notes), \ - f"Found confidential {' and '.join(confidential_types)}; please " \ - f"decide whether these should all be included, then pass either " \ - f"--include-confidential or --skip-confidential, or edit " \ + assert not ( + have_confidential_issues or have_confidential_notes + ), ( + f"Found confidential {' and '.join(confidential_types)}; please " + f"decide whether these should all be included, then pass either " + f"--include-confidential or --skip-confidential, or edit " f"issues.ndjson for more fine-grained control." + ) issue_jsons.sort(key=lambda x: x['iid']) max_issue_id = max(x['iid'] for x in issue_jsons) present_issue_id_set = {x['iid'] for x in issue_jsons} - missing_issue_ids = set(range(1, max_issue_id + 1)) - present_issue_id_set - if missing_issue_ids and not (skip_missing_issues or create_missing_issues): + missing_issue_ids = ( + set(range(1, max_issue_id + 1)) - present_issue_id_set + ) + if missing_issue_ids and not ( + skip_missing_issues or create_missing_issues + ): if skip_confidential: - because_confidential_msg = \ - " (possibly because some confidential issues were excluded)" + because_confidential_msg = " (possibly because some confidential issues were excluded)" else: because_confidential_msg = "" @@ -531,9 +550,10 @@ def run( elif author_id in user_ids_to_names: created_by = user_ids_to_names[author_id] else: - assert skip_unknown_users, \ - f"Unknown author #{author_id} of ticket #{gitlab_issue_id}, " \ + assert skip_unknown_users, ( + f"Unknown author #{author_id} of ticket #{gitlab_issue_id}, " f"please add to the users file." + ) created_by = None srht_issue_id = open_ticket( @@ -550,17 +570,23 @@ def run( closed_at=issue_json['closed_at'], is_closed=(issue_json['state'] == 'closed'), is_confidential=(issue_json.get('confidential') is True), - label_names=[x['label']['title'] for x in issue_json['label_links']], - milestone_name=issue_json.get('milestone', {}).get('title') or None, + label_names=[ + x['label']['title'] for x in issue_json['label_links'] + ], + milestone_name=issue_json.get('milestone', {}).get( + 'title' + ) + or None, gitlab_ticket_url=f"{gitlab_project_url}/-/issues/{gitlab_issue_id}", ) if not skip_missing_issues: - assert srht_issue_id == gitlab_issue_id, \ - f"Internal error, srht_issue_id {srht_issue_id} != " \ - f"gitlab_issue_id {gitlab_issue_id} " \ - f"(skip_missing_issues={skip_missing_issues}, " \ + assert srht_issue_id == gitlab_issue_id, ( + f"Internal error, srht_issue_id {srht_issue_id} != " + f"gitlab_issue_id {gitlab_issue_id} " + f"(skip_missing_issues={skip_missing_issues}, " f"create_missing_issues={create_missing_issues})." + ) issue_id_map[gitlab_issue_id] = srht_issue_id @@ -568,29 +594,40 @@ def run( for issue_json in issue_jsons: for note_json in issue_json['notes']: - system_action = note_json.get('system_note_metadata', {}).get('action', None) + system_action = note_json.get( + 'system_note_metadata', {} + ).get('action', None) body = note_json['note'] # The "Removed" part is a guess here, don't know if that actually shows up. if label_ids_to_names is not None and ( - system_action == 'label' or re.search(r'^(Added|Removed) ~[0-9]+ label', body) + system_action == 'label' + or re.search(r'^(Added|Removed) ~[0-9]+ label', body) ): + def expand_label(ref): ref_num = int(ref.group(1)) if ref_num in label_ids_to_names: return label_ids_to_names[ref_num] - assert skip_unknown_labels, \ - f"Unknown label #{ref_num}, please add to the labels file." - return ref.group(0) # Return the original "~id" string. + assert ( + skip_unknown_labels + ), f"Unknown label #{ref_num}, please add to the labels file." + return ref.group( + 0 + ) # Return the original "~id" string. body = re.sub(r'~([0-9]+)', expand_label, body) - if system_action == 'milestone' or re.search(r'^Milestone changed to %[0-9]+$', body): + if system_action == 'milestone' or re.search( + r'^Milestone changed to %[0-9]+$', body + ): + def expand_milestone(ref): ref_num = int(ref.group(1)) - assert ref_num in milestone_ids_to_titles, \ - f"Unknown milestone #{ref_num}." + assert ( + ref_num in milestone_ids_to_titles + ), f"Unknown milestone #{ref_num}." return milestone_ids_to_titles[ref_num] body = re.sub(r'%([0-9]+)', expand_milestone, body) @@ -770,8 +807,9 @@ def main(): export_dir = args['export_dir'] assert export_dir, f"Must have a exported project directory." export_dir_path = Path(export_dir) - assert export_dir_path.is_dir(), \ - f"Project directory is not a directory: {export_dir_path}" + assert ( + export_dir_path.is_dir() + ), f"Project directory is not a directory: {export_dir_path}" mode = args['mode'] frm = args['from'] @@ -779,39 +817,53 @@ def main(): labels_file = args['labels_file'] skip_labels = args['skip_labels'] skip_unknown_labels = args['skip_unknown_labels'] - assert labels_file or skip_labels, \ - f"One of --labels-file or --skip-labels must be provided." + assert ( + labels_file or skip_labels + ), f"One of --labels-file or --skip-labels must be provided." users_file = args['users_file'] skip_users = args['skip_users'] skip_unknown_users = args['skip_unknown_users'] - assert skip_users or users_file, \ - f"One of --users-file or --skip-users must be provided." + assert ( + skip_users or users_file + ), f"One of --users-file or --skip-users must be provided." skip_missing_issues = args['skip_missing_issues'] create_missing_issues = args['create_missing_issues'] - assert not (skip_missing_issues and create_missing_issues), \ - f"Can accept at most one of --skip-missing-issues and --create-missing-issues." + assert not ( + skip_missing_issues and create_missing_issues + ), f"Can accept at most one of --skip-missing-issues and --create-missing-issues." include_confidential = args['include_confidential'] skip_confidential = args['skip_confidential'] - assert not (include_confidential and skip_confidential), \ - f"Can accept at most one of --include-confidential and --skip-confidential." + assert not ( + include_confidential and skip_confidential + ), f"Can accept at most one of --include-confidential and --skip-confidential." if mode == 'print': smtp = None elif mode == 'send': smtp_ssl = args['smtp_ssl'] smtp_starttls = args['smtp_starttls'] - smtp_host = args['smtp_host'] or os.environ.get('SMTP_HOST', 'localhost') - smtp_port = args['smtp_port'] or os.environ.get('SMTP_PORT', 465 if smtp_ssl else 25) - smtp_user = args['smtp_user'] or os.environ.get('SMTP_USER', None) - smtp_password = args['smtp_password'] or os.environ.get('SMTP_PASSWORD', None) + smtp_host = args['smtp_host'] or os.environ.get( + 'SMTP_HOST', 'localhost' + ) + smtp_port = args['smtp_port'] or os.environ.get( + 'SMTP_PORT', 465 if smtp_ssl else 25 + ) + smtp_user = args['smtp_user'] or os.environ.get( + 'SMTP_USER', None + ) + smtp_password = args['smtp_password'] or os.environ.get( + 'SMTP_PASSWORD', None + ) assert smtp_user, f"No SMTP user given." assert smtp_password, f"No SMTP password given." - log.info(f"Connecting to {smtp_host}:{smtp_port}, user {smtp_user!r}.") + log.info( + f"Connecting to {smtp_host}:{smtp_port}, user {smtp_user!r}." + ) if smtp_ssl: smtp = smtplib.SMTP_SSL(host=smtp_host, port=smtp_port) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7deab36 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[tool.black] +line-length = 70 +skip-string-normalization = true -- cgit