Skip to content

Commit

Permalink
chore: Backport to Python 3.8
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr-Pepe committed Dec 14, 2023
1 parent 48059cb commit da378b2
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 30 deletions.
4 changes: 2 additions & 2 deletions docs/_scripts/generate_license_information.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import subprocess
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Optional
from typing import Dict, List, Optional

import jinja2

Expand Down Expand Up @@ -36,7 +36,7 @@
)

with open(licenses_file, encoding="utf-8") as handle:
licenses: list[dict[str, Optional[str]]] = json.load(fp=handle)
licenses: List[Dict[str, Optional[str]]] = json.load(fp=handle)

for license_ in licenses:
for key in ["LicenseFile", "NoticeFile"]:
Expand Down
5 changes: 3 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import json
import os
import sys
from typing import List

import importlib_metadata

Expand All @@ -36,10 +37,10 @@

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named "sphinx.ext.*") or your custom ones.
custom_extensions: list[str] = []
custom_extensions: List[str] = []

# DO NOT ADD ANY EXTENSIONS TO THIS LIST, USE THE `custom_extensions` list for your extensions
template_extensions: list[str] = [
template_extensions: List[str] = [
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"sphinx.ext.doctest",
Expand Down
16 changes: 8 additions & 8 deletions src/voraus_template_updater/_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from datetime import datetime
from enum import Enum
from typing import Optional
from typing import Dict, List, Optional

from github.PullRequest import PullRequest
from pydantic import BaseModel, ConfigDict
Expand Down Expand Up @@ -56,8 +56,8 @@ class Project(BaseModel):
class Summary(BaseModel):
"""A summary of the checked and updates projects."""

projects: list[Project] = []
skipped_projects: list[SkippedProject] = []
projects: List[Project] = []
skipped_projects: List[SkippedProject] = []

def print(self) -> None:
"""Prints the summary."""
Expand All @@ -69,7 +69,7 @@ def print(self) -> None:
_print_table_of_skipped_projects(self.skipped_projects)


def _print_table_of_projects(projects: list[Project]) -> None:
def _print_table_of_projects(projects: List[Project]) -> None:
title = _get_table_title(projects)
table = Table(title=title)
table.add_column("Maintainer")
Expand Down Expand Up @@ -125,7 +125,7 @@ def _print_table_of_projects(projects: list[Project]) -> None:
Console().print(table)


def _get_table_title(projects: list[Project]) -> str:
def _get_table_title(projects: List[Project]) -> str:
processed_projects = len(projects)
up_to_date_projects = len(list(filter(lambda p: p.status == Status.UP_TO_DATE, projects)))

Expand All @@ -136,8 +136,8 @@ def _get_table_title(projects: list[Project]) -> str:
)


def _get_projects_by_maintainer(projects: list[Project]) -> dict[Optional[str], list[Project]]:
projects_by_maintainer: dict[Optional[str], list[Project]] = {}
def _get_projects_by_maintainer(projects: List[Project]) -> Dict[Optional[str], List[Project]]:
projects_by_maintainer: Dict[Optional[str], List[Project]] = {}

for project in sorted(
projects, key=lambda x: x.maintainer or "z" * 100 # Projects without maintainers sorted to end
Expand All @@ -149,7 +149,7 @@ def _get_projects_by_maintainer(projects: list[Project]) -> dict[Optional[str],
return projects_by_maintainer


def _print_table_of_skipped_projects(projects: list[SkippedProject]) -> None:
def _print_table_of_skipped_projects(projects: List[SkippedProject]) -> None:
table = Table(title=f"Skipped projects: {len(projects)}")
table.add_column("Project")
table.add_column("URL")
Expand Down
27 changes: 15 additions & 12 deletions src/voraus_template_updater/_update_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from datetime import datetime
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Annotated, Optional
from typing import List, Optional

import cruft
import git
Expand All @@ -18,6 +18,7 @@
from github.Repository import Repository
from requests import HTTPError
from typer import Argument, Option, Typer
from typing_extensions import Annotated

from voraus_template_updater._schemas import CruftConfig, Project, SkippedProject, Status, Summary

Expand All @@ -37,7 +38,7 @@


@app.command()
def _check_and_update_projects(
def _check_and_update_projects( # pylint: disable=dangerous-default-value # Only meant for CLI usage
github_organization: Annotated[str, Argument(help="The GitHub organization in which to update repositories.")],
github_access_token: Annotated[
str,
Expand All @@ -49,16 +50,14 @@ def _check_and_update_projects(
),
] = "",
maintainer_field: Annotated[
list[str],
List[str],
Option(
help="Cookiecutter variable name that contains the name of a project maintainer. "
"For example, if one of the templates you are updating contains a 'maintainer' variable, specify this "
"option as 'maintainer'. Can be provided multiple times if multiple templates are processed and use "
"different variable names to define a maintainer. The first hit from the list will be used."
),
] = [
"full_name"
], # pylint: disable=dangerous-default-value
] = ["full_name"],
) -> Summary:
summary = Summary()

Expand Down Expand Up @@ -132,7 +131,7 @@ def _check_and_update_projects(

def _get_cruft_config(repo: Repository) -> CruftConfig:
cruft_json = repo.get_contents(".cruft.json")
if isinstance(cruft_json, list):
if isinstance(cruft_json, List):
raise RuntimeError(
f"Repository '{repo.name}' contains more than one '.cruft.json' file. "
"This use case is currently not supported."
Expand All @@ -144,7 +143,7 @@ def _get_cruft_config(repo: Repository) -> CruftConfig:
return CruftConfig.model_validate_json(response.content)


def _get_maintainer(maintainer_fields: list[str], cruft_config: CruftConfig) -> Optional[str]:
def _get_maintainer(maintainer_fields: List[str], cruft_config: CruftConfig) -> Optional[str]:
maintainer = None
for field_name in maintainer_fields:
if field_name in cruft_config.context["cookiecutter"]:
Expand All @@ -154,10 +153,12 @@ def _get_maintainer(maintainer_fields: list[str], cruft_config: CruftConfig) ->


def _clone_repo(repo_url: str, github_access_token: str, target_path: Path) -> Repo:
url = repo_url.replace("[email protected]:", "https://github.com/")
url = url[:-4] if url.endswith(".git") else url # str.removesuffix only supported by Python >= 3.9
url = url.replace("github.com", f"x-access-token:{github_access_token}@github.com")

return git.Repo.clone_from(
url=repo_url.replace("[email protected]:", "https://github.com/")
.removesuffix(".git")
.replace("github.com", f"x-access-token:{github_access_token}@github.com"),
url=url,
to_path=target_path,
)

Expand Down Expand Up @@ -213,7 +214,9 @@ def _get_pr_body(project: Project, github_access_token: str) -> str:
# example `feat: Added feature (#123)`. However GitHub will resolve these links to the current repository although
# they refer to pull requests in the template repository. We therefore need to change these links to point to the
# pull requests in the template repository.
link = project.template_url.replace("[email protected]:", "https://github.com/").removesuffix(".git") + "/pull/{}"
link = project.template_url.replace("[email protected]:", "https://github.com/")
link = link[:-4] if link.endswith(".git") else link # str.removesuffix only supported by Python >= 3.9
link += "/pull/{}"
for i_message, message in enumerate(commit_messages):
commit_messages[i_message] = re.sub(
r"\(#(\d+)\)", lambda match: f"([PR]({link.format(match.groups()[0])}))", message
Expand Down
12 changes: 6 additions & 6 deletions tests/unit/test_update_projects.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Contains unit tests for template updates."""

import logging
from collections.abc import Generator
from datetime import datetime
from pathlib import Path
from typing import Generator, List
from unittest.mock import MagicMock, patch

import pytest
Expand All @@ -26,7 +26,7 @@

@pytest.fixture(autouse=True)
def _set_up_mocks(
cloned_repo_mocks: list[MagicMock], # pylint: disable=unused-argument
cloned_repo_mocks: List[MagicMock], # pylint: disable=unused-argument
cruft_config: MagicMock, # pylint: disable=unused-argument
organization_mock: MagicMock,
repo_mock: MagicMock,
Expand Down Expand Up @@ -89,7 +89,7 @@ def _cruft_config_fixture(request: pytest.FixtureRequest) -> Generator[CruftConf


@pytest.fixture(name="cloned_repo_mocks")
def _cloned_repo_mocks_fixture(request: pytest.FixtureRequest) -> Generator[list[MagicMock], None, None]:
def _cloned_repo_mocks_fixture(request: pytest.FixtureRequest) -> Generator[List[MagicMock], None, None]:
"""Yields a list of git.Repo mocks that can be used for mocking behavior on a cloned project or template repo."""

if "no_clone_repo_mock" in request.keywords:
Expand Down Expand Up @@ -185,8 +185,8 @@ def test_repos_are_skipped_if_cruft_json_cannot_be_downloaded(
with caplog.at_level(logging.WARNING):
summary = _check_and_update_projects(ORGANIZATION)

assert requests_mock.get.called_once_with(repo_mock.get_contents.return_value.download_url, timeout=10)
assert response_mock.raise_for_status.called_once()
requests_mock.get.assert_called_once_with(repo_mock.get_contents.return_value.download_url, timeout=10)
response_mock.raise_for_status.assert_called_once()

assert caplog.record_tuples == [
(
Expand Down Expand Up @@ -324,7 +324,7 @@ def test_update_project_success(
cruft_check_mock: MagicMock,
cruft_update_mock: MagicMock,
repo_mock: MagicMock,
cloned_repo_mocks: list[MagicMock],
cloned_repo_mocks: List[MagicMock],
cruft_config: CruftConfig,
caplog: pytest.LogCaptureFixture,
) -> None:
Expand Down

0 comments on commit da378b2

Please sign in to comment.