-
-
Notifications
You must be signed in to change notification settings - Fork 10
Option to just see signatures #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub&rdqu 8000 o;, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Here's what I need for this:
|
For classes I think I need to do the same thing with
|
Almost got this working. I'm not sure how to differentiate between: def cli(
symbols,
files,
directories,
signatures,
silent
): And: def cli(
symbols,
files,
directories,
signatures,
silent): I can't see a mechanism for detecting if the closing Might be better to reconstruct the function definition from the node.args? |
If the function has a
|
The hacky way to do this would be to look for the line that ends with Don't want to get confused by this though: def foo(): return 1 |
Plus, |
I had this, which I had 50% written myself (based on an example spat out by GPT-4 earlier): def function_definition(function_node: AST):
function_name = function_node.name
arguments = []
for arg in function_node.args.args:
if getattr(arg.annotation, "id", None):
arguments.append(f"{arg.arg}: {arg.annotation.id}")
else:
arguments.append(arg.arg)
arguments_str = ", ".join(arguments)
return_annotation = ""
if function_node.returns:
if hasattr(function_node.returns, "id"):
return_annotation = f" -> {function_node.returns.id}"
elif function_node.returns.value is None:
# None shows as returns.value is None
return_annotation = " -> None"
return f"def {function_name}({arguments_str}){return_annotation}" And I ran this: symbex function_definition | llm --system 'rewrite this to handle default arguments, keyword-only arguments, varargs and other edge-cases' -m 4 I got back: def function_definition(function_node: AST):
function_name = function_node.name
arguments, default_arg_index = [], 0
for arg in function_node.args.args:
arg_str = f"{arg.arg}: {arg.annotation.id}" if getattr(arg.annotation, "id", None) else arg.arg
if default_arg_index < len(function_node.args.defaults):
arg_str += f"={repr(function_node.args.defaults[default_arg_index])}"
default_arg_index += 1
arguments.append(arg_str)
varargs = [f"*{arg.arg}: {arg.annotation.id}" for arg in function_node.args.vararg] if function_node.args.vararg else []
kwargs = [
f"{arg.arg}={repr(arg.default)}: {arg.annotation.id}"
if getattr(arg.annotation, "id", None)
else f"{arg.arg}={repr(arg.default)}"
for arg in function_node.args.kwonlyargs
]
combined_arguments = arguments + varargs + kwargs
arguments_str = ", ".join(combined_arguments)
return_annotation = ""
if function_node.returns:
if hasattr(function_node.returns, "id"):
return_annotation = f" -> {function_node.returns.id}"
elif function_node.returns.value is None:
return_annotation = " -> None"
return f"def {function_name}({arguments_str}){return_annotation}" This looked impressive on first glance, but it's not actually good enough code - nested list comprehensions are hard to understand and it didn't survive robust testing. |
Generating some test code with ChatGPT:
# Function with no arguments
def func_no_args():
pass
# Function with positional arguments
def func_positional_args(a, b, c):
pass
# Function with default arguments
def func_default_args(a, b=2, c=3):
pass
# Function with arbitrary number of positional arguments
def func_arbitrary_positional_args(*args):
pass
# Function with arbitrary number of keyword arguments
def func_arbitrary_keyword_args(**kwargs):
pass
# Function with both arbitrary positional and keyword arguments
def func_arbitrary_args(*args, **kwargs):
pass
# Function with positional-only arguments (Python 3.8 and above)
def func_positional_only_args(a, /, b, c):
pass
# Function with keyword-only arguments
def func_keyword_only_args(*, a, b, c):
pass
# Function with type annotations (Python 3.5 and above)
def func_type_annotations(a: int, b: str) -> bool:
pass
# Class with no base classes
class ClassNoBase:
pass
# Class with a single base class
class ClassSingleBase(int):
pass
# Class with multiple base classes
class ClassMultipleBase(int, str):
pass
# Class with a metaclass
class ClassWithMeta(metaclass=type):
pass |
This is absurdly useful.
|
I generated fixtures like this:
Output: ("func_no_args", "def func_no_args()"),
("func_positional_args", "def func_positional_args(a, b, c)"),
("func_default_args", "def func_default_args(a, b=2, c=3)"),
("func_arbitrary_positional_args", "def func_arbitrary_positional_args(*args)"),
("func_arbitrary_keyword_args", "def func_arbitrary_keyword_args(**kwargs)"),
("func_arbitrary_args", "def func_arbitrary_args(*args, **kwargs)"),
("func_positional_only_args", "def func_positional_only_args(a, /, b, c)"),
("func_keyword_only_args", "def func_keyword_only_args(*, a, b, c)"),
("func_type_annotations", "def func_type_annotations(a: int, b: str) -> bool"),
("ClassNoBase", "class ClassNoBase:"),
("ClassSingleBase", "class ClassSingleBase(int):"),
("ClassMultipleBase", "class ClassMultipleBase(int, str):"),
("ClassWithMeta", "class ClassWithMeta(metaclass=type):") |
I'm a bit stuck on this one: # Function with default arguments
def func_default_args(a, b=2, c=3):
pass In the debugger:
I'm not sure how to match up the I guess it's based purely on indexing from the end - if there are two defaults and three args then the last two args must be the ones with defaults. |
I tried using this to see if there were any obvious gaps in the function, but I couldn't figure out a prompt that didn't just show me invalid Python function examples instead:
|
A way to search and just get the function or class first line definitions.
Not sure what to do about multiline function definitions.
The text was updated successfully, but these errors were encountered: