Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract ErrorsList base errors list manager #105

Merged
merged 2 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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
Loading