### AST NodeVisitor Initialization and Usage Example (Python) Source: https://github.com/hunterhogan/asttoolkit/blob/main/notesClassFind/Idea.md Demonstrates the basic structure of an AST NodeVisitor class, specifically the `__call__` method which is invoked when an instance of the visitor is called with an AST node. This method typically performs an `isinstance` check. ```python class Find: def __call__(cls, node: ast.AST) -> TypeIs[ast.Class]: return isinstance(node, ast.Class) ``` -------------------------------- ### Transform AST Node: Change Multiplication to Addition using Python AST Source: https://github.com/hunterhogan/asttoolkit/blob/main/README.md This example shows how to transform an AST node using astToolkit. It defines a predicate 'Be.Mult' to find multiplication operations and a transformation 'Then.replaceWith(ast.Add())' to change them to addition operations. This demonstrates the NodeChanger and Then components for AST modification. ```python from astToolkit import Be, IfThis, Make, NodeChanger, Then import ast # Parse some Python code into an AST code = """ def double(x): return x * 2 """ tree = ast.parse(code) # Define a predicate to find the multiplication operation find_mult = Be.Mult # Define a transformation to change multiplication to addition change_to_add = Then.replaceWith(ast.Add()) # Apply the transformation changer = NodeChanger(find_mult, change_to_add) tree = changer.visit(tree) # Print the transformed code (optional) # print(ast.unparse(tree)) ``` -------------------------------- ### Add Logging to Function Definitions using NodeChanger and Grab Source: https://context7.com/hunterhogan/asttoolkit/llms.txt This example shows how to add a logging statement before the body of function definitions. It uses Grab.bodyAttribute to modify the function's body and NodeChanger to apply this transformation to all FunctionDef nodes. ```python from astToolkit import NodeChanger, Grab, Be, Make def add_logging(func_def): log_stmt = Make.Expr(Make.Call( Make.Name("logger"), [Make.Constant(f"Entering {func_def.name}")] )) return Grab.bodyAttribute(lambda body: [log_stmt] + list(body))(func_def) logger_adder = NodeChanger(Be.FunctionDef, add_logging) ``` -------------------------------- ### Extract Function Parameter Name and Type Annotation using Python AST Source: https://github.com/hunterhogan/asttoolkit/blob/main/README.md This example demonstrates how to use astToolkit's NodeTourist, Be, DOT, and Then to extract the name and type annotation of a function parameter from a Python AST. It first parses Python code, then uses NodeTourist with specific 'Be' predicates and 'Then.extractIt' actions to retrieve the desired information. ```python from astToolkit import Be, DOT, NodeTourist, Then import ast # Parse some Python code into an AST code = """ def process_data(state: DataClass): result = state.value * 2 return result """ tree = ast.parse(code) # Extract the parameter name from the function function_def = tree.body[0] param_name = NodeTourist( Be.arg, # Look for function parameters Then.extractIt(DOT.arg) # Extract the parameter name ).captureLastMatch(function_def) print(f"Function parameter name: {param_name}") # Outputs: state # Extract the parameter's type annotation annotation = NodeTourist( Be.arg, # Look for function parameters Then.extractIt(DOT.annotation) # Extract the type annotation ).captureLastMatch(function_def) if annotation and Be.Name(annotation): annotation_name = DOT.id(annotation) print(f"Parameter type: {annotation_name}") # Outputs: DataClass ``` -------------------------------- ### Parse Python Files and Modules to AST using Utility Functions Source: https://context7.com/hunterhogan/asttoolkit/llms.txt This snippet showcases utility functions for parsing Python code into AST objects. parsePathFilename2astModule parses a file path, while parseLogicalPath2astModule parses an installed module by its import path. It also includes functions to extract specific function or class definitions. ```python from astToolkit import ( parsePathFilename2astModule, parseLogicalPath2astModule, extractFunctionDef, extractClassDef ) # Parse a file to AST tree = parsePathFilename2astModule("mymodule.py") # Parse an installed module by import path typing_ast = parseLogicalPath2astModule("typing") # Extract specific definitions main_func = extractFunctionDef(tree, "main") my_class = extractClassDef(tree, "MyClass") ``` -------------------------------- ### Type Information Preservation Example (Python) Source: https://github.com/hunterhogan/asttoolkit/blob/main/notesClassFind/Idea.md Illustrates how to traverse an AST and extract type information, specifically focusing on annotated assignments and preserving the annotation for a node's target identifier. This function populates a dictionary with attribute names and their corresponding annotations. ```python def staticFunction(astClassDef: ast.ClassDef, dictionary_Attributes: dict[str, ast.expr]): for node in ast.walk(astClassDef): if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): dictionary_Attributes[node.target.id] = node.annotation ``` -------------------------------- ### Building Code Generation Systems Source: https://github.com/hunterhogan/asttoolkit/blob/main/README.md Illustrates setting up a foundation for code generation systems. It involves parsing a module, extracting a function, modifying its definition, and writing the new code to disk. ```python from astToolkit import ( Be, DOT, IngredientsFunction, IngredientsModule, LedgerOfImports, Make, NodeTourist, Then, parseLogicalPath2astModule, write_astModule ) import ast # Parse a module to extract a function # module_ast = parseLogicalPath2astModule("my_package.source_module") # Extract a function and track its imports function_name = "target_function" # function_def = NodeTourist( # IfThis.isFunctionDefIdentifier(function_name), # Then.extractIt # ).captureLastMatch(module_ast) # if function_def: # # Create a self-contained function with tracked imports # ingredients = IngredientsFunction( # function_def, # LedgerOfImports(module_ast) # ) # # Rename the function # ingredients.astFunctionDef.name = "optimized_" + function_name # # Add a decorator # decorator = Make.Call( # Make.Name("jit"), # [], # [Make.keyword("cache", Make.Constant(True))] # ) # ingredients.astFunctionDef.decorator_list.append(decorator) # # Add required import # ingredients.imports.addImportFrom_asStr("numba", "jit") # # Create a module and write it to disk # module = IngredientsModule(ingredients) # write_astModule(module, "path/to/generated_code.py", "my_package") ``` -------------------------------- ### Core Classes Overview Source: https://context7.com/hunterhogan/asttoolkit/llms.txt Introduction to the main components of astToolkit for working with Python's Abstract Syntax Tree (AST). ```APIDOC ## Introduction to astToolkit astToolkit is a Python package that provides a comprehensive, type-safe toolkit for working with Python's Abstract Syntax Tree (AST). It is built around the **antecedent-action pattern**, enabling developers to identify specific AST nodes using predicates (antecedents) and then apply transformations or extract information using action functions (consequents). Key classes include: - **Be**: Type guards for AST nodes. - **IfThis**: Composable predicate generators. - **Then**: Action functions for transformations. - **NodeTourist**: Read-only AST visitor. - **NodeChanger**: Destructive AST transformer. ``` -------------------------------- ### Then - Action Functions Source: https://context7.com/hunterhogan/asttoolkit/llms.txt Explains the usage of `Then` for defining actions to be performed when predicates match, including collection, replacement, removal, and insertion. ```APIDOC ## Then - Action Functions The `Then` class provides action functions to apply when predicates match, supporting both read-only collection and AST modification. ### Method N/A (Class Usage) ### Endpoint N/A (Class Usage) ### Parameters N/A ### Request Example ```python from astToolkit import Then, NodeTourist, NodeChanger, IfThis, Make # Collect matching nodes into a list function_names = [] collector = NodeTourist( IfThis.isFunctionDefIdentifier, Then.appendTo(function_names) ) # Extract a single node (returns the node unchanged) extractor = NodeTourist( IfThis.isClassDefIdentifier("MyClass"), Then.extractIt ) # result = extractor.captureLastMatch(tree) # Assuming 'tree' is defined # Replace nodes during transformation replacer = NodeChanger( IfThis.isNameIdentifier("old_name"), Then.replaceWith(Make.Name("new_name")) ) # new_tree = replacer.visit(tree) # Assuming 'tree' is defined # Remove matching nodes remover = NodeChanger(Be.Pass, Then.removeIt) # cleaned_tree = remover.visit(tree) # Assuming 'tree' is defined # Insert statements above or below matched nodes inserter = NodeChanger( IfThis.isFunctionDefIdentifier("main"), Then.insertThisAbove([Make.Expr(Make.Call(Make.Name("setup"), []))]) ) # Assuming 'tree' is defined ``` ### Response N/A (Illustrative Usage) ``` -------------------------------- ### IfThis - Composable Predicate Generators Source: https://context7.com/hunterhogan/asttoolkit/llms.txt Shows how to use `IfThis` to create and combine predicates for matching specific AST patterns. ```APIDOC ## IfThis - Composable Predicate Generators The `IfThis` class provides static methods that generate predicate functions for matching specific AST patterns. ### Method N/A (Class Usage) ### Endpoint N/A (Class Usage) ### Parameters N/A ### Request Example ```python from astToolkit import IfThis, Be # Match function definitions by name find_init = IfThis.isFunctionDefIdentifier("__init__") # Match calls to specific functions find_print_calls = IfThis.isCallIdentifier("print") # Match attribute access patterns (e.g., self.value) find_self_attrs = IfThis.isAttributeNamespaceIdentifier("self", "value") # Combine predicates with logical operators find_any_def = IfThis.isAnyOf( IfThis.isFunctionDefIdentifier("setup"), IfThis.isFunctionDefIdentifier("teardown") ) find_both_conditions = IfThis.isAllOf( Be.Call, IfThis.isCallIdentifier("open") ) # Match nodes but not their descendants find_outermost_calls = IfThis.matchesMeButNotAnyDescendant(Be.Call) ``` ### Response N/A (Illustrative Usage) ``` -------------------------------- ### Create AST Nodes using Make Class Source: https://context7.com/hunterhogan/asttoolkit/llms.txt The Make class provides factory methods for constructing various AST nodes, such as function definitions, class definitions, imports, and binary operations. It simplifies the process of programmatically generating AST structures. ```python from astToolkit import Make import ast # Create a simple function definition func = Make.FunctionDef( "greet", Make.arguments(list_arg=[Make.arg("name")]), body=[ Make.Return( Make.BinOp( Make.Constant("Hello, "), ast.Add(), Make.Name("name") ) ) ] ) # Create a class definition cls = Make.ClassDef( "Vehicle", bases=[Make.Name("ABC")], body=[ Make.FunctionDef( "__init__", Make.arguments(list_arg=[Make.arg("self"), Make.arg("speed")]), body=[ Make.Assign( [Make.Attribute(Make.Name("self"), "speed")], Make.Name("speed") ) ] ) ] ) # Create imports import_stmt = Make.Import("collections.abc", asName="abc") from_import = Make.ImportFrom("typing", [Make.alias("Optional"), Make.alias("List")]) # Join expressions with operators combined = Make.Or.join([Make.Name("a"), Make.Name("b"), Make.Name("c")]) # Produces: a or b or c ``` -------------------------------- ### NodeTourist - Read-Only AST Visitor Source: https://context7.com/hunterhogan/asttoolkit/llms.txt Details on using `NodeTourist` for non-destructive AST traversal and data extraction. ```APIDOC ## NodeTourist - Read-Only AST Visitor `NodeTourist` extends `ast.NodeVisitor` for non-destructive AST traversal and information extraction. ### Method N/A (Class Usage) ### Endpoint N/A (Class Usage) ### Parameters N/A ### Request Example ```python from astToolkit import NodeTourist, IfThis, Then, Be # Assuming 'tree' is defined (e.g., from ast.parse(source)) # Find all function names in a module function_names = [] tourist = NodeTourist(Be.FunctionDef, Then.appendTo(function_names)) # tourist.visit(tree) # Extract a specific function definition finder = NodeTourist( IfThis.isFunctionDefIdentifier("calculate"), Then.extractIt ) # calc_function = finder.captureLastMatch(tree) # Collect all string constants strings = [] string_finder = NodeTourist( Be.Constant.valueIs(lambda v: isinstance(v, str)), Then.appendTo(strings) ) # string_finder.visit(tree) ``` ### Response N/A (Illustrative Usage) ``` -------------------------------- ### Apply Simple AST Transformation Source: https://github.com/hunterhogan/asttoolkit/blob/main/README.md Applies a transformation to an Abstract Syntax Tree (AST) to change addition operations to multiplication. It uses NodeChanger with predefined find and change functions. ```python from astToolkit import NodeChanger, find_mult, change_to_add import ast # Assuming 'tree' is a pre-existing AST object # NodeChanger(find_mult, change_to_add).visit(tree) # print(ast.unparse(tree)) ``` -------------------------------- ### Advanced AST Transformation with Custom Predicates Source: https://github.com/hunterhogan/asttoolkit/blob/main/README.md Demonstrates advanced AST transformation by defining custom predicates using class inheritance. It finds and modifies a specific 'while' loop condition. ```python from astToolkit import str, Be, DOT, Grab, IfThis as astToolkit_IfThis, Make, NodeChanger, Then import ast # Define custom predicates by extending IfThis class IfThis(astToolkit_IfThis): @staticmethod def isAttributeNamespaceIdentifierGreaterThan0( namespace: str, identifier: str ) -> Callable[[ast.AST], TypeIs[ast.Compare] | bool]: return lambda node: ( Be.Compare(node) and IfThis.isAttributeNamespaceIdentifier(namespace, identifier)(DOT.left(node)) and Be.Gt(node.ops[0]) and IfThis.isConstant_value(0)(node.comparators[0])) @staticmethod def isWhileAttributeNamespaceIdentifierGreaterThan0( namespace: str, identifier: str ) -> Callable[[ast.AST], TypeIs[ast.While] | bool]: return lambda node: ( Be.While(node) and IfThis.isAttributeNamespaceIdentifierGreaterThan0(namespace, identifier)(DOT.test(node))) # Parse some code code = """ while claude.counter > 0: result += counter counter -= 1 """ tree = ast.parse(code) # Find the while loop with our custom predicate find_while_loop = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0("claude", "counter") # Replace counter > 0 with counter > 1 change_condition = Grab.testAttribute( Grab.comparatorsAttribute( Then.replaceWith([Make.Constant(1)]) ) ) # Apply the transformation NodeChanger(find_while_loop, change_condition).visit(tree) print(ast.unparse(tree)) ``` -------------------------------- ### Be - Type Guards for AST Nodes Source: https://context7.com/hunterhogan/asttoolkit/llms.txt Demonstrates how to use the `Be` class for type-safe node identification and attribute condition checking. ```APIDOC ## Be - Type Guards for AST Nodes The `Be` class provides type guards for every AST node type, enabling type-safe node identification with automatic type narrowing. ### Method N/A (Class Usage) ### Endpoint N/A (Class Usage) ### Parameters N/A ### Request Example ```python import ast from astToolkit import Be source = "x = 42" tree = ast.parse(source) # Type-safe node checking with automatic narrowing for node in ast.walk(tree): if Be.FunctionDef(node): print(f"Function: {node.name}") # Type checker knows node is ast.FunctionDef if Be.Call(node) and Be.Name(node.func): print(f"Call to: {node.func.id}") # Type-safe nested access # Attribute condition checking is_main_function = Be.FunctionDef.nameIs(lambda name: name == "main") ``` ### Response N/A (Illustrative Usage) ``` -------------------------------- ### Extending Core AST Classes for Custom Patterns Source: https://github.com/hunterhogan/asttoolkit/blob/main/README.md Shows how to extend core astToolkit classes to create specialized AST pattern matching functions for a codebase. It defines custom predicates for attribute namespace identifiers. ```python from astToolkit import str, Be, IfThis as astToolkit_IfThis from collections.abc import Callable from typing import TypeIs import ast class IfThis(astToolkit_IfThis): @staticmethod def isAttributeNamespaceIdentifierGreaterThan0( namespace: str, identifier: str ) -> Callable[[ast.AST], TypeIs[ast.Compare] | bool]: """Find comparisons like 'state.counter > 0'""" return lambda node: ( Be.Compare(node) and IfThis.isAttributeNamespaceIdentifier(namespace, identifier)(node.left) and Be.Gt(node.ops[0]) and IfThis.isConstant_value(0)(node.comparators[0]) ) @staticmethod def isWhileAttributeNamespaceIdentifierGreaterThan0( namespace: str, identifier: str ) -> Callable[[ast.AST], TypeIs[ast.While] | bool]: """Find while loops like 'while state.counter > 0:'""" return lambda node: ( Be.While(node) and IfThis.isAttributeNamespaceIdentifierGreaterThan0(namespace, identifier)(node.test) ) ``` -------------------------------- ### Read-Only AST Traversal with NodeTourist Source: https://context7.com/hunterhogan/asttoolkit/llms.txt `NodeTourist` is a class for non-destructive AST traversal and data extraction. It extends `ast.NodeVisitor` and uses predicates and actions to process nodes without modifying the tree. ```python from astToolkit import NodeTourist, IfThis, Then, Be # Find all function names in a module function_names = [] tourist = NodeTourist(Be.FunctionDef, Then.appendTo(function_names)) tourist.visit(tree) # Extract a specific function definition finder = NodeTourist( IfThis.isFunctionDefIdentifier("calculate"), Then.extractIt ) calc_function = finder.captureLastMatch(tree) # Collect all string constants strings = [] string_finder = NodeTourist( Be.Constant.valueIs(lambda v: isinstance(v, str)), Then.appendTo(strings) ) string_finder.visit(tree) ``` -------------------------------- ### NodeChanger - Destructive AST Transformer Source: https://context7.com/hunterhogan/asttoolkit/llms.txt Explains how to use `NodeChanger` for targeted and destructive modifications to the AST. ```APIDOC ## NodeChanger - Destructive AST Transformer `NodeChanger` extends `ast.NodeTransformer` for targeted AST modifications. ### Method N/A (Class Usage) ### Endpoint N/A (Class Usage) ### Parameters N/A ### Request Example ```python from astToolkit import NodeChanger, IfThis, Then, Make, Grab # Assuming 'tree' is defined (e.g., from ast.parse(source)) # Rename all occurrences of a variable renamer = NodeChanger( IfThis.isNameIdentifier("old_var"), Then.replaceWith(Make.Name("new_var")) ) # renamed_tree = renamer.visit(tree) ``` ### Response N/A (Illustrative Usage) ``` -------------------------------- ### Composable Predicate Generation with IfThis Source: https://context7.com/hunterhogan/asttoolkit/llms.txt The `IfThis` class offers static methods to create predicate functions for matching various AST patterns. These predicates can be combined using logical operators for complex pattern matching. ```python from astToolkit import IfThis, Be # Match function definitions by name find_init = IfThis.isFunctionDefIdentifier("__init__") # Match calls to specific functions find_print_calls = IfThis.isCallIdentifier("print") # Match attribute access patterns (e.g., self.value) find_self_attrs = IfThis.isAttributeNamespaceIdentifier("self", "value") # Combine predicates with logical operators find_any_def = IfThis.isAnyOf( IfThis.isFunctionDefIdentifier("setup"), IfThis.isFunctionDefIdentifier("teardown") ) find_both_conditions = IfThis.isAllOf( Be.Call, IfThis.isCallIdentifier("open") ) # Match nodes but not their descendants find_outermost_calls = IfThis.matchesMeButNotAnyDescendant(Be.Call) ``` -------------------------------- ### Action Functions with Then for AST Manipulation Source: https://context7.com/hunterhogan/asttoolkit/llms.txt The `Then` class provides action functions for AST manipulation, including collecting data, replacing nodes, removing nodes, and inserting new nodes. These actions are typically used in conjunction with `NodeTourist` or `NodeChanger`. ```python from astToolkit import Then, NodeTourist, NodeChanger, IfThis, Make # Collect matching nodes into a list function_names = [] collector = NodeTourist( IfThis.isFunctionDefIdentifier, Then.appendTo(function_names) ) # Extract a single node (returns the node unchanged) extractor = NodeTourist( IfThis.isClassDefIdentifier("MyClass"), Then.extractIt ) result = extractor.captureLastMatch(tree) # Replace nodes during transformation replacer = NodeChanger( IfThis.isNameIdentifier("old_name"), Then.replaceWith(Make.Name("new_name")) ) new_tree = replacer.visit(tree) # Remove matching nodes remover = NodeChanger(Be.Pass, Then.removeIt) cleaned_tree = remover.visit(tree) # Insert statements above or below matched nodes inserter = NodeChanger( IfThis.isFunctionDefIdentifier("main"), Then.insertThisAbove([Make.Expr(Make.Call(Make.Name("setup"), []))]) ) ``` -------------------------------- ### Type-Safe AST Node Checking with Be Source: https://context7.com/hunterhogan/asttoolkit/llms.txt The `Be` class in astToolkit provides type guards for AST nodes, enabling type-safe identification and automatic type narrowing. It allows for checking node types and their attributes in a structured manner. ```python import ast from astToolkit import Be source = "x = 42" tree = ast.parse(source) # Type-safe node checking with automatic narrowing for node in ast.walk(tree): if Be.FunctionDef(node): print(f"Function: {node.name}") # Type checker knows node is ast.FunctionDef if Be.Call(node) and Be.Name(node.func): print(f"Call to: {node.func.id}") # Type-safe nested access # Attribute condition checking is_main_function = Be.FunctionDef.nameIs(lambda name: name == "main") ``` -------------------------------- ### Modify AST Node Attributes using Grab Class Source: https://context7.com/hunterhogan/asttoolkit/llms.txt The Grab class facilitates the creation of transformation functions that modify specific attributes of AST nodes. It supports modifying attributes like 'body' and 'name', and allows chaining multiple modifications. ```python from astToolkit import Grab, NodeChanger, Be, Make # Modify function body to add a docstring add_docstring = Grab.bodyAttribute( lambda body: [Make.Expr(Make.Constant("Docstring here"))] + list(body) ) # Rename function rename_func = Grab.nameAttribute(lambda name: f"test_{name}") # Chain multiple modifications: rename and add a pass statement modify_func = Grab.andDoAllOf([ Grab.nameAttribute(lambda n: f"new_{n}"), Grab.bodyAttribute(lambda b: list(b) + [Make.Pass()]) ]) # Use with NodeChanger to apply the chained modifications transformer = NodeChanger(Be.FunctionDef, modify_func) ``` -------------------------------- ### Destructive AST Transformation with NodeChanger Source: https://context7.com/hunterhogan/asttoolkit/llms.txt `NodeChanger` is designed for targeted AST modifications, extending `ast.NodeTransformer`. It allows for operations like renaming variables, replacing nodes, and removing nodes by applying actions based on defined predicates. ```python from astToolkit import NodeChanger, IfThis, Then, Make, Grab # Rename all occurrences of a variable renamer = NodeChanger( IfThis.isNameIdentifier("old_var"), Then.replaceWith(Make.Name("new_var")) ) renamed_tree = renamer.visit(tree) ``` -------------------------------- ### Access AST Node Attributes Safely using DOT Class Source: https://context7.com/hunterhogan/asttoolkit/llms.txt The DOT class offers type-safe, read-only accessors for AST node attributes. This prevents common errors associated with direct attribute access and provides a consistent interface for retrieving node properties. ```python from astToolkit import DOT, Be import ast # Assume 'tree' is a parsed AST for node in ast.walk(tree): if Be.FunctionDef(node): name = DOT.name(node) # Returns str args = DOT.args(node) # Returns ast.arguments body = DOT.body(node) # Returns list[ast.stmt] decorators = DOT.decorator_list(node) if Be.Call(node): func = DOT.func(node) # Returns ast.expr arguments = DOT.args(node) # Returns list[ast.expr] keywords = DOT.keywords(node) ``` -------------------------------- ### Remove Print Statements using NodeChanger Source: https://context7.com/hunterhogan/asttoolkit/llms.txt This snippet demonstrates how to remove all 'print' function calls from an AST using the NodeChanger class. It utilizes IfThis.isCallIdentifier to identify print calls and Then.removeIt to remove them. ```python from astToolkit import NodeChanger, IfThis, Then print_remover = NodeChanger( IfThis.isCallIdentifier("print"), Then.removeIt ) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.