def METHOD_NAME(covariate_definitions, rows):
    """
    Create a DataFrame from an iterator of rows
    """
    convertors = {
        name: get_pandas_convertor(funcname, **kwargs)
        for name, (funcname, kwargs) in covariate_definitions.items()
    }
    # `patient_id` isn't included in `covariate_definitions` so we need to add
    # it manually
    convertors["patient_id"] = int
    # First row is expected to be header row
    headers = next(rows)
    convertor_funcs = [convertors[column] for column in headers]
    def convert_row(row):
        new_row = []
        for convertor, value, header in zip(convertor_funcs, row, headers):
            try:
                new_row.append(convertor(value))
            except Exception:
                # add some debugging context that pandas error wont have
                logger.error(
                    f"pandas error converting column {header} with converter {convertor} with values {value}"
                )
                raise
        return new_row
    data = map(convert_row, rows)
    df = pandas.DataFrame(data, columns=headers)
    # Change categorical columns from arrays of ints to proper Pandas
    # Categorical objects
    for column in headers:
        convertor = convertors[column]
        if isinstance(convertor, Categoriser):
            categorical = pandas.Categorical.from_codes(
                df[column], categories=convertor.get_categories(), ordered=False
            )
            df[column] = categorical
    return df