FreedomBox/plinth/diagnostic_check.py
James Valleroy f08211d228
upgrades: Add diagnostic for held packages
- Add a new diagnostic check result for skipped tests.

Tests:

- Put a hold on a package. The diagnostic is failed.

- Remove the hold from the package. The diagnostic is passed.

- Start installing an app, then immediately run the upgrades
  diagnostics. The diagnostic is skipped.

Helps: #2347

Signed-off-by: James Valleroy <jvalleroy@mailbox.org>
[sunil: Allow i18n for new state 'skipped']
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
2024-08-25 14:22:46 -07:00

74 lines
2.1 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""Diagnostic check data type."""
import dataclasses
import json
from dataclasses import dataclass, field
from enum import StrEnum
from typing import TypeAlias
from django.utils.translation import gettext
from plinth.utils import SafeFormatter
DiagnosticCheckParameters: TypeAlias = dict[str, str | int | bool | None]
class Result(StrEnum):
"""The result of a diagnostic check."""
NOT_DONE = 'not_done'
SKIPPED = 'skipped'
PASSED = 'passed'
WARNING = 'warning'
FAILED = 'failed'
ERROR = 'error'
@dataclass
class DiagnosticCheck:
"""A diagnostic check and optional result and parameters."""
check_id: str
description: str
result: Result = Result.NOT_DONE
parameters: DiagnosticCheckParameters = field(default_factory=dict)
component_id: str | None = None
@property
def translated_description(self):
"""Return translated string for description."""
description = gettext(self.description)
if self.parameters:
return SafeFormatter().vformat(description, [], self.parameters)
return description
class CheckJSONEncoder(json.JSONEncoder):
"""Encode objects that include DiagnosticChecks."""
def default(self, o):
"""Add class tag to DiagnosticChecks."""
if isinstance(o, DiagnosticCheck):
o = dataclasses.asdict(o)
o.update({'__class__': 'DiagnosticCheck'})
return o
return super().default(o)
class CheckJSONDecoder(json.JSONDecoder):
"""Decode objects that include DiagnosticChecks."""
def __init__(self):
json.JSONDecoder.__init__(self, object_hook=CheckJSONDecoder.from_dict)
@staticmethod
def from_dict(data):
"""Convert tagged data to DiagnosticCheck."""
if data.get('__class__') == 'DiagnosticCheck':
return DiagnosticCheck(data['check_id'], data['description'],
data['result'], data['parameters'],
data.get('component_id'))
return data