From: Plom Heller Date: Mon, 4 May 2026 04:26:50 +0000 (+0200) Subject: Differentiate output formats. X-Git-Url: https://plomlompom.com/repos/%7B%7Bprefix%7D%7D/%22https:/validator.w3.org/balance?a=commitdiff_plain;h=60ceff6441d140a4a02aab49ce71fcb6efba61e3;p=bricksplom Differentiate output formats. --- diff --git a/bricksplom.py b/bricksplom.py index 3532a61..c085448 100755 --- a/bricksplom.py +++ b/bricksplom.py @@ -34,7 +34,7 @@ Page = tuple[PageColumn, ...] class Textfiled(ABC): - 'Table to be read from textfile.' + 'Table to be read from textfile, and compatible output in .raw().' @staticmethod def lines_of( @@ -73,8 +73,17 @@ class Textfiled(ABC): ) -> dict[str, Self]: 'Build from file at path.' + @abstractmethod + def raw(self) -> str: + 'Output in format used for reading in.' + + def __str__( + self + ) -> str: + return self.raw() -class WithDb(ABC): + +class WithDb: 'Add db:Optional[BricksDB] field to __init__, setting ._db.' def __init__( @@ -86,7 +95,23 @@ class WithDb(ABC): super().__init__(**kwargs) -class Color(Textfiled): +class Lookupable: + 'Provide methods used by BricksDb.lookup.' + + def searchable( + self + ) -> str: + 'String analyzed by "?" full-text searches.' + return str(self) + + def show( + self + ) -> str: + 'Default single-item display of self.' + return str(self) + + +class Color(Textfiled, Lookupable): 'Color incl. solidness/transparency field.' def __init__( @@ -113,7 +138,7 @@ class Color(Textfiled): collected[id_] = cls(id_, desc[0] == CHAR_COL_SOLID, desc[1:]) return collected - def __str__( + def raw( self ) -> str: return (f'{self.id_:>3} ' @@ -121,7 +146,7 @@ class Color(Textfiled): + self.wavelength) -class Design(Textfiled): +class Design(Textfiled, Lookupable): 'Shape and texture configurations with descriptions and equalities.' def __init__( @@ -156,7 +181,7 @@ class Design(Textfiled): collected[id_].alternates = alternatives return collected - def __str__( + def raw( self ) -> str: return '\n'.join([f'{self.id_:>6} _{self.description}'] @@ -177,7 +202,7 @@ class Design(Textfiled): return None -class Piece(Textfiled): +class Piece(Textfiled, Lookupable): 'Individual configuration of design and color.' def __init__( @@ -207,14 +232,14 @@ class Piece(Textfiled): collected[piece_id] = cls(piece_id, design_id, color_id, comment) return collected - def __str__( + def raw( self ) -> str: return (f'{self.id_:>7} {self.design_id:>6} ' f'{self.color_id:>3} {self.comment}').rstrip() -class Collection(Textfiled, WithDb): +class Collection(Textfiled, WithDb, Lookupable): 'Named collection of pieces in order of pages of columns of counts.' def __init__( @@ -274,15 +299,35 @@ class Collection(Textfiled, WithDb): db=db) for k, v in collected.items()} - def __str__( + @property + def _is_in_str( + self + ) -> str: + return (CHAR_COLL_INACTIVE if self.is_in is None + else (CHAR_COLL_IN if self.is_in else CHAR_COLL_OUT)) + + def raw( self ) -> str: - is_in_str = (CHAR_COLL_INACTIVE if self.is_in is None - else (CHAR_COLL_IN if self.is_in else CHAR_COLL_OUT)) - return (f'{self.id_} {is_in_str}{self.description}\n' + return (f'{self.id_} {self._is_in_str}{self.description}\n' + self._format_paginated(lambda count, p_id, comment: f' {count:2} {p_id:>7} {comment}')) + def show( + self + ) -> str: + return self.raw() + + def __str__( + self + ) -> str: + return f'{self.id_} {self._is_in_str} {self.description}' + + def searchable( + self + ) -> str: + return self.raw() + def _format_paginated( self, format_line: Callable[[int, str, str], str] @@ -332,7 +377,7 @@ class Collection(Textfiled, WithDb): print(line) -class Box(WithDb): +class Box(WithDb, Lookupable): 'Order of designs.' def __init__( @@ -350,15 +395,14 @@ class Box(WithDb): ) -> str: return f'{self.id_:>2} {",".join(self.designs)}' - def print_pieces( + def show( self, - ) -> None: - 'Print explanatory listings of pieces expected by .designs.' + ) -> str: assert self._db - print(f'box:{self.id_}') + lines = [] for design_id in self.designs: design = self._db.designs[design_id] - print(f'=== {design_id:>6}: {design.description} ===') + lines += [f'=== {design_id:>6}: {design.description} ==='] for piece in [p for p in self._db.pieces.values() if p.design_id in {design.id_} | design.alternates]: count_pieces = 0 @@ -367,7 +411,15 @@ class Box(WithDb): for c in self._db.collections.values()]: for count in [t[0] for t in listings if t[1] == piece.id_]: count_pieces += count - print(f'{count_pieces:>2}× {piece.id_:>7} / {color}') + lines += [f'{count_pieces:>2}× {piece.id_:>7} / {color}'] + return '\n'.join(lines) + + def raw( + self + ) -> str: + 'Call .raw() of base Collection.' + assert self._db + return self._db.collections[f'box:{self.id_}'].raw() class BricksDb: @@ -459,18 +511,20 @@ class BricksDb: def lookup( self, table_name: str, - inquiry: str + inquiry: str, + show_raw: bool ) -> str: 'Return result of inquiry on table of table_name.' assert table_name in self.lookupable maybe_dict = getattr(self, table_name) table = maybe_dict if isinstance(maybe_dict, dict) else maybe_dict() - return (CHAR_NEWLINE.join([str(v) for - v in sorted(table.values(), - key=lambda v: f'{v.id_:>7}') - if inquiry[1:].upper() in str(v).upper()]) - if inquiry.startswith(CHAR_INQUIRY) - else table[inquiry]) + if inquiry.startswith(CHAR_INQUIRY): + return CHAR_NEWLINE.join( + [(v.raw() if show_raw else str(v)) for + v in sorted(table.values(), key=lambda v: f'{v.id_:>7}') + if inquiry[1:].upper() in str(v.searchable()).upper()]) + item = table[inquiry] + return item.raw() if show_raw else item.show() def piece_to_box_listing( self, @@ -522,8 +576,9 @@ def main( parser = ArgumentParser() add_abbrev_choices_arg(parser, 'table', set(db.lookupable)) parser.add_argument('inquiry', nargs='?', default=CHAR_INQUIRY) + parser.add_argument('--raw', action='store_true') args = parser.parse_args() - print(db.lookup(args.table, args.inquiry)) + print(db.lookup(args.table, args.inquiry, args.raw)) main()