~khumba/public-inbox

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH] chore: blacken the file

Details
Message ID
<20240505073514.3814-2-mcepl@cepl.eu>
DKIM signature
pass
Download raw message
Patch: +182 -127
Formatting produced by Black is commonly agreed one, and it
simplifies life a lot.

Add black to your pre-commit hook.

Signed-off-by: Matěj Cepl <mcepl@cepl.eu>
---
 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 <ID>,<NAME>: {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 <ID>,<NAME>: {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
-- 
2.44.0
Details
Message ID
<20240505081727.7eaa0818@khumba.net>
In-Reply-To
<20240505073514.3814-2-mcepl@cepl.eu> (view parent)
DKIM signature
pass
Download raw message
On Sun,  5 May 2024 09:35:06 +0200
Matěj Cepl <mcepl@cepl.eu> wrote:

> Formatting produced by Black is commonly agreed one, and it
> simplifies life a lot.
> 
> Add black to your pre-commit hook.
> 
> Signed-off-by: Matěj Cepl <mcepl@cepl.eu>
> ---
>  import_issues.py | 306 +++++++++++++++++++++++++++--------------------
>  pyproject.toml   |   3 +
>  2 files changed, 182 insertions(+), 127 deletions(-)
>  create mode 100644 pyproject.toml

Thanks, I haven't looked at Black in ages and I quite like the style
it recommends now.

> 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

Would you be alright with using the Black defaults for these two
options too?  Even 80 feels a bit tight sometimes, and we might as
well normalize the strings, even if it makes the diff larger now.
Reply to thread Export thread (mbox)