import re


def extract_params(text):
    """
    Function used to extract parameters from a function docstring.

    Parameters
    ----------
    text : str
        Parameters section of a function docstring. For example what you are
        reading right now is within the parameters section of the extract_params
        docstring.

    Returns
    -------
    params : dict
        Dictionary containing all parameters found and their descriptions,
        datatypes, and whether they are optional or not.
    """
    # this will match a parameter name, type, and description
    param_re = re.compile(r"(?s)\w+ : .*?(?=\w+ :)")
    # the above will not find the final parameter, this will
    param_re2 = re.compile(r"(?s)\w+ : .*")
    # initialise parameter dictionary
    params = {}
    while True:
        new_param = param_re.search(text)
        # print(new_param)
        if new_param is None:
            # if no parameters have been found, try with modified regex
            new_param = param_re2.search(text)
            if new_param is None:
                # if we still cannot find any new parameters, break
                break
        # extract text
        new_param = new_param.group()

        # split by newline character
        new_param = new_param.split("\n")

        # first line is param name and description, get both
        name, dtype = new_param[0].split(":")

        # formatting description
        desc = "\n".join(new_param[1:])
        desc = re.sub(r"\s+", " ", desc)

        # check if a parameter is optional
        if "optional" in dtype:
            dtype = dtype.split(",")[0]
            optional = True
        else:
            optional = False

        # add parameter details to params dictionary
        params[name.strip()] = {"dtype": dtype.strip(), "description": desc.strip(), "optional": optional}

        text = text.replace("\n".join(new_param), "")

    return params