def METHOD_NAME(fields: List[pa.Field], deep: bool = True) -> List[pa.Field]:
    """
    Converts a list of Arrow Fields into non-nullable (i.e. required, not optional)
    fields. This function will recurse down into nested types (List, Struct) if 
    deep is True. Otherwise, a shallow copy will result where lists and nested
    types may contain optional fields.
    :param fields: list of fields to make required
    :param deep: whether to produce a deep copy
    :return: new fields that are required
    """
    new_fields = []
    for field in fields:
        if type(field.type) == pa.StructType and deep:
            struct_fields = [field.type[i]
                             for i in range(field.type.num_fields)]
            # Recurse
            new_struct_fields = METHOD_NAME(struct_fields)
            new_fields.append(pa.field(field.name, pa.struct(
                new_struct_fields), False, metadata=field.metadata))
        elif type(field.type) == pa.ListType and deep:
            # Recurse
            list_type = [field.type.value_field]
            new_list_type = METHOD_NAME(list_type)
            new_fields.append(pa.field(field.name, pa.list_(
                new_list_type[0]), False, metadata=field.metadata))
        else:
            new_fields.append(pa.field(field.name, field.type,
                                       False, metadata=field.metadata))
    return new_fields