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.TextCasefor items. If None, no case change is applied.
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
Blankif 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 onlyomit: 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.
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.