Module gametime_watcher.filters
Filtering of listings by section, price, and quantity.
Functions
def filter_listings(listings: Iterable[Listing],
*,
sections: Union[str, Sequence[str], SectionMatcher, None] = None,
max_price_dollars: Optional[float] = None,
quantity: Optional[int] = None,
allow_larger: bool = False) ‑> List[Listing]-
Expand source code
def filter_listings( listings: Iterable[Listing], *, sections: Union[str, Sequence[str], SectionMatcher, None] = None, max_price_dollars: Optional[float] = None, quantity: Optional[int] = None, allow_larger: bool = False, ) -> List[Listing]: """Return listings matching all provided criteria, cheapest first. Args: sections: section spec (see :class:`SectionMatcher`) or a matcher. max_price_dollars: maximum all-in price *per ticket*, in dollars. quantity: number of seats you want to buy together; only listings that offer this lot size are kept (see :meth:`Listing.can_buy`). allow_larger: if True, also keep listings offering a larger lot. """ matcher = sections if isinstance(sections, SectionMatcher) else SectionMatcher.parse(sections) result = [] for listing in listings: if not matcher.matches(listing): continue if max_price_dollars is not None and listing.price_total_dollars > max_price_dollars: continue if quantity is not None and not listing.can_buy(quantity, allow_larger=allow_larger): continue result.append(listing) result.sort(key=lambda listing: (listing.price_total, listing.section, listing.row or "")) return resultReturn listings matching all provided criteria, cheapest first.
Args
sections- section spec (see :class:
SectionMatcher) or a matcher. max_price_dollars- maximum all-in price per ticket, in dollars.
quantity- number of seats you want to buy together; only listings that
offer this lot size are kept (see :meth:
Listing.can_buy). allow_larger- if True, also keep listings offering a larger lot.
Classes
class SectionMatcher (matchers: Optional[Sequence] = None)-
Expand source code
class SectionMatcher: """Matches listings against a flexible section specification. A spec is one or more tokens (comma-separated string, or a sequence). Each token is one of: * a numeric range, e.g. ``"200-299"`` (inclusive) * an exact numeric section, e.g. ``"119"`` * a section/group name, e.g. ``"Solon Club"`` (case-insensitive; matches the section label exactly or the section group as a substring) A listing matches if it satisfies *any* token. An empty spec matches all. """ def __init__(self, matchers: Optional[Sequence] = None): self._matchers = list(matchers or []) @classmethod def parse(cls, spec: Union[str, Sequence[str], None]) -> "SectionMatcher": if spec is None: return cls([]) tokens: List[str] if isinstance(spec, str): tokens = [t for t in (s.strip() for s in spec.split(",")) if t] else: tokens = [t.strip() for t in spec if t and t.strip()] matchers = [] for token in tokens: rng = _RANGE_RE.match(token) if rng: low, high = int(rng.group(1)), int(rng.group(2)) if low > high: low, high = high, low matchers.append(_Range(low, high)) continue alpha_rng = _ALPHA_RANGE_RE.match(token) if alpha_rng: low, high = alpha_rng.group(1).upper(), alpha_rng.group(2).upper() if low > high: low, high = high, low matchers.append(_AlphaRange(low, high)) elif token.isdigit(): matchers.append(_Exact(int(token))) else: matchers.append(_Name(token)) return cls(matchers) @property def is_empty(self) -> bool: return not self._matchers def matches(self, listing: Listing) -> bool: if not self._matchers: return True return any(m.matches(listing) for m in self._matchers)Matches listings against a flexible section specification.
A spec is one or more tokens (comma-separated string, or a sequence). Each token is one of:
- a numeric range, e.g.
"200-299"(inclusive) - an exact numeric section, e.g.
"119" - a section/group name, e.g.
"Solon Club"(case-insensitive; matches the section label exactly or the section group as a substring)
A listing matches if it satisfies any token. An empty spec matches all.
Static methods
def parse(spec: Union[str, Sequence[str], None]) ‑> SectionMatcher
Instance variables
prop is_empty : bool-
Expand source code
@property def is_empty(self) -> bool: return not self._matchers
Methods
def matches(self, listing: Listing) ‑> bool-
Expand source code
def matches(self, listing: Listing) -> bool: if not self._matchers: return True return any(m.matches(listing) for m in self._matchers)
- a numeric range, e.g.