Code editing task: documentation
Topic: Language; change kind: corrective

Original code:
import ast

from typing import Tuple

def build_documentation(code: str) -> Tuple[str, str]:
    results = []
    parsed_ast = ast.parse(code)
    def visit_FunctionDef(node: ast.FunctionDef) -> None:
        name = node.name
        args_node = node.args
        return_annotation = node.returns
        if return_annotation is None:
            return_annotation = "None"
        else:
            return_annotation = return_annotation.id
        args = []
        for arg in args_node.args:
            args.append(f"{arg.arg}: {arg.annotation}")
        function_signature = f"{name}({', '.join(args)}): {return_annotation}"
        docstring = ast.get_docstring(node)
        if docstring is None:
            docstring = ""
        results.append((function_signature, docstring))
    for node in ast.walk(parsed_ast):
        if isinstance(node, ast.FunctionDef):
            visit_FunctionDef(node)
    
    return results

Instruction (descriptive):
Handle the case that a type annotation does not exist on an arg. To do this, check if the type annotation exists first, and prepend ": " to the label if so.

Instruction (lazy):
Handle the case that a type annotation does not exist on an arg

Edited code:
import ast

from typing import Tuple

def build_documentation(code: str) -> Tuple[str, str]:
    results = []
    parsed_ast = ast.parse(code)
    def visit_FunctionDef(node: ast.FunctionDef) -> None:
        name = node.name
        args_node = node.args
        return_annotation = node.returns
        if return_annotation is None:
            return_annotation = "None"
        else:
            return_annotation = return_annotation.id
        args = []
        for arg in args_node.args:
            type_annotation = arg.annotation if arg.annotation is not None else ""
            if type_annotation != "":
                type_annotation = ": " + type_annotation.id
            args.append(f"{arg.arg}{type_annotation}")
        function_signature = f"{name}({', '.join(args)}): {return_annotation}"
        docstring = ast.get_docstring(node)
        if docstring is None:
            docstring = ""
        results.append((function_signature, docstring))
    for node in ast.walk(parsed_ast):
        if isinstance(node, ast.FunctionDef):
            visit_FunctionDef(node)
    
    return results

Tests:
### START TESTS ###
if True: # pragma: no cover
    code = '''def test_function_no_args():
    """This is a test function with no arguments."""
    pass

def test_function_with_args(arg1, arg2) -> str:
    """Test function with arguments."""
    return ""

def add(a, b) -> int:
    return a + b

def add_typed(a: int, b: int) -> int:
    """
    Add two integers together.
    """
    return a + b'''

    expected = [
        ('test_function_no_args(): None', 'This is a test function with no arguments.'),
        ('test_function_with_args(arg1, arg2): str', 'Test function with arguments.'),
        ('add(a, b): int', ''),
        ('add_typed(a: int, b: int): int', "Add two integers together.")
    ]
    results = build_documentation(code)

    assert len(results) == len(expected), "Number of extracted functions does not match expected."
    for result, exp in zip(results, expected):
        assert result[0] == exp[0], f"Function signature does not match expected. Got {result[0]}, expected {exp[0]}"
        assert result[1] == exp[1], f"Docstring does not match expected. Got {result[1]}, expected {exp[1]}"