def get_values(source, dest, extra=None):
        """
        Get a list of the configuration parameters and their defaults.
        """

        def get_value(value):
            """
            Get the actual value from the ast allowing recursion
            """
            class_name = value.__class__.__name__
            # if this is a literal then get its value
            value_type = AST_LITERAL_TYPES.get(class_name)
            if value_type:
                attr_value = getattr(value, value_type)
            else:
                if class_name == "Dict":
                    attr_value = {
                        get_value(k): get_value(v)
                        for k, v in zip(value.keys, value.values)
                    }
                elif class_name == "List":
                    attr_value = [get_value(e) for e in value.elts]
                elif class_name == "Name":
                    # in python 2 True, False, None are Names rather than
                    # NameConstant so we use them for the default
                    default = python2_names.get(value.id)
                    attr_value = extra.get(value.id, default)
                elif class_name == "Tuple":
                    attr_value = tuple(get_value(e) for e in value.elts)
                elif class_name == "UnaryOp":
                    op = value.op.__class__.__name__
                    attr_value = get_value(value.operand)
                    # we only understand negation
                    if op == "USub":
                        attr_value = -attr_value
                    else:
                        attr_value = f"UNKNOWN {class_name} UnaryOp {op}"
                elif class_name == "BinOp":
                    left = get_value(value.left)
                    right = get_value(value.right)
                    op = value.op.__class__.__name__
                    try:
                        if op == "Add":
                            attr_value = left + right
                        elif op == "Mult":
                            attr_value = left * right
                        else:
                            attr_value = f"UNKNOWN {class_name} BinOp {op}"
                    except Exception:
                        attr_value = f"UNKNOWN {class_name} BinOp error"
                else:
                    attr_value = f"UNKNOWN {class_name}"
            return attr_value

        if extra is None:
            extra = {}

        for line in source:
            if isinstance(line, ast.Assign):
                if len(line.targets) == 1 and isinstance(line.targets[0], ast.Name):
                    attr = line.targets[0].id
                    value = line.value
                    dest[attr] = get_value(value)

        Get a list of the configuration parameters and their defaults.
        
tests/test_module_doc.py