Your squad¶
The thing most people want from a save is their own squad: who is at the club, how good they are, what they are paid and when their deals run out. This page goes from a file on disk to that, in about twenty lines.
Open the save¶
import fmsave
with fmsave.open("career.fm") as career_save:
my_club = career_save.managed_clubs()[0] # empty when you are between jobs
squad = career_save.players().where(club_uid=my_club.club_uid)
fmsave.open is a context manager. Call the readers you need inside the with block; asking a
closed save for another table raises SaveClosedError. The records and tables themselves keep
working after the save closes, so you can carry squad out of the block and use it for the rest
of the program.
players() returns every player in the save, which for a running career is well over a hundred
thousand. where(club_uid=...) cuts that to one club. A club’s players are everyone it
registers, youth and B teams included; team_id and team_slot tell its teams apart.
Sort it¶
best = squad.sorted_by(lambda player: player.ability.current, reverse=True)
for player in best[:5]:
print(player.name, player.age, player.ability.current, player.ability.potential)
# "Alex Example" 24 148 165
A slice of a Table is a Table, and tables are immutable, so sorted_by hands back a new
table and leaves the original alone.
Read a player¶
player = best[0]
player.attributes.finishing # 16
player.attributes.determination # 17
player.positions.stc # 20
player.natural_positions # ("STC", "AMC")
player.personality.professionalism
player.contract.wage # 34500
player.contract.end # datetime.date(2029, 6, 30)
attributes holds all 52 attributes on the 1 to 20 display scale, from crossing and passing
to handling and reflexes for a goalkeeper. positions rates the fifteen position slots on the
same scale, and natural_positions is the shorthand for the ones rated 18 or better.
ability carries current and potential, reputation carries four figures, and personality
carries the eight personality attributes.
Wages and transfer values come back in the unit the save stores them in, which is not the currency the game displays. fmsave does not convert them.
Some fields are coded values: they carry both the number the save holds and the label fmsave reads it as.
status = player.contract.squad_status
status.label # SquadStatus.STAR_PLAYER, the reading
status.raw # 1, the number the save holds
A value fmsave cannot read is None rather than a guess. Before you lean on a field, check
whether it is verified. See Trusting a number.
Narrow it down¶
squad.where(on_loan=True)
squad.filter(lambda player: player.age <= 21 and player.ability.potential >= 150)
squad.find(name="Alex Example")
where(**fields)matches top-level fields for equality. Flat column names such ascontract_wageare not field names; usefilterfor anything nested.filter(predicate)takes any function of a record.find(name=...)looks a person up by name and raisesAmbiguousNameErrorwhen more than one matches, rather than picking one for you.
Passing an enum label to a coded-value field matches every record carrying that label:
with fmsave.open("career.fm") as career_save:
starters = career_save.contracts().where(squad_status=fmsave.SquadStatus.STAR_PLAYER)
Out to pandas, CSV or JSON¶
frame = squad.to_pandas() # needs fmsave[pandas]
frame[["name", "age", "ability_current", "contract_wage"]].head()
squad.write_csv("squad.csv")
The DataFrame and the CSV use flat column names: nested groups become ability_current,
contract_wage, attributes_finishing. Getting data out covers the rest of the
formats, the flattening rules, and doing the same job from the command line.
The rest of the club¶
The squad is one table of twenty-six. The same club uid opens the others:
with fmsave.open("career.fm") as career_save:
club_uid = career_save.managed_clubs()[0].club_uid
staff = career_save.staff().where(club_uid=club_uid)
finances = career_save.finances().where(club_uid=club_uid)
injuries = career_save.injuries().where(club_uid=club_uid)
What a save holds lists all twenty-six, and is honest about what none of them can give you.