Skip to content

Commit

Permalink
Extract ErrorsList base errors list manager
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidSouther committed Oct 8, 2024
1 parent f94d8dd commit 794d59c
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 89 deletions.
39 changes: 5 additions & 34 deletions aws_doc_sdk_examples_tools/entities.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from typing import List, Optional, TypeVar, Dict, Set, Union, Tuple, Iterator, Iterable
from typing import Optional, TypeVar, Dict, Set, Tuple
from dataclasses import dataclass
import re

from .metadata_errors import ErrorsList

K = TypeVar("K")


Expand All @@ -28,39 +30,8 @@ def message(self):
return f"{self.entity} not found."


class EntityErrors:
def __init__(self):
self._errors: List[EntityError] = []

def append(self, maybe_error: Union[K, EntityError]):
if not isinstance(maybe_error, EntityError):
raise InvalidItemException(maybe_error)
self._errors.append(maybe_error)

def extend(self, errors: Iterable[EntityError]):
self._errors.extend(errors)

def __getitem__(self, key: int) -> EntityError:
return self._errors[key]

def __setitem__(self, key: int, value: EntityError):
self._errors[key] = value

def __len__(self) -> int:
return len(self._errors)

def __iter__(self) -> Iterator[EntityError]:
return self._errors.__iter__()

def __repr__(self) -> str:
return repr(self._errors)

def __str__(self) -> str:
errs = "\n".join([f"\t{err}" for err in self._errors])
return f"EntityErrors with {len(self)} errors:\n{errs}"

def __eq__(self, __value: object) -> bool:
return isinstance(__value, EntityErrors) and self._errors == __value._errors
class EntityErrors(ErrorsList[EntityError]):
pass


def expand_all_entities(
Expand Down
123 changes: 68 additions & 55 deletions aws_doc_sdk_examples_tools/metadata_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,66 +6,33 @@
import re
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, Iterator, Iterable, List, TypeVar
from typing import Optional, Iterator, Iterable, List, TypeVar, Generic


@dataclass
class MetadataError:
file: Optional[Path] = None
id: Optional[str] = None

def prefix(self):
prefix = f"In {self.file or 'several'} at {self.id},"
return prefix

def message(self) -> str:
return ""

def __str__(self):
return f"{self.prefix()} {self.message()}"
ErrorT = TypeVar("ErrorT")


@dataclass
class MetadataParseError(MetadataError):
id: Optional[str] = None
language: Optional[str] = None
sdk_version: Optional[int] = None

def prefix(self):
prefix = super().prefix() + f" example {self.id}"
if self.language:
prefix += f" {self.language}"
if self.sdk_version:
prefix += f":{self.sdk_version}"
return prefix

def __str__(self):
return f"{self.prefix()} {self.message()}"


K = TypeVar("K")


class InvalidItemException(Exception):
def __init__(self, item: MetadataParseError):
class InvalidItemException(Exception, Generic[ErrorT]):
def __init__(self, item: ErrorT):
super().__init__(self, f"Cannot append {item!r} to ExampleErrors")


class DuplicateItemException(Exception):
def __init__(self, item: MetadataError):
super().__init__(self, f"Already have item {item!r} in ExampleErrors")


class MetadataErrors:
class ErrorsList(Generic[ErrorT]):
"""MyPy isn't catching List[Foo].append(List[Foo])"""

def __init__(self, no_duplicates: bool = False):
self.no_duplicates = no_duplicates
self._errors: List[MetadataError] = []

def append(self, item: MetadataError):
if not isinstance(item, MetadataError):
self._errors: List[ErrorT] = []

def append(self, item: ErrorT):
# Look up the generic type. This is reliant on the internal implementation
# of __orig_bases__, but it will definitely fail tests if a python minor
# version breaks it.
generic = self.__orig_bases__[0] # type: ignore
T = generic.__args__[0]
if not isinstance(item, T):
raise InvalidItemException(item)

"""
It is dangerous to go alone: 🗡️
If you're seeing duplicated Errors, and aren't sure why, uncommenting these lines may help you debug it.
Expand All @@ -74,25 +41,25 @@ def append(self, item: MetadataError):
# raise DuplicateItemException(item)
self._errors.append(item)

def extend(self, errors: Iterable[MetadataError]):
def extend(self, errors: Iterable[ErrorT]):
self._errors.extend(errors)

def maybe_extend(self, maybe_errors: K | MetadataErrors) -> K | None:
if isinstance(maybe_errors, MetadataErrors):
def maybe_extend(self, maybe_errors: K | ErrorsList[ErrorT]) -> K | None:
if isinstance(maybe_errors, ErrorsList):
self.extend(maybe_errors._errors)
return None
return maybe_errors

def __getitem__(self, key: int) -> MetadataError:
def __getitem__(self, key: int) -> ErrorT:
return self._errors[key]

def __setitem__(self, key: int, value: MetadataError):
def __setitem__(self, key: int, value: ErrorT):
self._errors[key] = value

def __len__(self) -> int:
return len(self._errors)

def __iter__(self) -> Iterator[MetadataError]:
def __iter__(self) -> Iterator[ErrorT]:
return self._errors.__iter__()

def __repr__(self) -> str:
Expand All @@ -103,7 +70,53 @@ def __str__(self) -> str:
return f"ExampleErrors with {len(self)} errors:\n{errs}"

def __eq__(self, __value: object) -> bool:
return isinstance(__value, MetadataErrors) and self._errors == __value._errors
return isinstance(__value, ErrorsList) and self._errors == __value._errors


@dataclass
class MetadataError:
file: Optional[Path] = None
id: Optional[str] = None

def prefix(self):
prefix = f"In {self.file or 'several'} at {self.id},"
return prefix

def message(self) -> str:
return ""

def __str__(self):
return f"{self.prefix()} {self.message()}"


class MetadataErrors(ErrorsList[MetadataError]):
pass


@dataclass
class MetadataParseError(MetadataError):
id: Optional[str] = None
language: Optional[str] = None
sdk_version: Optional[int] = None

def prefix(self):
prefix = super().prefix() + f" example {self.id}"
if self.language:
prefix += f" {self.language}"
if self.sdk_version:
prefix += f":{self.sdk_version}"
return prefix

def __str__(self):
return f"{self.prefix()} {self.message()}"


K = TypeVar("K")


class DuplicateItemException(Exception):
def __init__(self, item: MetadataError):
super().__init__(self, f"Already have item {item!r} in ExampleErrors")


@dataclass
Expand Down

0 comments on commit 794d59c

Please sign in to comment.