Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/backend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
env:
DJANGO_SETTINGS_MODULE: config.settings
run: |
pytest lineups/tests.py accounts/tests.py roster/tests.py simulator/tests.py --cov=lineups --cov=accounts --cov=roster --cov=simulator --cov-report=xml --cov-report=term-missing
pytest lineups/tests.py accounts/tests.py roster/tests/ simulator/tests.py --cov=lineups --cov=accounts --cov=roster --cov=simulator --cov-report=xml --cov-report=term-missing

- name: Check for security vulnerabilities in dependencies
run: |
Expand Down
5 changes: 5 additions & 0 deletions backend/.coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ omit =
*/venv/*
*/.venv/*
*/env/*
manage.py
config/asgi.py
config/wsgi.py
*/tests_*.py


[report]
exclude_lines =
Expand Down
2 changes: 1 addition & 1 deletion backend/config/settings_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": ":memory:",
"NAME": BASE_DIR / "db.sqlite3",
}
}
4 changes: 2 additions & 2 deletions backend/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[pytest]
DJANGO_SETTINGS_MODULE = config.settings
DJANGO_SETTINGS_MODULE = config.settings_test
python_files = tests.py test_*.py *_tests.py
python_classes = Test*
python_functions = test_*
Expand All @@ -8,7 +8,7 @@ addopts =
--strict-markers
--tb=short
--reuse-db
--ds=config.settings
--ds=config.settings_test
--cov=.
--cov-report=term-missing
--cov-report=html
Expand Down
5 changes: 2 additions & 3 deletions backend/roster/management/commands/import_test_data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.core.management.base import BaseCommand, CommandError

from roster.services.importer import import_from_csv
from roster.services.player_import import PlayerImportService


class Command(BaseCommand):
Expand Down Expand Up @@ -30,8 +30,7 @@ def handle(self, *args, **options):
dry_run = options.get("dry_run")

try:
result = import_from_csv(
path, team_id=team_id_arg, dry_run=dry_run)
result = PlayerImportService.import_from_csv(path, team_id=team_id_arg, dry_run=dry_run)
except FileNotFoundError:
raise CommandError(f"File not found: {path}")

Expand Down
87 changes: 43 additions & 44 deletions backend/roster/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,58 @@ class Player(models.Model):
name = models.CharField(max_length=100, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
team = models.ForeignKey(
Team,
on_delete=models.CASCADE,
related_name="players",
null=True,
blank=True,
)
team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="players", null=True, blank=True)

# Baseball Savant (2025) batter stats snapshot
# Note: These are per-season aggregates
savant_player_id = models.PositiveIntegerField(
null=True, blank=True) # External player_id
year = models.PositiveIntegerField(
null=True, blank=True) # Season year (e.g., 2025)
# Note: These are per-season aggregates; if you later want multi-year history,
# Stat explanations from: https://baseballsavant.mlb.com/leaderboard/custom?year=2025&type=batter&filter=&min=q&selections=pa%2Chome_run%2Ck_percent%2Cbb_percent%2Cslg_percent%2Con_base_percent%2Cisolated_power%2Cr_total_stolen_base%2Cwoba%2Cxwoba%2Cbarrel_batted_rate%2Chard_hit_percent%2Csprint_speed&chart=false&x=pa&y=pa&r=no&chartType=beeswarm&sort=1&sortDir=desc
savant_player_id = models.PositiveIntegerField(null=True, blank=True) # External player_id
year = models.PositiveIntegerField(null=True, blank=True) # Season year (e.g., 2025)
ab = models.PositiveIntegerField(null=True, blank=True) # At bat count
pa = models.PositiveIntegerField(
null=True, blank=True) # Plate appearances
pa = models.PositiveIntegerField(null=True, blank=True) # Plate appearances
hit = models.PositiveIntegerField(null=True, blank=True) # Total hits
single = models.PositiveIntegerField(null=True, blank=True) # Singles
double = models.PositiveIntegerField(null=True, blank=True) # Doubles
triple = models.PositiveIntegerField(null=True, blank=True) # Triples
home_run = models.PositiveIntegerField(null=True, blank=True) # Home runs
strikeout = models.PositiveIntegerField(
null=True, blank=True) # Strikeouts
strikeout = models.PositiveIntegerField(null=True, blank=True) # Strikeouts
walk = models.PositiveIntegerField(null=True, blank=True) # Walks - BB
# K%: Frequency of strikeouts per plate appearance
k_percent = models.FloatField(null=True, blank=True)
# BB%: Frequency of walks per plate appearance
bb_percent = models.FloatField(null=True, blank=True)
# SLG: Slugging percentage - total bases per at-bat
slg_percent = models.FloatField(null=True, blank=True)
# OBP: On-base percentage - how often batter reaches base
on_base_percent = models.FloatField(null=True, blank=True)
# ISO: Isolated power - extra bases per at-bat (pure power)
isolated_power = models.FloatField(null=True, blank=True)
# TB: Total bases
b_total_bases = models.FloatField(null=True, blank=True)
# CS: Caught Stealing
r_total_caught_stealing = models.FloatField(null=True, blank=True)
# SB: Stolen bases
r_total_stolen_base = models.FloatField(null=True, blank=True)
# G: Games played
b_game = models.FloatField(null=True, blank=True)
# GIDP: Grounded Into Double Play
b_gnd_into_dp = models.FloatField(null=True, blank=True)
# HBP: Hit by pitch
b_hit_by_pitch = models.FloatField(null=True, blank=True)
# IBB: Intentional walk
b_intent_walk = models.FloatField(null=True, blank=True)
# SH: Sacrifice bunt
b_sac_bunt = models.FloatField(null=True, blank=True)
# SF: Sacrifice fly
b_sac_fly = models.FloatField(null=True, blank=True)
k_percent = models.FloatField(null=True, blank=True) # Frequency of strikeouts per plate appearance - K% = (SO / PA) * 100
bb_percent = models.FloatField(null=True, blank=True) # Frequency of walks per plate appearance - BB% = (BB / PA) * 100
slg_percent = models.FloatField(
null=True, blank=True
) # Measures total bases per at-bat, emphasizes extra-base hits - SLG = (1B + 2*2B + 3*3B + 4*HR) / AB
on_base_percent = models.FloatField(
null=True, blank=True
) # On-base percentage: Measures how often a batter reaches base safely - OBP = (H + BB + HBP) / (AB + BB + HBP + SF)
isolated_power = models.FloatField(
null=True, blank=True
) # Shows extra bases per at-bat (pure power) - ISO = SLG - AVG | (AVG = H / AB)
b_total_bases = models.FloatField(
null=True, blank=True
) # TB: Total bases - 1 x Singles + 2 x Doubles + 3 x Triples + 4 x Home Runs
r_total_caught_stealing = models.FloatField(
null=True, blank=True
) # CS: Caught Stealing - When a runner is put out by the defense while attempting to steal a base
r_total_stolen_base = models.FloatField(
null=True, blank=True
) # SB: Stolen bases - Count of successful stolen base attempts
b_game = models.FloatField(null=True, blank=True) # G: Games played - Total games played in a season
b_gnd_into_dp = models.FloatField(
null=True, blank=True
) # GIPD: Grounded Into Double Play - Counts the times a batter hits a ground ball that results in two outs in one continuous play
b_hit_by_pitch = models.FloatField(
null=True, blank=True
) # HPB: A hit-by-pitch occurs when a batter is struck by a pitched ball without swinging at it.
b_intent_walk = models.FloatField(
null=True, blank=True
) # IBB: Intentional Base on Balls / Intentional walk - A strategic play where the defending team deliberately allows a batter to reach first base without having to swing at a pitch.
b_sac_bunt = models.FloatField(
null=True, blank=True
) # SH: Sacrfice bunt: Occurs when a batter deliberately bunts the ball to advance a baserunner, usually at the cost of being put out themselves
b_sac_fly = models.FloatField(
null=True, blank=True
) # SF: Sacrifice Fly - Occurs when a batter hits a deep fly ball that is caught by an outfielder (or an infielder playing in the outfield), but a baserunner on third base tags up and scores before the play is over.

class Meta:
db_table = "players"
Expand Down
2 changes: 0 additions & 2 deletions backend/roster/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,8 @@ class Meta(PlayerSerializer.Meta):
"id",
"name",
"team",
"xwoba",
"bb_percent",
"k_percent",
"barrel_batted_rate",
"wos_score",
]

Expand Down
169 changes: 0 additions & 169 deletions backend/roster/services/importer.py

This file was deleted.

Loading