Skip to content

Library reference

Generated from the source. Each docstring names the Chadwick C function it translates.

Parser, games and files (Chadwick's cwlib)

chadwickpy.parse

Port of Chadwick's play-text parser (src/cwlib/parse.c).

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later. This module is a Python translation of its parser, so it is a derivative work and keeps that notice. Function names map one-to-one onto the C functions (cw_parse_x -> _x) so the two can be read side by side. Where the C code has quirks (a shared token buffer, return value 0 meaning both "batter out" and "invalid", fixed-size arrays) the quirk is kept on purpose: the goal is byte-identical cwevent output.

Ev

Bases: IntEnum

CWEventType. Codes 0-24 are the Retrosheet event codes.

EventData dataclass

CWEventData: everything the play text alone says about the play.

is_batter(e)

cw_event_is_batter

is_official_ab(e)

cw_event_is_official_ab

outs_on_play(e)

cw_event_outs_on_play

parse_event(text)

cw_parse_event: parse play text into :class:EventData.

Returns the (possibly half-filled, as in C) data and whether it parsed.

rbi_on_play(e)

cw_event_rbi_on_play

runner_put_out(e, base)

cw_event_runner_put_out

runs_on_play(e)

cw_event_runs_on_play

chadwickpy.game

Port of Chadwick's game container (src/cwlib/game.c, reading side).

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice. It follows cw_game_read: events carry the substitutions, comments and adjustment records (badj, padj, ladj, radj, presadj) that appear after them in the file.

Appearance dataclass

CWAppearance: a start or sub record.

Comment dataclass

CWComment: a com record, with the ej, and umpchange, fields split out.

Event dataclass

CWEvent: one play record plus what trails it.

Game dataclass

CWGame

comment_append(text)

cw_game_comment_append: to the last event, or the game before any event

data_append(data)

cw_game_data_append

data_set_er(player_id, er)

cw_game_data_set_er: set the earned runs of a pitcher's data,er record

evdata_append(data)

cw_game_evdata_append

event_append(inning, batting_team, batter, count, pitches, event_text)

cw_game_event_append

info_append(label, data)

cw_game_info_append

info_lookup(label)

cw_game_info_lookup: the last info record with this label.

info_set(label, data)

cw_game_info_set: replace the first record with this label, else append.

(info_lookup reads the last one; the C is inconsistent and so is this.)

line_append(data)

cw_game_line_append

replace_player(key_old, key_new)

cw_game_replace_player: every use of the id, in the order the C visits them

set_version(version)

cw_game_set_version

starter_append(player_id, name, team, slot, pos)

cw_game_starter_append

starter_by_position(team, pos)

cw_game_starter_find_by_position

starter_find(team, slot)

cw_game_starter_find

stat_append(data)

cw_game_stat_append

substitute_append(player_id, name, team, slot, pos)

cw_game_substitute_append: to the last event

truncate(event)

cw_game_truncate: drop event and every event after it

count_pitches(pitches, criterion)

cw_pitch_count_pitches

event_comment_append(event, text)

cw_event_comment_append: a comment on an event, with no ej,/umpchange, parsing

pitch_ball_thrown(c)

cw_pitch_ball_thrown

pitch_strike_thrown(c)

cw_pitch_strike_thrown

read_game(file)

cw_game_read: the next game, or None at the end of the file or on a bad header.

read_games(data)

Every game cw_game_read returns from the file contents, as cwevent reads them.

Reading stops, as in Chadwick, when cw_game_read returns NULL. If bytes are left unread then (a file not starting with an id record, say) a warning is logged, because Chadwick stops there without a message.

chadwickpy.gameiter

Port of Chadwick's game iterator (src/cwlib/gameiter.c).

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice. Names map onto the C functions (cw_gamestate_x -> State.x or a module function) so the two can be read side by side.

Unset C pointers (NULL strings) are None here.

Appearance dataclass

CWAppearance: a start or sub record.

GameIter

CWGameIterator

copy()

cw_gameiter_copy

future_runs()

cwevent_future_runs: runs scored after this play in the half inning.

next()

cw_gameiter_next

runner_fate(base)

cw_gameiter_runner_fate: where the runner on base ends up.

truncated_pa()

cwevent_truncated_pa_flag

Runner dataclass

One entry of CWGameState.runners; base 0 is the batter-runner.

Slot dataclass

One lineup entry (CWLineupEntry).

State dataclass

CWGameState

base_occupied(base)

cw_gamestate_base_occupied

change_sides(event)

cw_gamestate_change_sides

charged_batter_hand(batter, d, off_roster, def_roster)

cw_gamestate_charged_batter_hand

copy()

cw_gamestate_copy

lineup_slot(team, player_id)

cw_gamestate_lineup_slot: search from slot 9 down to prefer batting-order slots.

player_position(team, player_id)

cw_gamestate_player_position

runner_position(team, player_id)

cw_gamestate_runner_position: the position associated with a runner, without the batted-around adjustment used for the batter's PH/PR statistics.

substitute(batter, count, player_id, name, team, slot, pos)

cw_gamestate_substitute

update(batter, d)

cw_gamestate_update

chadwickpy.roster

Port of Chadwick's src/cwlib/roster.c and league.c (reading side).

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice.

A TEAMyyyy file lists the teams of a season (league.c); each team has a <team><year>.ROS roster file (roster.c) giving the players' batting and throwing hands, which cwevent prints for players without a badj/padj.

League dataclass

CWLeague: the rosters named in a team file

read(data)

cw_league_read: append a roster per line of a TEAMyyyy file's contents

roster_append(roster)

cw_league_roster_append

roster_find(team)

cw_league_roster_find

Player dataclass

CWPlayer

set_first_name(name)

cw_player_set_first_name

set_last_name(name)

cw_player_set_last_name

Roster dataclass

CWRoster

player_append(player)

cw_roster_player_append

player_count()

cw_roster_player_count

player_find(player_id)

cw_roster_player_find

player_insert(player)

cw_roster_player_insert: before the first player whose id is not smaller (strcmp)

read(data)

cw_roster_read: append the players of a .ROS file's contents

set_city(city)

cw_roster_set_city

set_league(league)

cw_roster_set_league

set_nickname(nickname)

cw_roster_set_nickname

roster_batting_hand(roster, player_id)

cw_roster_batting_hand: ? when the roster or the player is unknown

roster_throwing_hand(roster, player_id)

cw_roster_throwing_hand

chadwickpy.box

Port of Chadwick's boxscore builder (src/cwlib/box.c and box.h).

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice. Names map onto the C functions (cw_box_x -> x) so the two can be read side by side.

Data layout follows box.h. Players and pitchers stay doubly linked (slots[slot][team] and pitchers[team] point at the current entry; walk prev for earlier ones), because Chadwick's tools walk them that way. The notable-event lists (b2_list ...) are plain Python lists in file order instead of linked lists. Unset C pointers are None.

Where the C ends the program (exit(1)) or dereferences NULL, this port raises ValueError; messages Chadwick prints to stderr go to logging.

BoxBatting dataclass

CWBoxBatting

BoxEvent dataclass

CWBoxEvent: a notable event (extra-base hit, wild pitch, ...).

BoxFielding dataclass

CWBoxFielding

BoxPitcher

CWBoxPitcher: a pitcher's entry in the boxscore.

__init__(player_id, name)

cw_box_pitcher_create

BoxPitching dataclass

CWBoxPitching

BoxPlayer

CWBoxPlayer: a player's entry in the boxscore.

__init__(player_id, name)

cw_box_player_create

add_position(pos)

positions[num_positions++] = pos (the C array has 40 entries and no check)

Boxscore

CWBoxscore

add_event(events, inning, half, *players)

cw_box_add_event: players are the count strings of its variable arguments.

add_substitute(box, gi)

cw_box_add_substitute: add a substitute into a slot

batter_stats(box, gi)

cw_box_batter_stats: update batter/pitcher stats with the current play

box_create(game)

cw_box_create: compile a boxscore for game

enter_starters(box, game)

cw_box_enter_starters: initialize slots with starting players

fielder_stats(box, gi)

cw_box_fielder_stats: update fielding stats with the current play

find_current_player(box, player_id, batting_only)

cw_box_find_current_player

Unlike find_player this only searches, and returns, entries from among players currently in the game. That matters when building the boxscore, in the case of an illegal (or sanctioned but unorthodox) re-entry of a player in a different lineup slot.

find_pitcher(box, player_id)

cw_box_find_pitcher (strcmp against NULL is undefined; it never matches here)

find_player(box, player_id, batter)

cw_box_find_player

If batter, search only batting entries; this implements the 'Ohtani rule' for DHes, in which a player who DHes for himself has two identities within the game, one in the batting order and one as the DHed-for pitcher.

get_fielding(player, pos)

player->fielding[pos] for a position taken from the data.

The C does not check pos. Retrosheet writes a missing or unreadable position as -1, and fielding[-1] is then the 8 bytes just before the array: positions[38] and positions[39] of the same struct. The C survives and never reads those back as positions, so the port keeps such entries in stray_fielding. (Positions 10 and up would overwrite the prev/next links, which the port cannot mimic, so they raise.)

get_starter(box, team, slot)

cw_box_get_starter: the starter for team in batting order position slot

get_starting_pitcher(box, team)

cw_box_get_starting_pitcher

iterate_game(box, game)

cw_box_iterate_game: iterate through the game, building the boxscore

pitch_stats(box, gi)

cw_box_pitch_stats: update pitch stats with the current event

Called even for NP events, as pitches may occur prior to a substitution. Only counts pitches following the last period in the pitch string.

process_boxscore_file(box, game)

cw_box_process_boxscore_file

In these files, all the statistical information is stored in extended stat records.

put_fielding(player, pos, value)

player->fielding[pos] = value; see :func:get_fielding.

runner_stats(box, gi)

cw_box_runner_stats: update baserunning stats with the current play

set_position_slot(player, index, value)

player->positions[index] = value for an index taken from the data (seq - 1).

Retrosheet writes an unreadable sequence number as -1, so index is -2. In the C struct the four ints in front of positions are ph_inn, pr_inn, num_positions and start_position, so positions[-1] is start_position, [-2] is num_positions, [-3] is pr_inn and [-4] is ph_inn: the write lands on that field.

chadwickpy.book

Port of Chadwick's src/cwlib/book.c (cw_scorebook_read) and cw_file_find_first_game.

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice.

Scorebook dataclass

CWScorebook: the leading comments of an event file and its games

append_game(game)

cw_scorebook_append_game: False (nothing done) for NULL

insert_game(game)

cw_scorebook_insert_game: before the first game not earlier by date, then number

iterate(f=None)

cw_scorebook_iterate / _iterator_next: games for which f is true

read(data)

cw_scorebook_read: the number of games read, or -1 for an empty file

remove_game(game_id)

cw_scorebook_remove_game: the first game with this id, or None

find_first_game(file)

cw_file_find_first_game: rewind, then stop at the first line that begins id

scorebook_read(data)

cw_scorebook_read: every game of an event file, or None where C returns -1.

None is the "could not open file" case of cwtools_process_scorebook: an empty file.

chadwickpy.file

Port of the reading helpers in Chadwick's src/cwlib/file.c.

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice.

Chadwick 0.11.0 reads event, roster and team files with a record reader (CWRecordReader) and splits each line with a tokenizer (CWTokenizer). Both are reproduced here, including the quirks that decide what a file means: a line may be any length, every is dropped wherever it stands (so CRLF and CR-only breaks inside a line vanish), a last line with no trailing newline is read like any other, and text is handled as C strings, so a NUL byte ends a line. Text is held as latin-1 so that one byte is one character, as in C.

CFile

The part of a C FILE * that the record reader uses on a file.

getline()

cw_record_reader_next: the next line without its and without any .

    Returns ``None`` at the end of the file: ``cw_getline`` reports -1 when the end was
    reached with nothing kept, which includes a final stretch of nothing but ``

. The end-of-file flag is set when the read ran into the end of the data, asfeof`` is.

getpos()

fgetpos

setpos(pos)

fsetpos: also clears the end-of-file flag

ReportedError

Bases: ValueError

The C prints this message itself (on stderr) and calls exit(1).

The port logs the message and raises this, so the command line ends with status 1 without printing the message a second time.

Tokenizer

CWTokenizer: split a line on commas, honouring a quote at the start of a field.

tok(line) is cw_tokenizer_init followed by the first cw_tokenizer_next; tok(None) is a further cw_tokenizer_next. The C tokenizer writes a NUL over each comma or closing quote that ends a field, so the line it was given afterwards reads as the text up to the first such NUL; :meth:line_text gives that text, which the "invalid record" warning prints.

line_text()

The line as the C sees it after tokenizing: up to the first NUL written so far

next()

cw_tokenizer_next

cw_atoi(text, msg=None)

cw_atoi: strtol with validity checking; -1 (Retrosheet's null) when invalid.

Like strtol, it skips leading white space, accepts a sign, and stops at the first non-digit, so trailing text is ignored. Only a string with no digits at all, or a value outside int, is invalid.

scan_int(text, pos=0)

One %d conversion of sscanf at pos: (value, position after it), or None when no integer is there (sscanf then stops and leaves its outputs unset)

The tools (Chadwick's cwtools)

chadwickpy.tools.events

Port of Chadwick's cwevent field logic (src/cwtools/cwevent.c).

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice. One function per cwevent field, in the same order, producing the text cwevent -q (quoted/ascii mode) prints for that field. Rows are dicts keyed by the cwevent column names.

0.11.0 prints every string field through cw_buffer_emit_string, which turns a NULL into "" (0.10 passed it to %s, which glibc prints as "(null)"); None renders "" here.

event_lines(data, league=None, game_id='', first_date='0101', last_date='1231', ascii_=True, fields=DEFAULT_FIELDS, ext_fields=())

Lines for the selected games of an event file, as cwevent prints them.

event_rows(data, league=None, game_id='', first_date='0101', last_date='1231')

Rows for the selected games of an event file, as cwevent -q -f 0-96 -x 0-66 does.

league holds the rosters read from the team file; without it every hand not given by a badj/padj record is ?.

game_lines(game, visitors=None, home=None, ascii_=True, fields=DEFAULT_FIELDS, ext_fields=())

cwevent_process_game: one output line per non-NP event of the game

game_rows(game, visitors=None, home=None)

cwevent_process_game: one row per non-NP event of the game.

header_line(fields, ext_fields)

cwevent_initialize with -n: the quoted column names (ascii format only)

chadwickpy.tools.tools

Port of the parts of Chadwick's src/cwtools/cwtools.c that every tool shares.

Chadwick is Copyright (c) 2002-2026 Dr T L Turocy and the Chadwick Baseball Bureau, licensed GPL-2.0-or-later; this module is a derivative of it and keeps that notice.

cwtools.c is the driver of cwevent, cwgame and the other tools: it reads the team file and rosters, reads each event file as a scorebook, picks the games the options select, and hands each game with its two rosters to the tool. Reading files from disk and the command line are left to the caller; these functions take bytes.

cut_at_nul(row)

printf("%s") of an output row stops at the first NUL byte that a field wrote.

date_digits(date, indices=(0, 1, 2, 3, 5, 6, 8, 9))

The eight characters cwgame_date and cwdaily_date print: date[0..3], [5], [6], [8], [9] (YYYYMMDD for a YYYY/MM/DD date), read with %c and no length check.

For a date shorter than 10 characters the C reads the string's terminating NUL, which is in bounds, as one of those characters. printf("%s") then stops at it, so the text ends there and the rest of the output row is lost. The result holds that NUL (the caller cuts the row at it). Where the C would read beyond the terminator the bytes are leftovers, so that raises. indices are the characters read, in print order (cwgame has several date formats).

game_in_range(game, first, last)

cwtools_game_in_range: is the game's month and day between first and last

iterate_games(data, league=None, game_id='', first='0101', last='1231')

cwtools_process_scorebook + cwtools_iterate_games: the selected games of one event file with the visiting and home rosters (None where the team is not in the team file).

An empty file yields nothing (Chadwick prints "could not open file").

read_rosters(team_file, year, roster_file)

cwtools_read_rosters: the team file, then each team's <team><year>.ROS if present.

roster_file is given a file name and returns its contents, or None where Chadwick's fopen fails; a missing roster file is silently skipped, as in Chadwick.

select_game(game, game_id='', first='0101', last='1231')

cwtools_select_game