mapFolding 0.9.1__py3-none-any.whl → 0.9.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mapFolding/oeis.py CHANGED
@@ -1,23 +1,21 @@
1
1
  """
2
2
  Interface to The Online Encyclopedia of Integer Sequences (OEIS) for map folding sequences.
3
3
 
4
- This module provides a comprehensive interface for accessing and utilizing integer sequences
5
- from the OEIS that relate to map folding problems. It serves as the bridge between
6
- mathematical sequence definitions and the computational algorithm, implementing:
4
+ This module provides a comprehensive interface for accessing and utilizing integer sequences from the OEIS that relate
5
+ to map folding problems. It serves as the bridge between mathematical sequence definitions and the computational
6
+ algorithm, implementing:
7
7
 
8
8
  1. Retrieval of sequence data from OEIS with local caching for performance optimization.
9
9
  2. Mapping of sequence indices to corresponding map shapes based on sequence definitions.
10
10
  3. Command-line and programmatic interfaces for sequence lookups and validation.
11
11
  4. Computation of sequence terms not available in the OEIS database.
12
12
 
13
- The module maintains a registry of implemented OEIS sequences (A001415-A001418, A195646)
14
- with their metadata, known values, and conversion functions between sequence indices and
15
- map dimensions. This allows the package to validate results against established mathematical
16
- literature while also extending sequences beyond their currently known terms.
13
+ The module maintains a registry of implemented OEIS sequences (A001415-A001418, A195646) with their metadata, known
14
+ values, and conversion functions between sequence indices and map dimensions. This allows the package to validate
15
+ results against established mathematical literature while also extending sequences beyond their currently known terms.
17
16
 
18
- Each sequence is carefully mapped to its corresponding map folding problem, enabling
19
- seamless integration between the mathematical definition in OEIS and the computational
20
- implementation in the package.
17
+ Each sequence is carefully mapped to its corresponding map folding problem, enabling seamless integration between the
18
+ mathematical definition in OEIS and the computational implementation in the package.
21
19
  """
22
20
  from collections.abc import Callable
23
21
  from datetime import datetime, timedelta
@@ -104,10 +102,8 @@ def validateOEISid(oeisIDcandidate: str) -> str:
104
102
  """
105
103
  Validates an OEIS sequence ID against implemented sequences.
106
104
 
107
- If the provided ID is recognized within the application's implemented
108
- OEIS sequences, the function returns the verified ID in uppercase.
109
- Otherwise, a KeyError is raised indicating that the sequence is not
110
- directly supported.
105
+ If the provided ID is recognized within the application's implemented OEIS sequences, the function returns the
106
+ verified ID in uppercase. Otherwise, a KeyError is raised indicating that the sequence is not directly supported.
111
107
 
112
108
  Parameters:
113
109
  oeisIDcandidate: The OEIS sequence identifier to validate.
@@ -138,20 +134,18 @@ def _parseBFileOEIS(OEISbFile: str, oeisID: str) -> dict[int, int]:
138
134
  """
139
135
  Parses the content of an OEIS b-file for a given sequence ID.
140
136
 
141
- This function processes a multiline string representing an OEIS b-file and
142
- creates a dictionary mapping integer indices to their corresponding sequence
143
- values. The first line of the b-file is expected to contain a comment that
137
+ This function processes a multiline string representing an OEIS b-file and creates a dictionary mapping integer
138
+ indices to their corresponding sequence values. The first line of the b-file is expected to contain a comment that
144
139
  matches the given sequence ID. If it does not match, a ValueError is raised.
145
140
 
146
141
  Parameters:
147
- OEISbFile: A multiline string representing an OEIS b-file.
148
- oeisID: The expected OEIS sequence identifier.
142
+ OEISbFile: A multiline string representing an OEIS b-file. oeisID: The expected OEIS sequence identifier.
149
143
  Returns:
150
- OEISsequence: A dictionary where each key is an integer index `n` and
151
- each value is the sequence value `a(n)` corresponding to that index.
144
+ OEISsequence: A dictionary where each key is an integer index `n` and each value is the sequence value `a(n)`
145
+ corresponding to that index.
152
146
  Raises:
153
- ValueError: If the first line of the file does not indicate the expected
154
- sequence ID or if the content format is invalid.
147
+ ValueError: If the first line of the file does not indicate the expected sequence ID or if the content format is
148
+ invalid.
155
149
  """
156
150
  bFileLines: list[str] = OEISbFile.strip().splitlines()
157
151
  # if not bFileLines.pop(0).startswith(f"# {oeisID}"):
@@ -170,23 +164,21 @@ def getOEISofficial(pathFilenameCache: Path, url: str) -> None | str:
170
164
  """
171
165
  Retrieve OEIS sequence data from cache or online source.
172
166
 
173
- This function implements a caching strategy for OEIS sequence data, first checking
174
- if a local cached copy exists and is not expired. If a valid cache exists, it returns
175
- the cached content; otherwise, it fetches the data from the OEIS website and
176
- writes it to the cache for future use.
167
+ This function implements a caching strategy for OEIS sequence data, first checking if a local cached copy exists and
168
+ is not expired. If a valid cache exists, it returns the cached content; otherwise, it fetches the data from the OEIS
169
+ website and writes it to the cache for future use.
177
170
 
178
171
  Parameters:
179
- pathFilenameCache: Path to the local cache file.
180
- url: URL to retrieve the OEIS sequence data from if cache is invalid or missing.
172
+ pathFilenameCache: Path to the local cache file. url: URL to retrieve the OEIS sequence data from if cache is
173
+ invalid or missing.
181
174
 
182
175
  Returns:
183
- oeisInformation: The retrieved OEIS sequence information as a string, or None if
184
- the information could not be retrieved.
176
+ oeisInformation: The retrieved OEIS sequence information as a string, or None if the information could not be
177
+ retrieved.
185
178
 
186
179
  Notes:
187
- The cache expiration period is controlled by the global `cacheDays` variable.
188
- If the function fails to retrieve data from both cache and online source,
189
- it will return None and issue a warning.
180
+ The cache expiration period is controlled by the global `cacheDays` variable. If the function fails to retrieve
181
+ data from both cache and online source, it will return None and issue a warning.
190
182
  """
191
183
  tryCache: bool = False
192
184
  if pathFilenameCache.exists():
@@ -213,22 +205,20 @@ def getOEISofficial(pathFilenameCache: Path, url: str) -> None | str:
213
205
 
214
206
  def getOEISidValues(oeisID: str) -> dict[int, int]:
215
207
  """
216
- Retrieves the specified OEIS sequence as a dictionary mapping integer indices
217
- to their corresponding values.
208
+ Retrieves the specified OEIS sequence as a dictionary mapping integer indices to their corresponding values.
218
209
 
219
- This function checks for a cached local copy of the sequence data, using it if
220
- it has not expired. Otherwise, it fetches the sequence data from the OEIS
221
- website and writes it to the cache. The parsed data is returned as a dictionary
222
- mapping each index to its sequence value.
210
+ This function checks for a cached local copy of the sequence data, using it if it has not expired. Otherwise, it
211
+ fetches the sequence data from the OEIS website and writes it to the cache. The parsed data is returned as a
212
+ dictionary mapping each index to its sequence value.
223
213
 
224
214
  Parameters:
225
215
  oeisID: The identifier of the OEIS sequence to retrieve.
226
216
  Returns:
227
- OEISsequence: A dictionary where each key is an integer index, `n`, and each
228
- value is the corresponding `a(n)` from the OEIS entry.
217
+ OEISsequence: A dictionary where each key is an integer index, `n`, and each value is the corresponding `a(n)`
218
+ from the OEIS entry.
229
219
  Raises:
230
- ValueError: If the cached or downloaded file format is invalid.
231
- IOError: If there is an error reading from or writing to the local cache.
220
+ ValueError: If the cached or downloaded file format is invalid. IOError: If there is an error reading from or
221
+ writing to the local cache.
232
222
  """
233
223
 
234
224
  pathFilenameCache: Path = pathCache / getFilenameOEISbFile(oeisID)
@@ -244,23 +234,19 @@ def getOEISidInformation(oeisID: str) -> tuple[str, int]:
244
234
  """
245
235
  Retrieve the description and offset for an OEIS sequence.
246
236
 
247
- This function fetches the metadata for a given OEIS sequence ID, including
248
- its textual description and index offset value. It uses a caching mechanism
249
- to avoid redundant network requests while ensuring data freshness.
237
+ This function fetches the metadata for a given OEIS sequence ID, including its textual description and index offset
238
+ value. It uses a caching mechanism to avoid redundant network requests while ensuring data freshness.
250
239
 
251
240
  Parameters:
252
241
  oeisID: The OEIS sequence identifier to retrieve information for.
253
242
 
254
243
  Returns:
255
- A tuple containing:
256
- - description: A string describing the sequence's mathematical meaning.
257
- - offset: An integer representing the starting index of the sequence.
258
- Usually 0 or 1, depending on the mathematical context.
244
+ A tuple containing: - description: A string describing the sequence's mathematical meaning. - offset: An integer
245
+ representing the starting index of the sequence. Usually 0 or 1, depending on the mathematical context.
259
246
 
260
247
  Notes:
261
- Sequence descriptions are parsed from the machine-readable format of OEIS.
262
- If information cannot be retrieved, warning messages are issued and
263
- fallback values are returned.
248
+ Sequence descriptions are parsed from the machine-readable format of OEIS. If information cannot be retrieved,
249
+ warning messages are issued and fallback values are returned.
264
250
  """
265
251
  oeisID = validateOEISid(oeisID)
266
252
  pathFilenameCache: Path = pathCache / f"{oeisID}.txt"
@@ -294,22 +280,22 @@ def makeSettingsOEIS() -> dict[str, SettingsOEIS]:
294
280
  """
295
281
  Construct the comprehensive settings dictionary for all implemented OEIS sequences.
296
282
 
297
- This function builds a complete configuration dictionary for all supported OEIS
298
- sequences by retrieving and combining:
283
+ This function builds a complete configuration dictionary for all supported OEIS sequences by retrieving and
284
+ combining:
299
285
  1. Sequence values from OEIS b-files
300
286
  2. Sequence metadata (descriptions and offsets)
301
287
  3. Hardcoded mapping functions and test values
302
288
 
303
- The resulting dictionary provides a single authoritative source for all OEIS-related
304
- configurations used throughout the package, including:
289
+ The resulting dictionary provides a single authoritative source for all OEIS-related configurations used throughout
290
+ the package, including:
305
291
  - Mathematical descriptions of each sequence
306
292
  - Functions to convert between sequence indices and map dimensions
307
293
  - Known sequence values retrieved from OEIS
308
294
  - Testing and benchmarking reference values
309
295
 
310
296
  Returns:
311
- A dictionary mapping OEIS sequence IDs to their complete settings objects,
312
- containing all metadata and known values needed for computation and validation.
297
+ A dictionary mapping OEIS sequence IDs to their complete settings objects, containing all metadata and known
298
+ values needed for computation and validation.
313
299
  """
314
300
  settingsTarget: dict[str, SettingsOEIS] = {}
315
301
  for oeisID in oeisIDsImplemented:
@@ -340,7 +326,7 @@ def makeDictionaryFoldsTotalKnown() -> dict[tuple[int, ...], int]:
340
326
 
341
327
  for n, foldingsTotal in sequence.items():
342
328
  mapShape = settings['getMapShape'](n)
343
- mapShape = tuple(sorted(mapShape))
329
+ mapShape = tuple(mapShape)
344
330
  dictionaryMapDimensionsToFoldsTotalKnown[mapShape] = foldingsTotal
345
331
  return dictionaryMapDimensionsToFoldsTotalKnown
346
332
 
@@ -348,21 +334,20 @@ def getFoldsTotalKnown(mapShape: tuple[int, ...]) -> int:
348
334
  """
349
335
  Retrieve the known total number of foldings for a given map shape.
350
336
 
351
- This function looks up precalculated folding totals for specific map dimensions
352
- from OEIS sequences. It serves as a rapid reference for known values without
353
- requiring computation, and can be used to validate algorithm results.
337
+ This function looks up precalculated folding totals for specific map dimensions from OEIS sequences. It serves as a
338
+ rapid reference for known values without requiring computation, and can be used to validate algorithm results.
354
339
 
355
340
  Parameters:
356
341
  mapShape: A tuple of integers representing the dimensions of the map.
357
342
 
358
343
  Returns:
359
- foldingsTotal: The known total number of foldings for the given map shape,
360
- or -1 if the map shape doesn't match any known values in the OEIS sequences.
344
+ foldingsTotal: The known total number of foldings for the given map shape, or -1 if the map shape doesn't match
345
+ any known values in the OEIS sequences.
361
346
 
362
347
  Notes:
363
- The function uses a cached dictionary (via makeDictionaryFoldsTotalKnown) to
364
- efficiently retrieve values without repeatedly parsing OEIS data. Map shape
365
- tuples are sorted internally to ensure consistent lookup regardless of dimension order.
348
+ The function uses a cached dictionary (via makeDictionaryFoldsTotalKnown) to efficiently retrieve values without
349
+ repeatedly parsing OEIS data. Map shape tuples are sorted internally to ensure consistent lookup regardless of
350
+ dimension order.
366
351
  """
367
352
  lookupFoldsTotal = makeDictionaryFoldsTotalKnown()
368
353
  return lookupFoldsTotal.get(tuple(mapShape), -1)
@@ -395,15 +380,13 @@ def oeisIDfor_n(oeisID: str, n: int | Any) -> int:
395
380
  Calculate `a(n)` of a sequence from "The On-Line Encyclopedia of Integer Sequences" (OEIS).
396
381
 
397
382
  Parameters:
398
- oeisID: The ID of the OEIS sequence.
399
- n: A non-negative integer for which to calculate the sequence value.
383
+ oeisID: The ID of the OEIS sequence. n: A non-negative integer for which to calculate the sequence value.
400
384
 
401
385
  Returns:
402
386
  sequenceValue: `a(n)` of the OEIS sequence.
403
387
 
404
388
  Raises:
405
- ValueError: If `n` is negative.
406
- KeyError: If the OEIS sequence ID is not directly implemented.
389
+ ValueError: If `n` is negative. KeyError: If the OEIS sequence ID is not directly implemented.
407
390
  """
408
391
  oeisID = validateOEISid(oeisID)
409
392
 
@@ -13,8 +13,8 @@ Categories of reference implementations:
13
13
  - foldings.AA - Reconstructed Atlas Autocode version with corrections
14
14
 
15
15
  2. Direct translations:
16
- - lunnanWhile.py - Python translation using while loops
17
- - lunnanNumpy.py - NumPy-based translation with array operations
16
+ - lunnonWhile.py - Python translation using while loops
17
+ - lunnonNumpy.py - NumPy-based translation with array operations
18
18
 
19
19
  3. Alternative implementations:
20
20
  - irvineJavaPort.py - Port from Sean A. Irvine's Java implementation
@@ -52,15 +52,17 @@ from mapFolding.someAssemblyRequired._theTypes import (
52
52
  ast_Identifier as ast_Identifier,
53
53
  astClassHasDOTnameNotName as astClassHasDOTnameNotName,
54
54
  astClassHasDOTtarget as astClassHasDOTtarget,
55
- astClassHasDOTvalue_expr as astClassHasDOTvalue_expr,
56
- astClassHasDOTvalue_exprNone as astClassHasDOTvalue_exprNone,
57
- astClassHasDOTtargetAttributeNameSubscript as astClassHasDOTtargetAttributeNameSubscript,
58
55
  astClassHasDOTtarget_expr as astClassHasDOTtarget_expr,
56
+ astClassHasDOTtargetAttributeNameSubscript as astClassHasDOTtargetAttributeNameSubscript,
59
57
  astClassHasDOTvalue as astClassHasDOTvalue,
58
+ astClassHasDOTvalue_expr as astClassHasDOTvalue_expr,
59
+ astClassHasDOTvalue_exprNone as astClassHasDOTvalue_exprNone,
60
60
  astClassOptionallyHasDOTnameNotName as astClassOptionallyHasDOTnameNotName,
61
+ ImaCallToName as ImaCallToName,
61
62
  intORlist_ast_type_paramORstr_orNone as intORlist_ast_type_paramORstr_orNone,
62
63
  intORstr_orNone as intORstr_orNone,
63
64
  list_ast_type_paramORstr_orNone as list_ast_type_paramORstr_orNone,
65
+ NodeORattribute as NodeORattribute,
64
66
  str_nameDOTname as str_nameDOTname,
65
67
  个 as 个,
66
68
  )
@@ -13,10 +13,17 @@ else:
13
13
  astClassHasDOTnameNotName = stuPyd
14
14
  astClassHasDOTvalue_expr = stuPyd
15
15
 
16
+ class ImaCallToName(ast.Call):
17
+ func: ast.Name # pyright: ignore[reportIncompatibleVariableOverride]
18
+ # assert isinstance(ast.Call.func, ast.Name), "brinksmanship"
19
+ # func: ast.Name
20
+
16
21
  astClassHasDOTtargetAttributeNameSubscript: typing_TypeAlias = ast.AnnAssign | ast.AugAssign
17
22
  astClassHasDOTtarget_expr: typing_TypeAlias = ast.AsyncFor | ast.comprehension | ast.For
18
23
  astClassHasDOTtarget: typing_TypeAlias = ast.NamedExpr | astClassHasDOTtarget_expr | astClassHasDOTtargetAttributeNameSubscript
24
+
19
25
  astClassOptionallyHasDOTnameNotName: typing_TypeAlias = ast.ExceptHandler | ast.MatchAs | ast.MatchStar
26
+
20
27
  astClassHasDOTvalue_exprNone: typing_TypeAlias = ast.AnnAssign | ast.Return | ast.Yield
21
28
  astClassHasDOTvalue: typing_TypeAlias = ast.Constant | ast.MatchSingleton | astClassHasDOTvalue_expr | astClassHasDOTvalue_exprNone
22
29
 
@@ -27,7 +34,8 @@ intORstr_orNone: typing_TypeAlias = Any
27
34
  list_ast_type_paramORstr_orNone: typing_TypeAlias = Any
28
35
  str_nameDOTname: typing_TypeAlias = stuPyd
29
36
 
30
- 个 = typing_TypeVar('个', bound= ast.AST, covariant=True)
37
+ 个 = typing_TypeVar('个', bound = ast.AST, covariant = True)
38
+ NodeORattribute = typing_TypeVar('NodeORattribute', bound = ast.AST | ast_expr_Slice | ast_Identifier | str_nameDOTname | bool | Any | None, covariant = True)
31
39
 
32
40
  # All ast classes by subgroup:
33
41
  Ima_ast_boolop: typing_TypeAlias = ast.boolop | ast.And | ast.Or
@@ -83,7 +83,6 @@ class Make:
83
83
 
84
84
  @staticmethod
85
85
  def Constant(value: Any, **keywordArguments: intORstr_orNone) -> ast.Constant:
86
- """value: str|int|float|bool|None|bytes|bytearray|memoryview|complex|list|tuple|dict|set, or any other type that can be represented as a constant in Python."""
87
86
  return ast.Constant(value, **keywordArguments)
88
87
 
89
88
  @staticmethod
@@ -15,7 +15,7 @@ once they have been identified using predicate functions from ifThis.
15
15
  """
16
16
 
17
17
  from collections.abc import Callable, Sequence
18
- from mapFolding.someAssemblyRequired import ast_Identifier, astClassHasDOTvalue
18
+ from mapFolding.someAssemblyRequired import ast_Identifier, astClassHasDOTvalue, ImaCallToName, NodeORattribute
19
19
  from typing import Any
20
20
  import ast
21
21
 
@@ -46,6 +46,13 @@ class grab:
46
46
  return node
47
47
  return workhorse
48
48
 
49
+ @staticmethod
50
+ def funcDOTidAttribute(action: Callable[[ast_Identifier], Any]) -> Callable[[ImaCallToName], ImaCallToName]:
51
+ def workhorse(node: ImaCallToName) -> ImaCallToName:
52
+ node.func = grab.idAttribute(action)(node.func)
53
+ return node
54
+ return workhorse
55
+
49
56
  @staticmethod
50
57
  def idAttribute(action: Callable[[ast_Identifier], ast_Identifier]) -> Callable[[ast.Name], ast.Name]:
51
58
  def workhorse(node: ast.Name) -> ast.Name:
@@ -54,7 +61,7 @@ class grab:
54
61
  return workhorse
55
62
 
56
63
  @staticmethod
57
- def valueAttribute(action: Callable[[Any | ast.expr | bool | None], Any]) -> Callable[[astClassHasDOTvalue], astClassHasDOTvalue]:
64
+ def valueAttribute(action: Callable[[Any], Any]) -> Callable[[astClassHasDOTvalue], astClassHasDOTvalue]:
58
65
  def workhorse(node: astClassHasDOTvalue) -> astClassHasDOTvalue:
59
66
  node.value = action(node.value)
60
67
  return node
@@ -73,14 +80,14 @@ class Then:
73
80
  pattern-matching-and-action workflow for AST manipulation.
74
81
  """
75
82
  @staticmethod
76
- def appendTo(listOfAny: list[Any]) -> Callable[[ast.AST | ast_Identifier], list[Any]]:
77
- def workhorse(node: ast.AST | ast_Identifier) -> list[Any]:
83
+ def appendTo(listOfAny: list[Any]) -> Callable[[ast.AST | ast_Identifier], ast.AST | ast_Identifier]:
84
+ def workhorse(node: ast.AST | ast_Identifier) -> ast.AST | ast_Identifier:
78
85
  listOfAny.append(node)
79
- return listOfAny
86
+ return node
80
87
  return workhorse
81
88
 
82
89
  @staticmethod
83
- def extractIt(node: ast.AST) -> ast.AST | ast_Identifier:
90
+ def extractIt(node: NodeORattribute) -> NodeORattribute:
84
91
  return node
85
92
 
86
93
  @staticmethod
@@ -92,10 +99,11 @@ class Then:
92
99
  return lambda belowMe: [belowMe, *list_astAST]
93
100
 
94
101
  @staticmethod
95
- def removeIt(_node: ast.AST) -> None: return None
102
+ def removeIt(_removeMe: ast.AST) -> None:
103
+ return None
96
104
 
97
105
  @staticmethod
98
- def replaceWith(astAST: Any) -> Callable[[Any], Any]:
106
+ def replaceWith(astAST: NodeORattribute) -> Callable[[NodeORattribute], NodeORattribute]:
99
107
  return lambda _replaceMe: astAST
100
108
 
101
109
  @staticmethod
@@ -2,17 +2,22 @@
2
2
  AST Node Predicate and Access Utilities for Pattern Matching and Traversal
3
3
 
4
4
  This module provides utilities for accessing and matching AST nodes in a consistent way.
5
- It contains two primary classes:
5
+ It contains three primary classes:
6
6
 
7
7
  1. DOT: Provides consistent accessor methods for AST node attributes across different
8
8
  node types, simplifying the access to node properties.
9
9
 
10
- 2. ifThis: Contains predicate functions for matching AST nodes based on various criteria,
10
+ 2. be: Offers type-guard functions that verify AST node types, enabling safe type
11
+ narrowing for static type checking and improving code safety.
12
+
13
+ 3. ifThis: Contains predicate functions for matching AST nodes based on various criteria,
11
14
  enabling precise targeting of nodes for analysis or transformation.
12
15
 
13
16
  These utilities form the foundation of the pattern-matching component in the AST
14
17
  manipulation framework, working in conjunction with the NodeChanger and NodeTourist
15
- classes to enable precise and targeted code transformations.
18
+ classes to enable precise and targeted code transformations. Together, they implement
19
+ a declarative approach to AST manipulation that separates node identification (ifThis),
20
+ type verification (be), and data access (DOT).
16
21
  """
17
22
 
18
23
  from collections.abc import Callable
@@ -26,6 +31,7 @@ from mapFolding.someAssemblyRequired import (
26
31
  astClassHasDOTvalue_expr,
27
32
  astClassOptionallyHasDOTnameNotName,
28
33
  astClassHasDOTvalue_exprNone,
34
+ ImaCallToName,
29
35
  )
30
36
  from typing import Any, overload, TypeGuard
31
37
  import ast
@@ -65,9 +71,17 @@ class DOT:
65
71
  @staticmethod
66
72
  def attr(node: ast.Attribute) -> ast_Identifier:
67
73
  return node.attr
74
+
75
+ @staticmethod
76
+ @overload
77
+ def func(node: ImaCallToName) -> ast.Name:...
68
78
  @staticmethod
69
- def func(node: ast.Call) -> ast.expr:
79
+ @overload
80
+ def func(node: ast.Call) -> ast.expr:...
81
+ @staticmethod
82
+ def func(node: ast.Call | ImaCallToName) -> ast.expr | ast.Name:
70
83
  return node.func
84
+
71
85
  @staticmethod
72
86
  def id(node: ast.Name) -> ast_Identifier:
73
87
  return node.id
@@ -111,6 +125,75 @@ class DOT:
111
125
  def value(node: astClassHasDOTvalue) -> Any | ast.expr | bool | None:
112
126
  return node.value
113
127
 
128
+ class be:
129
+ """
130
+ Provide type-guard functions for safely verifying AST node types during manipulation.
131
+
132
+ The be class contains static methods that perform runtime type verification of AST nodes,
133
+ returning TypeGuard results that enable static type checkers to narrow node types in
134
+ conditional branches. These type-guards:
135
+
136
+ 1. Improve code safety by preventing operations on incompatible node types
137
+ 2. Enable IDE tooling to provide better autocompletion and error detection
138
+ 3. Document expected node types in a way that's enforced by the type system
139
+ 4. Support pattern-matching workflows where node types must be verified before access
140
+
141
+ When used with conditional statements, these type-guards allow for precise,
142
+ type-safe manipulation of AST nodes while maintaining full static type checking
143
+ capabilities, even in complex transformation scenarios.
144
+ """
145
+ @staticmethod
146
+ def AnnAssign(node: ast.AST) -> TypeGuard[ast.AnnAssign]:
147
+ return isinstance(node, ast.AnnAssign)
148
+
149
+ @staticmethod
150
+ def arg(node: ast.AST) -> TypeGuard[ast.arg]:
151
+ return isinstance(node, ast.arg)
152
+
153
+ @staticmethod
154
+ def Assign(node: ast.AST) -> TypeGuard[ast.Assign]:
155
+ return isinstance(node, ast.Assign)
156
+
157
+ @staticmethod
158
+ def Attribute(node: ast.AST) -> TypeGuard[ast.Attribute]:
159
+ return isinstance(node, ast.Attribute)
160
+
161
+ @staticmethod
162
+ def AugAssign(node: ast.AST) -> TypeGuard[ast.AugAssign]:
163
+ return isinstance(node, ast.AugAssign)
164
+
165
+ @staticmethod
166
+ def Call(node: ast.AST) -> TypeGuard[ast.Call]:
167
+ return isinstance(node, ast.Call)
168
+
169
+ @staticmethod
170
+ def ClassDef(node: ast.AST) -> TypeGuard[ast.ClassDef]:
171
+ return isinstance(node, ast.ClassDef)
172
+
173
+ @staticmethod
174
+ def FunctionDef(node: ast.AST) -> TypeGuard[ast.FunctionDef]:
175
+ return isinstance(node, ast.FunctionDef)
176
+
177
+ @staticmethod
178
+ def keyword(node: ast.AST) -> TypeGuard[ast.keyword]:
179
+ return isinstance(node, ast.keyword)
180
+
181
+ @staticmethod
182
+ def Name(node: ast.AST) -> TypeGuard[ast.Name]:
183
+ return isinstance(node, ast.Name)
184
+
185
+ @staticmethod
186
+ def Return(node: ast.AST) -> TypeGuard[ast.Return]:
187
+ return isinstance(node, ast.Return)
188
+
189
+ @staticmethod
190
+ def Starred(node: ast.AST) -> TypeGuard[ast.Starred]:
191
+ return isinstance(node, ast.Starred)
192
+
193
+ @staticmethod
194
+ def Subscript(node: ast.AST) -> TypeGuard[ast.Subscript]:
195
+ return isinstance(node, ast.Subscript)
196
+
114
197
  class ifThis:
115
198
  """
116
199
  Provide predicate functions for matching and filtering AST nodes based on various criteria.
@@ -135,41 +218,41 @@ class ifThis:
135
218
  @staticmethod
136
219
  def is_arg_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.arg] | bool]:
137
220
  """see also `isArgument_Identifier`"""
138
- return lambda node: isinstance(node, ast.arg) and ifThis._Identifier(identifier)(DOT.arg(node))
221
+ return lambda node: be.arg(node) and ifThis._Identifier(identifier)(DOT.arg(node))
139
222
  @staticmethod
140
223
  def is_keyword_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.keyword] | bool]:
141
224
  """see also `isArgument_Identifier`"""
142
- return lambda node: isinstance(node, ast.keyword) and ifThis._Identifier(identifier)(DOT.arg(node))
225
+ return lambda node: be.keyword(node) and ifThis._Identifier(identifier)(DOT.arg(node))
143
226
 
144
227
  @staticmethod
145
228
  def isAnnAssign_targetIs(targetPredicate: Callable[[ast.expr], TypeGuard[ast.expr] | bool]) -> Callable[[ast.AST], TypeGuard[ast.AnnAssign] | bool]:
146
229
  def workhorse(node: ast.AST) -> TypeGuard[ast.AnnAssign] | bool:
147
- return isinstance(node, ast.AnnAssign) and targetPredicate(DOT.target(node))
230
+ return be.AnnAssign(node) and targetPredicate(DOT.target(node))
148
231
  return workhorse
149
232
 
150
233
  @staticmethod
151
234
  def isArgument_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.arg | ast.keyword] | bool]:
152
- return lambda node: (isinstance(node, ast.arg) or isinstance(node, ast.keyword)) and ifThis._Identifier(identifier)(DOT.arg(node))
235
+ return lambda node: (be.arg(node) or be.keyword(node)) and ifThis._Identifier(identifier)(DOT.arg(node))
153
236
 
154
237
  @staticmethod
155
238
  def isAssignAndTargets0Is(targets0Predicate: Callable[[ast.AST], bool]) -> Callable[[ast.AST], TypeGuard[ast.AnnAssign] | bool]:
156
239
  """node is Assign and node.targets[0] matches `targets0Predicate`."""
157
- return lambda node: isinstance(node, ast.Assign) and targets0Predicate(node.targets[0])
240
+ return lambda node: be.Assign(node) and targets0Predicate(node.targets[0])
158
241
  @staticmethod
159
242
  def isAssignAndValueIs(valuePredicate: Callable[[ast.AST], bool]) -> Callable[[ast.AST], TypeGuard[ast.Assign] | bool]:
160
243
  """node is ast.Assign and node.value matches `valuePredicate`. """
161
- return lambda node: isinstance(node, ast.Assign) and valuePredicate(DOT.value(node))
244
+ return lambda node: be.Assign(node) and valuePredicate(DOT.value(node))
162
245
 
163
246
  @staticmethod
164
247
  def isAttribute_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Attribute] | bool]:
165
248
  """node is `ast.Attribute` and the top-level `ast.Name` is `identifier`"""
166
249
  def workhorse(node: ast.AST) -> TypeGuard[ast.Attribute]:
167
- return isinstance(node, ast.Attribute) and ifThis._nested_Identifier(identifier)(DOT.value(node))
250
+ return be.Attribute(node) and ifThis._nested_Identifier(identifier)(DOT.value(node))
168
251
  return workhorse
169
252
  @staticmethod
170
253
  def isAttributeName(node: ast.AST) -> TypeGuard[ast.Attribute]:
171
254
  """ Displayed as Name.attribute."""
172
- return isinstance(node, ast.Attribute) and isinstance(DOT.value(node), ast.Name)
255
+ return be.Attribute(node) and be.Name(DOT.value(node))
173
256
  @staticmethod
174
257
  def isAttributeNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Attribute] | bool]:
175
258
  return lambda node: ifThis.isAttributeName(node) and ifThis.isName_Identifier(namespace)(DOT.value(node)) and ifThis._Identifier(identifier)(DOT.attr(node))
@@ -177,42 +260,47 @@ class ifThis:
177
260
  @staticmethod
178
261
  def isAugAssign_targetIs(targetPredicate: Callable[[ast.expr], TypeGuard[ast.expr] | bool]) -> Callable[[ast.AST], TypeGuard[ast.AugAssign] | bool]:
179
262
  def workhorse(node: ast.AST) -> TypeGuard[ast.AugAssign] | bool:
180
- return isinstance(node, ast.AugAssign) and targetPredicate(DOT.target(node))
263
+ return be.AugAssign(node) and targetPredicate(DOT.target(node))
181
264
  return workhorse
182
265
 
183
266
  @staticmethod
184
- def isCall_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Call] | bool]:
185
- return lambda node: isinstance(node, ast.Call) and ifThis.isName_Identifier(identifier)(DOT.func(node))
267
+ def isCall_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ImaCallToName] | bool]:
268
+ def workhorse(node: ast.AST) -> TypeGuard[ImaCallToName] | bool:
269
+ return ifThis.isCallToName(node) and ifThis._Identifier(identifier)(DOT.id(DOT.func(node)))
270
+ return workhorse
271
+
186
272
  @staticmethod
187
273
  def isCallAttributeNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Call] | bool]:
188
- return lambda node: isinstance(node, ast.Call) and ifThis.isAttributeNamespace_Identifier(namespace, identifier)(DOT.func(node))
274
+ def workhorse(node: ast.AST) -> TypeGuard[ast.Call] | bool:
275
+ return be.Call(node) and ifThis.isAttributeNamespace_Identifier(namespace, identifier)(DOT.func(node))
276
+ return workhorse
189
277
  @staticmethod
190
- def isCallToName(node: ast.AST) -> TypeGuard[ast.Call]:
191
- return isinstance(node, ast.Call) and isinstance(DOT.func(node), ast.Name)
278
+ def isCallToName(node: ast.AST) -> TypeGuard[ImaCallToName]:
279
+ return be.Call(node) and be.Name(DOT.func(node))
192
280
 
193
281
  @staticmethod
194
282
  def isClassDef_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.ClassDef] | bool]:
195
- return lambda node: isinstance(node, ast.ClassDef) and ifThis._Identifier(identifier)(DOT.name(node))
283
+ return lambda node: be.ClassDef(node) and ifThis._Identifier(identifier)(DOT.name(node))
196
284
 
197
285
  @staticmethod
198
286
  def isFunctionDef_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.FunctionDef] | bool]:
199
- return lambda node: isinstance(node, ast.FunctionDef) and ifThis._Identifier(identifier)(DOT.name(node))
287
+ return lambda node: be.FunctionDef(node) and ifThis._Identifier(identifier)(DOT.name(node))
200
288
 
201
289
  @staticmethod
202
290
  def isName_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Name] | bool]:
203
- return lambda node: isinstance(node, ast.Name) and ifThis._Identifier(identifier)(DOT.id(node))
291
+ return lambda node: be.Name(node) and ifThis._Identifier(identifier)(DOT.id(node))
204
292
 
205
293
  @staticmethod
206
294
  def isStarred_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Starred] | bool]:
207
295
  """node is `ast.Starred` and the top-level `ast.Name` is `identifier`"""
208
296
  def workhorse(node: ast.AST) -> TypeGuard[ast.Starred]:
209
- return isinstance(node, ast.Starred) and ifThis._nested_Identifier(identifier)(DOT.value(node))
297
+ return be.Starred(node) and ifThis._nested_Identifier(identifier)(DOT.value(node))
210
298
  return workhorse
211
299
  @staticmethod
212
300
  def isSubscript_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Subscript] | bool]:
213
301
  """node is `ast.Subscript` and the top-level `ast.Name` is `identifier`"""
214
302
  def workhorse(node: ast.AST) -> TypeGuard[ast.Subscript]:
215
- return isinstance(node, ast.Subscript) and ifThis._nested_Identifier(identifier)(DOT.value(node))
303
+ return be.Subscript(node) and ifThis._nested_Identifier(identifier)(DOT.value(node))
216
304
  return workhorse
217
305
 
218
306
  @staticmethod
@@ -231,15 +319,3 @@ class ifThis:
231
319
  def Z0Z_unparseIs(astAST: ast.AST) -> Callable[[ast.AST], bool]:
232
320
  def workhorse(node: ast.AST) -> bool: return ast.unparse(node) == ast.unparse(astAST)
233
321
  return workhorse
234
-
235
-
236
- class be:
237
- @staticmethod
238
- def Call(node: ast.AST) -> TypeGuard[ast.Call]:
239
- return isinstance(node, ast.Call)
240
- @staticmethod
241
- def Name(node: ast.AST) -> TypeGuard[ast.Name]:
242
- return isinstance(node, ast.Name)
243
- @staticmethod
244
- def Return(node: ast.AST) -> TypeGuard[ast.Return]:
245
- return isinstance(node, ast.Return)
@@ -251,7 +251,6 @@ class IngredientsModule:
251
251
  def appendIngredientsFunction(self, *ingredientsFunction: IngredientsFunction) -> None:
252
252
  """Append one or more `IngredientsFunction`."""
253
253
  for allegedIngredientsFunction in ingredientsFunction:
254
- assert isinstance(allegedIngredientsFunction, IngredientsFunction), ValueError(f"I received `{type(allegedIngredientsFunction) = }`, but I can only accept `{IngredientsFunction}`.")
255
254
  self.listIngredientsFunctions.append(allegedIngredientsFunction)
256
255
 
257
256
  def removeImportFromModule(self, moduleWithLogicalPath: str_nameDOTname) -> None: