astToolkit 0.1.4__tar.gz → 0.2.0__tar.gz

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.
Files changed (37) hide show
  1. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/PKG-INFO +1 -1
  2. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/__init__.py +1 -0
  3. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolIfThis.py +0 -16
  4. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolkitNodeVisitor.py +8 -8
  5. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_types.py +2 -1
  6. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/transformationTools.py +5 -3
  7. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/PKG-INFO +1 -1
  8. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/pyproject.toml +1 -1
  9. asttoolkit-0.2.0/toolFactory/Z0Z_makeAstTools.py +42 -0
  10. asttoolkit-0.1.4/toolFactory/Z0Z_makeAstTools.py +0 -36
  11. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/LICENSE +0 -0
  12. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/README.md +0 -0
  13. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_astTypes.py +0 -0
  14. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolBe.py +0 -0
  15. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolClassIsAndAttribute.py +0 -0
  16. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolDOT.py +0 -0
  17. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolGrab.py +0 -0
  18. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolMake.py +0 -0
  19. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolThen.py +0 -0
  20. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolkitAST.py +0 -0
  21. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolkitContainers.py +0 -0
  22. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_typesSpecial.py +0 -0
  23. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/py.typed +0 -0
  24. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/theSSOT.py +0 -0
  25. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/SOURCES.txt +0 -0
  26. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/dependency_links.txt +0 -0
  27. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/requires.txt +0 -0
  28. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/top_level.txt +0 -0
  29. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/setup.cfg +0 -0
  30. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/tests/test_basic.py +0 -0
  31. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/Z0Z_hardcoded.py +0 -0
  32. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/__init__.py +0 -0
  33. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/astFactory.py +0 -0
  34. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/astFactory_annex.py +0 -0
  35. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/docstrings.py +0 -0
  36. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/py.typed +0 -0
  37. {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/startHere.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astToolkit
3
- Version: 0.1.4
3
+ Version: 0.2.0
4
4
  Summary: A powerfully composable, type-safe toolkit for Python abstract syntax tree (AST) manipulation, analysis, transformation, and code generation with a layered architecture designed for building sophisticated code processing assembly-lines.
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -13,6 +13,7 @@ from astToolkit._types import (
13
13
  NodeORattribute as NodeORattribute,
14
14
  str_nameDOTname as str_nameDOTname,
15
15
  个 as 个,
16
+ 个return as 个return,
16
17
  )
17
18
 
18
19
  from astToolkit._toolkitNodeVisitor import (
@@ -44,12 +44,6 @@ class IfThis:
44
44
  """see also `isArgument_Identifier`"""
45
45
  return lambda node: Be.keyword(node) and IfThis.isIdentifier(identifier)(DOT.arg(node))
46
46
 
47
- @staticmethod
48
- def isAnnAssign_targetIs(targetPredicate: Callable[[ast.expr], TypeGuard[ast.expr] | bool]) -> Callable[[ast.AST], TypeGuard[ast.AnnAssign] | bool]:
49
- def workhorse(node: ast.AST) -> TypeGuard[ast.AnnAssign] | bool:
50
- return Be.AnnAssign(node) and targetPredicate(DOT.target(node))
51
- return workhorse
52
-
53
47
  @staticmethod
54
48
  def isArgument_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.arg | ast.keyword] | bool]:
55
49
  return lambda node: (Be.arg(node) or Be.keyword(node)) and IfThis.isIdentifier(identifier)(DOT.arg(node))
@@ -58,10 +52,6 @@ class IfThis:
58
52
  def isAssignAndTargets0Is(targets0Predicate: Callable[[ast.AST], bool]) -> Callable[[ast.AST], TypeGuard[ast.AnnAssign] | bool]:
59
53
  """ `node` is `ast.Assign` and `node.targets[0]` matches `targets0Predicate`."""
60
54
  return lambda node: Be.Assign(node) and targets0Predicate(node.targets[0])
61
- @staticmethod
62
- def isAssignAndValueIs(valuePredicate: Callable[[ast.AST], bool]) -> Callable[[ast.AST], TypeGuard[ast.Assign] | bool]:
63
- """ `node` is `ast.Assign` and `node.value` matches `valuePredicate`. """
64
- return lambda node: Be.Assign(node) and valuePredicate(DOT.value(node))
65
55
 
66
56
  @staticmethod
67
57
  def isAttribute_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Attribute] | bool]:
@@ -82,12 +72,6 @@ class IfThis:
82
72
  def isAttributeNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Attribute] | bool]:
83
73
  return lambda node: IfThis.isAttributeName(node) and IfThis.isName_Identifier(namespace)(DOT.value(node)) and IfThis.isIdentifier(identifier)(DOT.attr(node))
84
74
 
85
- @staticmethod
86
- def isAugAssignAndTargetIs(targetPredicate: Callable[[ast.expr], TypeGuard[ast.expr] | bool]) -> Callable[[ast.AST], TypeGuard[ast.AugAssign] | bool]:
87
- def workhorse(node: ast.AST) -> TypeGuard[ast.AugAssign] | bool:
88
- return Be.AugAssign(node) and targetPredicate(DOT.target(node))
89
- return workhorse
90
-
91
75
  @staticmethod
92
76
  def isCall_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Call] | bool]:
93
77
  def workhorse(node: ast.AST) -> TypeGuard[ast.Call] | bool:
@@ -15,12 +15,13 @@ structures, creating a complete workflow for code analysis and transformation.
15
15
  """
16
16
 
17
17
  from collections.abc import Callable
18
- from typing import Any
18
+ from typing import Any, cast, Generic, TypeGuard, TypeVar
19
19
  import ast
20
+ from astToolkit import NodeORattribute, 个, 个return
20
21
 
21
22
  # TODO Identify the logic that narrows the type and can help the user during static type checking.
22
23
 
23
- class NodeTourist(ast.NodeVisitor):
24
+ class NodeTourist(ast.NodeVisitor, Generic[个, 个return]):
24
25
  """
25
26
  Visit and extract information from AST nodes that match a predicate.
26
27
 
@@ -31,19 +32,18 @@ class NodeTourist(ast.NodeVisitor):
31
32
  This class is particularly useful for analyzing AST structures, extracting specific nodes or node properties, and
32
33
  gathering information about code patterns.
33
34
  """
34
- def __init__(self, findThis: Callable[..., Any], doThat: Callable[..., Any]) -> None:
35
+ def __init__(self, findThis: Callable[[ast.AST], TypeGuard[个] | bool], doThat: Callable[[个], 个return]) -> None:
35
36
  self.findThis = findThis
36
37
  self.doThat = doThat
37
- self.nodeCaptured: Any | None = None
38
+ self.nodeCaptured: 个return | None = None
38
39
 
39
40
  def visit(self, node: ast.AST) -> None:
40
41
  if self.findThis(node):
41
- nodeActionReturn = self.doThat(node)
42
- if nodeActionReturn is not None:
43
- self.nodeCaptured = nodeActionReturn
42
+ node = cast(个, node)
43
+ self.nodeCaptured = self.doThat(node)
44
44
  self.generic_visit(node)
45
45
 
46
- def captureLastMatch(self, node: ast.AST) -> Any | None:
46
+ def captureLastMatch(self, node: ast.AST) -> 个return | None:
47
47
  self.nodeCaptured = None
48
48
  self.visit(node)
49
49
  return self.nodeCaptured
@@ -17,7 +17,8 @@ str_nameDOTname: typing_TypeAlias = str
17
17
 
18
18
  # Limited success with TypeVar.
19
19
  个 = typing_TypeVar('个', bound = ast.AST, covariant = True)
20
- NodeORattribute = typing_TypeVar('NodeORattribute', bound = ast.AST | ast_expr_Slice | ast_Identifier | str_nameDOTname | bool | Any | None, covariant = True)
20
+ 个return = typing_TypeVar('个return', covariant = True)
21
+ NodeORattribute = typing_TypeVar('NodeORattribute', bound = ast.AST | ast_Identifier | str_nameDOTname | bool | Any | None, covariant = True)
21
22
 
22
23
  # For my reference, all ast classes by subgroup:
23
24
  Ima_ast_boolop: typing_TypeAlias = ast.boolop | ast.And | ast.Or
@@ -1,6 +1,7 @@
1
1
  from astToolkit import (
2
2
  ast_Identifier,
3
3
  Be,
4
+ ClassIsAndAttribute,
4
5
  DOT,
5
6
  FREAKOUT,
6
7
  Grab,
@@ -65,7 +66,8 @@ def inlineFunctionDef(identifierToInline: ast_Identifier, module: ast.Module) ->
65
66
  raise ValueError(f"FunctionDefToInline not found in dictionaryIdentifier2FunctionDef: {identifierToInline = }") from ERRORmessage
66
67
 
67
68
  listIdentifiersCalledFunctions: list[ast_Identifier] = []
68
- findIdentifiersToInline = NodeTourist(findThis = IfThis.isCallToName, doThat = Grab.funcAttribute(cast(Callable[[ast.expr], ast.expr], Grab.idAttribute(cast(Callable[[ast_Identifier], ast_Identifier], Then.appendTo(listIdentifiersCalledFunctions))))))
69
+ findIdentifiersToInline = NodeTourist(findThis = IfThis.isCallToName
70
+ , doThat = Grab.funcAttribute(cast(Callable[[ast.expr], ast.expr], Grab.idAttribute(cast(Callable[[ast_Identifier], ast_Identifier], Then.appendTo(listIdentifiersCalledFunctions))))))
69
71
  findIdentifiersToInline.visit(FunctionDefToInline)
70
72
 
71
73
  dictionary4Inlining: dict[ast_Identifier, ast.FunctionDef] = {}
@@ -94,7 +96,7 @@ def inlineFunctionDef(identifierToInline: ast_Identifier, module: ast.Module) ->
94
96
  for astFunctionDef in dictionary4Inlining.values():
95
97
  inliner.visit(astFunctionDef)
96
98
  else:
97
- inliner = NodeChanger(IfThis.isAssignAndValueIs(IfThis.isCall_Identifier(identifier)),Then.replaceWith(FunctionDefTarget.body[0:-1]))
99
+ inliner = NodeChanger(ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCall_Identifier(identifier)),Then.replaceWith(FunctionDefTarget.body[0:-1]))
98
100
  for astFunctionDef in dictionary4Inlining.values():
99
101
  inliner.visit(astFunctionDef)
100
102
 
@@ -104,7 +106,7 @@ def inlineFunctionDef(identifierToInline: ast_Identifier, module: ast.Module) ->
104
106
  inliner = NodeChanger(IfThis.isCall_Identifier(identifier), Then.replaceWith(replacement))
105
107
  inliner.visit(FunctionDefToInline)
106
108
  else:
107
- inliner = NodeChanger(IfThis.isAssignAndValueIs(IfThis.isCall_Identifier(identifier)),Then.replaceWith(FunctionDefTarget.body[0:-1]))
109
+ inliner = NodeChanger(ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCall_Identifier(identifier)),Then.replaceWith(FunctionDefTarget.body[0:-1]))
108
110
  inliner.visit(FunctionDefToInline)
109
111
  ast.fix_missing_locations(FunctionDefToInline)
110
112
  return FunctionDefToInline
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astToolkit
3
- Version: 0.1.4
3
+ Version: 0.2.0
4
4
  Summary: A powerfully composable, type-safe toolkit for Python abstract syntax tree (AST) manipulation, analysis, transformation, and code generation with a layered architecture designed for building sophisticated code processing assembly-lines.
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -36,7 +36,7 @@ optional-dependencies = { testing = [
36
36
  readme = { file = "README.md", content-type = "text/markdown" }
37
37
  requires-python = ">=3.10"
38
38
  urls = { Donate = "https://www.patreon.com/integrated", Homepage = "https://github.com/hunterhogan/astToolkit", Issues = "https://github.com/hunterhogan/astToolkit/issues", Repository = "https://github.com/hunterhogan/astToolkit.git" }
39
- version = "0.1.4"
39
+ version = "0.2.0"
40
40
 
41
41
  [tool.coverage]
42
42
  report = { exclude_lines = [
@@ -0,0 +1,42 @@
1
+ from collections.abc import Callable, Sequence
2
+ import typeshed_client.finder
3
+ from toolFactory import FREAKOUT, pathTypeshed, Z0Z_typesSpecial, makeTools
4
+ from pathlib import Path
5
+ from typing import Any, TypeAlias as typing_TypeAlias, TypeVar as typing_TypeVar
6
+ import ast
7
+
8
+ ast_expr_Slice: typing_TypeAlias = ast.expr
9
+ ast_Identifier: typing_TypeAlias = str
10
+ str_nameDOTname: typing_TypeAlias = str
11
+
12
+ 个 = typing_TypeVar('个', bound = ast.AST, covariant = True)
13
+ NodeORattribute = typing_TypeVar('NodeORattribute', bound = ast.AST | ast_expr_Slice | ast_Identifier | str_nameDOTname | bool | Any | None, covariant = True)
14
+
15
+ # TODO Some `DOT` methods return lists, notably DOT.targets, which is an attribute of ast.Assign.
16
+ # But, none or almost none of the other functions and methods accept a list as input.
17
+ # This is most obviously a problem in `ClassIsAndAttribute.targetsIs` because the user needs to pass
18
+ # a function that can take list[ast.expr] as a parameter.
19
+ # I don't know if the following works, but it is interesting.
20
+ # ClassIsAndAttribute.targetsIs(ast.Assign, lambda list_expr: any([IfThis.isSubscript_Identifier('foldGroups')(node) for node in list_expr]))
21
+
22
+ class cleverName:
23
+ @staticmethod
24
+ def index(at: int) -> Callable[[Sequence[NodeORattribute]], NodeORattribute]:
25
+ def workhorse(zzz: Sequence[NodeORattribute]) -> NodeORattribute:
26
+ node = zzz[at]
27
+ return node
28
+ return workhorse
29
+
30
+ if __name__ == "__main__":
31
+ search_context = typeshed_client.finder.get_search_context(typeshed=pathTypeshed if pathTypeshed.exists() else None)
32
+
33
+ # pathFilenameStubFile: Path | None = typeshed_client.finder.get_stub_file("_ast", search_context=search_context)
34
+ # if pathFilenameStubFile is None: raise FREAKOUT
35
+ # astStubFile: ast.Module = ast.parse(pathFilenameStubFile.read_text())
36
+ # Z0Z_typesSpecial(astStubFile)
37
+
38
+ pathFilenameStubFile: Path | None = typeshed_client.finder.get_stub_file("ast", search_context=search_context)
39
+ if pathFilenameStubFile is None: raise FREAKOUT
40
+ astStubFile: ast.Module = ast.parse(pathFilenameStubFile.read_text())
41
+
42
+ makeTools(astStubFile)
@@ -1,36 +0,0 @@
1
- import typeshed_client.finder
2
- from toolFactory import FREAKOUT, pathTypeshed, Z0Z_typesSpecial, makeTools
3
- from pathlib import Path
4
- import ast
5
-
6
- # TODO I think there is a way to generalize this to all antecedents using a class analogous to Grab
7
-
8
- # NodeTransformer
9
- # NodeVisitor
10
- # ^\s*class \w+\(((operator)|(cmpop)|(AST)|(mod)|(stmt)|(expr)|(expr_context)|(type_ignore)|(_Slice)|(pattern)|(boolop)|(unaryop)|(binaryop)|(type_param)|(excepthandler))\)
11
-
12
- """
13
- @staticmethod
14
- def isAugAssignAndTargetIs(targetPredicate: Callable[[ast.expr], TypeGuard[ast.expr] | bool]) -> Callable[[ast.AST], TypeGuard[ast.AugAssign] | bool]:
15
- def workhorse(node: ast.AST) -> TypeGuard[ast.AugAssign] | bool:
16
- return Be.AugAssign(node) and targetPredicate(DOT.target(node))
17
- return workhorse
18
-
19
- findThis = Be.AnnAssign and Be.checkAttribute_target(IfThis.isName_Identifier(self.name))
20
- """
21
-
22
- if __name__ == "__main__":
23
- search_context = typeshed_client.finder.get_search_context(typeshed=pathTypeshed if pathTypeshed.exists() else None)
24
-
25
- # pathFilenameStubFile: Path | None = typeshed_client.finder.get_stub_file("_ast", search_context=search_context)
26
- # if pathFilenameStubFile is None: raise FREAKOUT
27
- # astStubFile: ast.Module = ast.parse(pathFilenameStubFile.read_text())
28
- # Z0Z_typesSpecial(astStubFile)
29
-
30
- pathFilenameStubFile: Path | None = typeshed_client.finder.get_stub_file("ast", search_context=search_context)
31
- # print(pathFilenameStubFile)
32
- if pathFilenameStubFile is None: raise FREAKOUT
33
- astStubFile: ast.Module = ast.parse(pathFilenameStubFile.read_text())
34
- # print(ast.dump(astStubFile))
35
-
36
- makeTools(astStubFile)
File without changes
File without changes
File without changes