Skip to content
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
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ jobs:
- run: coverage run --source=dfetch --append -m behave features # Run features tests
- run: coverage xml -o coverage.xml # Create XML report
- run: pyroma --directory --min=10 . # Check pyproject
- run: find dfetch -name "*.py" | xargs pyupgrade --py39-plus # Check syntax

- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@a38818475bb21847788496e9f0fddaa4e84955ba # master
Expand Down
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ repos:
entry: pyright
language: python
types: [file, python]
- id: pyupgrade
name: pyupgrade
description: Modernize python
entry: pyupgrade
language: python
files: ^dfetch/
args: [--py39-plus]
types: [file, python]

- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.3
hooks:
Expand Down
2 changes: 1 addition & 1 deletion dfetch/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import argparse
import sys
from typing import Sequence
from collections.abc import Sequence

import dfetch.commands.check
import dfetch.commands.diff
Expand Down
7 changes: 3 additions & 4 deletions dfetch/commands/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import argparse
import os
from typing import List

import dfetch.commands.command
import dfetch.manifest.manifest
Expand Down Expand Up @@ -88,7 +87,7 @@ def __call__(self, args: argparse.Namespace) -> None:
reporters = self._get_reporters(args, manifest)

with in_directory(os.path.dirname(manifest.path)):
exceptions: List[str] = []
exceptions: list[str] = []
for project in manifest.selected_projects(args.projects):
with catch_runtime_exceptions(exceptions) as exceptions:
dfetch.project.make(project).check_for_update(reporters)
Expand All @@ -106,7 +105,7 @@ def __call__(self, args: argparse.Namespace) -> None:
@staticmethod
def _get_reporters(
args: argparse.Namespace, manifest: Manifest
) -> List[CheckReporter]:
) -> list[CheckReporter]:
"""Get all reporters.

Args:
Expand All @@ -116,7 +115,7 @@ def _get_reporters(
Returns:
List[CheckReporter]: List of reporters that each provide a unique report
"""
reporters: List[CheckReporter] = [CheckStdoutReporter(manifest)]
reporters: list[CheckReporter] = [CheckStdoutReporter(manifest)]
if args.jenkins_json:
reporters += [JenkinsReporter(manifest, args.jenkins_json)]
if args.sarif:
Expand Down
4 changes: 2 additions & 2 deletions dfetch/commands/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sys
from abc import ABC, abstractmethod
from argparse import ArgumentParser # pylint: disable=unused-import
from typing import TYPE_CHECKING, Type, TypeVar
from typing import TYPE_CHECKING, TypeVar

if TYPE_CHECKING and sys.version_info >= (3, 10):
from typing import TypeAlias
Expand Down Expand Up @@ -56,7 +56,7 @@ def __call__(self, args: argparse.Namespace) -> None:
@staticmethod
def parser(
subparsers: SubparserActionType,
command: Type["Command.CHILD_TYPE"],
command: type["Command.CHILD_TYPE"],
) -> "argparse.ArgumentParser":
"""Generate the parser.

Expand Down
5 changes: 2 additions & 3 deletions dfetch/commands/common.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Module for common command operations."""

import os
from typing import List

import yaml

Expand All @@ -20,7 +19,7 @@ def check_child_manifests(manifest: Manifest, project: ProjectEntry) -> None:
project (ProjectEntry): The parent project.
"""
for childmanifest in get_childmanifests(skip=[manifest.path]):
recommendations: List[ProjectEntry] = []
recommendations: list[ProjectEntry] = []
for childproject in childmanifest.projects:
if childproject.remote_url not in [
project.remote_url for project in manifest.projects
Expand All @@ -35,7 +34,7 @@ def check_child_manifests(manifest: Manifest, project: ProjectEntry) -> None:


def _make_recommendation(
project: ProjectEntry, recommendations: List[ProjectEntry], childmanifest_path: str
project: ProjectEntry, recommendations: list[ProjectEntry], childmanifest_path: str
) -> None:
"""Make recommendations to the user.

Expand Down
7 changes: 3 additions & 4 deletions dfetch/commands/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@

import argparse
import os
from typing import List

import dfetch.commands.command
import dfetch.manifest.manifest
Expand Down Expand Up @@ -104,7 +103,7 @@ def __call__(self, args: argparse.Namespace) -> None:
revs = [r for r in args.revs.strip(":").split(":", maxsplit=1) if r]

with in_directory(os.path.dirname(manifest.path)):
exceptions: List[str] = []
exceptions: list[str] = []
projects = manifest.selected_projects(args.projects)
if not projects:
raise RuntimeError(
Expand Down Expand Up @@ -139,7 +138,7 @@ def _get_repo(path: str, project: ProjectEntry) -> VCS:
)


def _diff_from_repo(repo: VCS, project: ProjectEntry, revs: List[str]) -> str:
def _diff_from_repo(repo: VCS, project: ProjectEntry, revs: list[str]) -> str:
"""Generate a relative diff for a svn repo."""
if len(revs) > 2:
raise RuntimeError(f"Too many revisions given! {revs}")
Expand All @@ -160,7 +159,7 @@ def _diff_from_repo(repo: VCS, project: ProjectEntry, revs: List[str]) -> str:


def _dump_patch(
path: str, revs: List[str], project: ProjectEntry, patch_name: str, patch: str
path: str, revs: list[str], project: ProjectEntry, patch_name: str, patch: str
) -> None:
"""Dump the patch to a file."""
if patch:
Expand Down
5 changes: 2 additions & 3 deletions dfetch/commands/freeze.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import argparse
import os
import shutil
from typing import List

import dfetch.commands.command
import dfetch.manifest.project
Expand Down Expand Up @@ -72,8 +71,8 @@ def __call__(self, args: argparse.Namespace) -> None:

manifest = get_manifest()

exceptions: List[str] = []
projects: List[ProjectEntry] = []
exceptions: list[str] = []
projects: list[ProjectEntry] = []

with in_directory(os.path.dirname(manifest.path)):
for project in manifest.projects:
Expand Down
16 changes: 8 additions & 8 deletions dfetch/commands/import_.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@
import argparse
import os
import re
from collections.abc import Sequence
from itertools import combinations
from typing import List, Sequence, Set, Tuple

import dfetch.commands.command
from dfetch import DEFAULT_MANIFEST_NAME
Expand Down Expand Up @@ -150,7 +150,7 @@ def _import_projects() -> Sequence[ProjectEntry]:


def _import_from_svn() -> Sequence[ProjectEntry]:
projects: List[ProjectEntry] = []
projects: list[ProjectEntry] = []

for external in SvnRepo.externals():
projects.append(
Expand All @@ -172,7 +172,7 @@ def _import_from_svn() -> Sequence[ProjectEntry]:


def _import_from_git() -> Sequence[ProjectEntry]:
projects: List[ProjectEntry] = []
projects: list[ProjectEntry] = []
toplevel: str = ""
for submodule in GitLocalRepo.submodules():
projects.append(
Expand Down Expand Up @@ -241,7 +241,7 @@ def _generate_remote_name(remote_url: str) -> str:
return re.sub(r"[-]{2,}", "-", filtered).strip("-")


def _determine_best_remotes(projects_urls: Set[str]) -> Tuple[str, ...]:
def _determine_best_remotes(projects_urls: set[str]) -> tuple[str, ...]:
"""Determine the smallest amount of remotes, that cover the most urls.

Args:
Expand All @@ -254,17 +254,17 @@ def _determine_best_remotes(projects_urls: Set[str]) -> Tuple[str, ...]:
max_remotes = 5

# Determine all possible remotes
potential_remotes: Set[str] = set()
potential_remotes: set[str] = set()
for url in projects_urls:
potential_remotes.add(url[:max_remote_length].rsplit("/", maxsplit=1)[0])
potential_remotes.add(url[:max_remote_length].rsplit("/", maxsplit=2)[0])
potential_remotes.add(url[:max_remote_length].rsplit(":", maxsplit=1)[0])

useless_potential = set(["http", "https"])
useless_potential = {"http", "https"}
potential_remotes = potential_remotes - useless_potential

# For each permutation of any length, calculate the solution score
solutions: List[Tuple[int, Tuple[str, ...]]] = []
solutions: list[tuple[int, tuple[str, ...]]] = []
for i in range(min(len(potential_remotes), max_remotes)):
for solution in combinations(potential_remotes, i):
score = _calculate_solution_score(solution, projects_urls)
Expand All @@ -275,7 +275,7 @@ def _determine_best_remotes(projects_urls: Set[str]) -> Tuple[str, ...]:


def _calculate_solution_score(
solution: Tuple[str, ...], projects_urls: Set[str]
solution: tuple[str, ...], projects_urls: set[str]
) -> int:
"""Calculate a score with the given solution.

Expand Down
3 changes: 1 addition & 2 deletions dfetch/commands/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import argparse
import glob
import os
from typing import List

import dfetch.commands.command
import dfetch.manifest.manifest
Expand Down Expand Up @@ -79,7 +78,7 @@ def __call__(self, args: argparse.Namespace) -> None:
logger.info(f"Generated {reporter.name} report: {args.outfile}")

@staticmethod
def _determine_licenses(project: ProjectEntry) -> List[License]:
def _determine_licenses(project: ProjectEntry) -> list[License]:
"""Try to determine license of fetched project."""
if not os.path.exists(project.destination):
logger.print_warning_line(
Expand Down
9 changes: 4 additions & 5 deletions dfetch/commands/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import argparse
import os
from pathlib import Path
from typing import List

import dfetch.commands.command
import dfetch.manifest.manifest
Expand Down Expand Up @@ -71,8 +70,8 @@ def __call__(self, args: argparse.Namespace) -> None:
"""Perform the update."""
manifest = dfetch.manifest.manifest.get_manifest()

exceptions: List[str] = []
destinations: List[str] = [
exceptions: list[str] = []
destinations: list[str] = [
os.path.realpath(project.destination) for project in manifest.projects
]
with in_directory(os.path.dirname(manifest.path)):
Expand All @@ -92,7 +91,7 @@ def __call__(self, args: argparse.Namespace) -> None:

@staticmethod
def _check_destination(
project: dfetch.manifest.project.ProjectEntry, destinations: List[str]
project: dfetch.manifest.project.ProjectEntry, destinations: list[str]
) -> None:
"""Do some sanity checks on the destination path."""
real_path = os.path.realpath(project.destination)
Expand Down Expand Up @@ -137,7 +136,7 @@ def _check_dst_not_in_blacklist(
@staticmethod
def _check_overlapping_destination(
project: dfetch.manifest.project.ProjectEntry,
destinations: List[str],
destinations: list[str],
real_path: str,
) -> None:
"""Check if project will try to write to the same destination."""
Expand Down
29 changes: 15 additions & 14 deletions dfetch/manifest/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
import os
import pathlib
import re
from collections.abc import Sequence
from dataclasses import dataclass
from typing import IO, Any, Dict, List, Optional, Sequence, Tuple, Union
from typing import IO, Any, Optional, Union

import yaml
from typing_extensions import TypedDict
Expand Down Expand Up @@ -102,7 +103,7 @@ class ManifestDict( # pylint: disable=too-many-ancestors

version: Union[int, str]
remotes: Sequence[Union[RemoteDict, Remote]]
projects: Sequence[Union[ProjectEntryDict, ProjectEntry, Dict[str, str]]]
projects: Sequence[Union[ProjectEntryDict, ProjectEntry, dict[str, str]]]


class Manifest:
Expand Down Expand Up @@ -143,8 +144,8 @@ def __init__(
self._projects = self._init_projects(manifest["projects"])

def _init_projects(
self, projects: Sequence[Union[ProjectEntryDict, ProjectEntry, Dict[str, str]]]
) -> Dict[str, ProjectEntry]:
self, projects: Sequence[Union[ProjectEntryDict, ProjectEntry, dict[str, str]]]
) -> dict[str, ProjectEntry]:
"""Iterate over projects from manifest and initialize ProjectEntries from it.

Args:
Expand All @@ -156,7 +157,7 @@ def _init_projects(
Returns:
Dict[str, ProjectEntry]: Dictionary with key: Name of project, Value: ProjectEntry
"""
_projects: Dict[str, ProjectEntry] = {}
_projects: dict[str, ProjectEntry] = {}

for project in projects:
if isinstance(project, dict):
Expand Down Expand Up @@ -184,9 +185,9 @@ def _init_projects(
@staticmethod
def _determine_remotes(
remotes_from_manifest: Sequence[Union[RemoteDict, Remote]],
) -> Tuple[Dict[str, Remote], List[Remote]]:
default_remotes: List[Remote] = []
remotes: Dict[str, Remote] = {}
) -> tuple[dict[str, Remote], list[Remote]]:
default_remotes: list[Remote] = []
remotes: dict[str, Remote] = {}
for remote in remotes_from_manifest:
if isinstance(remote, dict):
last_remote = remotes[remote["name"]] = Remote.from_yaml(remote)
Expand Down Expand Up @@ -243,7 +244,7 @@ def from_file(path: str) -> "Manifest":
Raises:
FileNotFoundError: Given path was not a file.
"""
with open(path, "r", encoding="utf-8") as opened_file:
with open(path, encoding="utf-8") as opened_file:
return Manifest.from_yaml(opened_file, path)

@property
Expand Down Expand Up @@ -291,7 +292,7 @@ def __repr__(self) -> str:
"""Get string representing this object."""
return str(self._as_dict())

def _as_dict(self) -> Dict[str, ManifestDict]:
def _as_dict(self) -> dict[str, ManifestDict]:
"""Get this manifest as dict."""
remotes: Sequence[RemoteDict] = [
remote.as_yaml() for remote in self._remotes.values()
Expand All @@ -300,9 +301,9 @@ def _as_dict(self) -> Dict[str, ManifestDict]:
if len(remotes) == 1:
remotes[0].pop("default", None)

projects: List[Dict[str, str]] = []
projects: list[dict[str, str]] = []
for project in self.projects:
project_yaml: Dict[str, str] = project.as_yaml()
project_yaml: dict[str, str] = project.as_yaml()
if len(remotes) == 1:
project_yaml.pop("remote", None)
projects.append(project_yaml)
Expand Down Expand Up @@ -381,12 +382,12 @@ def get_manifest() -> Manifest:
return Manifest.from_file(manifest_path)


def get_childmanifests(skip: Optional[List[str]] = None) -> List[Manifest]:
def get_childmanifests(skip: Optional[list[str]] = None) -> list[Manifest]:
"""Get manifest and its path."""
skip = skip or []
logger.debug("Looking for sub-manifests")

childmanifests: List[Manifest] = []
childmanifests: list[Manifest] = []
for path in find_file(DEFAULT_MANIFEST_NAME, "."):
path = os.path.realpath(path)
if path not in skip:
Expand Down
Loading
Loading