classes.c32_pool

  1import random
  2import colorama
  3import regex
  4from inspect import cleandoc
  5from loguru import logger
  6from icecream import ic
  7
  8from lib import helpers, content
  9
 10DEBUG = False
 11
 12
 13class KPool:
 14    """
 15    A pool of items with optional shuffling and case transformation utilities.
 16    """
 17
 18    def __init__(
 19        self, items: list[str], shuffle=True, defaultCase: content.TextCase = None
 20    ) -> None:
 21        """
 22        Initialize the KPool instance.
 23
 24        Args:
 25            items: List of items to pool.
 26            shuffle: Randomize items on initialization. Defaults to True.
 27            defaultCase: Default `content.TextCase` for items. If None, no case change is applied.
 28        """
 29        if shuffle:
 30            random.shuffle(items)
 31
 32        self._shuffle: bool = shuffle
 33
 34        self._items = items
 35        """Internal copy of items without case change"""
 36
 37        self.items = content.changeCase(items, defaultCase)
 38        """Items with case possibly changed (upon initialization)"""
 39
 40    def __str__(self) -> str:
 41        """Returns a human-readable string representation of the KPool."""
 42        return cleandoc(
 43            f"""
 44            {colorama.Fore.BLACK}{colorama.Back.LIGHTCYAN_EX}KPool{colorama.Style.RESET_ALL} {helpers.truncateList(self.items)}
 45            """
 46        )
 47
 48    def __len__(self) -> int:
 49        """Returns the number of items in the pool."""
 50        return len(self.items)
 51
 52    def __getitem__(self, index):
 53        """
 54        Make subscriptable. Allows access to items using square brackets.
 55
 56        Args:
 57            index: Index of the item.
 58
 59        Returns:
 60            Item at the given index.
 61        """
 62        return self.items[index]
 63
 64    def getItemByWidth(
 65        self,
 66        width: int,
 67        alterCase: content.TextCase = None,
 68        avoidShape: content.WordShape = None,
 69    ) -> str:
 70        """
 71        Get an item matching the specified width, with optional case and shape filtering.
 72
 73        Args:
 74            width: Target width for the item.
 75            alterCase: Change text case for a single phrase.
 76            avoidShape: Exclude items with this shape.
 77
 78        Returns:
 79            Item matching the criteria, or `Blank` if none found.
 80        """
 81        if isinstance(alterCase, str):
 82            items = content.changeCase(self.items, alterCase)
 83        else:
 84            items = self.items
 85
 86        if avoidShape:
 87            items = content.filterByShape(items, avoidShape)
 88
 89        if not items:
 90            return "Blank"
 91
 92        if self._shuffle:
 93            random.shuffle(items)  # Shuffle on each run
 94
 95        match = content.getStringForWidth(items, width)
 96
 97        self._removeItem(match)
 98        return match
 99
100    def setCase(self, case: content.TextCase):
101        """
102        Change the text case of all items at the instance level.
103
104        Args:
105            case: Desired text case.
106
107        Returns:
108            The modified KPool instance.
109        """
110        self.items = content.changeCase(self.items, case)
111        return self
112
113    def filterPrefix(self, pattern: str | list[str], mode: helpers.Strategy = "pick"):
114        """
115        Return a filtered instance with items (not) starting with the given pattern(s).
116
117        Args:
118            pattern: Single string or multiple patterns.
119            mode: Which filtering strategy to use:
120                - `pick`: include items of pattern only
121                - `omit`: remove pattern from items
122
123        Returns:
124            Filtered KPool instance.
125        """
126
127        def _process(string: str):
128            def _isMatch(item: str) -> bool:
129                found = item.startswith(string)
130                return found if mode == "pick" else not found
131
132            return [
133                item for item in self.items if _isMatch(item)
134            ]  # Process items to preserve textCase
135
136        intersected = helpers.intersect(
137            [_process(p) for p in helpers.coerceList(pattern)]
138        )
139        return KPool(
140            intersected,
141            shuffle=self._shuffle,
142        )
143
144    def filterTokens(self, tokens: list[content.CharacterToken] = ["word", "nonword"]):
145        """
146        Return a filtered instance with items of certain Unicode tokens. See `lib.content.filterByTokens`.
147
148        Args:
149            tokens: Tokens to filter by.
150
151        Returns:
152            Filtered KPool instance.
153        """
154        return KPool(
155            content.filterByTokens(self.items, tokens), shuffle=self._shuffle
156        )  # Process items to preserve textCase
157
158    def filterWithRegex(self, pattern: str):
159        """
160        Return a filtered KPool instance with items matching the given regex pattern.
161
162        Examples:
163            - `[^bdfhkl]+` => filter ascenders
164            - `[^Qgjpqy]+` => filter descenders
165
166        Args:
167            pattern: Regex pattern to match.
168
169        Returns:
170            Filtered KPool instance.
171        """
172        return KPool(
173            list(filter(lambda item: regex.search(f"^{pattern}$", item), self.items)),
174            shuffle=self._shuffle,
175        )  # Process items to preserve textCase
176
177    def shuffle(self) -> "KPool":
178        """Shuffle the items in place and return self."""
179        random.shuffle(self.items)
180        return self
181
182    def stripChars(self, chars: str = ".,:;-+−'’") -> None:
183        """
184        Remove specified characters from all items.
185
186        Args:
187            chars: Characters to strip. Defaults to commonly used symbols and punctuation.
188        """
189        self.items = [item.strip(chars) for item in self.items]
190
191    def _removeItem(self, match: str):
192        """
193        Remove an item by value (case-insensitive).
194
195        Args:
196            match: Item to remove.
197
198        Returns:
199            The modified KPool instance.
200        """
201        poolLen = f"{len(self.items)}\t"
202        try:
203            if DEBUG:
204                logger.debug("[{} About to remove]\t{}", poolLen, match)
205            matchInsensitive = match.casefold()
206            itemsInsensitive = [item.casefold() for item in self.items]
207            index = itemsInsensitive.index(matchInsensitive)
208            value = self.items[index]
209            if DEBUG:
210                logger.debug("[{} Removing]\t{}", poolLen, value)
211            self.items.pop(index)
212        except:
213            logger.warning("[{} Error removing item]\t{}", poolLen, match)
214        return self
DEBUG = False
class KPool:
 14class KPool:
 15    """
 16    A pool of items with optional shuffling and case transformation utilities.
 17    """
 18
 19    def __init__(
 20        self, items: list[str], shuffle=True, defaultCase: content.TextCase = None
 21    ) -> None:
 22        """
 23        Initialize the KPool instance.
 24
 25        Args:
 26            items: List of items to pool.
 27            shuffle: Randomize items on initialization. Defaults to True.
 28            defaultCase: Default `content.TextCase` for items. If None, no case change is applied.
 29        """
 30        if shuffle:
 31            random.shuffle(items)
 32
 33        self._shuffle: bool = shuffle
 34
 35        self._items = items
 36        """Internal copy of items without case change"""
 37
 38        self.items = content.changeCase(items, defaultCase)
 39        """Items with case possibly changed (upon initialization)"""
 40
 41    def __str__(self) -> str:
 42        """Returns a human-readable string representation of the KPool."""
 43        return cleandoc(
 44            f"""
 45            {colorama.Fore.BLACK}{colorama.Back.LIGHTCYAN_EX}KPool{colorama.Style.RESET_ALL} {helpers.truncateList(self.items)}
 46            """
 47        )
 48
 49    def __len__(self) -> int:
 50        """Returns the number of items in the pool."""
 51        return len(self.items)
 52
 53    def __getitem__(self, index):
 54        """
 55        Make subscriptable. Allows access to items using square brackets.
 56
 57        Args:
 58            index: Index of the item.
 59
 60        Returns:
 61            Item at the given index.
 62        """
 63        return self.items[index]
 64
 65    def getItemByWidth(
 66        self,
 67        width: int,
 68        alterCase: content.TextCase = None,
 69        avoidShape: content.WordShape = None,
 70    ) -> str:
 71        """
 72        Get an item matching the specified width, with optional case and shape filtering.
 73
 74        Args:
 75            width: Target width for the item.
 76            alterCase: Change text case for a single phrase.
 77            avoidShape: Exclude items with this shape.
 78
 79        Returns:
 80            Item matching the criteria, or `Blank` if none found.
 81        """
 82        if isinstance(alterCase, str):
 83            items = content.changeCase(self.items, alterCase)
 84        else:
 85            items = self.items
 86
 87        if avoidShape:
 88            items = content.filterByShape(items, avoidShape)
 89
 90        if not items:
 91            return "Blank"
 92
 93        if self._shuffle:
 94            random.shuffle(items)  # Shuffle on each run
 95
 96        match = content.getStringForWidth(items, width)
 97
 98        self._removeItem(match)
 99        return match
100
101    def setCase(self, case: content.TextCase):
102        """
103        Change the text case of all items at the instance level.
104
105        Args:
106            case: Desired text case.
107
108        Returns:
109            The modified KPool instance.
110        """
111        self.items = content.changeCase(self.items, case)
112        return self
113
114    def filterPrefix(self, pattern: str | list[str], mode: helpers.Strategy = "pick"):
115        """
116        Return a filtered instance with items (not) starting with the given pattern(s).
117
118        Args:
119            pattern: Single string or multiple patterns.
120            mode: Which filtering strategy to use:
121                - `pick`: include items of pattern only
122                - `omit`: remove pattern from items
123
124        Returns:
125            Filtered KPool instance.
126        """
127
128        def _process(string: str):
129            def _isMatch(item: str) -> bool:
130                found = item.startswith(string)
131                return found if mode == "pick" else not found
132
133            return [
134                item for item in self.items if _isMatch(item)
135            ]  # Process items to preserve textCase
136
137        intersected = helpers.intersect(
138            [_process(p) for p in helpers.coerceList(pattern)]
139        )
140        return KPool(
141            intersected,
142            shuffle=self._shuffle,
143        )
144
145    def filterTokens(self, tokens: list[content.CharacterToken] = ["word", "nonword"]):
146        """
147        Return a filtered instance with items of certain Unicode tokens. See `lib.content.filterByTokens`.
148
149        Args:
150            tokens: Tokens to filter by.
151
152        Returns:
153            Filtered KPool instance.
154        """
155        return KPool(
156            content.filterByTokens(self.items, tokens), shuffle=self._shuffle
157        )  # Process items to preserve textCase
158
159    def filterWithRegex(self, pattern: str):
160        """
161        Return a filtered KPool instance with items matching the given regex pattern.
162
163        Examples:
164            - `[^bdfhkl]+` => filter ascenders
165            - `[^Qgjpqy]+` => filter descenders
166
167        Args:
168            pattern: Regex pattern to match.
169
170        Returns:
171            Filtered KPool instance.
172        """
173        return KPool(
174            list(filter(lambda item: regex.search(f"^{pattern}$", item), self.items)),
175            shuffle=self._shuffle,
176        )  # Process items to preserve textCase
177
178    def shuffle(self) -> "KPool":
179        """Shuffle the items in place and return self."""
180        random.shuffle(self.items)
181        return self
182
183    def stripChars(self, chars: str = ".,:;-+−'’") -> None:
184        """
185        Remove specified characters from all items.
186
187        Args:
188            chars: Characters to strip. Defaults to commonly used symbols and punctuation.
189        """
190        self.items = [item.strip(chars) for item in self.items]
191
192    def _removeItem(self, match: str):
193        """
194        Remove an item by value (case-insensitive).
195
196        Args:
197            match: Item to remove.
198
199        Returns:
200            The modified KPool instance.
201        """
202        poolLen = f"{len(self.items)}\t"
203        try:
204            if DEBUG:
205                logger.debug("[{} About to remove]\t{}", poolLen, match)
206            matchInsensitive = match.casefold()
207            itemsInsensitive = [item.casefold() for item in self.items]
208            index = itemsInsensitive.index(matchInsensitive)
209            value = self.items[index]
210            if DEBUG:
211                logger.debug("[{} Removing]\t{}", poolLen, value)
212            self.items.pop(index)
213        except:
214            logger.warning("[{} Error removing item]\t{}", poolLen, match)
215        return self

A pool of items with optional shuffling and case transformation utilities.

KPool( items: list[str], shuffle=True, defaultCase: Literal['UPPER', 'lower', 'Title', 'Caps'] = None)
19    def __init__(
20        self, items: list[str], shuffle=True, defaultCase: content.TextCase = None
21    ) -> None:
22        """
23        Initialize the KPool instance.
24
25        Args:
26            items: List of items to pool.
27            shuffle: Randomize items on initialization. Defaults to True.
28            defaultCase: Default `content.TextCase` for items. If None, no case change is applied.
29        """
30        if shuffle:
31            random.shuffle(items)
32
33        self._shuffle: bool = shuffle
34
35        self._items = items
36        """Internal copy of items without case change"""
37
38        self.items = content.changeCase(items, defaultCase)
39        """Items with case possibly changed (upon initialization)"""

Initialize the KPool instance.

Arguments:
  • items: List of items to pool.
  • shuffle: Randomize items on initialization. Defaults to True.
  • defaultCase: Default content.TextCase for items. If None, no case change is applied.
items

Items with case possibly changed (upon initialization)

def getItemByWidth( self, width: int, alterCase: Literal['UPPER', 'lower', 'Title', 'Caps'] = None, avoidShape: Literal['descender', 'ascender', 'caps'] = None) -> str:
65    def getItemByWidth(
66        self,
67        width: int,
68        alterCase: content.TextCase = None,
69        avoidShape: content.WordShape = None,
70    ) -> str:
71        """
72        Get an item matching the specified width, with optional case and shape filtering.
73
74        Args:
75            width: Target width for the item.
76            alterCase: Change text case for a single phrase.
77            avoidShape: Exclude items with this shape.
78
79        Returns:
80            Item matching the criteria, or `Blank` if none found.
81        """
82        if isinstance(alterCase, str):
83            items = content.changeCase(self.items, alterCase)
84        else:
85            items = self.items
86
87        if avoidShape:
88            items = content.filterByShape(items, avoidShape)
89
90        if not items:
91            return "Blank"
92
93        if self._shuffle:
94            random.shuffle(items)  # Shuffle on each run
95
96        match = content.getStringForWidth(items, width)
97
98        self._removeItem(match)
99        return match

Get an item matching the specified width, with optional case and shape filtering.

Arguments:
  • width: Target width for the item.
  • alterCase: Change text case for a single phrase.
  • avoidShape: Exclude items with this shape.
Returns:

Item matching the criteria, or Blank if none found.

def setCase(self, case: Literal['UPPER', 'lower', 'Title', 'Caps']):
101    def setCase(self, case: content.TextCase):
102        """
103        Change the text case of all items at the instance level.
104
105        Args:
106            case: Desired text case.
107
108        Returns:
109            The modified KPool instance.
110        """
111        self.items = content.changeCase(self.items, case)
112        return self

Change the text case of all items at the instance level.

Arguments:
  • case: Desired text case.
Returns:

The modified KPool instance.

def filterPrefix( self, pattern: str | list[str], mode: Literal['pick', 'omit'] = 'pick'):
114    def filterPrefix(self, pattern: str | list[str], mode: helpers.Strategy = "pick"):
115        """
116        Return a filtered instance with items (not) starting with the given pattern(s).
117
118        Args:
119            pattern: Single string or multiple patterns.
120            mode: Which filtering strategy to use:
121                - `pick`: include items of pattern only
122                - `omit`: remove pattern from items
123
124        Returns:
125            Filtered KPool instance.
126        """
127
128        def _process(string: str):
129            def _isMatch(item: str) -> bool:
130                found = item.startswith(string)
131                return found if mode == "pick" else not found
132
133            return [
134                item for item in self.items if _isMatch(item)
135            ]  # Process items to preserve textCase
136
137        intersected = helpers.intersect(
138            [_process(p) for p in helpers.coerceList(pattern)]
139        )
140        return KPool(
141            intersected,
142            shuffle=self._shuffle,
143        )

Return a filtered instance with items (not) starting with the given pattern(s).

Arguments:
  • pattern: Single string or multiple patterns.
  • mode: Which filtering strategy to use:
    • pick: include items of pattern only
    • omit: remove pattern from items
Returns:

Filtered KPool instance.

def filterTokens( self, tokens: list[typing.Literal['word', 'nonword']] = ['word', 'nonword']):
145    def filterTokens(self, tokens: list[content.CharacterToken] = ["word", "nonword"]):
146        """
147        Return a filtered instance with items of certain Unicode tokens. See `lib.content.filterByTokens`.
148
149        Args:
150            tokens: Tokens to filter by.
151
152        Returns:
153            Filtered KPool instance.
154        """
155        return KPool(
156            content.filterByTokens(self.items, tokens), shuffle=self._shuffle
157        )  # Process items to preserve textCase

Return a filtered instance with items of certain Unicode tokens. See lib.content.filterByTokens.

Arguments:
  • tokens: Tokens to filter by.
Returns:

Filtered KPool instance.

def filterWithRegex(self, pattern: str):
159    def filterWithRegex(self, pattern: str):
160        """
161        Return a filtered KPool instance with items matching the given regex pattern.
162
163        Examples:
164            - `[^bdfhkl]+` => filter ascenders
165            - `[^Qgjpqy]+` => filter descenders
166
167        Args:
168            pattern: Regex pattern to match.
169
170        Returns:
171            Filtered KPool instance.
172        """
173        return KPool(
174            list(filter(lambda item: regex.search(f"^{pattern}$", item), self.items)),
175            shuffle=self._shuffle,
176        )  # Process items to preserve textCase

Return a filtered KPool instance with items matching the given regex pattern.

Examples:
  • [^bdfhkl]+ => filter ascenders
  • [^Qgjpqy]+ => filter descenders
Arguments:
  • pattern: Regex pattern to match.
Returns:

Filtered KPool instance.

def shuffle(self) -> KPool:
178    def shuffle(self) -> "KPool":
179        """Shuffle the items in place and return self."""
180        random.shuffle(self.items)
181        return self

Shuffle the items in place and return self.

def stripChars(self, chars: str = ".,:;-+−'’") -> None:
183    def stripChars(self, chars: str = ".,:;-+−'’") -> None:
184        """
185        Remove specified characters from all items.
186
187        Args:
188            chars: Characters to strip. Defaults to commonly used symbols and punctuation.
189        """
190        self.items = [item.strip(chars) for item in self.items]

Remove specified characters from all items.

Arguments:
  • chars: Characters to strip. Defaults to commonly used symbols and punctuation.