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.
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/PKG-INFO +1 -1
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/__init__.py +1 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolIfThis.py +0 -16
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolkitNodeVisitor.py +8 -8
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_types.py +2 -1
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/transformationTools.py +5 -3
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/PKG-INFO +1 -1
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/pyproject.toml +1 -1
- asttoolkit-0.2.0/toolFactory/Z0Z_makeAstTools.py +42 -0
- asttoolkit-0.1.4/toolFactory/Z0Z_makeAstTools.py +0 -36
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/LICENSE +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/README.md +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_astTypes.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolBe.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolClassIsAndAttribute.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolDOT.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolGrab.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolMake.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolThen.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolkitAST.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_toolkitContainers.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/_typesSpecial.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/py.typed +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit/theSSOT.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/SOURCES.txt +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/dependency_links.txt +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/requires.txt +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/astToolkit.egg-info/top_level.txt +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/setup.cfg +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/tests/test_basic.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/Z0Z_hardcoded.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/__init__.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/astFactory.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/astFactory_annex.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/docstrings.py +0 -0
- {asttoolkit-0.1.4 → asttoolkit-0.2.0}/toolFactory/py.typed +0 -0
- {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.
|
|
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
|
|
@@ -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[
|
|
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:
|
|
38
|
+
self.nodeCaptured: 个return | None = None
|
|
38
39
|
|
|
39
40
|
def visit(self, node: ast.AST) -> None:
|
|
40
41
|
if self.findThis(node):
|
|
41
|
-
|
|
42
|
-
|
|
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) ->
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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.
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|