# Find the most called functionmost_called = max(codebase.functions, key=lambda f: len(f.call_sites))print(f"\nMost called function: {most_called.name}")print(f"Called {len(most_called.call_sites)} times from:")for call in most_called.call_sites: print(f" - {call.parent_function.name} at line {call.start_point[0]}")# Find function that makes the most callsmost_calls = max(codebase.functions, key=lambda f: len(f.function_calls))print(f"\nFunction making most calls: {most_calls.name}")print(f"Makes {len(most_calls.function_calls)} calls to:")for call in most_calls.function_calls: print(f" - {call.name}")# Find functions with no callers (potential dead code)unused = [f for f in codebase.functions if len(f.call_sites) == 0]print(f"\nUnused functions:")for func in unused: print(f" - {func.name} in {func.filepath}")# Find recursive functionsrecursive = [f for f in codebase.functions if any(call.name == f.name for call in f.function_calls)]print(f"\nRecursive functions:")for func in recursive: print(f" - {func.name}")
The Argument class represents values passed to a function, while Parameter represents the receiving variables in the function definition:Consider the following code:
# Get the function callcall = file.function_calls[0]# Working with argumentsfor arg in call.args: print(f"Arg {arg.index}: {arg.value}") # Access argument value print(f"Is named: {arg.is_named}") # Check if it's a kwarg print(f"Name: {arg.name}") # For kwargs, e.g. "debug" # Get corresponding parameter if param := arg.parameter: print(f"Parameter type: {param.type}") print(f"Is optional: {param.is_optional}") print(f"Has default: {param.default}")# Finding specific argumentsdebug_arg = call.get_arg_by_parameter_name("debug")first_arg = call.get_arg_by_index(0)
# Adding new argumentscall.args.append('cloud="aws"') # Add a new keyword argumentcall.args.append('"value"') # Add a new positional argument# Real-world example: Adding arguments to a decorator@app.function(image=runner_image)def my_func(): pass# Add cloud and region if not presentif "cloud=" not in decorator.call.source: decorator.call.args.append('cloud="aws"')if "region=" not in decorator.call.source: decorator.call.args.append('region="us-east-1"')
The set_kwarg method provides intelligent argument manipulation:
If the argument exists and is positional, it converts it to a keyword argument
If the argument exists and is already a keyword, it updates its value (if override_existing=True)
If the argument doesn’t exist, it creates it (if create_on_missing=True)
When creating new arguments, it intelligently places them based on parameter order
Arguments and parameters support safe edit operations like so:
Copy
Ask AI
# Modifying argumentsdebug_arg.edit("False") # Change argument valuefirst_arg.add_keyword("input_data") # Convert to named argument# modifying parametersparam = codebase.get_function('process_data').get_parameter('debug')param.rename('_debug') # updates all call-sitesparam.set_type_annotation('bool')
You can find the parent function of the helper call:
Copy
Ask AI
# Manipulation code:# Find the helper() callhelper_call = file.get_function("outer").function_calls[1]# Get containing functionparent = helper_call.parent_functionprint(f"Call is inside: {parent.name}") # 'inner'# Get the full call hierarchyouter = parent.parent_functionprint(f"Which is inside: {outer.name}") # 'outer'
# Manipulation code:# Get the `limit` call in the chainlimit_call = next(f for f in file.function.function_calls if f.name == "limit", None)# Navigate backwards through the chainorder_by = limit_call.predecessorwhere = order_by.predecessorselect = where.predecessor# Get the full chain at oncechain = limit_call.call_chain # [select, where, order_by, limit]# Access the root objectbase = limit_call.base # Returns the 'query' object# Check call relationshipsprint(f"After {order_by.name}: {limit_call.name}")print(f"Before {where.name}: {select.name}")