from dataclasses import dataclass
from collections.abc import Iterable, Iterator, Sequence
from typing import Optional, overload, List, Callable, TypeVar, Self
import requests
T = TypeVar('T')
def parse_listfile(contents: str, ctor: Callable[[str, Optional[str]], T]) -> List[T]:
acc = []
comment_acc = []
for line in contents.splitlines():
if not len(line):
continue
elif line.startswith("##"):
comment_acc.append(line[2:].strip())
elif line.startswith("#"):
continue
else:
acc.append(ctor(line, " ".join(comment_acc) if len(comment_acc) else None))
comment_acc = []
return acc
@dataclass(frozen=True)
class ListFileEntry:
entry: str
comment: Optional[str]
L = TypeVar('L', bound=ListFileEntry)
class BaseListFile(Sequence[L]):
def __init__(self, contents: str):
self._contents: str = contents
self._entries: List[L] = []
@overload
def __getitem__(self, key: int) -> L:
pass
@overload
def __getitem__(self, key: slice) -> Sequence[L]:
pass
def __getitem__(self, key):
return self._entries[key]
def __len__(self) -> int:
return self._entries.__len__()
@classmethod
def from_url(cls, url: str) -> Optional[Self]:
req = requests.get(url, stream = False)
if not req.ok:
return None
return cls(req.text)
class ListFile(BaseListFile[ListFileEntry]):
def __init__(self, contents: str):
super().__init__(contents)
self._entries = parse_listfile(contents, ListFileEntry)
__all__ = ["parse_listfile", "ListFileEntry", "BaseListFile", "ListFIle"]