(encoder, datum, schema, named_schemas, fname)
A union is encoded by first writing a long value indicating the
    zero-based position within the union of the schema of its value. The value
    is then encoded per the indicated schema within the union.
A union is encoded by first writing a long value indicating the
    zero-based position within the union of the schema of its value. The value
    is then encoded per the indicated schema within the union.
A union is encoded by first writing a long value indicating the zero - based position within the union of the schema of its value . The value is then encoded per the indicated schema within the union .
def write_union(encoder, datum, schema, named_schemas, fname):
    """A union is encoded by first writing a long value indicating the
    zero-based position within the union of the schema of its value. The value
    is then encoded per the indicated schema within the union."""

    best_match_index = -1
    if isinstance(datum, tuple):
        (name, datum) = datum
        for index, candidate in enumerate(schema):
            extracted_type = extract_record_type(candidate)
            if extracted_type in NAMED_TYPES:
                schema_name = candidate["name"]
            else:
                schema_name = extracted_type
            if name == schema_name:
                best_match_index = index
                break

        if best_match_index == -1:
            field = f"on field {fname}" if fname else ""
            msg = (
                f"provided union type name {name} not found in schema "
                + f"{schema} {field}"
            )
            raise ValueError(msg)
        index = best_match_index
    else:
        pytype = type(datum)
        most_fields = -1

        # All of Python's floating point values are doubles, so to
        # avoid loss of precision, we should always prefer 'double'
        # if we are forced to choose between float and double.
        #
        # If 'double' comes before 'float' in the union, then we'll immediately
        # choose it, and don't need to worry. But if 'float' comes before
        # 'double', we don't want to pick it.
        #
        # So, if we ever see 'float', we skim through the rest of the options,
        # just to see if 'double' is a possibility, because we'd prefer it.
        could_be_float = False

        for index, candidate in enumerate(schema):

            if could_be_float:
                if extract_record_type(candidate) == "double":
                    best_match_index = index
                    break
                else:
                    # Nothing except "double" is even worth considering.
                    continue

            if _validate(datum, candidate, named_schemas, raise_errors=False):
                record_type = extract_record_type(candidate)
                if record_type == "record":
                    logical_type = extract_logical_type(candidate)
                    if logical_type:
                        prepare = LOGICAL_WRITERS.get(logical_type)
                        if prepare:
                            datum = prepare(datum, candidate)

                    candidate_fields = set(f["name"] for f in candidate["fields"])
                    datum_fields = set(datum)
                    fields = len(candidate_fields.intersection(datum_fields))
                    if fields > most_fields:
                        best_match_index = index
                        most_fields = fields
                elif record_type == "float":
                    best_match_index = index
                    # Continue in the loop, because it's possible that there's
                    # another candidate which has record type 'double'
                    could_be_float = True
                else:
                    best_match_index = index
                    break
        if best_match_index == -1:
            field = f"on field {fname}" if fname else ""
            raise ValueError(
                f"{repr(datum)} (type {pytype}) do not match {schema} {field}"
            )
        index = best_match_index

    # write data
    # TODO: There should be a way to give just the index
    encoder.write_index(index, schema[index])
    write_data(encoder, datum, schema[index], named_schemas, fname)
def write_union ( encoder , datum , schema , named_schemas , fname ) : best_match_index = - 1 if isinstance ( datum , tuple ) : ( name , datum ) = datum for index , candidate in enumerate ( schema ) : extracted_type = extract_record_type ( candidate ) if extracted_type in NAMED_TYPES : schema_name = candidate [ "name" ] else : schema_name = extracted_type if name == schema_name : best_match_index = index break if best_match_index == - 1 : field = f"on field {fname}" if fname else "" msg = ( f"provided union type name {name} not found in schema " + f"{schema} {field}" ) raise ValueError ( msg ) index = best_match_index else : pytype = type ( datum ) most_fields = - 1 # All of Python's floating point values are doubles, so to # avoid loss of precision, we should always prefer 'double' # if we are forced to choose between float and double. # # If 'double' comes before 'float' in the union, then we'll immediately # choose it, and don't need to worry. But if 'float' comes before # 'double', we don't want to pick it. # # So, if we ever see 'float', we skim through the rest of the options, # just to see if 'double' is a possibility, because we'd prefer it. could_be_float = False for index , candidate in enumerate ( schema ) : if could_be_float : if extract_record_type ( candidate ) == "double" : best_match_index = index break else : # Nothing except "double" is even worth considering. continue if _validate ( datum , candidate , named_schemas , raise_errors = False ) : record_type = extract_record_type ( candidate ) if record_type == "record" : logical_type = extract_logical_type ( candidate ) if logical_type : prepare = LOGICAL_WRITERS . get ( logical_type ) if prepare : datum = prepare ( datum , candidate ) candidate_fields = set ( f [ "name" ] for f in candidate [ "fields" ] ) datum_fields = set ( datum ) fields = len ( candidate_fields . intersection ( datum_fields ) ) if fields > most_fields : best_match_index = index most_fields = fields elif record_type == "float" : best_match_index = index # Continue in the loop, because it's possible that there's # another candidate which has record type 'double' could_be_float = True else : best_match_index = index break if best_match_index == - 1 : field = f"on field {fname}" if fname else "" raise ValueError ( f"{repr(datum)} (type {pytype}) do not match {schema} {field}" ) index = best_match_index # write data # TODO: There should be a way to give just the index encoder . write_index ( index , schema [ index ] ) write_data ( encoder , datum , schema [ index ] , named_schemas , fname )