Skip to content

Domain Model

The object graph produced by read_cl2. Aggregates (Meet, Club, Swimmer, the result types) are mutable with identity equality; the small value types are frozen and hashable.

models

Tunas domain model.

Aggregates (Meet, Club, Swimmer, MeetResult subclasses, RelaySwim) are slotted, keyword-only dataclasses with identity equality (eq=False) to support efficient single-pass parsing. Value types (Time, Split, SwimmerContact, SwimmerRegistration, MeetHost, SourceFile, ClubEntryCounts) are frozen and hashable.

Split dataclass

Split(
    distance: int, time: Time | None, split_type: SplitType
)

A split entry representing the swim time at a cumulative distance of a swim.

Attributes:

Name Type Description
distance int

Cumulative distance from start (50, 100, 150, etc.).

time Time | None

The split time, or None if present but unparseable.

split_type SplitType

Split representation style (INTERVAL or CUMULATIVE).

SwimmerContact dataclass

SwimmerContact(
    address: str | None = None,
    city: str | None = None,
    state: State | None = None,
    postal_code: str | None = None,
    country: Country | None = None,
    region: Region | None = None,
    alt_mailing_name: str | None = None,
    phone_primary: str | None = None,
    phone_secondary: str | None = None,
)

Contact details for a swimmer (contains PII).

Attributes:

Name Type Description
address str | None

Mailing street address.

city str | None

Mailing city.

state State | None

Mailing US state.

postal_code str | None

Mailing ZIP or postal code.

country Country | None

Mailing country code.

region Region | None

Geographic region code.

alt_mailing_name str | None

Alternate mailing recipient name.

phone_primary str | None

Primary contact phone number.

phone_secondary str | None

Secondary contact phone number.

SwimmerRegistration dataclass

SwimmerRegistration(
    member_status: MemberStatus | None = None,
    registration_date: date | None = None,
    season: Season | None = None,
    ethnicity_primary: Ethnicity | None = None,
    ethnicity_secondary: Ethnicity | None = None,
    affiliations: frozenset[Affiliation] = frozenset(),
    old_member_number: str | None = None,
    fina_other_federation: str | None = None,
    admin_info: str | None = None,
)

Registration and demographic details for a swimmer (contains sensitive PII).

Attributes:

Name Type Description
member_status MemberStatus | None

USS membership status (e.g. member, non-member).

registration_date date | None

Original registration date.

season Season | None

Swim season identifier.

ethnicity_primary Ethnicity | None

Primary ethnicity category.

ethnicity_secondary Ethnicity | None

Secondary ethnicity category.

affiliations frozenset[Affiliation]

Set of organizational affiliations.

old_member_number str | None

Historic member registration number.

fina_other_federation str | None

FINA federation identifier.

admin_info str | None

Administrative metadata or flags.

MeetHost dataclass

MeetHost(
    name: str | None = None,
    address_one: str | None = None,
    address_two: str | None = None,
    city: str | None = None,
    state: State | None = None,
    postal_code: str | None = None,
    country: Country | None = None,
    phone: str | None = None,
)

Meet host details from B2.

Attributes:

Name Type Description
name str | None

Name of the host organization.

address_one str | None

Primary mailing address.

address_two str | None

Secondary mailing address.

city str | None

City of the host.

state State | None

US state of the host.

postal_code str | None

Postal or ZIP code.

country Country | None

Country code.

phone str | None

Host contact phone number.

SourceFile dataclass

SourceFile(
    path: str | None = None,
    file_type: FileType | None = None,
    sdif_version: str | None = None,
    software_name: str | None = None,
    software_version: str | None = None,
    contact_name: str | None = None,
    contact_phone: str | None = None,
    created: date | None = None,
    submitted_by_lsc: LSC | None = None,
    notes: str | None = None,
    hy3_file_type: Hy3FileType | None = None,
    created_time: time | None = None,
    licensee: str | None = None,
)

File-level metadata from a results file's header/terminator.

Fields are sourced from SDIF A0/Z0 records or, for .hy3 files, the A1 record. The hy3_* fields and created_time/licensee are only populated by :func:~tunas.read_hy3; the SDIF-only fields are only populated by :func:~tunas.read_cl2.

Attributes:

Name Type Description
path str | None

Original file path or stream label.

file_type FileType | None

Coded SDIF file type.

sdif_version str | None

SDIF version string.

software_name str | None

Generating software product name.

software_version str | None

Generating software version.

contact_name str | None

Contact person for the file.

contact_phone str | None

Contact phone number.

created date | None

Date the file was generated.

submitted_by_lsc LSC | None

LSC that submitted or processed the file.

notes str | None

Arbitrary text notes or comments.

hy3_file_type Hy3FileType | None

Coded Hy-Tek file type.

created_time time | None

Time the file was generated.

licensee str | None

Organization licensed to run the software.

ClubEntryCounts dataclass

ClubEntryCounts(
    num_individual_swims: int | None = None,
    num_athletes: int | None = None,
    num_relay_entries: int | None = None,
    num_relay_name_records: int | None = None,
    num_split_records: int | None = None,
)

Entry counts from a C2 record.

Attributes:

Name Type Description
num_individual_swims int | None

Expected individual-swim count.

num_athletes int | None

Expected athlete count.

num_relay_entries int | None

Expected relay-entry count.

num_relay_name_records int | None

Expected relay-swimmer record count.

num_split_records int | None

Expected split-time record count.

Swim

Bases: ABC

Abstract base class for a swimmer's swim (IndividualSwim or RelaySwim).

Declares no instance fields to prevent slotted layout conflicts. Both subclasses expose a uniform interface (swimmer, time, status, session, event, date, meet, course, swimmer_age_class, splits, is_relay_leg).

is_relay_leg abstractmethod property
is_relay_leg: bool

True for a RelaySwim, False for an IndividualSwim.

MeetResult dataclass

MeetResult(
    *,
    meet: Meet,
    club: Club | None,
    organization: Organization | None,
    session: Session,
    event: Event,
    event_min_age: int | None,
    event_max_age: int | None,
    event_sex: Sex,
    status: ResultStatus,
    time: Time | None,
    date: date | None,
    event_number: str | None = None,
    heat: int | None = None,
    lane: int | None = None,
    rank: int | None = None,
    points: float | None = None,
    seed_time: Time | None = None,
    seed_course: Course | None = None,
    event_min_time_class: EventTimeClass | None = None,
    event_max_time_class: EventTimeClass | None = None,
    dq_code: str | None = None,
    dq_reason: str | None = None,
    converted_seed_time: Time | None = None,
    converted_seed_course: Course | None = None,
    backup_times: tuple[Time, ...] = (),
)

Base class for a meet result row (IndividualSwim or Relay).

Attributes:

Name Type Description
meet Meet

Meet this result belongs to.

club Club | None

Club the swimmer or squad represents.

organization Organization | None

Governing body code (e.g. USA Swimming).

session Session

Meet session (prelims, finals, swim-offs).

event Event

The swum event.

event_min_age int | None

Minimum age restriction for the event.

event_max_age int | None

Maximum age restriction for the event.

event_sex Sex

Sex category for the event.

status ResultStatus

The result status (OK, DQ, scratch, etc.).

time Time | None

The final swim time, or None if no time was recorded/OK.

date date | None

Date the event was swum.

event_number str | None

Coded event number.

heat int | None

Swum heat number.

lane int | None

Swum lane number.

rank int | None

Official place finish.

points float | None

Scored points.

seed_time Time | None

Entry/seed time.

seed_course Course | None

Entry/seed course.

event_min_time_class EventTimeClass | None

Minimum entry time class required.

event_max_time_class EventTimeClass | None

Maximum entry time class.

dq_code str | None

2-character Hy-Tek DQ code (e.g. "3D").

dq_reason str | None

Human-readable DQ description.

converted_seed_time Time | None

Seed time converted to the meet's course (Hy-Tek only).

converted_seed_course Course | None

Seed course converted to the meet's course (Hy-Tek only).

backup_times tuple[Time, ...]

Watch or manual backup times (Hy-Tek only).

IndividualSwim dataclass

IndividualSwim(
    *,
    meet: Meet,
    club: Club | None,
    organization: Organization | None,
    session: Session,
    event: Event,
    event_min_age: int | None,
    event_max_age: int | None,
    event_sex: Sex,
    status: ResultStatus,
    time: Time | None,
    date: date | None,
    event_number: str | None = None,
    heat: int | None = None,
    lane: int | None = None,
    rank: int | None = None,
    points: float | None = None,
    seed_time: Time | None = None,
    seed_course: Course | None = None,
    event_min_time_class: EventTimeClass | None = None,
    event_max_time_class: EventTimeClass | None = None,
    dq_code: str | None = None,
    dq_reason: str | None = None,
    converted_seed_time: Time | None = None,
    converted_seed_course: Course | None = None,
    backup_times: tuple[Time, ...] = (),
    swimmer: Swimmer,
    swimmer_age_class: str | None = None,
    attach_status: AttachStatus = ATTACHED,
    splits: list[Split] = list(),
)

Bases: MeetResult, Swim

Result of an individual swim event.

Attributes:

Name Type Description
swimmer Swimmer

Swimmer who produced this result.

swimmer_age_class str | None

Coded age class at the time of the swim.

attach_status AttachStatus

Attached or unattached status.

splits list[Split]

Cumulative splits recorded for this swim.

is_relay_leg property
is_relay_leg: bool

Always False.

course property
course: Course | None

Swim course (derived from the event).

Relay dataclass

Relay(
    *,
    meet: Meet,
    club: Club | None,
    organization: Organization | None,
    session: Session,
    event: Event,
    event_min_age: int | None,
    event_max_age: int | None,
    event_sex: Sex,
    status: ResultStatus,
    time: Time | None,
    date: date | None,
    event_number: str | None = None,
    heat: int | None = None,
    lane: int | None = None,
    rank: int | None = None,
    points: float | None = None,
    seed_time: Time | None = None,
    seed_course: Course | None = None,
    event_min_time_class: EventTimeClass | None = None,
    event_max_time_class: EventTimeClass | None = None,
    dq_code: str | None = None,
    dq_reason: str | None = None,
    converted_seed_time: Time | None = None,
    converted_seed_course: Course | None = None,
    backup_times: tuple[Time, ...] = (),
    relay_letter: str,
    total_age: int | None = None,
    legs: list[RelaySwim] = list(),
    alternates: list[RelaySwim] = list(),
    splits: list[Split] = list(),
)

Bases: MeetResult

Squad relay result (the legs are RelaySwims).

Attributes:

Name Type Description
relay_letter str

Squad designation letter (e.g. "A", "B").

total_age int | None

Combined age of all squad members.

legs list[RelaySwim]

Ordered list of swimmers who raced (positions 1-4).

alternates list[RelaySwim]

Roster alternates who did not race.

splits list[Split]

Whole-relay cumulative split times (e.g. 50/100/150/200).

RelaySwim dataclass

RelaySwim(
    *,
    swimmer: Swimmer | None,
    relay: Relay,
    order: RelayLegOrder | None = None,
    time: Time | None = None,
    status: ResultStatus = OK,
    takeoff_time: int | None = None,
    course: Course | None = None,
    swimmer_age_class: str | None = None,
    citizenship: CitizenshipOrCountry | None = None,
)

Bases: Swim

A swimmer's relay leg or roster slot.

Attributes:

Name Type Description
swimmer Swimmer | None

The rostered swimmer, or None if unnamed.

relay Relay

The parent Relay result row.

order RelayLegOrder | None

Leg sequence or alternate order.

time Time | None

Time swum on this specific leg, or None.

status ResultStatus

The leg's result status.

takeoff_time int | None

Hundredths of a second takeoff reaction time.

course Course | None

Course code (derived or stored).

swimmer_age_class str | None

Coded age class at the time of the swim.

citizenship CitizenshipOrCountry | None

Citizenship or country code.

is_relay_leg property
is_relay_leg: bool

Always True.

event property
event: Event | None

Individual event swum on this leg (e.g., FREE_100_SCY).

splits property
splits: list[Split]

This leg's splits, derived from the relay's whole-relay cumulative splits.

Both readers store splits on the relay row (:attr:Relay.splits) as whole-relay cumulative marks (e.g. 50/100/150/200 for a 4×50). A leg's splits are the marks swum during that leg, re-based to the leg start so the leg reads like a flat-start swim: distances count from 0 and a cumulative time is measured from the leg's takeoff. (Interval splits keep their per-segment time; only the distance is re-based.)

Empty when there is nothing to derive — the relay carries no splits, the slot is an alternate / has no leg number, or no relay mark falls within this leg's distance window.

date property
date: date | None

Date of the swim (parent relay date).

meet property
meet: Meet

Meet this leg belongs to.

session property
session: Session

Session of the swim.

Swimmer dataclass

Swimmer(
    *,
    meet: Meet,
    first_name: str,
    last_name: str,
    sex: Sex,
    id_short: str | None = None,
    id_long: str | None = None,
    middle_initial: str | None = None,
    preferred_first_name: str | None = None,
    birthday: date | None = None,
    citizenship: CitizenshipOrCountry | None = None,
    contact: SwimmerContact | None = None,
    registration: SwimmerRegistration | None = None,
    club: Club | None = None,
    swims: list[IndividualSwim | RelaySwim] = list(),
)

A swimmer scoped to one meet.

Attributes:

Name Type Description
meet Meet

The meet this swimmer is registered for.

first_name str

The swimmer's first name.

last_name str

The swimmer's last name.

sex Sex

The swimmer's sex.

id_short str | None

12-character short ID (USS#).

id_long str | None

14-character new long ID.

middle_initial str | None

Swimmer's middle initial.

preferred_first_name str | None

Swimmer's preferred first name.

birthday date | None

Swimmer's birthday.

citizenship CitizenshipOrCountry | None

Citizenship or country code.

contact SwimmerContact | None

Swimmer contact details (contains PII).

registration SwimmerRegistration | None

Swimmer registration details (contains PII).

club Club | None

The club the swimmer belongs to at this meet.

swims list[IndividualSwim | RelaySwim]

List of individual and relay swims for this swimmer at the meet.

individual_swims property
individual_swims: list[IndividualSwim]

Swimmer's individual swims.

relay_swims property
relay_swims: list[RelaySwim]

Swimmer's counting relay legs (excluding alternates).

full_name property
full_name: str

Combined first, middle initial, and last name.

swims_in
swims_in(event: Event) -> list[IndividualSwim | RelaySwim]

Swims for an individual event in source order.

Source code in src/tunas/models.py
def swims_in(self, event: Event) -> list[IndividualSwim | RelaySwim]:
    """Swims for an individual event in source order."""
    return [s for s in self.swims if s.event == event]

Club dataclass

Club(
    *,
    meet: Meet,
    organization: Organization | None,
    team_code: str,
    lsc: LSC | None = None,
    full_name: str | None = None,
    abbreviated_name: str | None = None,
    address_one: str | None = None,
    address_two: str | None = None,
    city: str | None = None,
    state: State | None = None,
    postal_code: str | None = None,
    country: Country | None = None,
    region: Region | None = None,
    coach: str | None = None,
    coach_phone: str | None = None,
    short_name: str | None = None,
    email: str | None = None,
    entry_counts: ClubEntryCounts | None = None,
    results: list[MeetResult] = list(),
    swimmers: list[Swimmer] = list(),
)

A club scoped to one meet, keyed by (team_code, lsc).

Attributes:

Name Type Description
meet Meet

The meet this club is scoped to.

organization Organization | None

Governing body code.

team_code str

Unique code identifying the team.

lsc LSC | None

Local Swimming Committee code.

full_name str | None

Full team/club name.

abbreviated_name str | None

Shortened club name.

address_one str | None

Primary club address.

address_two str | None

Secondary club address.

city str | None

Club city.

state State | None

Club US state.

postal_code str | None

ZIP or postal code.

country Country | None

Country code.

region Region | None

Geographic region code.

coach str | None

Head coach name.

coach_phone str | None

Coach contact phone.

short_name str | None

Alternate short name.

email str | None

Contact email address.

entry_counts ClubEntryCounts | None

Official entry counts from the file.

results list[MeetResult]

Club's individual and relay results at the meet.

swimmers list[Swimmer]

Swimmers representing this club at the meet.

individual_swims property
individual_swims: list[IndividualSwim]

Club's individual-event results at the meet.

relays property
relays: list[Relay]

Club's relay results at the meet.

Meet dataclass

Meet(
    *,
    organization: Organization | None,
    name: str,
    start_date: date,
    end_date: date | None = None,
    city: str | None = None,
    address_one: str | None = None,
    state: State | None = None,
    address_two: str | None = None,
    postal_code: str | None = None,
    country: Country | None = None,
    course: Course | None = None,
    altitude: int | None = None,
    meet_type: MeetType | None = None,
    venue: str | None = None,
    age_up_date: date | None = None,
    sanction_number: str | None = None,
    host: MeetHost | None = None,
    source_file: SourceFile | None = None,
    results: list[MeetResult] = list(),
    swimmers: list[Swimmer] = list(),
    clubs: list[Club] = list(),
)

A single swimming meet containing clubs, swimmers, and results.

Attributes:

Name Type Description
organization Organization | None

Governing body hosting the meet.

name str

Name of the meet.

start_date date

Start date of the competition.

end_date date | None

End date of the competition.

city str | None

City where the meet took place.

address_one str | None

Primary venue address.

state State | None

US state where the meet took place.

address_two str | None

Secondary venue address.

postal_code str | None

Venue postal or ZIP code.

country Country | None

Venue country code.

course Course | None

Course code (SCY, SCM, LCM).

altitude int | None

Venue altitude in feet or meters.

meet_type MeetType | None

Meet classification code.

venue str | None

Facility or pool name.

age_up_date date | None

Age-determination date for the meet.

sanction_number str | None

Meet sanction identifier.

host MeetHost | None

Host details.

source_file SourceFile | None

Metadata of the file this meet was parsed from.

results list[MeetResult]

All individual and relay results at this meet.

swimmers list[Swimmer]

All athletes registered at this meet.

clubs list[Club]

All clubs registered at this meet.

individual_swims property
individual_swims: list[IndividualSwim]

All individual-event results at the meet.

relays property
relays: list[Relay]

All relay results at the meet.

individual_swims_for
individual_swims_for(event: Event) -> list[IndividualSwim]

Individual swims for an event in source order.

Source code in src/tunas/models.py
def individual_swims_for(self, event: Event) -> list[IndividualSwim]:
    """Individual swims for an event in source order."""
    return [r for r in self.individual_swims if r.event == event]
relays_for
relays_for(event: Event) -> list[Relay]

Relays for an event in source order.

Source code in src/tunas/models.py
def relays_for(self, event: Event) -> list[Relay]:
    """Relays for an event in source order."""
    return [r for r in self.relays if r.event == event]