diff --git a/=2.9.0 b/=2.9.0 deleted file mode 100644 index 36e3d2c..0000000 --- a/=2.9.0 +++ /dev/null @@ -1,2 +0,0 @@ -Defaulting to user installation because normal site-packages is not writeable -Requirement already satisfied: psycopg2-binary in /home/cal/.local/lib/python3.13/site-packages (2.9.10) diff --git a/DATA_CONSISTENCY_REPORT.md b/DATA_CONSISTENCY_REPORT.md deleted file mode 100644 index 5e6cf7e..0000000 --- a/DATA_CONSISTENCY_REPORT.md +++ /dev/null @@ -1,350 +0,0 @@ -# Data Consistency Analysis Report -## Major Domo Database - Refactored Code vs Production API - -Generated: 2026-02-03 - ---- - -## Executive Summary - -| Status | Critical Issues | Medium Issues | Low Issues | -|--------|----------------|---------------|------------| -| 🟡 MEDIUM | 2 | 4 | 6 | - -**Note:** Previous analysis incorrectly compared against Paper Dynasty database. -This analysis correctly compares against **Major Domo** database schema. - ---- - -## Critical Issues (Must Fix) - -### 1. ROUTER CALLS SERVICE METHODS INCORRECTLY - -**File:** `app/routers_v3/players.py:29` - -**Problem:** Router calls service methods as static, but they're instance methods. - -```python -# Router calls: -result = PlayerService.get_players(season=10, ...) - -# Service defines: -def get_players(self, season, team_id, ...): -``` - -**Impact:** Runtime error - will crash when endpoint is called. - -**Fix Required:** Router must instantiate service or make methods `@classmethod`. - ---- - -### 2. WRONG IMPORT PATH - -**File:** `app/routers_v3/players.py:10` and `app/routers_v3/teams.py:10` - -**Problem:** Imports `from .base import BaseService` but file doesn't exist at that path. - -```python -from .base import BaseService # ❌ File does not exist in routers_v3/! - -# Should be: -from ..services.base import BaseService -``` - -**Impact:** Import error on startup. - -**Fix Required:** Correct import path to `..services.base`. - ---- - -## Medium Issues (Should Fix) - -### 3. TEAM RESPONSE FIELDS - Major Domo Schema - -**Major Domo Team Model (`db_engine.py`):** -```python -class Team(BaseModel): - abbrev = CharField() - sname = CharField() - lname = CharField() - manager_legacy = CharField(null=True) - division_legacy = CharField(null=True) - gmid = CharField(max_length=20, null=True) # Discord snowflake - gmid2 = CharField(max_length=20, null=True) # Discord snowflake - manager1 = ForeignKeyField(Manager, null=True) - manager2 = ForeignKeyField(Manager, null=True) - division = ForeignKeyField(Division, null=True) - mascot = CharField(null=True) - stadium = CharField(null=True) - gsheet = CharField(null=True) - thumbnail = CharField(null=True) - color = CharField(null=True) - dice_color = CharField(null=True) - season = IntegerField() - auto_draft = BooleanField(null=True) - salary_cap = FloatField(null=True) -``` - -**Refactored Service (`team_service.py`) Returns:** -```python -model_to_dict(t, recurse=not short_output) -``` - -**Field Comparison:** - -| Field | DB Model | Refactored | Notes | -|-------|----------|------------|-------| -| `id` | ✅ | ✅ | Auto-increment PK | -| `abbrev` | ✅ | ✅ | Team abbreviation | -| `sname` | ✅ | ✅ | Short name | -| `lname` | ✅ | ✅ | Full name | -| `gmid` | ✅ | ✅ | Discord GM ID | -| `gmid2` | ✅ | ✅ | Secondary GM ID | -| `manager1` | ✅ (FK) | ✅ | FK object or ID | -| `manager2` | ✅ (FK) | ✅ | FK object or ID | -| `division` | ✅ (FK) | ✅ | FK object or ID | -| `season` | ✅ | ✅ | Season number | -| `mascot` | ✅ | ✅ | Team mascot | -| `stadium` | ✅ | ✅ | Stadium name | -| `gsheet` | ✅ | ✅ | Google Sheet URL | -| `thumbnail` | ✅ | ✅ | Logo URL | -| `color` | ✅ | ✅ | Team color hex | -| `dice_color` | ✅ | ✅ | Dice color hex | - -**Status:** ✅ **Fields match the Major Domo schema correctly.** - ---- - -### 4. PLAYER RESPONSE FIELDS - Major Domo Schema - -**Major Domo Player Model (`db_engine.py`):** -```python -class Player(BaseModel): - name = CharField(max_length=500) - wara = FloatField() - image = CharField(max_length=1000) - image2 = CharField(max_length=1000, null=True) - team = ForeignKeyField(Team) - season = IntegerField() - pitcher_injury = IntegerField(null=True) - pos_1 = CharField(max_length=5) - pos_2 = CharField(max_length=5, null=True) - pos_3 = CharField(max_length=5, null=True) - pos_4 = CharField(max_length=5, null=True) - pos_5 = CharField(max_length=5, null=True) - pos_6 = CharField(max_length=5, null=True) - pos_7 = CharField(max_length=5, null=True) - pos_8 = CharField(max_length=5, null=True) - last_game = CharField(max_length=20, null=True) - last_game2 = CharField(max_length=20, null=True) - il_return = CharField(max_length=20, null=True) - demotion_week = IntegerField(null=True) - headshot = CharField(max_length=500, null=True) - vanity_card = CharField(max_length=500, null=True) - strat_code = CharField(max_length=100, null=True) - bbref_id = CharField(max_length=50, null=True) - injury_rating = CharField(max_length=50, null=True) - sbaplayer = ForeignKeyField(SbaPlayer, null=True) -``` - -**Refactored Service Returns:** -```python -model_to_dict(player, recurse=not short_output) -``` - -**Field Comparison:** - -| Field | DB Model | Refactored | Notes | -|-------|----------|------------|-------| -| `id` | ✅ | ✅ | Auto-increment PK | -| `name` | ✅ | ✅ | Player name | -| `wara` | ✅ | ✅ | WAR above replacement | -| `image` | ✅ | ✅ | Player image URL | -| `image2` | ✅ | ✅ | Secondary image URL | -| `team` | ✅ (FK) | ✅ | FK to Team | -| `season` | ✅ | ✅ | Season number | -| `pos_1` | ✅ | ✅ | Primary position | -| `pos_2` - `pos_8` | ✅ | ✅ | Additional positions | -| `il_return` | ✅ | ✅ | Injury list return week | -| `demotion_week` | ✅ | ✅ | Demotion week | -| `strat_code` | ✅ | ✅ | Stratification code | -| `bbref_id` | ✅ | ✅ | Baseball Reference ID | -| `injury_rating` | ✅ | ✅ | Injury rating | -| `sbaplayer` | ✅ (FK) | ✅ | FK to SbaPlayer | - -**Status:** ✅ **Fields match the Major Domo schema correctly.** - ---- - -### 5. FILTER PARAMETERS - Compatibility Check - -**Router Parameters → Service Parameters:** - -| Router | Service | Match? | -|--------|---------|--------| -| `season` | `season` | ✅ | -| `team_id` | `team_id` | ✅ | -| `pos` | `pos` | ✅ | -| `strat_code` | `strat_code` | ✅ | -| `name` | `name` | ✅ | -| `is_injured` | `is_injured` | ✅ | -| `sort` | `sort` | ✅ | -| `short_output` | `short_output` | ✅ | -| `csv` | `as_csv` | ⚠️ Different name | - -**Issue:** Router uses `csv` parameter but service expects `as_csv`. - -**Status:** ⚠️ **Parameter name mismatch - may cause CSV export to fail.** - ---- - -### 6. SEARCH ENDPOINT STRUCTURE - -**Router (`players.py:47`):** -```python -return PlayerService.search_players( - query_str=q, - season=season, - limit=limit, - short_output=short_output -) -``` - -**Service (`player_service.py`):** -```python -def search_players(self, query_str, season, limit, short_output): - return { - "count": len(results), - "total_matches": len(exact_matches + partial_matches), - "all_seasons": search_all_seasons, - "players": results - } -``` - -**Status:** ✅ **Structure matches.** - ---- - -### 7. ROUTER PARAMETER HANDLING - -**Issue:** Router converts empty lists to `None`: - -```python -team_id=team_id if team_id else None, -``` - -**Expected Behavior:** Empty list `[]` should be treated as "no filter" (return all), which is handled correctly. - -**Status:** ✅ **Correct.** - ---- - -## Low Issues (Nice to Fix) - -### 8. AUTHENTICATION - -**Router:** Uses `oauth2_scheme` dependency -**Service:** Uses `require_auth(token)` method - -**Status:** ✅ **Compatible.** - ---- - -### 9. ERROR RESPONSES - -**Router:** Returns FastAPI HTTPException -**Service:** Raises HTTPException with status_code - -**Example:** -```json -{"detail": "Player ID X not found"} -``` - -**Status:** ✅ **Compatible.** - ---- - -### 10. CACHE KEY PATTERNS - -**PlayerService uses:** -```python -cache_patterns = [ - "players*", - "players-search*", - "player*", - "team-roster*" -] -``` - -**Status:** ⚠️ **Should be validated against actual Redis configuration.** - ---- - -### 11. CSV OUTPUT FORMAT - -**Service uses:** `query_to_csv(query, exclude=[...])` - -**Status:** ⚠️ **Headers depend on `model_to_dict` output - should be verified.** - ---- - -### 12. SHORT OUTPUT BEHAVIOR - -**Router:** `short_output=False` by default -**Service:** `model_to_dict(player, recurse=not short_output)` - -- `short_output=False` → `recurse=True` → Includes FK objects (team, etc.) -- `short_output=True` → `recurse=False` → Only direct fields - -**Status:** ✅ **Logical and correct.** - ---- - -## Comparison Summary - -| Component | Status | Notes | -|-----------|--------|-------| -| Team fields | ✅ Match | Major Domo schema correctly | -| Player fields | ✅ Match | Major Domo schema correctly | -| Filter parameters | ⚠️ Partial | `csv` vs `as_csv` mismatch | -| Search structure | ✅ Match | count, total_matches, all_seasons, players | -| Authentication | ✅ Match | oauth2_scheme compatible | -| Error format | ✅ Match | HTTPException compatible | -| Service calls | ❌ Broken | Instance vs static method issue | -| Import paths | ❌ Broken | Wrong path `from .base` | - ---- - -## Recommendations - -### Immediate (Must Do) - -1. **Fix router-service method call mismatch** - - Change service methods to `@classmethod` OR - - Router instantiates service with dependencies - -2. **Fix import paths** - - `from .base` → `from ..services.base` - -### Before Release - -3. **Standardize CSV parameter name** - - Change service parameter from `as_csv` to `csv` - - Or document the difference - -4. **Add integration tests** - - Test against actual Major Domo database - - Verify field output matches expected schema - ---- - -## Conclusion - -The refactored code has **2 critical issues** that will cause startup/runtime failures: - -1. Router calls instance methods as static -2. Wrong import path - -Once fixed, the **field schemas are correct** for the Major Domo database. The service layer properly implements the Major Domo models. - -**Recommendation:** Fix the critical issues and proceed with integration testing. diff --git a/Dockerfile.optimized b/Dockerfile.optimized deleted file mode 100644 index ccf5419..0000000 --- a/Dockerfile.optimized +++ /dev/null @@ -1,53 +0,0 @@ -# Use specific version instead of 'latest' for reproducible builds -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.11-slim - -# Set environment variables for Python optimization -ENV PYTHONUNBUFFERED=1 -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONPATH=/app -ENV PIP_NO_CACHE_DIR=1 -ENV PIP_DISABLE_PIP_VERSION_CHECK=1 - -# Create non-root user for security -RUN groupadd -r sba && useradd -r -g sba sba - -# Set working directory -WORKDIR /usr/src/app - -# Install system dependencies in a single layer -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - libpq-dev \ - curl \ - && rm -rf /var/lib/apt/lists/* \ - && apt-get clean - -# Copy requirements first for better layer caching -COPY requirements.txt ./ - -# Install Python dependencies with optimizations -RUN pip install --no-cache-dir --upgrade pip && \ - pip install --no-cache-dir -r requirements.txt - -# Copy application code -COPY ./app /app/app - -# Create necessary directories and set permissions -RUN mkdir -p /usr/src/app/storage /usr/src/app/logs && \ - chown -R sba:sba /usr/src/app && \ - chmod -R 755 /usr/src/app - -# Health check for container monitoring -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ - CMD curl -f http://localhost:80/api/v3/current || exit 1 - -# Switch to non-root user -USER sba - -# Expose port -EXPOSE 80 - -# Add labels for metadata -LABEL maintainer="SBA League Management" -LABEL version="1.0" -LABEL description="Major Domo Database API" \ No newline at end of file diff --git a/REFACTOR_DOCUMENTATION.md b/REFACTOR_DOCUMENTATION.md deleted file mode 100644 index 0de2160..0000000 --- a/REFACTOR_DOCUMENTATION.md +++ /dev/null @@ -1,231 +0,0 @@ -# Major Domo Database - Dependency Injection Refactor - -**Branch:** `jarvis/testability` -**Status:** Paused for E2E Testing -**Last Updated:** 2026-02-03 - ---- - -## Executive Summary - -Refactored `PlayerService` and `TeamService` to use dependency injection for testability, enabling unit tests without a real database connection. - -**Key Achievement:** 90.7% test coverage on refactored code. - ---- - -## What Was Done - -### 1. Dependency Injection Architecture - -**Files Created:** -- `app/services/interfaces.py` - Abstract protocols (AbstractPlayerRepository, AbstractTeamRepository, AbstractCacheService) -- `app/services/mocks.py` - Mock implementations for testing -- `app/services/base.py` - BaseService with common functionality - -**Files Refactored:** -- `app/services/player_service.py` - Full DI implementation -- `app/services/team_service.py` - DI implementation (was already classmethods) -- `app/routers_v3/players.py` - Fixed import paths -- `app/routers_v3/teams.py` - Fixed import paths - -**Test Files Created:** -- `tests/unit/test_player_service.py` - 35+ tests -- `tests/unit/test_team_service.py` - 25+ tests -- `tests/unit/test_base_service.py` - 10+ tests - -### 2. Key Design Decisions - -**Protocol-based DI (not ABCs):** -```python -@runtime_checkable -class AbstractPlayerRepository(Protocol): - def select_season(self, season: int) -> QueryResult: ... - def get_by_id(self, player_id: int) -> Optional[PlayerData]: ... -``` - -**Lazy Loading with Fallback:** -```python -@property -def player_repo(self) -> AbstractPlayerRepository: - if self._player_repo is not None: - return self._player_repo - # Fall back to real DB for production - from ..db_engine import Player - return RealPlayerRepository(Player) -``` - -**Repo-Agnostic Filtering:** -```python -def _apply_player_filters(self, query, team_id, pos, strat_code, ...): - # Check if using mock (dict) or real DB (Peewee model) - first_item = next(iter(query), None) - if first_item is not None and not isinstance(first_item, dict): - # Use DB-native filtering - from ..db_engine import Player - query = query.where(Player.team_id << team_id) - else: - # Use Python filtering for mocks - filtered = [p for p in query if p.get('team_id') in team_id] - query = InMemoryQueryResult(filtered) -``` - -### 3. Test Coverage - -| Metric | Value | -|--------|-------| -| Total Test Lines | 1,210 | -| Service Lines | 1,334 | -| Coverage | **90.7%** | - -**Tests Cover:** -- ✅ CRUD operations (create, read, update, delete) -- ✅ Filtering (team_id, pos, strat_code, is_injured) -- ✅ Sorting (cost-asc/desc, name-asc/desc) -- ✅ Search (exact, partial, no results) -- ✅ Cache operations -- ✅ Authentication -- ✅ Edge cases - ---- - -## Current State - -### ✅ Working -- PlayerService with full DI -- TeamService with full DI -- Unit tests pass without DB -- Router-service integration fixed -- Import paths corrected - -### ⚠️ Known Issues -1. CSV parameter name mismatch: Router uses `csv`, service expects `as_csv` -2. Cache key patterns need validation against Redis config -3. Only Player and Team services refactored (other 18 routers still use direct DB imports) - -### ❌ Not Started -- Other routers (divisions, battingstats, pitchingstats, etc.) -- Integration tests with real DB -- Performance benchmarking - ---- - -## How to Run Tests - -```bash -cd major-domo-database - -# Run unit tests (no DB needed) -python3 -c " -from app.services.player_service import PlayerService -from app.services.mocks import MockPlayerRepository, MockCacheService - -repo = MockPlayerRepository() -repo.add_player({'id': 1, 'name': 'Test', ...}) -cache = MockCacheService() - -service = PlayerService(player_repo=repo, cache=cache) -result = service.get_players(season=10) -print(f'Count: {result[\"count\"]}') -" - -# Full pytest suite -pytest tests/ -v -``` - ---- - -## API Compatibility - -### Response Structures (Verified for Major Domo) - -**Team Response:** -```json -{ - "id": 1, - "abbrev": "ARI", - "sname": "Diamondbacks", - "lname": "Arizona Diamondbacks", - "gmid": "69420666", - "manager1": {"id": 1, "name": "..."}, - "manager2": null, - "division": {"id": 1, ...}, - "season": 10, - ... -} -``` - -**Player Response:** -```json -{ - "id": 1, - "name": "Mike Trout", - "wara": 5.2, - "team": {"id": 1, "abbrev": "ARI", ...}, - "season": 10, - "pos_1": "CF", - "pos_2": "LF", - ... -} -``` - ---- - -## To Continue This Work - -### Option 1: Complete Full Refactor -1. Apply same pattern to remaining 18 routers -2. Create services for: Division, Manager, Standing, Schedule, Transaction, etc. -3. Add integration tests -4. Set up CI/CD pipeline - -### Option 2: Expand Test Coverage -1. Add integration tests with real PostgreSQL -2. Add performance benchmarks -3. Add cache invalidation tests - -### Option 3: Merge and Pause -1. Merge `jarvis/testability` into main -2. Document pattern for future contributors -3. Return when needed - ---- - -## Files Reference - -``` -major-domo-database/ -├── app/ -│ ├── services/ -│ │ ├── base.py # BaseService with auth, caching, error handling -│ │ ├── interfaces.py # Protocol definitions -│ │ ├── mocks.py # Mock implementations -│ │ ├── player_service.py # Full DI implementation -│ │ └── team_service.py # Full DI implementation -│ ├── routers_v3/ -│ │ ├── players.py # Fixed imports, calls PlayerService -│ │ └── teams.py # Fixed imports, calls TeamService -│ └── db_engine.py # Original models (unchanged) -├── tests/ -│ └── unit/ -│ ├── test_base_service.py -│ ├── test_player_service.py -│ └── test_team_service.py -└── DATA_CONSISTENCY_REPORT.md # Detailed analysis -``` - ---- - -## Questions to Answer After E2E Testing - -1. Do the refactored endpoints return the same data as before? -2. Are there any performance regressions? -3. Does authentication work correctly? -4. Do cache invalidations work as expected? -5. Are there any edge cases that fail? - ---- - -## Contact - -**Context:** This work was started to enable testability of the Major Domo codebase. The PoC demonstrates the pattern works for Player and Team. The same pattern should be applied to other models as needed. diff --git a/data_consistency_check.py b/data_consistency_check.py deleted file mode 100644 index 7a479b7..0000000 --- a/data_consistency_check.py +++ /dev/null @@ -1,185 +0,0 @@ -""" -Data Consistency Validator -Compares refactored service layer output with expected router output. -""" - -# ============================================================================ -# DATA STRUCTURE COMPARISON -# ============================================================================ - -""" -EXPECTED OUTPUT STRUCTURES (from router definition): -=================================================== - -GET /api/v3/players ------------------- -Response: { - "count": int, - "players": [ - { - "id": int, - "name": str, - "wara": float, - "image": str, - "image2": str | None, - "team_id": int, - "season": int, - "pitcher_injury": str | None, - "pos_1": str, - "pos_2": str | None, - ... - "team": { "id": int, "abbrev": str, "sname": str, ... } | int # if short_output - } - ] -} - -GET /api/v3/players/{player_id} -------------------------------- -Response: Player dict or null - -GET /api/v3/players/search --------------------------- -Response: { - "count": int, - "total_matches": int, - "all_seasons": bool, - "players": [Player dicts] -} - - -GET /api/v3/teams ------------------- -Response: { - "count": int, - "teams": [ - { - "id": int, - "abbrev": str, - "sname": str, - "lname": str, - "gmid": int | None, - "gmid2": int | None, - "manager1_id": int | None, - "manager2_id": int | None, - "division_id": int | None, - "stadium": str | None, - "thumbnail": str | None, - "color": str | None, - "dice_color": str | None, - "season": int - } - ] -} - -GET /api/v3/teams/{team_id} ----------------------------- -Response: Team dict or null - - -EXPECTED BEHAVIOR DIFFERENCES (Issues Found): -============================================= - -1. STATIC VS INSTANCE METHOD MISMATCH - ├─ PlayerService.get_players() - Called as static in router - │ └─ ISSUE: Method has `self` parameter - will fail! - └─ TeamService.get_teams() - Correctly uses @classmethod - └─ OK: Uses cls instead of self - -2. FILTER FIELD INCONSISTENCY - ├─ Router: name=str (exact match filter) - └─ Service: name.lower() comparison - └─ ISSUE: Different behavior! - -3. POSITION FILTER INCOMPLETE - ├─ Router: pos=[list of positions] - └─ Service: Only checks pos_1 through pos_8 - └─ OK: Actually correct implementation - -4. CSV OUTPUT DIFFERENCE - ├─ Router: csv=bool, returns Response with content - └─ Service: as_csv=bool, returns CSV string - └─ OK: Just parameter name difference - -5. INJURED FILTER SEMANTICS - ├─ Router: is_injured=True → show injured players - └─ Service: is_injured is not None → filter il_return IS NOT NULL - └─ OK: Same behavior - -6. SORT PARAMETER MAPPING - ├─ Router: sort="name-asc" | "cost-desc" | etc - └─ Service: Maps to Player.name.asc(), Player.wara.desc() - └─ OK: Correct mapping - -7. DEPENDENCY INJECTION INCOMPLETE - ├─ Service imports: from ..db_engine import Player, Team - │ └─ ISSUE: Still uses direct model imports for filtering! - ├─ Service uses: Player.team_id << team_id (Peewee query) - │ └─ ISSUE: This won't work with MockPlayerRepository! - └─ Service uses: peewee_fn.lower(Player.strat_code) - └─ ISSUE: This won't work with MockPlayerRepository! - └─ ISSUE: MockPlayerRepository doesn't support peewee_fn! - -8. RESPONSE FIELD DIFFERENCES - ├─ get_players: count + players [✓ match] - ├─ get_one_player: returns dict or null [✓ match] - ├─ search_players: count + players + all_seasons [✓ match] - ├─ get_teams: count + teams [✓ match] - └─ get_one_team: returns dict or null [✓ match] - -""" - -# ============================================================================ -# RECOMMENDED FIXES -# ============================================================================ - -""" -To make refactored code return EXACT SAME data: - -1. FIX PLAYERSERVICE METHOD SIGNATURE - Current: - def get_players(self, season, team_id, pos, strat_code, name, ...): - - Fix: Add @classmethod decorator - def get_players(cls, season, team_id, pos, strat_code, name, ...): - - Use cls instead of self - - Use Team.select() instead of self.team_repo - -2. STANDARDIZE PARAMETER NAMES - Rename: - - as_csv → csv (to match router) - - short_output stays (both use same) - -3. IMPLEMENT REPO-AGNOSTIC FILTERING - Current (broken): - query.where(Player.team_id << team_id) - - Fix for Mock: - def _apply_filters(query, team_id, pos, strat_code, name, is_injured): - result = [] - for item in query: - if team_id and item.get('team_id') not in team_id: - continue - if strat_code and item.get('strat_code', '').lower() not in [s.lower() for s in strat_code]: - continue - result.append(item) - return result - -4. REMOVE DEPENDENCY ON peewee_fn IN SERVICE LAYER - Current: - query.where(peewee_fn.lower(Player.name) == name.lower()) - - Fix: Do string comparison in Python - for player in query: - if name and player.name.lower() != name.lower(): - continue - -5. REMOVE UNNECESSARY IMPORTS - Current in player_service.py: - from peewee import fn as peewee_fn - from ..db_engine import Player - - These imports break the dependency injection pattern. - The service should ONLY use the repo interface. -""" - -print(__doc__) diff --git a/db_engine.py b/db_engine.py deleted file mode 100644 index 92ece53..0000000 --- a/db_engine.py +++ /dev/null @@ -1,1811 +0,0 @@ -import copy -import math - -from peewee import * - -from playhouse.shortcuts import model_to_dict - -db = SqliteDatabase( - 'storage/sba_master.db', - pragmas={ - 'journal_mode': 'wal', - 'cache_size': -1 * 64000, - 'synchronous': 0 - } -) - - -""" -Per season updates: - Result: regular_season & post_season - set season length - update_standings - confirm division alignments and records - Standings: recalculate - e_number function, set season length - - wildcard section, set league abbrevs -""" - - -def win_pct(this_team_stan): - if this_team_stan.wins + this_team_stan.losses == 0: - return 0 - else: - return (this_team_stan.wins / (this_team_stan.wins + this_team_stan.losses)) + \ - (this_team_stan.run_diff * .000001) - - -def games_back(leader, chaser): - return ((leader.wins - chaser.wins) + (chaser.losses - leader.losses)) / 2 - - -def e_number(leader, chaser): - e_num = 89 - leader.wins - chaser.losses - return e_num if e_num > 0 else 0 - - -class BaseModel(Model): - class Meta: - database = db - - -class Current(BaseModel): - week = IntegerField(default=0) - freeze = BooleanField(default=True) - season = IntegerField() - transcount = IntegerField(default=0) - bstatcount = IntegerField(default=0) - pstatcount = IntegerField(default=0) - bet_week = IntegerField(default=0) - trade_deadline = IntegerField() - pick_trade_start = IntegerField() - pick_trade_end = IntegerField() - playoffs_begin = IntegerField() - injury_count = IntegerField() - - @staticmethod - def latest(): - latest_current = Current.select().order_by(-Current.id).get() - return latest_current - - -class Division(BaseModel): - division_name = CharField() - division_abbrev = CharField() - league_name = CharField(null=True) - league_abbrev = CharField(null=True) - season = IntegerField(default=0) - - def abbrev(self): - league_short = self.league_abbrev + ' ' if self.league_abbrev else '' - return f'{league_short}{self.division_abbrev}' - - def short_name(self): - league_short = self.league_abbrev + ' ' if self.league_abbrev else '' - return f'{league_short}{self.division_name}' - - def full_name(self): - league_long = self.league_name + ' ' if self.league_name else '' - return f'{league_long}{self.division_name}' - - def sort_division(self, season): - div_query = Standings.select_season(season).where(Standings.team.division == self) - div_teams = [team_stan for team_stan in div_query] - div_teams.sort(key=lambda team: win_pct(team), reverse=True) - - # Assign div_gb and e_num - for x in range(len(div_teams)): - # # Used for two playoff teams per divsion - # # Special calculations for the division leader - # if x == 0: - # div_teams[0].div_gb = -games_back(div_teams[0], div_teams[2]) - # div_teams[0].div_e_num = None - # div_teams[0].wc_gb = None - # div_teams[0].wc_e_num = None - # elif x == 1: - # div_teams[1].div_gb = 0 - # div_teams[1].div_e_num = None - # div_teams[1].wc_gb = None - # div_teams[1].wc_e_num = None - # else: - # div_teams[x].div_gb = games_back(div_teams[1], div_teams[x]) - # div_teams[x].div_e_num = e_number(div_teams[1], div_teams[x]) - # Used for one playoff team per division - if x == 0: - div_teams[0].div_gb = -games_back(div_teams[0], div_teams[1]) - div_teams[0].div_e_num = None - div_teams[0].wc_gb = None - div_teams[0].wc_e_num = None - else: - div_teams[x].div_gb = games_back(div_teams[0], div_teams[x]) - div_teams[x].div_e_num = e_number(div_teams[0], div_teams[x]) - - div_teams[x].save() - - @staticmethod - def sort_wildcard(season, league_abbrev): - divisions = Division.select().where(Division.league_abbrev == league_abbrev) - teams_query = Standings.select_season(season).where( - Standings.wc_gb.is_null(False) & (Standings.team.division << divisions) - ) - league_teams = [team_stan for team_stan in teams_query] - league_teams.sort(key=lambda team: win_pct(team), reverse=True) - - for x in range(len(league_teams)): - # Special calculations for two wildcard teams - if x == 0: - league_teams[0].wc_gb = -games_back(league_teams[0], league_teams[2]) - league_teams[0].wc_e_num = None - elif x == 1: - league_teams[1].wc_gb = 0 - league_teams[1].wc_e_num = None - else: - league_teams[x].wc_gb = games_back(league_teams[1], league_teams[x]) - league_teams[x].wc_e_num = e_number(league_teams[1], league_teams[x]) - - league_teams[x].save() - - -class Manager(BaseModel): - name = CharField(unique=True) - image = CharField(null=True) - headline = CharField(null=True) - bio = CharField(null=True) - - -class Team(BaseModel): - abbrev = CharField() - sname = CharField() - lname = CharField() - manager_legacy = CharField(null=True) - division_legacy = CharField(null=True) - gmid = IntegerField() - gmid2 = IntegerField(null=True) - manager1 = ForeignKeyField(Manager, null=True) - manager2 = ForeignKeyField(Manager, null=True) - division = ForeignKeyField(Division, null=True) - mascot = CharField(null=True) - stadium = CharField(null=True) - gsheet = CharField(null=True) - thumbnail = CharField(null=True) - color = CharField(null=True) - dice_color = CharField(null=True) - season = IntegerField() - auto_draft = BooleanField() - - @staticmethod - def select_season(num): - return Team.select().where(Team.season == num) - - @staticmethod - def get_by_owner(gmid, season): - team = Team.get_or_none(Team.gmid == gmid, Team.season == season) - if not team: - team = Team.get_or_none(Team.gmid2 == gmid, Team.season == season) - if not team: - return None - return team - - @staticmethod - def get_season(name_or_abbrev, season): - team = Team.get_or_none(fn.Upper(Team.abbrev) == name_or_abbrev.upper(), Team.season == season) - if not team: - team = Team.get_or_none(fn.Lower(Team.sname) == name_or_abbrev.lower(), Team.season == season) - if not team: - team = Team.get_or_none(fn.Lower(Team.lname) == name_or_abbrev.lower(), Team.season == season) - return team - - def get_record(self, week): - wins = Result.select_season(Current.latest().season).where( - (((Result.hometeam == self) & (Result.homescore > Result.awayscore)) | - ((Result.awayteam == self) & (Result.awayscore > Result.homescore))) & (Result.week <= week) - ) - losses = Result.select_season(Current.latest().season).where( - (((Result.awayteam == self) & (Result.homescore > Result.awayscore)) | - ((Result.hometeam == self) & (Result.awayscore > Result.homescore))) & (Result.week <= week) - ) - if wins.count() + losses.count() > 0: - pct = wins.count() / (wins.count() + losses.count()) - else: - pct = 0 - return {'w': wins.count(), 'l': losses.count(), 'pct': pct} - - def get_gms(self): - if self.gmid2: - return [self.gmid, self.gmid2] - else: - return [self.gmid] - - def get_this_week(self): - active_team = Player.select_season(self.season).where(Player.team == self) - - active_roster = {'C': 0, '1B': 0, '2B': 0, '3B': 0, 'SS': 0, 'LF': 0, 'CF': 0, 'RF': 0, 'DH': 0, - 'SP': 0, 'RP': 0, 'CP': 0, 'WARa': 0, 'players': []} - - combo_pitchers = 0 - for guy in active_team: - active_roster['WARa'] += guy.wara - active_roster['players'].append(guy) - guy_pos = guy.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - try: - for pos in guy_pos: - active_roster[pos] += 1 - except KeyError: - # This happens for season 1 without player positions listed - pass - - if combo_pitchers > 0: - if active_roster['SP'] < 5: - if 5 - active_roster['SP'] <= combo_pitchers: - delta = 5 - active_roster['SP'] - else: - delta = combo_pitchers - active_roster['SP'] += delta - combo_pitchers -= delta - - if combo_pitchers > 0: - active_roster['RP'] += combo_pitchers - - short_il = Player.select_season(self.season).join(Team).where(Player.team.abbrev == f'{self.abbrev}IL') - - short_roster = {'C': 0, '1B': 0, '2B': 0, '3B': 0, 'SS': 0, 'LF': 0, 'CF': 0, 'RF': 0, 'DH': 0, - 'SP': 0, 'RP': 0, 'CP': 0, 'WARa': 0, 'players': []} - - combo_pitchers = 0 - for guy in short_il: - short_roster['WARa'] += guy.wara - short_roster['players'].append(guy) - guy_pos = guy.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - short_roster[pos] += 1 - - if combo_pitchers > 0: - if short_roster['SP'] < 5: - if 5 - short_roster['SP'] <= combo_pitchers: - delta = 5 - short_roster['SP'] - else: - delta = combo_pitchers - short_roster['SP'] += delta - combo_pitchers -= delta - - if combo_pitchers > 0: - short_roster['RP'] += combo_pitchers - - long_il = Player.select_season(self.season).join(Team).where(Player.team.abbrev == f'{self.abbrev}MiL') - - long_roster = {'C': 0, '1B': 0, '2B': 0, '3B': 0, 'SS': 0, 'LF': 0, 'CF': 0, 'RF': 0, 'DH': 0, - 'SP': 0, 'RP': 0, 'CP': 0, 'WARa': 0, 'players': []} - - combo_pitchers = 0 - for guy in long_il: - long_roster['WARa'] += guy.wara - long_roster['players'].append(guy) - guy_pos = guy.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - long_roster[pos] += 1 - - if combo_pitchers > 0: - if long_roster['SP'] < 5: - if 5 - long_roster['SP'] <= combo_pitchers: - delta = 5 - long_roster['SP'] - else: - delta = combo_pitchers - long_roster['SP'] += delta - combo_pitchers -= delta - - if combo_pitchers > 0: - long_roster['RP'] += combo_pitchers - - return {'active': active_roster, 'shortil': short_roster, 'longil': long_roster} - - def get_next_week(self): - current = Current.latest() - active_team = Player.select_season(current.season).where(Player.team == self) - - active_roster = {'C': 0, '1B': 0, '2B': 0, '3B': 0, 'SS': 0, 'LF': 0, 'CF': 0, 'RF': 0, 'DH': 0, - 'SP': 0, 'RP': 0, 'CP': 0, 'WARa': 0, 'players': []} - - combo_pitchers = 0 - for guy in active_team: - active_roster['WARa'] += guy.wara - active_roster['players'].append(guy) - guy_pos = guy.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - active_roster[pos] += 1 - - all_drops = Transaction.select_season(Current.latest().season).where( - (Transaction.oldteam == self) & (Transaction.week == current.week + 1) & (Transaction.cancelled == 0) - ) - all_adds = Transaction.select_season(Current.latest().season).where( - (Transaction.newteam == self) & (Transaction.week == current.week + 1) & (Transaction.cancelled == 0) - ) - - for move in all_drops: - guy_pos = move.player.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers -= 1 - else: - for pos in guy_pos: - active_roster[pos] -= 1 - # print(f'dropping {move.player.name} id ({move.player.get_id()}) for {move.player.wara} WARa') - active_roster['WARa'] -= move.player.wara - try: - active_roster['players'].remove(move.player) - except: - print(f'I could not drop {move.player.name}') - - for move in all_adds: - guy_pos = move.player.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - active_roster[pos] += 1 - # print(f'adding {move.player.name} id ({move.player.get_id()}) for {move.player.wara} WARa') - active_roster['WARa'] += move.player.wara - active_roster['players'].append(move.player) - - if combo_pitchers > 0: - if active_roster['SP'] < 5: - if 5 - active_roster['SP'] <= combo_pitchers: - delta = 5 - active_roster['SP'] - else: - delta = combo_pitchers - active_roster['SP'] += delta - combo_pitchers -= delta - - if combo_pitchers > 0: - active_roster['RP'] += combo_pitchers - - short_il = Player.select_season(current.season).join(Team).where(Player.team.abbrev == f'{self.abbrev}SIL') - - short_roster = {'C': 0, '1B': 0, '2B': 0, '3B': 0, 'SS': 0, 'LF': 0, 'CF': 0, 'RF': 0, 'DH': 0, - 'SP': 0, 'RP': 0, 'CP': 0, 'WARa': 0, 'players': []} - - combo_pitchers = 0 - for guy in short_il: - short_roster['WARa'] += guy.wara - short_roster['players'].append(guy) - guy_pos = guy.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - short_roster[pos] += 1 - - sil_team = Team.get_season(f'{self.abbrev}SIL', current.season) - all_drops = Transaction.select_season(Current.latest().season).where( - (Transaction.oldteam == sil_team) & (Transaction.week == current.week + 1) & (Transaction.cancelled == 0) - ) - all_adds = Transaction.select_season(Current.latest().season).where( - (Transaction.newteam == sil_team) & (Transaction.week == current.week + 1) & (Transaction.cancelled == 0) - ) - - for move in all_drops: - guy_pos = move.player.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers -= 1 - else: - for pos in guy_pos: - short_roster[pos] -= 1 - short_roster['WARa'] -= move.player.wara - # print(f'SIL dropping {move.player.name} id ({move.player.get_id()}) for {move.player.wara} WARa') - try: - short_roster['players'].remove(move.player) - except: - print(f'I could not drop {move.player.name}') - - for move in all_adds: - guy_pos = move.player.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - short_roster[pos] += 1 - # print(f'SIL adding {move.player.name} id ({move.player.get_id()}) for {move.player.wara} WARa') - short_roster['WARa'] += move.player.wara - short_roster['players'].append(move.player) - - if combo_pitchers > 0: - if short_roster['SP'] < 5: - if 5 - short_roster['SP'] <= combo_pitchers: - delta = 5 - short_roster['SP'] - else: - delta = combo_pitchers - short_roster['SP'] += delta - combo_pitchers -= delta - - if combo_pitchers > 0: - short_roster['RP'] += combo_pitchers - - long_il = Player.select_season(current.season).join(Team).where(Player.team.abbrev == f'{self.abbrev}MiL') - - long_roster = {'C': 0, '1B': 0, '2B': 0, '3B': 0, 'SS': 0, 'LF': 0, 'CF': 0, 'RF': 0, 'DH': 0, - 'SP': 0, 'RP': 0, 'CP': 0, 'WARa': 0, 'players': []} - - combo_pitchers = 0 - for guy in long_il: - long_roster['WARa'] += guy.wara - long_roster['players'].append(guy) - guy_pos = guy.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - long_roster[pos] += 1 - - lil_team = Team.get_season(f'{self.abbrev}LIL', current.season) - all_drops = Transaction.select_season(Current.latest().season).where( - (Transaction.oldteam == lil_team) & (Transaction.week == current.week + 1) & (Transaction.cancelled == 0) - ) - all_adds = Transaction.select_season(Current.latest().season).where( - (Transaction.newteam == lil_team) & (Transaction.week == current.week + 1) & (Transaction.cancelled == 0) - ) - - for move in all_drops: - guy_pos = move.player.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers -= 1 - else: - for pos in guy_pos: - long_roster[pos] -= 1 - long_roster['WARa'] -= move.player.wara - # print(f'LIL dropping {move.player.name} id ({move.player.get_id()}) for {move.player.wara} WARa') - try: - long_roster['players'].remove(move.player) - except: - print(f'I could not drop {move.player.name}') - - for move in all_adds: - guy_pos = move.player.get_positions() - if 'SP' in guy_pos and 'RP' in guy_pos: - combo_pitchers += 1 - else: - for pos in guy_pos: - long_roster[pos] += 1 - # print(f'LIL adding {move.player.name} id ({move.player.get_id()}) for {move.player.wara} WARa') - long_roster['WARa'] += move.player.wara - long_roster['players'].append(move.player) - - if combo_pitchers > 0: - if long_roster['SP'] < 5: - if 5 - long_roster['SP'] <= combo_pitchers: - delta = 5 - long_roster['SP'] - else: - delta = combo_pitchers - long_roster['SP'] += delta - combo_pitchers -= delta - - if combo_pitchers > 0: - long_roster['RP'] += combo_pitchers - - return {'active': active_roster, 'shortil': short_roster, 'longil': long_roster} - - def run_pythag_last8(self): - team_stan = Standings.get_or_none(Standings.team == self) - - runs_scored_home = Result.select(fn.SUM(Result.homescore).alias('runs')).where( - Result.hometeam == self - )[0].runs - runs_scored_away = Result.select(fn.SUM(Result.awayscore).alias('runs')).where( - Result.awayteam == self - )[0].runs - runs_allowed_home = Result.select(fn.SUM(Result.homescore).alias('runs')).where( - Result.awayteam == self - )[0].runs - runs_allowed_away = Result.select(fn.SUM(Result.awayscore).alias('runs')).where( - Result.hometeam == self - )[0].runs - - if not runs_scored_home: - runs_scored_home = 0 - if not runs_scored_away: - runs_scored_away = 0 - if not runs_allowed_home: - runs_allowed_home = 0 - if not runs_allowed_away: - runs_allowed_away = 0 - - runs_scored = runs_scored_home + runs_scored_away - runs_allowed = runs_allowed_home + runs_allowed_away - if runs_allowed == 0: - pythag_win_pct = 0 - else: - pythag_win_pct = runs_scored ** 1.83 / ((runs_scored ** 1.83) + (runs_allowed ** 1.83)) - - games_played = team_stan.wins + team_stan.losses - team_stan.pythag_wins = round(games_played * pythag_win_pct) - team_stan.pythag_losses = games_played - team_stan.pythag_wins - - last_games = Result.select_season(self.season).where( - (Result.hometeam == self) | (Result.awayteam == self) - ).order_by(-Result.id).limit(8) - - for game in last_games: - if game.homescore > game.awayscore: - if game.hometeam == self: - team_stan.last8_wins += 1 - else: - team_stan.last8_losses += 1 - else: - if game.hometeam == self: - team_stan.last8_losses += 1 - else: - team_stan.last8_wins += 1 - - return team_stan.save() - - -class Result(BaseModel): - week = IntegerField() - game = IntegerField() - awayteam = ForeignKeyField(Team) - hometeam = ForeignKeyField(Team) - awayscore = IntegerField() - homescore = IntegerField() - season = IntegerField() - scorecard_url = CharField(null=True) - - @staticmethod - def regular_season(num): - if num == 1: - return Result.select().where((Result.season == 1) & (Result.week < 21)) - elif num == 2: - return Result.select().where((Result.season == 2) & (Result.week < 19)) - elif num == 3 or num == 4: - return Result.select().where((Result.season == num) & (Result.week < 23)) - else: - return None - - @staticmethod - def post_season(num): - if num == 1: - return Result.select().where((Result.season == 1) & (Result.week >= 21)) - elif num == 2: - return Result.select().where((Result.season == 2) & (Result.week >= 19)) - elif num == 3 or num == 4: - return Result.select().where((Result.season == num) & (Result.week >= 23)) - else: - return None - - @staticmethod - def select_season(num): - return Result.select().where(Result.season == num) - - def update_standings(self): - away_stan = Standings.get_season(self.awayteam) - home_stan = Standings.get_season(self.hometeam) - away_div = Division.get_by_id(self.awayteam.division.id) - home_div = Division.get_by_id(self.hometeam.division.id) - - if self.homescore > self.awayscore: - # - generic w/l & home/away w/l - home_stan.wins += 1 - home_stan.home_wins += 1 - away_stan.losses += 1 - away_stan.away_losses += 1 - - # - update streak wl and num - if home_stan.streak_wl == 'w': - home_stan.streak_num += 1 - else: - home_stan.streak_wl = 'w' - home_stan.streak_num = 1 - - if away_stan.streak_wl == 'l': - away_stan.streak_num += 1 - else: - away_stan.streak_wl = 'l' - away_stan.streak_num = 1 - - # - if 1-run, tally accordingly - if self.homescore == self.awayscore + 1: - home_stan.one_run_wins += 1 - away_stan.one_run_losses += 1 - - # Used for one league with 3 divisions - # - update record v division - # if away_div.division_abbrev == 'BE': - # home_stan.div1_wins += 1 - # elif away_div.division_abbrev == 'DO': - # home_stan.div2_wins += 1 - # else: - # home_stan.div3_wins += 1 - # - # if home_div.division_abbrev == 'BE': - # away_stan.div1_losses += 1 - # elif home_div.division_abbrev == 'DO': - # away_stan.div2_losses += 1 - # else: - # away_stan.div3_losses += 1 - - # Used for two league plus divisions - if away_div.league_abbrev == 'AL': - if away_div.division_abbrev == 'E': - home_stan.div1_wins += 1 - else: - home_stan.div2_wins += 1 - else: - if away_div.division_abbrev == 'E': - home_stan.div3_wins += 1 - else: - home_stan.div4_wins += 1 - - if home_div.league_abbrev == 'AL': - if home_div.division_abbrev == 'E': - away_stan.div1_losses += 1 - else: - away_stan.div2_losses += 1 - else: - if home_div.division_abbrev == 'E': - away_stan.div3_losses += 1 - else: - away_stan.div4_losses += 1 - - # - adjust run_diff - home_stan.run_diff += self.homescore - self.awayscore - away_stan.run_diff -= self.homescore - self.awayscore - else: - # - generic w/l & home/away w/l - home_stan.losses += 1 - home_stan.home_losses += 1 - away_stan.wins += 1 - away_stan.away_wins += 1 - - # - update streak wl and num - if home_stan.streak_wl == 'l': - home_stan.streak_num += 1 - else: - home_stan.streak_wl = 'l' - home_stan.streak_num = 1 - - if away_stan.streak_wl == 'w': - away_stan.streak_num += 1 - else: - away_stan.streak_wl = 'w' - away_stan.streak_num = 1 - - # - if 1-run, tally accordingly - if self.awayscore == self.homescore + 1: - home_stan.one_run_losses += 1 - away_stan.one_run_wins += 1 - - # Used for one league with 3 divisions - # - update record v division - # if away_div.division_abbrev == 'BE': - # home_stan.div1_losses += 1 - # elif away_div.division_abbrev == 'DO': - # home_stan.div2_losses += 1 - # else: - # home_stan.div3_losses += 1 - # - # if home_div.division_abbrev == 'BE': - # away_stan.div1_wins += 1 - # elif home_div.division_abbrev == 'DO': - # away_stan.div2_wins += 1 - # else: - # away_stan.div3_wins += 1 - - # Used for two league plus divisions - if away_div.league_abbrev == 'AL': - if away_div.division_abbrev == 'E': - home_stan.div1_losses += 1 - else: - home_stan.div2_losses += 1 - else: - if away_div.division_abbrev == 'E': - home_stan.div3_losses += 1 - else: - home_stan.div4_losses += 1 - - if home_div.league_abbrev == 'AL': - if home_div.division_abbrev == 'E': - away_stan.div1_wins += 1 - else: - away_stan.div2_wins += 1 - else: - if home_div.division_abbrev == 'E': - away_stan.div3_wins += 1 - else: - away_stan.div4_wins += 1 - - # - adjust run_diff - home_stan.run_diff -= self.awayscore - self.homescore - away_stan.run_diff += self.awayscore - self.homescore - - home_stan.save() - away_stan.save() - - -class Player(BaseModel): - name = CharField() - wara = FloatField() - image = CharField() - image2 = CharField(null=True) - team = ForeignKeyField(Team) - season = IntegerField() - pitcher_injury = IntegerField(null=True) - pos_1 = CharField() - pos_2 = CharField(null=True) - pos_3 = CharField(null=True) - pos_4 = CharField(null=True) - pos_5 = CharField(null=True) - pos_6 = CharField(null=True) - pos_7 = CharField(null=True) - pos_8 = CharField(null=True) - last_game = CharField(null=True) - last_game2 = CharField(null=True) - il_return = CharField(null=True) - demotion_week = IntegerField(null=True) - headshot = CharField(null=True) - vanity_card = CharField(null=True) - strat_code = CharField(null=True) - bbref_id = CharField(null=True) - injury_rating = CharField(null=True) - - @staticmethod - def select_season(num): - return Player.select().where(Player.season == num) - - @staticmethod - def get_season(name, num): - player = None - try: - player = Player.get(fn.Lower(Player.name) == name.lower(), Player.season == num) - except Exception as e: - print(f'**Error** (db_engine player): {e}') - finally: - return player - - def get_positions(self): - """ - Params: None - Return: List of positions (ex ['1b', '3b']) - """ - pos_list = [] - if self.pos_1: - pos_list.append(self.pos_1) - if self.pos_2: - pos_list.append(self.pos_2) - if self.pos_3: - pos_list.append(self.pos_3) - if self.pos_4: - pos_list.append(self.pos_4) - if self.pos_5: - pos_list.append(self.pos_5) - if self.pos_6: - pos_list.append(self.pos_6) - if self.pos_7: - pos_list.append(self.pos_7) - if self.pos_8: - pos_list.append(self.pos_8) - - return pos_list - - -class Schedule(BaseModel): - week = IntegerField() - awayteam = ForeignKeyField(Team) - hometeam = ForeignKeyField(Team) - gamecount = IntegerField() - season = IntegerField() - - @staticmethod - def select_season(season): - return Schedule.select().where(Schedule.season == season) - - -class Transaction(BaseModel): - week = IntegerField() - player = ForeignKeyField(Player) - oldteam = ForeignKeyField(Team) - newteam = ForeignKeyField(Team) - season = IntegerField() - moveid = IntegerField() - cancelled = BooleanField(default=False) - frozen = BooleanField(default=False) - - @staticmethod - def select_season(num): - return Transaction.select().where(Transaction.season == num) - - -class BattingStat(BaseModel): - player = ForeignKeyField(Player) - team = ForeignKeyField(Team) - pos = CharField() - pa = IntegerField() - ab = IntegerField() - run = IntegerField() - hit = IntegerField() - rbi = IntegerField() - double = IntegerField() - triple = IntegerField() - hr = IntegerField() - bb = IntegerField() - so = IntegerField() - hbp = IntegerField() - sac = IntegerField() - ibb = IntegerField() - gidp = IntegerField() - sb = IntegerField() - cs = IntegerField() - bphr = IntegerField() - bpfo = IntegerField() - bp1b = IntegerField() - bplo = IntegerField() - xba = IntegerField() - xbt = IntegerField() - xch = IntegerField() - xhit = IntegerField() - error = IntegerField() - pb = IntegerField() - sbc = IntegerField() - csc = IntegerField() - roba = IntegerField() - robs = IntegerField() - raa = IntegerField() - rto = IntegerField() - week = IntegerField() - game = IntegerField() - season = IntegerField() - - @staticmethod - def combined_season(season): - """ - Params: season, integer (season number), optional - Return: ModelSelect object for season - """ - return BattingStat.select().where(BattingStat.season == season) - - @staticmethod - def regular_season(season): - """ - Params: num, integer (season number) - Return: ModelSelect object for season's regular season - """ - if season == 1: - return BattingStat.select().where((BattingStat.season == 1) & (BattingStat.week < 21))\ - .order_by(BattingStat.week) - elif season == 2: - return BattingStat.select().where((BattingStat.season == 2) & (BattingStat.week < 19))\ - .order_by(BattingStat.week) - elif season > 2: - return BattingStat.select().where((BattingStat.season == season) & (BattingStat.week < 23))\ - .order_by(BattingStat.week) - else: - return None - - @staticmethod - def post_season(season): - """ - Params: num, integer (season number) - Return: ModelSelect object for season's post season - """ - if season == 1: - return BattingStat.select().where((BattingStat.season == 1) & (BattingStat.week >= 21)) - elif season == 2: - return BattingStat.select().where((BattingStat.season == 2) & (BattingStat.week >= 19)) - elif season > 2: - return BattingStat.select().where((BattingStat.season == season) & (BattingStat.week >= 23)) - else: - return None - - @staticmethod - def team_season(team, season): - b_stats = BattingStat.regular_season(season).join(Player).select( - fn.SUM(BattingStat.pa).alias('pas'), - fn.SUM(BattingStat.ab).alias('abs'), - fn.SUM(BattingStat.run).alias('runs'), - fn.SUM(BattingStat.hit).alias('hits'), - fn.SUM(BattingStat.rbi).alias('rbis'), - fn.SUM(BattingStat.double).alias('doubles'), - fn.SUM(BattingStat.triple).alias('triples'), - fn.SUM(BattingStat.hr).alias('hrs'), - fn.SUM(BattingStat.bb).alias('bbs'), - fn.SUM(BattingStat.so).alias('sos'), - fn.SUM(BattingStat.hbp).alias('hbps'), - fn.SUM(BattingStat.sac).alias('sacs'), - fn.SUM(BattingStat.ibb).alias('ibbs'), - fn.SUM(BattingStat.gidp).alias('gidps'), - fn.SUM(BattingStat.sb).alias('sbs'), - fn.SUM(BattingStat.cs).alias('css'), - fn.SUM(BattingStat.bphr).alias('bphr'), - fn.SUM(BattingStat.bpfo).alias('bpfo'), - fn.SUM(BattingStat.bp1b).alias('bp1b'), - fn.SUM(BattingStat.bplo).alias('bplo'), - # fn.SUM(BattingStat.xba).alias('xba'), - # fn.SUM(BattingStat.xbt).alias('xbt'), - fn.COUNT(BattingStat.game).alias('games'), - ).where(BattingStat.team == team) - - total = { - 'game': b_stats[0].games if b_stats[0].games else 0, - 'pa': b_stats[0].pas if b_stats[0].pas else 0, - 'ab': b_stats[0].abs if b_stats[0].abs else 0, - 'run': b_stats[0].runs if b_stats[0].runs else 0, - 'hit': b_stats[0].hits if b_stats[0].hits else 0, - 'rbi': b_stats[0].rbis if b_stats[0].rbis else 0, - 'double': b_stats[0].doubles if b_stats[0].doubles else 0, - 'triple': b_stats[0].triples if b_stats[0].triples else 0, - 'hr': b_stats[0].hrs if b_stats[0].hrs else 0, - 'bb': b_stats[0].bbs if b_stats[0].bbs else 0, - 'so': b_stats[0].sos if b_stats[0].sos else 0, - 'hbp': b_stats[0].hbps if b_stats[0].hbps else 0, - 'sac': b_stats[0].sacs if b_stats[0].sacs else 0, - 'ibb': b_stats[0].ibbs if b_stats[0].ibbs else 0, - 'gidp': b_stats[0].gidps if b_stats[0].gidps else 0, - 'sb': b_stats[0].sbs if b_stats[0].sbs else 0, - 'cs': b_stats[0].css if b_stats[0].css else 0, - 'ba': 0, - 'obp': 0, - 'slg': 0, - 'woba': 0, - 'kpct': 0, - 'bphr': b_stats[0].bphr if b_stats[0].bphr else 0, - 'bpfo': b_stats[0].bpfo if b_stats[0].bpfo else 0, - 'bp1b': b_stats[0].bp1b if b_stats[0].bp1b else 0, - 'bplo': b_stats[0].bplo if b_stats[0].bplo else 0, - # 'xba': b_stats[0].xba if b_stats[0].xba else 0, - # 'xbt': b_stats[0].xbt if b_stats[0].xbt else 0, - } - - if b_stats[0].abs: - total['ba'] = b_stats[0].hits / b_stats[0].abs - - total['obp'] = ( - (b_stats[0].bbs + b_stats[0].hits + b_stats[0].hbps + b_stats[0].ibbs) / b_stats[0].pas - ) - - total['slg'] = ( - ((b_stats[0].hrs * 4) + (b_stats[0].triples * 3) + (b_stats[0].doubles * 2) + - (b_stats[0].hits - b_stats[0].hrs - b_stats[0].triples - b_stats[0].doubles)) / b_stats[0].abs - ) - - total['woba'] = ( - ((b_stats[0].bbs * .69) + (b_stats[0].hbps * .722) + (b_stats[0].doubles * 1.271) + - (b_stats[0].triples * 1.616) + (b_stats[0].hrs * 2.101) + - ((b_stats[0].hits - b_stats[0].hrs - b_stats[0].triples - b_stats[0].doubles) * .888)) / - (b_stats[0].pas - b_stats[0].ibbs) - ) - - total['kpct'] = (total['so'] * 100) / total['ab'] - - total_innings = PitchingStat.regular_season(season).join(Player).select( - fn.SUM(PitchingStat.ip).alias('ips'), - ).where(PitchingStat.player.team == team) - total['rper9'] = (total['run'] * 9) / total_innings[0].ips - - return total - - @staticmethod - def team_fielding_season(team, season): - f_stats = BattingStat.regular_season(season).select( - fn.SUM(BattingStat.xch).alias('xchs'), - fn.SUM(BattingStat.xhit).alias('xhits'), - fn.SUM(BattingStat.error).alias('errors'), - # fn.SUM(BattingStat.roba).alias('roba'), - # fn.SUM(BattingStat.robs).alias('robs'), - # fn.SUM(BattingStat.raa).alias('raa'), - # fn.SUM(BattingStat.rto).alias('rto'), - fn.SUM(BattingStat.pb).alias('pbs'), - fn.SUM(BattingStat.sbc).alias('sbas'), - fn.SUM(BattingStat.csc).alias('cscs'), - fn.COUNT(BattingStat.game).alias('games'), - ).where(BattingStat.team == team) - - total = { - 'game': f_stats[0].games if f_stats[0].games else 0, - 'xch': f_stats[0].xchs if f_stats[0].xchs else 0, - 'xhit': f_stats[0].xhits if f_stats[0].xhits else 0, - 'error': f_stats[0].errors if f_stats[0].errors else 0, - # 'roba': f_stats[0].roba if f_stats[0].roba else 0, - # 'robs': f_stats[0].robs if f_stats[0].robs else 0, - # 'raa': f_stats[0].raa if f_stats[0].raa else 0, - # 'rto': f_stats[0].rto if f_stats[0].rto else 0, - 'pb': f_stats[0].pbs if f_stats[0].pbs else 0, - 'sbc': f_stats[0].sbas if f_stats[0].sbas else 0, - 'csc': f_stats[0].cscs if f_stats[0].cscs else 0, - 'wfpct': 0, - 'cspct': 0, - } - - if total['xch'] > 0: - total['wfpct'] = (total['xch'] - (total['error'] * .5) - (total['xhit'] * .75)) / (total['xch']) - if total['sbc'] > 0: - total['cspct'] = (total['csc'] / total['sbc']) * 100 - - return total - - -class PitchingStat(BaseModel): - player = ForeignKeyField(Player) - team = ForeignKeyField(Team) - ip = FloatField() - hit = FloatField() - run = FloatField() - erun = FloatField() - so = FloatField() - bb = FloatField() - hbp = FloatField() - wp = FloatField() - balk = FloatField() - hr = FloatField() - ir = FloatField() - irs = FloatField() - gs = FloatField() - win = FloatField() - loss = FloatField() - hold = FloatField() - sv = FloatField() - bsv = FloatField() - week = IntegerField() - game = IntegerField() - season = IntegerField() - - @staticmethod - def select_season(season): - return PitchingStat.select().where(PitchingStat.season == season) - - @staticmethod - def regular_season(season): - if season == 1: - return PitchingStat.select().where((PitchingStat.season == 1) & (PitchingStat.week < 21))\ - .order_by(PitchingStat.week) - elif season == 2: - return PitchingStat.select().where((PitchingStat.season == 2) & (PitchingStat.week < 19))\ - .order_by(PitchingStat.week) - elif season > 2: - return PitchingStat.select().where((PitchingStat.season == season) & (PitchingStat.week < 23))\ - .order_by(PitchingStat.week) - else: - return None - - @staticmethod - def post_season(season): - if season == 1: - return PitchingStat.select().where((PitchingStat.season == 1) & (PitchingStat.week >= 21))\ - .order_by(PitchingStat.week) - elif season == 2: - return PitchingStat.select().where((PitchingStat.season == 2) & (PitchingStat.week >= 19))\ - .order_by(PitchingStat.week) - elif season > 2: - return PitchingStat.select().where((PitchingStat.season == season) & (PitchingStat.week >= 23))\ - .order_by(PitchingStat.week) - else: - return None - - @staticmethod - def team_season(team, season): - p_stats = PitchingStat.regular_season(season).select( - fn.SUM(PitchingStat.ip).alias('ips'), - fn.SUM(PitchingStat.hit).alias('hits'), - fn.SUM(PitchingStat.run).alias('runs'), - fn.SUM(PitchingStat.erun).alias('eruns'), - fn.SUM(PitchingStat.so).alias('sos'), - fn.SUM(PitchingStat.bb).alias('bbs'), - fn.SUM(PitchingStat.hbp).alias('hbps'), - fn.SUM(PitchingStat.wp).alias('wps'), - fn.SUM(PitchingStat.ir).alias('ir'), - fn.SUM(PitchingStat.irs).alias('irs'), - fn.SUM(PitchingStat.balk).alias('balks'), - fn.SUM(PitchingStat.hr).alias('hrs'), - fn.COUNT(PitchingStat.game).alias('games'), - fn.SUM(PitchingStat.gs).alias('gss'), - fn.SUM(PitchingStat.win).alias('wins'), - fn.SUM(PitchingStat.loss).alias('losses'), - fn.SUM(PitchingStat.hold).alias('holds'), - fn.SUM(PitchingStat.sv).alias('saves'), - fn.SUM(PitchingStat.bsv).alias('bsaves'), - ).where(PitchingStat.team == team) - - total = { - 'ip': p_stats[0].ips if p_stats[0].ips else 0, - 'hit': int(p_stats[0].hits) if p_stats[0].hits else 0, - 'run': int(p_stats[0].runs) if p_stats[0].runs else 0, - 'erun': int(p_stats[0].eruns) if p_stats[0].eruns else 0, - 'so': int(p_stats[0].sos) if p_stats[0].sos else 0, - 'bb': int(p_stats[0].bbs) if p_stats[0].bbs else 0, - 'hbp': int(p_stats[0].hbps) if p_stats[0].hbps else 0, - 'wp': int(p_stats[0].wps) if p_stats[0].wps else 0, - 'balk': int(p_stats[0].balks) if p_stats[0].balks else 0, - 'hr': int(p_stats[0].hrs) if p_stats[0].hrs else 0, - 'game': int(p_stats[0].games) if p_stats[0].games else 0, - 'gs': int(p_stats[0].gss) if p_stats[0].gss else 0, - 'win': int(p_stats[0].wins) if p_stats[0].wins else 0, - 'loss': int(p_stats[0].losses) if p_stats[0].losses else 0, - 'hold': int(p_stats[0].holds) if p_stats[0].holds else 0, - 'sv': int(p_stats[0].saves) if p_stats[0].saves else 0, - 'bsv': int(p_stats[0].bsaves) if p_stats[0].bsaves else 0, - 'wl%': 0, - 'era': 0, - 'whip': 0, - 'ir': int(p_stats[0].ir) if p_stats[0].ir else 0, - 'irs': int(p_stats[0].irs) if p_stats[0].irs else 0, - } - - if total['ip']: - total['era'] = (total['erun'] * 9) / total['ip'] - - total['whip'] = (total['bb'] + total['hit']) / total['ip'] - - if total['win'] + total['loss'] > 0: - total['wl%'] = total['win'] / (total['win'] + total['loss']) - - return total - - -class Standings(BaseModel): - team = ForeignKeyField(Team) - wins = IntegerField(default=0) - losses = IntegerField(default=0) - run_diff = IntegerField(default=0) - div_gb = FloatField(default=0.0, null=True) - div_e_num = IntegerField(default=0, null=True) - wc_gb = FloatField(default=99.0, null=True) - wc_e_num = IntegerField(default=99, null=True) - home_wins = IntegerField(default=0) - home_losses = IntegerField(default=0) - away_wins = IntegerField(default=0) - away_losses = IntegerField(default=0) - last8_wins = IntegerField(default=0) - last8_losses = IntegerField(default=0) - streak_wl = CharField(default='w') - streak_num = IntegerField(default=0) - one_run_wins = IntegerField(default=0) - one_run_losses = IntegerField(default=0) - pythag_wins = IntegerField(default=0) - pythag_losses = IntegerField(default=0) - div1_wins = IntegerField(default=0) - div1_losses = IntegerField(default=0) - div2_wins = IntegerField(default=0) - div2_losses = IntegerField(default=0) - div3_wins = IntegerField(default=0) - div3_losses = IntegerField(default=0) - div4_wins = IntegerField(default=0) - div4_losses = IntegerField(default=0) - - @staticmethod - def select_season(season): - return Standings.select().join(Team).where(Standings.team.season == season) - - @staticmethod - def get_season(team): - return Standings.get_or_none(Standings.team == team) - - @staticmethod - def recalculate(season, full_wipe=True): - all_teams = Team.select_season(season).where(Team.division) - if full_wipe: - # Wipe existing data - delete_lines = Standings.select_season(season) - for line in delete_lines: - line.delete_instance() - - # Recreate current season Standings objects - create_teams = [Standings(team=team) for team in all_teams] - with db.atomic(): - Standings.bulk_create(create_teams) - - # Iterate through each individual result - for game in Result.select_season(season).where(Result.week <= 22): - # tally win and loss for each standings object - game.update_standings() - - # Set pythag record and iterate through last 8 games for last8 record - for team in all_teams: - team.run_pythag_last8() - - # Pull each division at a time and sort by win pct - for division in Division.select().where(Division.season == season): - division.sort_division(season) - - # Pull each league (filter by not null wc_gb) and sort by win pct - - # # For one league: - # Division.sort_wildcard(season, 'SBa') - - # For two leagues - Division.sort_wildcard(season, 'AL') - Division.sort_wildcard(season, 'NL') - - -class BattingCareer(BaseModel): - name = CharField() - pa = FloatField(default=0) - ab = FloatField(default=0) - run = FloatField(default=0) - hit = FloatField(default=0) - rbi = FloatField(default=0) - double = FloatField(default=0) - triple = FloatField(default=0) - hr = FloatField(default=0) - bb = FloatField(default=0) - so = FloatField(default=0) - hbp = FloatField(default=0) - sac = FloatField(default=0) - ibb = FloatField(default=0) - gidp = FloatField(default=0) - sb = FloatField(default=0) - cs = FloatField(default=0) - bphr = FloatField(default=0) - bpfo = FloatField(default=0) - bp1b = FloatField(default=0) - bplo = FloatField(default=0) - xba = FloatField(default=0) - xbt = FloatField(default=0) - game = FloatField(default=0) - - @staticmethod - def recalculate(): - # Wipe existing data - delete_lines = BattingCareer.select() - for line in delete_lines: - line.delete_instance() - - # For each seasonstat, find career or create new and increment - for this_season in BattingSeason.select().where(BattingSeason.season_type == 'Regular'): - this_career = BattingCareer.get_or_none(BattingCareer.name == this_season.player.name) - if not this_career: - this_career = BattingCareer(name=this_season.player.name) - this_career.save() - - this_career.pa += this_season.pa - this_career.ab += this_season.ab - this_career.run += this_season.run - this_career.hit += this_season.hit - this_career.rbi += this_season.rbi - this_career.double += this_season.double - this_career.triple += this_season.triple - this_career.hr += this_season.hr - this_career.bb += this_season.bb - this_career.so += this_season.so - this_career.hbp += this_season.hbp - this_career.sac += this_season.sac - this_career.ibb += this_season.ibb - this_career.gidp += this_season.gidp - this_career.sb += this_season.sb - this_career.cs += this_season.cs - this_career.bphr += this_season.bphr - this_career.bpfo += this_season.bpfo - this_career.bp1b += this_season.bp1b - this_career.bplo += this_season.bplo - this_career.xba += this_season.xba - this_career.xbt += this_season.xbt - this_career.save() - - -class PitchingCareer(BaseModel): - name = CharField() - ip = FloatField(default=0) - hit = FloatField(default=0) - run = FloatField(default=0) - erun = FloatField(default=0) - so = FloatField(default=0) - bb = FloatField(default=0) - hbp = FloatField(default=0) - wp = FloatField(default=0) - balk = FloatField(default=0) - hr = FloatField(default=0) - ir = FloatField(default=0) - irs = FloatField(default=0) - gs = FloatField(default=0) - win = FloatField(default=0) - loss = FloatField(default=0) - hold = FloatField(default=0) - sv = FloatField(default=0) - bsv = FloatField(default=0) - game = FloatField(default=0) - - @staticmethod - def recalculate(): - # Wipe existing data - delete_lines = PitchingCareer.select() - for line in delete_lines: - line.delete_instance() - - # For each seasonstat, find career or create new and increment - for this_season in PitchingSeason.select().where(PitchingSeason.season_type == 'Regular'): - this_career = PitchingCareer.get_or_none(PitchingCareer.name == this_season.player.name) - if not this_career: - this_career = PitchingCareer(name=this_season.player.name) - this_career.save() - - this_career.ip += this_season.ip - this_career.hit += this_season.hit - this_career.run += this_season.run - this_career.erun += this_season.erun - this_career.so += this_season.so - this_career.bb += this_season.bb - this_career.hbp += this_season.hbp - this_career.wp += this_season.wp - this_career.balk += this_season.balk - this_career.hr += this_season.hr - this_career.ir += this_season.ir - this_career.irs += this_season.irs - this_career.gs += this_season.gs - this_career.win += this_season.win - this_career.loss += this_season.loss - this_career.hold += this_season.hold - this_career.sv += this_season.sv - this_career.bsv += this_season.bsv - this_career.save() - - -class FieldingCareer(BaseModel): - name = CharField() - pos = CharField() - xch = IntegerField(default=0) - xhit = IntegerField(default=0) - error = IntegerField(default=0) - pb = IntegerField(default=0) - sbc = IntegerField(default=0) - csc = IntegerField(default=0) - roba = IntegerField(default=0) - robs = IntegerField(default=0) - raa = IntegerField(default=0) - rto = IntegerField(default=0) - game = IntegerField(default=0) - - @staticmethod - def recalculate(): - # Wipe existing data - delete_lines = FieldingCareer.select() - for line in delete_lines: - line.delete_instance() - - # For each seasonstat, find career or create new and increment - for this_season in FieldingSeason.select().where(FieldingSeason.season_type == 'Regular'): - this_career = FieldingCareer.get_or_none( - FieldingCareer.name == this_season.player.name, FieldingCareer.pos == this_season.pos - ) - if not this_career: - this_career = FieldingCareer(name=this_season.player.name, pos=this_season.pos) - this_career.save() - - this_career.xch += this_season.xch - this_career.xhit += this_season.xhit - this_career.error += this_season.error - this_career.pb += this_season.pb - this_career.sbc += this_season.sbc - this_career.csc += this_season.csc - this_career.roba += this_season.roba - this_career.robs += this_season.robs - this_career.raa += this_season.raa - this_career.rto += this_season.rto - this_career.save() - - -class BattingSeason(BaseModel): - player = ForeignKeyField(Player) - season = IntegerField() - season_type = CharField(default='Regular') - career = ForeignKeyField(BattingCareer, null=True) - pa = FloatField(default=0) - ab = FloatField(default=0) - run = FloatField(default=0) - hit = FloatField(default=0) - rbi = FloatField(default=0) - double = FloatField(default=0) - triple = FloatField(default=0) - hr = FloatField(default=0) - bb = FloatField(default=0) - so = FloatField(default=0) - hbp = FloatField(default=0) - sac = FloatField(default=0) - ibb = FloatField(default=0) - gidp = FloatField(default=0) - sb = FloatField(default=0) - cs = FloatField(default=0) - bphr = FloatField(default=0) - bpfo = FloatField(default=0) - bp1b = FloatField(default=0) - bplo = FloatField(default=0) - xba = FloatField(default=0) - xbt = FloatField(default=0) - game = FloatField(default=0) - - @staticmethod - def select_season(season): - return BattingSeason.select().where(BattingSeason.season == season) - - # @staticmethod - # def recalculate(season, manager_id): - # # Wipe existing data - # delete_lines = BattingSeason.select_season(season) - # for line in delete_lines: - # line.delete_instance() - # - # # For each battingstat, find season or create new and increment - # for line in BattingStat.select().where( - # (BattingStat.season == season) & (BattingStat.player.team.manager1 == manager_id) - # ): - # if line.season == 1: - # s_type = 'Regular' if line.week < 21 else 'Post' - # elif line.season == 2: - # s_type = 'Regular' if line.week < 19 else 'Post' - # else: - # s_type = 'Regular' if line.week < 23 else 'Post' - # - # this_season = BattingSeason.get_or_none(player=line.player, season_type=s_type) - # if not this_season: - # this_season = BattingSeason(player=line.player, season_type=s_type, season=line.season) - # this_season.save() - # - # this_season.pa += line.pa - # this_season.ab += line.ab - # this_season.run += line.run - # this_season.hit += line.hit - # this_season.rbi += line.rbi - # this_season.double += line.double - # this_season.triple += line.triple - # this_season.hr += line.hr - # this_season.bb += line.bb - # this_season.so += line.so - # this_season.hbp += line.hbp - # this_season.sac += line.sac - # this_season.ibb += line.ibb - # this_season.gidp += line.gidp - # this_season.sb += line.sb - # this_season.cs += line.cs - # this_season.save() - - def recalculate(self): - self.pa = 0 - self.ab = 0 - self.run = 0 - self.hit = 0 - self.rbi = 0 - self.double = 0 - self.triple = 0 - self.hr = 0 - self.bb = 0 - self.so = 0 - self.hbp = 0 - self.sac = 0 - self.ibb = 0 - self.gidp = 0 - self.sb = 0 - self.cs = 0 - self.bphr = 0 - self.bpfo = 0 - self.bp1b = 0 - self.bplo = 0 - self.xba = 0 - self.xbt = 0 - self.game = 0 - - if self.season_type == 'Regular': - all_stats = BattingStat.regular_season(self.season).where(BattingStat.player == self.player) - else: - all_stats = BattingStat.post_season(self.season).where(BattingStat.player == self.player) - for line in all_stats: - self.pa += line.pa - self.ab += line.ab - self.run += line.run - self.hit += line.hit - self.rbi += line.rbi - self.double += line.double - self.triple += line.triple - self.hr += line.hr - self.bb += line.bb - self.so += line.so - self.hbp += line.hbp - self.sac += line.sac - self.ibb += line.ibb - self.gidp += line.gidp - self.sb += line.sb - self.cs += line.cs - self.bphr += line.bphr - self.bpfo += line.bpfo - self.bp1b += line.bp1b - self.bplo += line.bplo - self.xba += line.xba - self.xbt += line.xbt - self.game += 1 - - self.save() - return all_stats.count() - - -class PitchingSeason(BaseModel): - player = ForeignKeyField(Player) - season = IntegerField() - season_type = CharField(default='Regular') - career = ForeignKeyField(PitchingCareer, null=True) - ip = FloatField(default=0) - hit = FloatField(default=0) - run = FloatField(default=0) - erun = FloatField(default=0) - so = FloatField(default=0) - bb = FloatField(default=0) - hbp = FloatField(default=0) - wp = FloatField(default=0) - balk = FloatField(default=0) - hr = FloatField(default=0) - ir = FloatField(default=0) - irs = FloatField(default=0) - gs = FloatField(default=0) - win = FloatField(default=0) - loss = FloatField(default=0) - hold = FloatField(default=0) - sv = FloatField(default=0) - bsv = FloatField(default=0) - game = FloatField(default=0) - - @staticmethod - def select_season(season): - return PitchingSeason.select().where(PitchingSeason.season == season) - - # @staticmethod - # def recalculate(season, manager_id): - # # Wipe existing data - # delete_lines = PitchingSeason.select_season(season) - # for line in delete_lines: - # line.delete_instance() - # - # # For each pitchingstat, find season or create new and increment - # for line in PitchingStat.select().where( - # (PitchingStat.season == season) & (PitchingStat.player.team.manager1 == manager_id) - # ): - # if line.season == 1: - # s_type = 'Regular' if line.week < 21 else 'Post' - # elif line.season == 2: - # s_type = 'Regular' if line.week < 19 else 'Post' - # else: - # s_type = 'Regular' if line.week < 23 else 'Post' - # - # this_season = PitchingSeason.get_or_none(player=line.player, season_type=s_type) - # if not this_season: - # this_season = PitchingSeason(player=line.player, season_type=s_type, season=line.season) - # this_season.save() - # - # this_season.ip += line.ip - # this_season.hit += line.hit - # this_season.run += line.run - # this_season.erun += line.erun - # this_season.so += line.so - # this_season.bb += line.bb - # this_season.hbp += line.hbp - # this_season.wp += line.wp - # this_season.balk += line.balk - # this_season.hr += line.hr - # this_season.gs += line.gs - # this_season.win += line.win - # this_season.loss += line.loss - # this_season.hold += line.hold - # this_season.sv += line.sv - # this_season.bsv += line.bsv - # this_season.game += 1 - # this_season.save() - - def recalculate(self): - self.ip = 0 - self.hit = 0 - self.run = 0 - self.erun = 0 - self.so = 0 - self.bb = 0 - self.hbp = 0 - self.wp = 0 - self.balk = 0 - self.hr = 0 - self.ir = 0 - self.irs = 0 - self.gs = 0 - self.win = 0 - self.loss = 0 - self.hold = 0 - self.sv = 0 - self.bsv = 0 - self.game = 0 - - if self.season_type == 'Regular': - all_stats = PitchingStat.regular_season(self.season).where(PitchingStat.player == self.player) - else: - all_stats = PitchingStat.post_season(self.season).where(PitchingStat.player == self.player) - for line in all_stats: - self.ip += line.ip - self.hit += line.hit - self.run += line.run - self.erun += line.erun - self.so += line.so - self.bb += line.bb - self.hbp += line.hbp - self.wp += line.wp - self.balk += line.balk - self.hr += line.hr - self.ir += line.ir - self.irs += line.irs - self.gs += line.gs - self.win += line.win - self.loss += line.loss - self.hold += line.hold - self.sv += line.sv - self.bsv += line.bsv - self.game += 1 - - self.save() - return all_stats.count() - - -class FieldingSeason(BaseModel): - player = ForeignKeyField(Player) - season = IntegerField() - season_type = CharField(default='Regular') - pos = CharField() - career = ForeignKeyField(FieldingCareer, null=True) - xch = IntegerField(default=0) - xhit = IntegerField(default=0) - error = IntegerField(default=0) - pb = IntegerField(default=0) - sbc = IntegerField(default=0) - csc = IntegerField(default=0) - roba = IntegerField(default=0) - robs = IntegerField(default=0) - raa = IntegerField(default=0) - rto = IntegerField(default=0) - game = IntegerField(default=0) - - @staticmethod - def select_season(season): - return FieldingSeason.select().where(FieldingSeason.season == season) - - # @staticmethod - # def recalculate(season, manager_id): - # # Wipe existing data - # delete_lines = FieldingSeason.select() - # for line in delete_lines: - # line.delete_instance() - # - # # players = Player.select_season(season).where(Player.team) - # - # # For each battingstat, find season or create new and increment - # for line in BattingStat.select().join(Player).join(Team).where( - # (BattingStat.season == season) & (BattingStat.player.team.manager1 == manager_id) - # ): - # if line.season == 1: - # s_type = 'Regular' if line.week < 21 else 'Post' - # elif line.season == 2: - # s_type = 'Regular' if line.week < 19 else 'Post' - # else: - # s_type = 'Regular' if line.week < 23 else 'Post' - # - # this_season = BattingSeason.get_or_none(player=line.player, season_type=s_type, pos=line.pos) - # if not this_season: - # this_season = BattingSeason(player=line.player, season_type=s_type, pos=line.pos, season=line.season) - # this_season.save() - # - # this_season.xch += line.xch - # this_season.xhit += line.xhit - # this_season.error += line.error - # this_season.pb += line.pb - # this_season.sbc += line.sbc - # this_season.csc += line.csc - # this_season.game += 1 - # this_season.save() - - def recalculate(self): - self.xch = 0 - self.xhit = 0 - self.error = 0 - self.pb = 0 - self.sbc = 0 - self.csc = 0 - self.roba = 0 - self.robs = 0 - self.raa = 0 - self.rto = 0 - self.game = 0 - - if self.season_type == 'Regular': - all_stats = BattingStat.regular_season(self.season).where( - (BattingStat.player == self.player) & (BattingStat.pos == self.pos) - ) - else: - all_stats = BattingStat.post_season(self.season).where( - (BattingStat.player == self.player) & (BattingStat.pos == self.pos) - ) - - for line in all_stats: - self.xch += line.xch - self.xhit += line.xhit - self.error += line.error - self.pb += line.pb - self.sbc += line.sbc - self.csc += line.csc - self.roba += line.roba - self.robs += line.robs - self.raa += line.raa - self.rto += line.rto - self.game += 1 - - self.save() - return all_stats.count() - - -class DraftPick(BaseModel): - overall = IntegerField(null=True) - round = IntegerField() - origowner = ForeignKeyField(Team) - owner = ForeignKeyField(Team) - season = IntegerField() - player = ForeignKeyField(Player, null=True) - - @staticmethod - def select_season(num): - return DraftPick.select().where(DraftPick.season == num) - - @staticmethod - def get_season(team, rd, num): - return DraftPick.get(DraftPick.season == num, DraftPick.origowner == team, DraftPick.round == rd) - - -class DraftData(BaseModel): - currentpick = IntegerField() - timer = BooleanField() - pick_deadline = DateTimeField(null=True) - result_channel = IntegerField(null=True) - ping_channel = IntegerField(null=True) - pick_minutes = IntegerField(null=True) - - -class Award(BaseModel): - name = CharField() - season = IntegerField() - timing = CharField(default="In-Season") - manager1 = ForeignKeyField(Manager, null=True) - manager2 = ForeignKeyField(Manager, null=True) - player = ForeignKeyField(Player, null=True) - team = ForeignKeyField(Team, null=True) - image = CharField(null=True) - - -class DiceRoll(BaseModel): - season = IntegerField(default=Current.latest().season) - week = IntegerField(default=Current.latest().week) - team = ForeignKeyField(Team, null=True) - roller = IntegerField() - dsix = IntegerField(null=True) - twodsix = IntegerField(null=True) - threedsix = IntegerField(null=True) - dtwenty = IntegerField(null=True) - - -class DraftList(BaseModel): - season = IntegerField() - team = ForeignKeyField(Team) - rank = IntegerField() - player = ForeignKeyField(Player) - - -# class Streak(BaseModel): -# player = ForeignKeyField(Player) -# streak_type = CharField() -# start_season = IntegerField() -# start_week = IntegerField() -# start_game = IntegerField() -# end_season = IntegerField() -# end_week = IntegerField() -# end_game = IntegerField() -# game_length = IntegerField() -# active = BooleanField() -# -# def recalculate(self): -# # Pitcher streaks -# if self.streak_type in ['win', 'loss', 'save', 'scoreless']: -# all_stats = PitchingStat.select_season(self.start_season).where( -# (PitchingStat.player == self.player) & (PitchingStat.week >= self.start_week) -# ) -# sorted_stats = sorted(all_stats, key=lambda x: f'{x.season:0>2}-{x.week:0>2}-{x.game:}') -# -# for line in sorted_stats: diff --git a/main.py b/main.py deleted file mode 100644 index ef3c799..0000000 --- a/main.py +++ /dev/null @@ -1,7304 +0,0 @@ -from db_engine import * - -import datetime -import logging -import os - -from typing import Optional, List -from fastapi import FastAPI, HTTPException, Depends, Response -from fastapi.security import OAuth2PasswordBearer -import pydantic - -from playhouse.shortcuts import model_to_dict -from pandas import DataFrame - -# TODO: remove block comments from GET /schedules and /transactions - -date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}' -log_level = logging.INFO if os.environ.get('LOG_LEVEL') == 'INFO' else 'WARN' -logging.basicConfig( - filename=f'logs/database/{date}.log', - format='%(asctime)s - database - %(levelname)s - %(message)s', - level=log_level -) -SEASON_DEFAULT = 7 - -db.create_tables([Current, Division, Manager, Team, Result, Player, Schedule, Transaction, BattingStat, PitchingStat, - Standings, BattingCareer, PitchingCareer, FieldingCareer, Manager, Award, DiceRoll, DraftList]) -db.close() - -app = FastAPI() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -def valid_token(token): - if token == os.environ.get('API_TOKEN'): - return True - else: - return False - - -class PlayerPydantic(pydantic.BaseModel): - name: str - wara: float - image: str - image2: Optional[str] = None - team_id: int - season: int - pitcher_injury: Optional[int] = None - pos_1: str - pos_2: Optional[str] = None - pos_3: Optional[str] = None - pos_4: Optional[str] = None - pos_5: Optional[str] = None - pos_6: Optional[str] = None - pos_7: Optional[str] = None - pos_8: Optional[str] = None - last_game: Optional[str] = None - last_game2: Optional[str] = None - il_return: Optional[str] = None - demotion_week: Optional[int] = None - strat_code: Optional[str] = None - bbref_id: Optional[str] = None - injury_rating: Optional[str] = None - - -class PlayerModel(pydantic.BaseModel): - players: List[PlayerPydantic] - - -class ResultModel(pydantic.BaseModel): - week: int - game: int - away_team_id: int - home_team_id: int - away_score: int - home_score: int - season: int - scorecard_url: Optional[str] = None - - -class BatStat(pydantic.BaseModel): - player_id: int - team_id: int - pos: str - pa: int - ab: int - run: int - hit: int - rbi: int - double: int - triple: int - hr: int - bb: int - so: int - hbp: int - sac: int - ibb: int - gidp: int - sb: int - cs: int - bphr: int - bpfo: int - bp1b: int - bplo: int - xba: int - xbt: int - xch: int - xhit: int - error: int - pb: int - sbc: int - csc: int - roba: int - robs: int - raa: int - rto: int - week: int - game: int - season: int - - -class BattingStatModel(pydantic.BaseModel): - count: int - stats: List[BatStat] - - -class PitStat(pydantic.BaseModel): - player_id: int - team_id: int - ip: float - hit: int - run: int - erun: int - so: int - bb: int - hbp: int - wp: int - balk: int - hr: int - gs: int - win: int - loss: int - hold: int - sv: int - bsv: int - ir: int - irs: int - week: int - game: int - season: int - - -class PitchingStatModel(pydantic.BaseModel): - count: int - stats: List[PitStat] - - -class GameModel(pydantic.BaseModel): - season: int - week: int - away_team_id: int - home_team_id: int - game_num: int - - -class TransactionPydantic(pydantic.BaseModel): - week: int - player_id: int - oldteam_id: int - newteam_id: int - season: int - moveid: str - cancelled: Optional[bool] = False - frozen: Optional[bool] = False - - -class TransModel(pydantic.BaseModel): - count: int - moves: List[TransactionPydantic] - - -class DraftPickPydantic(pydantic.BaseModel): - overall: Optional[int] = None - round: int - origowner_id: int - owner_id: Optional[int] = None - season: int - player_id: Optional[int] = None - - -class DraftPickModel(pydantic.BaseModel): - picks: List[DraftPickPydantic] - - -class ManagerModel(pydantic.BaseModel): - name: str - image: Optional[str] = None - headline: Optional[str] = None - bio: Optional[str] = None - - -class AwardPydantic(pydantic.BaseModel): - name: str - season: int - timing: Optional[str] = "In-Season" - manager1_id: Optional[int] = None - manager2_id: Optional[int] = None - player_id: Optional[int] = None - team_id: Optional[int] = None - image: Optional[str] = None - - -class AwardModel(pydantic.BaseModel): - count: int - awards: List[AwardPydantic] - - -class DiceRollPydantic(pydantic.BaseModel): - season: int - week: int - team_id: int - roller: int - dsix: Optional[int] - twodsix: Optional[int] - threedsix: Optional[int] - dtwenty: Optional[int] - - -class DiceModel(pydantic.BaseModel): - count: int - rolls: List[DiceRollPydantic] - - -class DraftListPydantic(pydantic.BaseModel): - season: int - team_id: int - rank: int - player_id: int - - -class DraftListModel(pydantic.BaseModel): - count: int - draft_list: List[DraftListPydantic] - - -class SchedulePydantic(pydantic.BaseModel): - week: int - away_team_id: int - home_team_id: int - game_count: int - season: int - - -class ScheduleModel(pydantic.BaseModel): - count: int - schedules: List[SchedulePydantic] - - -class TeamModel(pydantic.BaseModel): - abbrev: str - sname: str - lname: str - gmid: Optional[int] = None - gmid2: Optional[int] = None - manager1_id: Optional[int] = None - manager2_id: Optional[int] = None - division_id: Optional[int] = None - stadium: Optional[str] = None - thumbnail: Optional[str] = None - color: Optional[str] = None - dice_color: Optional[str] = None - season: int - - -class CurrentModel(pydantic.BaseModel): - week: Optional[int] = 0 - freeze: Optional[bool] = False - season: int - transcount: Optional[int] = 0 - bstatcount: Optional[int] = 0 - pstatcount: Optional[int] = 0 - bet_week: Optional[int] = 0 - trade_deadline: int - pick_trade_start: int - pick_trade_end: int - playoffs_begin: int - injury_count: Optional[int] = 0 - - -@app.get('/api/v1/current') -async def v1_current(season: Optional[int] = None, return_type: Optional[str] = 'json'): - if season: - current = Current.get_or_none(season=season) - else: - current = Current.latest() - - if return_type == 'csv': - current_list = [ - ['season', 'week', 'trade deadline', 'pick trade start', 'pick trade end', 'playoffs begin', 'injury count'], - [current.season, current.week, current.trade_deadline, current.pick_trade_start, current.pick_trade_end, - current.playoffs_begin, current.injury_count] - ] - return_current = DataFrame(current_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_current, media_type='text/csv') - else: - db.close() - return model_to_dict(current) - - -@app.patch('/api/v1/current') -async def v1_current_patch( - season: Optional[int] = SEASON_DEFAULT, week: Optional[int] = None, freeze: Optional[bool] = None, - transcount: Optional[int] = None, bstatcount: Optional[int] = None, pstatcount: Optional[int] = None, - bet_week: Optional[int] = None, trade_deadline: Optional[int] = None, pick_trade_start: Optional[int] = None, - pick_trade_end: Optional[int] = None, injury_count: Optional[int] = None, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post current') - current = Current.get_or_none(season=season) - if not current: - db.close() - raise HTTPException(status_code=404, detail=f'Current for season {season} not found') - - if week is not None: - current.week = week - if freeze is not None: - current.freeze = freeze - if transcount is not None: - current.transcount = transcount - if bstatcount is not None: - current.bstatcount = bstatcount - if pstatcount is not None: - current.pstatcount = pstatcount - if bet_week is not None: - current.bet_week = bet_week - if trade_deadline is not None: - current.trade_deadline = trade_deadline - if pick_trade_start is not None: - current.pick_trade_start = pick_trade_start - if pick_trade_end is not None: - current.pick_trade_end = pick_trade_end - if injury_count is not None: - current.injury_count = injury_count - - current.save() - db.close() - return model_to_dict(current) - - -@app.post('/api/v1/current') -async def v1_current_post(current: CurrentModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post current') - - this_current = Current( - week=current.week, - freeze=current.freeze, - season=current.season, - transcount=current.transcount, - bstatcount=current.bstatcount, - pstatcount=current.pstatcount, - bet_week=current.bet_week, - trade_deadline=current.trade_deadline, - pick_trade_start=current.pick_trade_start, - pick_trade_end=current.pick_trade_end, - playoffs_begin=current.playoffs_begin, - injury_count=current.injury_count - ) - - saved = this_current.save() - db.close() - if saved == 1: - return model_to_dict(this_current) - else: - raise HTTPException(status_code=418, detail='Well slap my ass and call me a teapot. I could not post that.') - - -@app.get('/api/v1/teams') -async def v1_teams_get( - season: Optional[int] = None, owner_id: Optional[int] = None, manager_id: Optional[int] = None, - active_only: Optional[bool] = False, return_type: Optional[str] = 'json', csv: Optional[bool] = False): - """ - Param: season: int - Param: team_abbrev: string - Param: owner_id: int - """ - if season: - all_teams = Team.select_season(season) - else: - all_teams = Team.select() - - if manager_id: - print(f'query: {all_teams}') - try: - this_manager = Manager.get_by_id(manager_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager ID {manager_id} not found') - - all_teams = all_teams.where( - (Team.manager1 == this_manager) | (Team.manager2 == this_manager) - ).order_by(-Team.season) - - if owner_id: - all_teams = all_teams.where((Team.gmid == owner_id) | (Team.gmid2 == owner_id)) - - if active_only: - all_teams = all_teams.where( - ~(Team.abbrev.endswith('IL')) & ~(Team.abbrev.endswith('MiL')) - ) - - if all_teams.count() == 0: - db.close() - logging.error(f'No teams found\n\nseason: {season} / {owner_id}') - raise HTTPException(status_code=404, detail=f'Season {season} not found') - - if return_type == 'csv' or csv: - teams_list = [['abbrev', 'sname', 'lname', 'league', 'division', 'stadium', 'manager1', 'manager2', 'thumbnail', - 'color', 'season', 'dice_color', 'id']] - for line in all_teams: - teams_list.append( - [ - line.abbrev, line.sname, line.lname, line.division.league_abbrev if line.division else '', - line.division.division_name if line.division else '', line.stadium, - line.manager1.name if line.manager1 else '', line.manager2.name if line.manager2 else '', - line.thumbnail, line.color, line.season, line.dice_color, line.id - ] - ) - return_teams = DataFrame(teams_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_teams, media_type='text/csv') - - else: - return_teams = {'count': all_teams.count(), 'teams': []} - for team in all_teams: - return_teams['teams'].append(model_to_dict(team)) - - db.close() - return return_teams - - -@app.get('/api/v1/teams/{id_or_abbrev}') -async def v1_teams_get_one(id_or_abbrev, season: Optional[int] = SEASON_DEFAULT): - try: - this_team = Team.get_by_id(id_or_abbrev) - except Exception as e: - if season: - this_team = Team.get_season(id_or_abbrev, season) - else: - this_team = Team.get_season(id_or_abbrev, Current.latest().season) - - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {id_or_abbrev} not found') - else: - db.close() - return model_to_dict(this_team) - - -@app.get('/api/v1/teams/{id_or_abbrev}/roster/{which}') -async def v1_teams_get_roster(id_or_abbrev, which, sort: Optional[str] = None): - try: - this_team = Team.get_by_id(id_or_abbrev) - except Exception as e: - this_team = Team.get_season(id_or_abbrev, SEASON_DEFAULT) - - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {id_or_abbrev} not found') - - if which != 'current' and which != 'next': - db.close() - raise HTTPException(status_code=404, detail=f'Missing /current or /next') - - if which == 'current': - full_roster = this_team.get_this_week() - else: - full_roster = this_team.get_next_week() - - active_players = copy.deepcopy(full_roster['active']['players']) - sil_players = copy.deepcopy(full_roster['shortil']['players']) - lil_players = copy.deepcopy(full_roster['longil']['players']) - full_roster['active']['players'] = [] - full_roster['shortil']['players'] = [] - full_roster['longil']['players'] = [] - - for player in active_players: - full_roster['active']['players'].append(model_to_dict(player)) - for player in sil_players: - full_roster['shortil']['players'].append(model_to_dict(player)) - for player in lil_players: - full_roster['longil']['players'].append(model_to_dict(player)) - - if sort: - if sort == 'wara-desc': - full_roster['active']['players'].sort(key=lambda p: p["wara"], reverse=True) - full_roster['active']['players'].sort(key=lambda p: p["wara"], reverse=True) - full_roster['active']['players'].sort(key=lambda p: p["wara"], reverse=True) - - db.close() - return full_roster - - -@app.get('/api/v1/teams/{id_or_abbrev}/record/{week_num}') -async def v1_teams_get_record(id_or_abbrev, week_num: int): - try: - this_team = Team.get_by_id(id_or_abbrev) - except Exception as e: - this_team = Team.get_season(id_or_abbrev, Current.latest().season) - - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {id_or_abbrev} not found') - - db.close() - return this_team.get_record(week=week_num) - - -@app.patch('/api/v1/teams/{team_id}') -async def v1_teams_patch( - team_id, manager1_id: Optional[int] = None, manager2_id: Optional[int] = None, gmid: Optional[int] = None, - gmid2: Optional[int] = None, mascot: Optional[str] = None, stadium: Optional[str] = None, - thumbnail: Optional[str] = None, color: Optional[str] = None, abbrev: Optional[str] = None, - sname: Optional[str] = None, lname: Optional[str] = None, dice_color: Optional[str] = None, - division_id: Optional[int] = None, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch teams') - try: - this_team = Team.get_by_id(team_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {team_id}') - - if abbrev is not None: - this_team.abbrev = abbrev - if manager1_id is not None: - if manager1_id == 0: - this_team.manager1 = None - else: - try: - this_manager = Manager.get_by_id(manager1_id) - this_team.manager1 = this_manager - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No manager found with id {manager1_id}') - if manager2_id is not None: - print('in mgr2') - if manager2_id == 0: - print('deleting mgr2') - this_team.manager2 = None - else: - try: - print('trying mgr2') - this_manager = Manager.get_by_id(manager2_id) - this_team.manager2 = this_manager - print('set mgr2') - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No manager found with id {manager2_id}') - if gmid is not None: - this_team.gmid = gmid - if gmid2 is not None: - if gmid2 == 0: - this_team.gmid2 = None - else: - this_team.gmid2 = gmid2 - if mascot is not None: - if mascot == 'False': - this_team.mascot = None - else: - this_team.mascot = mascot - if stadium is not None: - this_team.stadium = stadium - if thumbnail is not None: - this_team.thumbnail = thumbnail - if color is not None: - this_team.color = color - if dice_color is not None: - this_team.dice_color = dice_color - if sname is not None: - this_team.sname = sname - if lname is not None: - this_team.lname = lname - if division_id is not None: - if division_id == 0: - this_team.division = None - else: - try: - this_division = Division.get_by_id(division_id) - this_team.division = this_division - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No division found with id {division_id}') - - if this_team.save(): - db.close() - return model_to_dict(this_team) - else: - db.close() - raise HTTPException(status_code=400, detail='This update did not go through') - - -@app.post('/api/v1/teams') -async def v1_teams_post(team: TeamModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post teams') - - dupe_team = Team.get_or_none(Team.season == team.season, Team.abbrev == team.abbrev) - if dupe_team: - db.close() - raise HTTPException(status_code=400, detail=f'There is already a season {team.season} team using {team.abbrev}') - - manager1 = None - if team.manager1_id: - try: - manager1 = Manager.get_by_id(team.manager1_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager with id {team.manager1_id} not found') - - manager2 = None - if team.manager2_id: - try: - manager2 = Manager.get_by_id(team.manager2_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager with id {team.manager2_id} not found') - - division = None - if team.division_id: - try: - division = Division.get_by_id(team.division_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Division with id {team.division_id} not found') - - this_team = Team( - season=team.season, - abbrev=team.abbrev, - sname=team.sname, - lname=team.lname, - gmid=team.gmid, - gmid2=team.gmid2, - manager1=manager1, - manager2=manager2, - division=division, - stadium=team.stadium, - thumbnail=team.thumbnail, - color=team.color, - dice_color=team.dice_color - ) - - saved = this_team.save() - db.close() - if saved == 1: - return model_to_dict(this_team) - else: - raise HTTPException(status_code=418, detail='Well slap my ass and call me a teapot; I could not save that team') - - -@app.delete('/api/v1/teams/{team_id}') -async def v1_teams_delete(team_id, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to delete teams') - try: - this_team = Team.get_by_id(team_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {team_id}') - - count = this_team.delete_instance() - db.close() - - if count == 1: - raise HTTPException(status_code=200, detail=f'Team {team_id} has been deleted') - else: - raise HTTPException(status_code=500, detail=f'Team {team_id} was not deleted') - - -@app.get('/api/v1/results') -async def v1_results_get( - season: int, team_abbrev: Optional[str] = None, week: Optional[int] = None, game: Optional[int] = None, - away_abbrev: Optional[str] = None, home_abbrev: Optional[str] = None, return_type: Optional[str] = 'json', - csv: Optional[bool] = False): - """ - Param: team_abbrev: string, may not use with away_abbrev or home_abbrev - Param: week: int - Param: away_abbrev: string, may not use with team_abbrev - Param: home_abbrev: string, may not use with team_abbrev - """ - all_results = Result.select_season(season) - # if all_results.count() == 0: - # db.close() - # raise HTTPException(status_code=404, detail=f'Season {season} not found') - - if week: - all_results = all_results.where(Result.week == week) - - if game: - all_results = all_results.where(Result.game == game) - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_results = all_results.where( - (Result.awayteam == this_team) | (Result.hometeam == this_team) - ) - else: - if away_abbrev: - this_team = Team.get_season(away_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Player {away_abbrev} not found') - - all_results = all_results.where(Result.awayteam == this_team) - - if home_abbrev: - this_team = Team.get_season(home_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Player {home_abbrev} not found') - - all_results = all_results.where(Result.hometeam == this_team) - - if return_type == 'csv' or csv: - helper_list = [['season', 'week', 'game_num', 'away_team', 'away_score', 'home_team', 'home_score']] - for game in all_results: - helper_list.append([game.season, game.week, game.game, game.awayteam.abbrev, game.awayscore, - game.hometeam.abbrev, game.homescore]) - - return_results = DataFrame(helper_list).to_csv(header=False, index=False) - db.close() - return Response(content=return_results, media_type='text/csv') - else: - return_results = {} - for game in all_results: - return_results[f'{game.id}'] = model_to_dict(game) - - db.close() - return return_results - - -@app.post('/api/v1/results') -async def v1_results_post(result: ResultModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post results') - - away_team = Team.get_by_id(result.away_team_id) - if not away_team: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {result.away_team_id}') - - home_team = Team.get_by_id(result.home_team_id) - if not home_team: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {result.home_team_id}') - - new_result = Result( - week=result.week, - game=result.game, - awayteam=away_team, - hometeam=home_team, - awayscore=result.away_score, - homescore=result.home_score, - season=result.season, - scorecard_url=result.scorecard_url - ) - - saved = new_result.save() - if saved != 1: - db.close() - raise HTTPException(status_code=400, detail=f'Unable to create {away_team.abbrev} @ {home_team.abbrev} ' - f'w{result.week}g{result.game}') - - # new_result.update_standings() - - # away_team.run_pythag_last8() - # home_team.run_pythag_last8() - # - # away_team.division.sort_division(new_result.season) - # if away_team.division != home_team.division: - # home_team.division.sort_division(new_result.season) - # - # away_team.division.sort_wildcard(new_result.season, away_team.division.league_abbrev) - # if away_team.division.league_abbrev != home_team.division.league_abbrev: - # home_team.division.sort_wildcard(new_result.season, home_team.division.league_abbrev) - - db.close() - raise HTTPException(status_code=200, detail=f'{away_team.abbrev} @ {home_team.abbrev} ' - f'w{result.week}g{result.game} has been logged') - - -@app.patch('/api/v1/results/{result_id}') -async def v1_results_patch( - result_id, away_score: Optional[int] = None, home_score: Optional[int] = None, - scorecard_url: Optional[str] = None, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch results') - - try: - this_result = Result.get_by_id(result_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Result id {result_id} not found') - - if away_score: - this_result.awayscore = away_score - if home_score: - this_result.homescore = home_score - if scorecard_url: - this_result.scorecard_url = scorecard_url - - this_result.save() - db.close() - return model_to_dict(this_result) - - -@app.delete('/api/v1/results/{result_id}') -async def v1_results_delete(result_id, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch results') - - try: - this_result = Result.get_by_id(result_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Result id {result_id} not found') - - this_result.delete_instance() - db.close() - raise HTTPException(status_code=200, detail=f'Deleted 1 result') - - -@app.get('/api/v1/schedules') -async def v1_schedules_get( - season: Optional[int] = SEASON_DEFAULT, team_abbrev1: Optional[str] = None, team_abbrev2: Optional[str] = None, - away_abbrev: Optional[str] = None, home_abbrev: Optional[str] = None, week_start: Optional[int] = None, - week_end: Optional[int] = None, return_type: Optional[str] = 'json', csv: Optional[bool] = False): - """ - Param: team_abbrev1: string, may not use with away_abbrev or home_abbrev - Param: team_abbrev2: string, may not use with away_abbrev or home_abbrev - Param: away_abbrev: string, may not use with team_abbrev1/2 - Param: home_abbrev: string, may not use with team_abbrev1/2 - Param: week_start: int - Param: week_end: int - """ - if not season: - season = SEASON_DEFAULT - schedule = Schedule.select_season(season) - # if schedule.count() == 0: - # db.close() - # raise HTTPException(status_code=404, detail=f'Season {season} not found') - - # Check for team_abbrev or away/home_abbrev - if team_abbrev1 or team_abbrev2: - if team_abbrev1: - this_team = Team.get_season(team_abbrev1, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev1} not found') - - schedule = schedule.where( - (Schedule.hometeam == this_team) | (Schedule.awayteam == this_team) - ) - if team_abbrev2: - this_team = Team.get_season(team_abbrev2, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev2} not found') - - schedule = schedule.where( - (Schedule.hometeam == this_team) | (Schedule.awayteam == this_team) - ) - else: - if away_abbrev: - this_team = Team.get_season(away_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {away_abbrev} not found') - - schedule = schedule.where(Schedule.awayteam == this_team) - - if home_abbrev: - this_team = Team.get_season(home_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {home_abbrev} not found') - - schedule = schedule.where(Schedule.hometeam == this_team) - - # Check for week limits - start = 0 - end = Schedule.select(fn.MAX(Schedule.week)).scalar() - if week_start: - start = week_start - - if week_end: - end = week_end - - if start > end: - logging.error('Start week is after end week - cannot pull schedule') - db.close() - raise HTTPException(status_code=404, - detail=f'Start week {start} is after end week {end} - cannot pull schedule') - - schedule = schedule.where( - (Schedule.week >= start) & (Schedule.week <= end) - ) - logging.info(f'schedule query: {schedule}') - - if return_type == 'csv' or csv: - schedule_list = [['season', 'week', 'away_abbrev', 'home_abbrev', 'game_count']] - for line in schedule: - schedule_list.append( - [ - line.season, line.week, line.awayteam.abbrev, line.hometeam.abbrev, line.gamecount - ] - ) - return_schedule = DataFrame(schedule_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_schedule, media_type='text/csv') - else: - return_schedule = {} - for game in schedule: - return_schedule[f'{game.id}'] = model_to_dict(game) - - db.close() - return return_schedule - - -@app.post('/api/v1/schedules') -async def v1_schedules_post(schedule: ScheduleModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post schedules') - all_scheds = [] - - for x in schedule.schedules: - try: - away_team = Team.get_by_id(x.away_team_id) - if not away_team: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {x.away_team_id}') - - home_team = Team.get_by_id(x.home_team_id) - if not home_team: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {x.home_team_id}') - - this_sched = Schedule( - season=x.season, - week=x.week, - awayteam=away_team, - hometeam=home_team, - gamecount=x.game_count - ) - all_scheds.append(this_sched) - except: - db.close() - raise HTTPException( - status_code=404, - detail=f'Failed to enter Team {x.away_team_id} @ Team {x.home_team_id}' - ) - - with db.atomic(): - Schedule.bulk_create(all_scheds, batch_size=20) - - db.close() - raise HTTPException(status_code=200, detail=f'Added {schedule.count} game{"s" if schedule.count > 1 else ""}') - - -@app.patch('/api/v1/schedules/{schedule_id}') -async def v1_schedules_patch( - schedule_id: int, week: Optional[int] = None, away_team_id: Optional[int] = None, - home_team_id: Optional[int] = None, game_count: Optional[int] = None, season: Optional[int] = None, - token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch schedules') - - this_schedule = None - try: - this_schedule = Schedule.get_by_id(schedule_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No schedule found with id {schedule_id}') - - if week is not None: - this_schedule.week = week - if away_team_id is not None: - try: - away_team = Team.get_by_id(away_team_id) - this_schedule.awayteam = away_team - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {away_team_id}') - if home_team_id is not None: - try: - home_team = Team.get_by_id(home_team_id) - this_schedule.hometeam = home_team - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {home_team_id}') - if game_count is not None: - this_schedule.gamecount = game_count - if season is not None: - this_schedule.season = season - - this_schedule.save() - db.close() - return model_to_dict(this_schedule) - - -@app.delete('/api/v1/schedules/{schedule_id}') -async def v1_schedules_delete(schedule_id: int, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to delete schedules') - - delete_query = Schedule.delete().where(Schedule.id == schedule_id) - - count = delete_query.execute() - db.close() - if count > 0: - raise HTTPException(status_code=200, detail=f'Removed {count} schedules') - else: - raise HTTPException(status_code=418, detail=f'Well slap my ass and call me a teapot; ' - f'I did not delete any records') - - -@app.get('/api/v1/transactions') -async def v1_transactions( - season = SEASON_DEFAULT, team_abbrev: Optional[str] = None, week_start: Optional[int] = 0, - week_end: Optional[int] = None, cancelled: Optional[bool] = None, frozen: Optional[bool] = None, - player_name: Optional[str] = None, player_id: Optional[int] = None, move_id: Optional[str] = None, - is_trade: Optional[bool] = None, return_type: Optional[str] = 'json', csv: Optional[bool] = False): - """ - Param: season: int - Param: team_abbrev: string - Param: week_start: int - Param: week_end: int - Param: player_id: int, overrides player_name (and season) - Param: player_name: string, overridden by player_id - Param: include_cancelled: bool, default False - Param: include_frozen: bool, default False - """ - if season: - transactions = Transaction.select_season(season) - else: - transactions = Transaction.select() - - # if transactions.count() == 0: - # db.close() - # raise HTTPException(status_code=404, detail=f'Season {season} not found') - - if team_abbrev: - these_teams = Team.select().where( - (Team.abbrev == team_abbrev.upper()) | (Team.abbrev == f'{team_abbrev.upper()}SIL') | - (Team.abbrev == f'{team_abbrev.upper()}MiL') | (Team.abbrev == f'{team_abbrev.upper()}IL') - ) - if these_teams.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - transactions = transactions.where( - (Transaction.newteam << these_teams) | (Transaction.oldteam << these_teams) - ) - - if week_start is not None: - transactions = transactions.where(Transaction.week >= week_start) - - if week_end is not None: - transactions = transactions.where(Transaction.week <= week_end) - - if move_id: - transactions = transactions.where(Transaction.moveid == move_id) - - if player_id or player_name: - if player_id: - try: - this_player = Player.get_by_id(player_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - - transactions = transactions.where(Transaction.player == this_player) - else: - these_players = Player.select().where(fn.Lower(Player.name) == player_name.lower()) - print(f'these_players: {these_players}\nCount: {these_players.count()}') - if these_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Player {player_name} not found') - - transactions = transactions.where(Transaction.player << these_players) - - if cancelled: - transactions = transactions.where(Transaction.cancelled == 1) - else: - transactions = transactions.where(Transaction.cancelled == 0) - - if frozen: - transactions = transactions.where(Transaction.frozen == 1) - else: - transactions = transactions.where(Transaction.frozen == 0) - - if is_trade is not None: - if not is_trade: - db.close() - raise HTTPException(status_code=501, detail='The is_trade parameter only supports True') - - # if is_trade is not None: - # if is_trade: - # old_team = Team.alias() - # new_team = Team.alias() - # transactions = transactions.join(Team, on=Transaction.oldteam).where( - # Transaction.oldteam.gmid != Transaction.newteam.gmid - # ) - # logging.info(transactions) - # - # # # Get IL, MIL and FA teams - # # ilteams = Team.select_season(season).where((fn.Lower(Team.abbrev).endswith('il'))) - # # all_teams = Team.select_season(season).where( - # # ~(Team.abbrev.endswith('IL')) & ~(Team.abbrev.endswith('MiL')) - # # ) - # # fa_team = Team.get(Team.season == season, Team.abbrev == 'FA') - # # - # # # Get transactions where new team << bad_teams - # # transactions = transactions.where( - # # (~(Transaction.oldteam << fa_team) & (Transaction.oldteam << all_teams) & - # # ~(Transaction.newteam << ilteams)) | - # # ((Transaction.oldteam << all_teams) & ~(Transaction.newteam << ilteams)) - # # ) - # # # Get transactions where old team << bad_teams - # else: - # db.close() - # raise HTTPException(status_code=501, detail='The "is_trade" parameter only supports True') - - transactions = transactions.order_by(-Transaction.week, Transaction.moveid) - - if return_type == 'csv' or csv: - trans_list = [['season', 'week', 'player_name', 'old_team_abbrev', 'new_team_abbrev', 'move_id']] - for line in transactions: - if (is_trade and line.oldteam.gmid and line.newteam.gmid and line.oldteam.gmid != line.newteam.gmid and - 'rule5' not in line.moveid) or not is_trade: - trans_list.append( - [ - line.season, line.week, line.player.name, line.oldteam.abbrev, line.newteam.abbrev, line.moveid - ] - ) - return_trans = DataFrame(trans_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_trans, media_type='text/csv') - else: - return_trans = {} - for line in transactions: - if (is_trade and line.oldteam.gmid and line.newteam.gmid and line.oldteam.gmid != line.newteam.gmid and - 'rule5' not in line.moveid) or not is_trade: - return_trans[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_trans - - -@app.post('/api/v1/transactions') -async def v1_transactions_post(moves: TransModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post transactions') - - all_moves = [] - - for x in moves.moves: - try: - old_team = Team.get_by_id(x.oldteam_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Old team with id {x.oldteam_id} not found') - try: - new_team = Team.get_by_id(x.newteam_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Away team with id {x.newteam_id} not found') - try: - this_player = Player.get_by_id(x.player_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {x.player_id} not found') - - this_move = Transaction( - week=x.week, - player=this_player, - oldteam=old_team, - newteam=new_team, - season=x.season, - moveid=x.moveid, - cancelled=x.cancelled, - frozen=x.frozen - ) - - all_moves.append(this_move) - - with db.atomic(): - Transaction.bulk_create(all_moves, batch_size=15) - - db.close() - raise HTTPException(status_code=200, detail=f'{len(all_moves)} of {moves.count} lines have been added') - - -@app.patch('/api/v1/transactions/{move_id}') -async def v1_transactions_patch( - move_id, token: str = Depends(oauth2_scheme), frozen: Optional[bool] = None, cancelled: Optional[bool] = None): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch transactions') - - these_moves = Transaction.select().where(Transaction.moveid == move_id) - if these_moves.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Move ID {move_id} not found') - - if frozen is not None: - for x in these_moves: - x.frozen = frozen - x.save() - if cancelled is not None: - for x in these_moves: - x.cancelled = cancelled - x.save() - - db.close() - raise HTTPException(status_code=200, detail=f'Updated {these_moves.count()} transactions') - - -@app.delete('/api/v1/transactions/{move_id}') -async def v1_transactions_delete( - move_id, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch transactions') - - delete_query = Transaction.delete().where(Transaction.moveid == move_id) - - count = delete_query.execute() - db.close() - if count > 0: - raise HTTPException(status_code=200, detail=f'Removed {count} transactions') - else: - raise HTTPException(status_code=418, detail=f'Well slap my ass and call me a teapot; ' - f'I did not delete any records') - - -@app.get('/api/v1/players') -async def v1_players_get( - season: Optional[int] = SEASON_DEFAULT, team_abbrev: Optional[str] = None, sort: Optional[str] = None, - injured: Optional[bool] = None, return_type: Optional[str] = 'json', csv: Optional[bool] = False): - """ - Param: season: int - Param: team_abbrev: string - Param: sort: string, [wara-desc] - """ - all_players = Player.select_season(season) - if all_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Season {season} not found') - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_players = all_players.where(Player.team == this_team) - - if sort: - if sort == 'wara-desc': - all_players = all_players.order_by(-Player.wara) - - if injured is not None: - all_players = all_players.where(Player.il_return.is_null(False)) - - if return_type == 'csv' or csv: - player_list = [ - ['name', 'wara', 'image', 'vanity_card', 'team_abbrev', 'pit_inj', 'pos_1', 'pos_2', 'pos_3', 'pos_4', - 'pos_5', 'pos_6', 'pos_7', 'pos_8', 'last_game', 'last_game2', 'il_return', 'dem_week'] - ] - for line in all_players: - player_list.append( - [ - line.name, line.wara, line.image, line.vanity_card, line.team.abbrev, line.pitcher_injury, - line.pos_1, line.pos_2, line.pos_3, line.pos_4, line.pos_5, line.pos_6, line.pos_7, line.pos_8, - line.last_game, line.last_game2, line.il_return, line.demotion_week - ] - ) - return_players = DataFrame(player_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_players, media_type='text/csv') - else: - return_players = {} - for player in all_players: - return_players[f'{player.name}'] = model_to_dict(player) - - db.close() - return return_players - - -@app.get('/api/v2/players') -async def v2_players_get( - season: Optional[int] = SEASON_DEFAULT, team_abbrev: Optional[str] = None, sort: Optional[str] = None, - injured: Optional[bool] = None, csv: Optional[bool] = False): - """ - Param: season: int - Param: team_abbrev: string - Param: sort: string, [wara-desc] - """ - all_players = Player.select_season(season) - if all_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Season {season} not found') - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_players = all_players.where(Player.team == this_team) - - if sort: - if sort == 'wara-desc': - all_players = all_players.order_by(-Player.wara) - - if injured is not None: - all_players = all_players.where(Player.il_return.is_null(False)) - - if csv: - player_list = [ - ['name', 'wara', 'image', 'vanity_card', 'team_abbrev', 'inj_rat', 'pos_1', 'pos_2', 'pos_3', 'pos_4', - 'pos_5', 'pos_6', 'pos_7', 'pos_8', 'last_game', 'last_game2', 'il_return', 'dem_week', 'strat_code', - 'bbref_id'] - ] - for line in all_players: - player_list.append( - [ - line.name, line.wara, line.image, line.vanity_card, line.team.abbrev, line.injury_rating, - line.pos_1, line.pos_2, line.pos_3, line.pos_4, line.pos_5, line.pos_6, line.pos_7, line.pos_8, - line.last_game, line.last_game2, line.il_return, line.demotion_week, line.strat_code, line.bbref_id - ] - ) - return_players = DataFrame(player_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_players, media_type='text/csv') - else: - return_players = {} - for player in all_players: - return_players[f'{player.name}'] = model_to_dict(player) - - db.close() - return return_players - - -@app.get('/api/v3/players') -async def v3_players_get( - season: Optional[int] = SEASON_DEFAULT, team_abbrev: Optional[str] = None, sort: Optional[str] = None, - injured: Optional[bool] = None, csv: Optional[bool] = False): - """ - Param: season: int - Param: team_abbrev: string - Param: sort: string, [wara-desc] - """ - all_players = Player.select_season(season) - if all_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Season {season} not found') - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_players = all_players.where(Player.team == this_team) - - if sort: - if sort == 'wara-desc': - all_players = all_players.order_by(-Player.wara) - - if injured is not None: - all_players = all_players.where(Player.il_return.is_null(False)) - - if csv: - player_list = [ - ['name', 'wara', 'image', 'vanity_card', 'team_abbrev', 'inj_rat', 'pos_1', 'pos_2', 'pos_3', 'pos_4', - 'pos_5', 'pos_6', 'pos_7', 'pos_8', 'last_game', 'last_game2', 'il_return', 'dem_week', 'strat_code', - 'bbref_id'] - ] - for line in all_players: - player_list.append( - [ - line.name, line.wara, line.image, line.vanity_card, line.team.abbrev, line.injury_rating, - line.pos_1, line.pos_2, line.pos_3, line.pos_4, line.pos_5, line.pos_6, line.pos_7, line.pos_8, - line.last_game, line.last_game2, line.il_return, line.demotion_week, line.strat_code, line.bbref_id - ] - ) - return_players = DataFrame(player_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_players, media_type='text/csv') - else: - return_players = {'count': all_players.count(), 'players': []} - for player in all_players: - return_players['players'].append(model_to_dict(player)) - - db.close() - return return_players - - -@app.get('/api/v2/players/{id_or_name}') -async def v2_players_get_one(id_or_name, season: Optional[int] = SEASON_DEFAULT, csv: Optional[bool] = False): - this_player = None - - try: - this_player = Player.get_by_id(id_or_name) - except Exception as e: - this_player = Player.get_season(id_or_name, season) - - if this_player: - if csv: - player_list = [['name', 'wara', 'image', 'image2', 'team_abbrev', 'inj_rat', 'pos_1', 'pos_2', 'pos_3', - 'pos_4', 'pos_5', 'pos_6', 'pos_7', 'pos_8', 'last_game', 'last_game2', 'il_return', - 'dem_week', 'strat_code', 'bbref_id'], - [this_player.name, this_player.wara, this_player.image, this_player.image2, - this_player.team.abbrev, this_player.injury_rating, this_player.pos_1, this_player.pos_2, - this_player.pos_3, this_player.pos_4, this_player.pos_5, this_player.pos_6, - this_player.pos_7, this_player.pos_8, this_player.last_game, this_player.last_game2, - this_player.il_return, this_player.demotion_week, this_player.strat_code, - this_player.bbref_id] - ] - return_players = DataFrame(player_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_players, media_type='text/csv') - else: - db.close() - return model_to_dict(this_player) - else: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {id_or_name} not found') - - -@app.get('/api/v1/players/{id_or_name}') -async def v1_players_get_one(id_or_name, season: Optional[int] = SEASON_DEFAULT, return_type: Optional[str] = 'json', - csv: Optional[bool] = False): - this_player = None - - try: - this_player = Player.get_by_id(id_or_name) - except Exception as e: - this_player = Player.get_season(id_or_name, season) - - if this_player: - if return_type == 'csv' or csv: - player_list = [['name', 'wara', 'image', 'image2', 'team_abbrev', 'pit_inj', 'pos_1', 'pos_2', 'pos_3', - 'pos_4', 'pos_5', 'pos_6', 'pos_7', 'pos_8', 'last_game', 'last_game2', 'il_return', - 'dem_week'], - [this_player.name, this_player.wara, this_player.image, this_player.image2, - this_player.team.abbrev, this_player.pitcher_injury, this_player.pos_1, this_player.pos_2, - this_player.pos_3, this_player.pos_4, this_player.pos_5, this_player.pos_6, - this_player.pos_7, this_player.pos_8, this_player.last_game, this_player.last_game2, - this_player.il_return, this_player.demotion_week] - ] - return_players = DataFrame(player_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_players, media_type='text/csv') - else: - db.close() - return model_to_dict(this_player) - else: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {id_or_name} not found') - - -@app.patch('/api/v2/players/{pid}') -async def v1_players_patch( - pid: int, token: str = Depends(oauth2_scheme), name: Optional[str] = None, wara: Optional[float] = None, - image: Optional[str] = None, image2=None, team_id: Optional[int] = None, season: Optional[int] = None, - pitcher_injury=None, pos_1=None, pos_2=None, pos_3=None, pos_4=None, pos_5=None, pos_6=None, pos_7=None, - pos_8=None, last_game=None, last_game2=None, il_return=None, demotion_week=None, headshot=None, - vanity_card=None, strat_code=None, bbref_id=None, injury_rating=None): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch players') - - try: - this_player = Player.get_by_id(pid) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {pid} not found') - - if team_id: - try: - this_team = Team.get_by_id(team_id) - this_player.team = this_team - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Team id {team_id} not found') - if name: - this_player.name = name - if wara is not None: - this_player.wara = wara - if image: - this_player.image = image - if image2 is not None: - if image2.lower() == 'false': - this_player.image2 = None - else: - this_player.image2 = image2 - if season: - this_player.season = season - if pitcher_injury is not None: - if pitcher_injury.lower() == 'false': - this_player.pitcher_injury = None - else: - this_player.pitcher_injury = pitcher_injury - if pos_1: - this_player.pos_1 = pos_1 - if pos_2 is not None: - if pos_2.lower() == 'false': - this_player.pos_2 = None - else: - this_player.pos_2 = pos_2 - if pos_3 is not None: - if pos_3.lower() == 'false': - this_player.pos_3 = None - else: - this_player.pos_3 = pos_3 - if pos_4 is not None: - if pos_4.lower() == 'false': - this_player.pos_4 = None - else: - this_player.pos_4 = pos_4 - if pos_5 is not None: - if pos_5.lower() == 'false': - this_player.pos_5 = None - else: - this_player.pos_5 = pos_5 - if pos_6 is not None: - if pos_6.lower() == 'false': - this_player.pos_6 = None - else: - this_player.pos_6 = pos_6 - if pos_7 is not None: - if pos_7.lower() == 'false': - this_player.pos_7 = None - else: - this_player.pos_7 = pos_7 - if pos_8 is not None: - if pos_8.lower() == 'false': - this_player.pos_8 = None - else: - this_player.pos_8 = pos_8 - if last_game is not None: - if last_game.lower() == 'false': - this_player.last_game = None - else: - this_player.last_game = last_game - if last_game2 is not None: - if last_game2.lower() == 'false': - this_player.last_game2 = None - else: - this_player.last_game2 = last_game2 - if il_return is not None: - if il_return.lower() == 'false': - this_player.il_return = None - else: - this_player.il_return = il_return - if demotion_week is not None: - if demotion_week.lower() == 'false': - this_player.demotion_week = None - else: - this_player.demotion_week = demotion_week - if headshot is not None: - if headshot.lower() == 'false': - this_player.headshot = None - else: - this_player.headshot = headshot - if vanity_card is not None: - if vanity_card.lower() == 'false': - this_player.vanity_card = None - else: - this_player.vanity_card = vanity_card - if strat_code is not None: - if strat_code.lower() == 'false': - this_player.strat_code = None - else: - this_player.strat_code = strat_code - if bbref_id is not None: - if bbref_id.lower() == 'false': - this_player.bbref_id = None - else: - this_player.bbref_id = bbref_id - if injury_rating is not None: - if injury_rating.lower() == 'false': - this_player.injury_rating = None - else: - this_player.injury_rating = injury_rating - - saved = this_player.save() - db.close() - if saved == 1: - return model_to_dict(this_player) - else: - raise HTTPException(status_code=400, detail=f'Unable to update {this_player.name}') - - -@app.post('/api/v2/players') -async def v1_players_post(players: PlayerModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post players') - - new_players = [] - for x in players.players: - logging.info(f'x: {x}') - this_player = Player( - name=x.name, - wara=x.wara, - image=x.image, - image2=x.image2, - team_id=x.team_id, - season=x.season, - pitcher_injury=x.pitcher_injury, - pos_1=x.pos_1, - pos_2=x.pos_2, - pos_3=x.pos_3, - pos_4=x.pos_4, - pos_5=x.pos_5, - pos_6=x.pos_6, - pos_7=x.pos_7, - pos_8=x.pos_8, - last_game=x.last_game, - last_game2=x.last_game2, - il_return=x.il_return, - demotion_week=x.demotion_week, - strat_code=x.strat_code, - bbref_id=x.bbref_id, - injury_rating=x.injury_rating - ) - new_players.append(this_player) - - with db.atomic(): - Player.bulk_create(new_players, batch_size=15) - db.close() - - raise HTTPException(status_code=200, detail=f'{len(new_players)} players have been added') - - -@app.get('/api/v1/battingcareer/{id_or_name}') -async def v1_battingcareer_get(id_or_name, csv: Optional[bool] = False): - this_career = None - try: - this_career = BattingCareer.get_by_id(id_or_name) - except Exception as e: - logging.info(f'Could not find BattingCareer with id {id_or_name}') - - if not this_career: - this_career = BattingCareer.get_or_none(fn.Lower(BattingCareer.name) == id_or_name.lower()) - - if this_career: - if csv: - career_list = [ - ['name', 'pa', 'ab', 'run', 'hit', 'rbi', 'double', 'triple', 'hr', 'bb', 'so', 'hbp', 'sac', 'ibb', - 'gidp', 'sb', 'cs', 'bphr', 'bpfo', 'bp1b', 'bplo', 'games'], - [this_career.name, this_career.pa, this_career.ab, this_career.run, this_career.hit, this_career.rbi, - this_career.double, this_career.triple, this_career.hr, this_career.bb, this_career.so, - this_career.hbp, this_career.sac, this_career.ibb, this_career.gidp, this_career.sb, this_career.cs, - this_career.bphr, this_career.bpfo, this_career.bp1b, this_career.bplo, this_career.games] - ] - return_career = DataFrame(career_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_career, media_type='text/csv') - else: - db.close() - return model_to_dict(this_career) - else: - db.close() - raise HTTPException(status_code=404, detail=f'Career id {id_or_name} not found') - - -@app.get('/api/v1/pitchingcareer/{id_or_name}') -async def v1_pitchingcareer_get(id_or_name, csv: Optional[bool] = False): - this_career = None - try: - this_career = PitchingCareer.get_by_id(id_or_name) - except Exception as e: - logging.info(f'Could not find PitchingCareer with id {id_or_name}') - - if not this_career: - this_career = PitchingCareer.get_or_none(fn.Lower(PitchingCareer.name) == id_or_name.lower()) - - if this_career: - if csv: - career_list = [ - ['name', 'ip', 'hit', 'run', 'erun', 'so', 'bb', 'hbp', 'wp', 'balk', 'hr', 'ir', 'irs', 'gs', 'win', - 'loss', 'hold', 'sv', 'bsv', 'game'], - [this_career.name, this_career.ip, this_career.hit, this_career.run, this_career.erun, this_career.so, - this_career.bb, this_career.hbp, this_career.wp, this_career.balk, this_career.hr, this_career.ir, - this_career.irs, this_career.gs, this_career.win, this_career.loss, this_career.hold, this_career.sv, - this_career.bsv, this_career.game] - ] - return_career = DataFrame(career_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_career, media_type='text/csv') - else: - db.close() - return model_to_dict(this_career) - else: - db.close() - raise HTTPException(status_code=404, detail=f'Career id {id_or_name} not found') - - -@app.get('/api/v1/battingstats/s{season}/{s_type}') -async def v1_battingstats_get( - s_type: str, season: int = SEASON_DEFAULT, team_abbrev: Optional[str] = None, - player_name: Optional[str] = None, player_id: Optional[int] = None, week_start: Optional[int] = None, - week_end: Optional[int] = None, game_num: Optional[int] = None, position: Optional[str] = None, - limit: Optional[int] = None, sort: Optional[str] = None, return_type: Optional[str] = 'json', - csv: Optional[bool] = False): - """ - :param season: int - :param s_type: string (regular, post, combined) - :param team_abbrev: string - :param player_name: string - :param player_id: integer, overrides player_name - :param week_start: integer - :param week_end: integer - :param game_num: integer - :param position: string - :param limit: int - :param sort: string, 'oldest' or 'newest' to return first - :return: - """ - if s_type.lower() == 'post': - all_stats = BattingStat.post_season(season) - if all_stats.count() == 0: - db.close() - return {} - elif s_type.lower() == 'combined': - all_stats = BattingStat.combined_season(season) - if all_stats.count() == 0: - db.close() - return {} - else: - all_stats = BattingStat.regular_season(season) - if not all_stats: - db.close() - return {} - - if position: - all_stats = all_stats.where(BattingStat.pos == position.upper()) - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_stats = all_stats.where(BattingStat.team == this_team) - - if player_name or player_id: - if player_id: - try: - this_player = Player.get_by_id(player_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - else: - this_player = Player.get_season(player_name, season) - if not this_player: - db.close() - raise HTTPException(status_code=404, detail=f'Player {player_name} not found') - - all_stats = all_stats.where(BattingStat.player == this_player) - - start = 1 - end = Current.get(Current.season == season).week - if week_start is not None: - start = week_start - - if week_end is not None: - end = min(week_end, end) - - if start > end: - db.close() - raise HTTPException(status_code=404, - detail=f'Start week {start} is after end week {end} - cannot pull stats') - if start + 5 < end and team_abbrev is None and player_name is None and player_id is None and not csv: - start = end - 5 - - logging.info(f'\n\nweek_start: {week_start} / week_end: {week_end} / game_num: {game_num} / ' - f'start: {start} / end: {end}') - all_stats = all_stats.where( - (BattingStat.week >= start) & (BattingStat.week <= end) - ) - - if game_num: - all_stats = all_stats.where(BattingStat.game == game_num) - - if limit: - all_stats = all_stats.limit(limit) - - if sort: - if sort == 'newest': - all_stats = all_stats.order_by(-BattingStat.week, -BattingStat.game) - - if return_type == 'csv' or csv: - stats_list = [['season', 'week', 'game_num', 'player', 'team', 'pos', 'pa', 'ab', 'run', 'hit', 'rbi', 'double', - 'triple', 'hr', 'bb', 'so', 'hbp', 'sac', 'ibb', 'gidp', 'sb', 'cs', 'xba', 'xbt']] - for line in all_stats: - stats_list.append( - [ - line.season, line.week, line.game, line.player.name, line.team.abbrev, line.pos, line.pa, line.ab, - line.run, line.hit, line.rbi, line.double, line.triple, line.hr, line.bb, line.so, line.hbp, - line.sac, line.ibb, line.gidp, line.sb, line.cs, line.xba, line.xbt - ] - ) - return_stats = DataFrame(stats_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_stats, media_type='text/csv') - else: - return_stats = {} - for line in all_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - # Need recurse set to false to allow JSON data - # return_stats[f'{line.id}'] = model_to_dict(line, recurse=False) - - db.close() - return return_stats - - -@app.post('/api/v1/battingstats') -async def v1_battingstats_post(stats: BattingStatModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post batting stats') - - all_stats = [] - season = None - week = None - teams = [] - game_num = None - - for x in stats.stats: - try: - team = Team.get_by_id(x.team_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {x.team_id}') - try: - this_player = Player.get_by_id(x.player_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {x.player_id} not found') - - # Helpers for query - if team not in teams: - teams.append(team) - if not season: - season = x.season - if not week: - week = x.week - if not game_num: - game_num = x.game - - new_stats = BattingStat( - player=this_player, - team=team, - pos=x.pos, - pa=x.pa, - ab=x.ab, - run=x.run, - hit=x.hit, - rbi=x.rbi, - double=x.double, - triple=x.triple, - hr=x.hr, - bb=x.bb, - so=x.so, - hbp=x.hbp, - sac=x.sac, - ibb=x.ibb, - gidp=x.gidp, - sb=x.sb, - cs=x.cs, - bphr=x.bphr, - bpfo=x.bpfo, - bp1b=x.bp1b, - bplo=x.bplo, - xba=x.xba, - xbt=x.xbt, - xch=x.xch, - xhit=x.xhit, - error=x.error, - pb=x.pb, - sbc=x.sbc, - csc=x.csc, - roba=x.roba, - robs=x.robs, - raa=x.raa, - rto=x.rto, - week=x.week, - game=x.game, - season=x.season, - ) - all_stats.append(new_stats) - - with db.atomic(): - BattingStat.bulk_create(all_stats, batch_size=15) - - this_game_stats = BattingStat.select().where( - (BattingStat.season == season) & (BattingStat.week == week) & - (BattingStat.game == game_num) & ((BattingStat.team == teams[0]) | (BattingStat.team == teams[1])) - ) - - logging.warning(f'I pulled {this_game_stats.count()} batting lines with this query:\n{this_game_stats}') - - # Update season and career stats with freshly submitted for regular season games - if (season > 2) and week <= 22: - s_type = 'Regular' - else: - s_type = 'Post' - - for line in this_game_stats: - this_season = BattingSeason.get_or_none(player=line.player, season=line.player.season, season_type=s_type) - if not this_season: - this_season = BattingSeason(player=line.player, season=line.player.season, season_type=s_type) - this_season.save() - this_career = BattingCareer.get_or_none(BattingCareer.name == this_season.player.name) - if not this_career: - this_career = BattingCareer(name=this_season.player.name) - this_career.save() - - fielding_season = FieldingSeason.get_or_none( - player=line.player, season=line.player.season, pos=line.pos, season_type=s_type - ) - if not fielding_season: - fielding_season = FieldingSeason( - player=line.player, season=line.player.season, pos=line.pos, season_type=s_type - ) - fielding_season.save() - fielding_career = FieldingCareer.get_or_none(name=line.player.name, pos=line.pos) - if not fielding_career: - fielding_career = FieldingCareer(name=line.player.name, pos=line.pos) - fielding_career.save() - - this_season.pa += line.pa - this_season.ab += line.ab - this_season.run += line.run - this_season.hit += line.hit - this_season.rbi += line.rbi - this_season.double += line.double - this_season.triple += line.triple - this_season.hr += line.hr - this_season.bb += line.bb - this_season.so += line.so - this_season.hbp += line.hbp - this_season.sac += line.sac - this_season.ibb += line.ibb - this_season.gidp += line.gidp - this_season.sb += line.sb - this_season.cs += line.cs - this_season.bphr += line.bphr - this_season.bpfo += line.bpfo - this_season.bp1b += line.bp1b - this_season.bplo += line.bplo - this_season.xba += line.xba - this_season.xbt += line.xbt - this_season.game += 1 - fielding_season.xch += line.xch - fielding_season.xhit += line.xhit - fielding_season.error += line.error - fielding_season.pb += line.pb - fielding_season.sbc += line.sbc - fielding_season.csc += line.csc - fielding_season.roba += line.roba - fielding_season.robs += line.robs - fielding_season.raa += line.raa - fielding_season.rto += line.rto - fielding_season.game += 1 - - if s_type == 'Regular': - this_career.pa += line.pa - this_career.ab += line.ab - this_career.run += line.run - this_career.hit += line.hit - this_career.rbi += line.rbi - this_career.double += line.double - this_career.triple += line.triple - this_career.hr += line.hr - this_career.bb += line.bb - this_career.so += line.so - this_career.hbp += line.hbp - this_career.sac += line.sac - this_career.ibb += line.ibb - this_career.gidp += line.gidp - this_career.sb += line.sb - this_career.cs += line.cs - this_career.bphr += line.bphr - this_career.bpfo += line.bpfo - this_career.bp1b += line.bp1b - this_career.bplo += line.bplo - this_career.xba += line.xba - this_career.xbt += line.xbt - this_career.game += 1 - fielding_career.xch += line.xch - fielding_career.xhit += line.xhit - fielding_career.error += line.error - fielding_career.pb += line.pb - fielding_career.sbc += line.sbc - fielding_career.csc += line.csc - fielding_career.roba += line.roba - fielding_career.robs += line.robs - fielding_career.raa += line.raa - fielding_career.rto += line.rto - fielding_career.game += 1 - - this_season.save() - this_career.save() - fielding_season.save() - fielding_career.save() - - db.close() - raise HTTPException(status_code=200, detail=f'{len(all_stats)} of {stats.count} lines have been added') - - -@app.delete('/api/v1/battingstats') -async def v1_battingstats_delete(game: GameModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to delete batting stats') - - # Get teams - try: - away_team = Team.get_by_id(game.away_team_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Away team with id {game.away_team_id} not found') - try: - home_team = Team.get_by_id(game.home_team_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Away team with id {game.home_team_id} not found') - - # Check for matchup - this_matchup = Schedule.select_season(Current.latest().season).where( - (Schedule.awayteam == away_team) & (Schedule.hometeam == home_team) & (Schedule.week == game.week) - ) - if this_matchup.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No game found between {away_team.abbrev} and {home_team.abbrev} ' - f'in week {game.week}') - - # Check for game batting stats - this_game_stats = BattingStat.select().where( - (BattingStat.season == game.season) & (BattingStat.week == game.week) & (BattingStat.game == game.game_num) & - ((BattingStat.team == away_team) | (BattingStat.team == home_team)) & (BattingStat.pa > 0) - ) - if this_game_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No stats found for {away_team.abbrev} at {home_team.abbrev} in ' - f'that matchup') - - # # Remove stats from season lines - # for line in this_game_stats: - # this_season = BattingSeason.get_or_none(player=line.player, season=line.player.season) - # if not this_season: - # db.close() - # raise HTTPException(status_code=404, detail=f'Could not find existing batting season stats ' - # f'for {line.player.name} (ID: {line.player.id})') - # this_career = BattingCareer.get_or_none(BattingCareer.name == this_season.player.name) - # if not this_career: - # this_career = BattingCareer(name=this_season.player.name) - # this_career.save() - # - # this_season.pa -= line.pa - # # this_career.pa -= line.pa - # this_season.ab -= line.ab - # # this_career.ab -= line.ab - # this_season.run -= line.run - # # this_career.run -= line.run - # this_season.hit -= line.hit - # # this_career.hit -= line.hit - # this_season.rbi -= line.rbi - # # this_career.rbi -= line.rbi - # this_season.double -= line.double - # # this_career.double -= line.double - # this_season.triple -= line.triple - # # this_career.triple -= line.triple - # this_season.hr -= line.hr - # # this_career.hr -= line.hr - # this_season.bb -= line.bb - # # this_career.bb -= line.bb - # this_season.so -= line.so - # # this_career.so -= line.so - # this_season.hbp -= line.hbp - # # this_career.hbp -= line.hbp - # this_season.sac -= line.sac - # # this_career.sac -= line.sac - # this_season.ibb -= line.ibb - # # this_career.ibb -= line.ibb - # this_season.gidp -= line.gidp - # # this_career.gidp -= line.gidp - # this_season.sb -= line.sb - # # this_career.sb -= line.sb - # this_season.cs -= line.cs - # # this_career.cs -= line.cs - # this_season.game -= 1 - # # this_career.game -= 1 - # - # this_season.save() - # # this_career.save() - # - # this_career.recalculate() - # - # # Check for game fielding stats - # this_game_stats = BattingStat.select().where( - # (BattingStat.season == game.season) & (BattingStat.week == game.week) & (BattingStat.game == game.game_num) & - # ((BattingStat.team == away_team) | (BattingStat.team == home_team)) & (BattingStat.xch + BattingStat.sbc > 0) - # ) - # if this_game_stats.count() == 0: - # db.close() - # raise HTTPException(status_code=404, detail=f'No stats found for {away_team.abbrev} at {home_team.abbrev} in ' - # f'that matchup') - # - # # Remove stats from season lines - # for line in this_game_stats: - # this_season = FieldingSeason.get_or_none(player=line.player, season=line.player.season) - # if not this_season: - # db.close() - # raise HTTPException(status_code=404, detail=f'Could not find existing batting season stats ' - # f'for {line.player.name} (ID: {line.player.id})') - # this_career = FieldingCareer.get_or_none(FieldingCareer.name == this_season.player.name, - # FieldingCareer.pos == line.pos) - # if not this_career: - # this_career = FieldingCareer(name=this_season.player.name, pos=this_season.pos) - # this_career.save() - # - # this_season.xch -= line.xch - # # this_career.xch -= line.xch - # this_season.xhit -= line.xhit - # # this_career.xhit -= line.xhit - # this_season.error -= line.error - # # this_career.error -= line.error - # this_season.pb -= line.pb - # # this_career.pb -= line.pb - # this_season.sbc -= line.sbc - # # this_career.sbc -= line.sbc - # this_season.csc -= line.csc - # # this_career.csc -= line.csc - # this_season.game -= 1 - # # this_career.game -= 1 - # - # this_season.save() - # # this_career.save() - # - # this_career.recalculate() - - # Delete the stats - delete_query = BattingStat.delete().where( - (BattingStat.season == game.season) & (BattingStat.week == game.week) & - ((BattingStat.team == away_team) | (BattingStat.team == home_team)) - ) - if game.game_num: - delete_query = delete_query.where(BattingStat.game == game.game_num) - - count = delete_query.execute() - db.close() - if count > 0: - raise HTTPException(status_code=200, detail=f'Removed {count} batting stat lines') - else: - raise HTTPException(status_code=418, detail=f'Well slap my ass and call me a teapot; ' - f'I did not delete any records') - - -@app.get('/api/v1/pitchingstats/s{season}/{s_type}') -async def v1_pitchingstat_get( - s_type: str, season: int, team_abbrev: Optional[str] = None, - player_name: Optional[str] = None, player_id: Optional[int] = None, week_start: Optional[int] = None, - week_end: Optional[int] = None, game_num: Optional[int] = None, limit: Optional[int] = None, - sort: Optional[str] = None, return_type: Optional[str] = 'json', csv: Optional[bool] = False): - """ - :param season: int - :param s_type: string (regular, post, combined) - :param team_abbrev: string - :param player_name: string - :param player_id: integer, overrides player_name - :param week_start: integer - :param week_end: integer - :param limit: int - :param sort: string, 'newest' or 'oldest' to get those first - :return: - """ - if s_type.lower() == 'post': - all_stats = PitchingStat.post_season(season) - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No postseason stats found for season {season}') - elif s_type.lower() == 'combined': - all_stats = PitchingStat.combined_season(season) - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No stats found for season {season}') - else: - all_stats = PitchingStat.regular_season(season) - if not all_stats: - db.close() - return {} - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_stats = all_stats.where(PitchingStat.team == this_team) - - if player_name or player_id: - if player_id: - try: - this_player = Player.get_by_id(player_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - else: - this_player = Player.get_season(player_name, season) - if not this_player: - db.close() - raise HTTPException(status_code=404, detail=f'Player {player_name} not found') - - all_stats = all_stats.where(PitchingStat.player == this_player) - - start = 1 - end = Current.get(Current.season == season).week - if week_start is not None: - start = week_start - - if week_end is not None: - end = min(week_end, end) - - if start > end: - db.close() - raise HTTPException(status_code=404, - detail=f'Start week {start} is after end week {end} - cannot pull stats') - if start + 5 < end and team_abbrev is None and player_name is None and player_id is None and not csv: - start = end - 5 - - all_stats = all_stats.where( - (PitchingStat.week >= start) & (PitchingStat.week <= end) - ) - - if game_num: - all_stats = all_stats.where(PitchingStat.game == game_num) - - if limit: - all_stats = all_stats.limit(limit) - - if sort: - if sort == 'newest': - all_stats = all_stats.order_by(-PitchingStat.week, -PitchingStat.game) - - if return_type == 'csv' or csv: - stats_list = [['pitcher', 'team', 'ip', 'h', 'r', 'er', 'so', 'bb', 'hbp', 'wp', 'bk', 'hr', - 'gs', 'w', 'l', 'hd', 'sv', 'bs', 'week', 'game', 'code']] - for line in all_stats: - stats_list.append( - [ - line.player.name, line.team.abbrev, line.ip, line.hit, line.run, line.erun, line.so, line.bb, - line.hbp, line.wp, line.balk, line.hr, line.gs, line.win, line.loss, line.hold, line.sv, line.bsv, - line.week, line.game, f'{line.week}.{line.game}' - ] - ) - return_stats = DataFrame(stats_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_stats, media_type='text/csv') - - else: - return_stats = {} - for line in all_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.post('/api/v1/pitchingstats') -async def v1_pitchingstats_post(stats: PitchingStatModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post pitching stats') - - all_stats = [] - season = None - week = None - teams = [] - game_num = None - - for x in stats.stats: - team = Team.get_by_id(x.team_id) - if not team: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {x.team_id}') - - player = Player.get_by_id(x.player_id) - if not player: - db.close() - raise HTTPException(status_code=404, detail=f'No player found with id {x.player_id}') - - # Helpers for query - if team not in teams: - teams.append(team) - if not season: - season = x.season - if not week: - week = x.week - if not game_num: - game_num = x.game - - new_stats = PitchingStat( - player=player, - team=team, - ip=x.ip, - hit=x.hit, - run=x.run, - erun=x.erun, - so=x.so, - bb=x.bb, - hbp=x.hbp, - wp=x.wp, - balk=x.balk, - hr=x.hr, - gs=x.gs, - win=x.win, - loss=x.loss, - hold=x.hold, - sv=x.sv, - bsv=x.bsv, - ir=x.ir, - irs=x.irs, - week=x.week, - game=x.game, - season=x.season - ) - all_stats.append(new_stats) - - with db.atomic(): - PitchingStat.bulk_create(all_stats, batch_size=20) - - this_game_stats = PitchingStat.select().where( - (PitchingStat.season == season) & (PitchingStat.week == week) & (PitchingStat.game == game_num) & - ((PitchingStat.team == teams[0]) | (PitchingStat.team == teams[1])) - ) - - # Update season stats with freshly submitted for regular season games - if (season > 2) and week <= 22: - s_type = 'Regular' - else: - s_type = 'Post' - - for line in this_game_stats: - this_season = PitchingSeason.get_or_none( - player=line.player, season=line.season, season_type=s_type - ) - if not this_season: - this_season = PitchingSeason(player=line.player, season=line.season, season_type=s_type) - this_season.save() - - this_career = PitchingCareer.get_or_none(name=line.player.name) - if not this_career: - this_career = PitchingCareer(name=line.player.name) - this_career.save() - - this_season.ip += line.ip - this_season.hit += line.hit - this_season.run += line.run - this_season.erun += line.erun - this_season.so += line.so - this_season.bb += line.bb - this_season.hbp += line.hbp - this_season.wp += line.wp - this_season.balk += line.balk - this_season.hr += line.hr - this_season.ir += line.ir - this_season.irs += line.irs - this_season.gs += line.gs - this_season.win += line.win - this_season.loss += line.loss - this_season.hold += line.hold - this_season.sv += line.sv - this_season.bsv += line.bsv - this_season.game += 1 - - if s_type == 'Regular': - this_career.ip += line.ip - this_career.hit += line.hit - this_career.run += line.run - this_career.erun += line.erun - this_career.so += line.so - this_career.bb += line.bb - this_career.hbp += line.hbp - this_career.wp += line.wp - this_career.balk += line.balk - this_career.hr += line.hr - this_career.ir += line.ir - this_career.irs += line.irs - this_career.gs += line.gs - this_career.win += line.win - this_career.loss += line.loss - this_career.hold += line.hold - this_career.sv += line.sv - this_career.bsv += line.bsv - this_career.game += 1 - - this_season.save() - this_career.save() - - db.close() - raise HTTPException(status_code=200, detail=f'{len(all_stats)} of {stats.count} lines have been added') - - -@app.delete('/api/v1/pitchingstats') -async def v1_pitchingstats_delete(game: GameModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to delete pitching stats') - - # Get teams - try: - away_team = Team.get_by_id(game.away_team_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Away team with id {game.away_team_id} not found') - try: - home_team = Team.get_by_id(game.home_team_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Away team with id {game.home_team_id} not found') - - # Check for matchup - this_matchup = Schedule.select_season(Current.latest().season).where( - (Schedule.awayteam == away_team) & (Schedule.hometeam == home_team) & (Schedule.week == game.week) - ) - if this_matchup.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No game found between {away_team.abbrev} and {home_team.abbrev} ' - f'in week {game.week}') - - # # Check for game stats - # this_game_stats = PitchingStat.select().where( - # (PitchingStat.season == game.season) & (PitchingStat.week == game.week) & - # ((PitchingStat.team == away_team) | (PitchingStat.team == home_team)) - # ) - # if game.game_num: - # this_game_stats = this_game_stats.where(PitchingStat.game == game.game_num) - # if this_game_stats.count() == 0: - # db.close() - # raise HTTPException(status_code=404, detail=f'No stats found for {away_team.abbrev} at {home_team.abbrev} in ' - # f'that matchup') - # - # # Remove stats from season lines - # for line in this_game_stats: - # this_season = PitchingSeason.get_or_none(player=line.player, season=line.player.season) - # if not this_season: - # db.close() - # raise HTTPException(status_code=404, detail=f'Could not find existing pitching season stats ' - # f'for {line.player.name} (ID: {line.player.id})') - # this_career = PitchingCareer.get_or_none(PitchingCareer.name == this_season.player.name) - # if not this_career: - # this_career = PitchingCareer(name=this_season.player.name) - # this_career.save() - # - # # this_career.ip -= line.ip - # this_season.ip -= line.ip - # # this_career.hit -= line.hit - # this_season.hit -= line.hit - # # this_career.run -= line.run - # this_season.run -= line.run - # # this_career.erun -= line.erun - # this_season.erun -= line.erun - # # this_career.so -= line.so - # this_season.so -= line.so - # # this_career.bb -= line.bb - # this_season.bb -= line.bb - # # this_career.hbp -= line.hbp - # this_season.hbp -= line.hbp - # # this_career.wp -= line.wp - # this_season.wp -= line.wp - # # this_career.balk -= line.balk - # this_season.balk -= line.balk - # # this_career.hr -= line.hr - # this_season.hr -= line.hr - # # this_career.gs -= line.gs - # this_season.gs -= line.gs - # # this_career.win -= line.win - # this_season.win -= line.win - # # this_career.loss -= line.loss - # this_season.loss -= line.loss - # # this_career.hold -= line.hold - # this_season.hold -= line.hold - # this_season.sv -= line.sv - # # this_career.sv -= line.sv - # this_season.bsv -= line.bsv - # # this_career.bsv -= line.bsv - # this_season.game -= 1 - # # this_career.game -= 1 - # - # this_season.save() - # # this_career.save() - # - # this_career.recalculate() - - # Delete the stats - delete_query = PitchingStat.delete().where( - (PitchingStat.season == game.season) & (PitchingStat.week == game.week) & - ((PitchingStat.team == away_team) | (PitchingStat.team == home_team)) - ) - if game.game_num: - delete_query = delete_query.where(PitchingStat.game == game.game_num) - - count = delete_query.execute() - db.close() - if count > 0: - raise HTTPException(status_code=200, detail=f'Removed {count} pitching stat lines') - else: - raise HTTPException(status_code=418, detail=f'Well slap my ass and call me a teapot; ' - f'I did not delete any records') - - -@app.get('/api/v1/fieldingstats/s{season}/{s_type}') -async def v1_fieldingstats_get( - s_type: str, season: int = SEASON_DEFAULT, team_abbrev: Optional[str] = None, - player_name: Optional[str] = None, player_id: Optional[int] = None, week_start: Optional[int] = None, - week_end: Optional[int] = None, position: Optional[str] = None, return_type: Optional[str] = 'json', - csv: Optional[bool] = False): - """ - :param season: int - :param s_type: string (regular, post, combined) - :param team_abbrev: string - :param player_name: string - :param player_id: integer, overrides player_name - :param week_start: integer - :param week_end: integer - :param position: string - :return: - """ - if s_type.lower() == 'post': - all_stats = BattingStat.post_season(season) - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No postseason stats found for season {season}') - elif s_type.lower() == 'combined': - all_stats = BattingStat.combined_season(season) - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No stats found for season {season}') - else: - all_stats = BattingStat.regular_season(season) - if not all_stats: - db.close() - return {} - - all_stats = all_stats.where( - (BattingStat.xch > 0) | (BattingStat.pb > 0) | (BattingStat.sbc > 0) - ) - - if position: - all_stats = all_stats.where(BattingStat.pos == position.upper()) - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_stats = all_stats.where(BattingStat.team == this_team) - - if player_name or player_id: - if player_id: - try: - this_player = Player.get_by_id(player_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - else: - this_player = Player.get_season(player_name, season) - if not this_player: - db.close() - raise HTTPException(status_code=404, detail=f'Player {player_name} not found') - - all_stats = all_stats.where(BattingStat.player == this_player) - - start = 1 - end = Current.get(Current.season == season).week - if week_start is not None: - start = week_start - - if week_end is not None: - end = min(week_end, end) - - if start > end: - db.close() - raise HTTPException(status_code=404, - detail=f'Start week {start} is after end week {end} - cannot pull stats') - if start + 5 < end and team_abbrev is None and player_name is None and player_id is None and not csv: - start = end - 5 - - all_stats = all_stats.where( - (BattingStat.week >= start) & (BattingStat.week <= end) - ) - - if return_type == 'csv' or csv: - stats_list = [['season', 'week', 'game_num', 'player', 'team', 'pos', 'xch', 'xhit', 'error', - 'pb', 'sbc', 'csc', 'roba', 'robs', 'raa', 'rto']] - for line in all_stats: - stats_list.append( - [ - line.season, line.week, line.game, line.player.name, line.team.abbrev, line.pos, line.xch, - line.xhit, line.error, line.pb, line.sbc, line.csc, line.roba, line.robs, line.raa, line.rto - ] - ) - return_stats = DataFrame(stats_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_stats, media_type='text/csv') - else: - return_stats = {} - for line in all_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.post('/api/v1/battingseasons/recalculate') -async def v1_battingseasons_recalculate( - season: Optional[int] = None, team_id: Optional[int] = None, player_id: Optional[int] = None, - token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to recalculate stats') - - all_players = BattingSeason.select() - - if season: - all_players = all_players.where(BattingSeason.season == season) - if team_id: - try: - this_team = Team.get_by_id(team_id) - all_players = all_players.join(Player).where(BattingSeason.player.team == this_team) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team id {team_id} not found') - if player_id: - try: - this_player = Player.get_by_id(player_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - - all_players = all_players.where(BattingSeason.player == this_player) - if all_players.count() == 0: - if BattingStat.select().where(BattingStat.player == this_player).count() > 0: - this_season = BattingSeason(player=this_player, season=this_player.season) - this_season.save() - else: - db.close() - raise HTTPException(status_code=404, detail=f'No batting stats found for player id {player_id}') - - for line in all_players: - count = line.recalculate() - - db.close() - raise HTTPException(status_code=200, detail=f'Recalculated {all_players.count()} batting seasons') - - -@app.post('/api/v1/pitchingseasons/recalculate') -async def v1_pitchingseasons_recalculate( - season: Optional[int] = None, team_id: Optional[int] = None, player_id: Optional[int] = None, - token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to recalculate stats') - - all_players = PitchingSeason.select() - - if season: - all_players = all_players.where(PitchingSeason.season == season) - if team_id: - try: - this_team = Team.get_by_id(team_id) - all_players = all_players.join(Player).where(PitchingSeason.player.team == this_team) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team id {team_id} not found') - if player_id: - try: - this_player = Player.get_by_id(player_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - - all_players = all_players.where(PitchingSeason.player == this_player) - if all_players.count() == 0: - if PitchingStat.select().where(PitchingStat.player == this_player).count() > 0: - this_season = PitchingSeason(player=this_player, season=this_player.season) - this_season.save() - else: - db.close() - raise HTTPException(status_code=404, detail=f'No pitching stats found for player id {player_id}') - - for line in all_players: - count = line.recalculate() - - db.close() - raise HTTPException(status_code=200, detail=f'Recalculated {all_players.count()} pitching seasons') - - -@app.post('/api/v1/fieldingseasons/recalculate') -async def v1_fieldingseasons_recalculate( - season: Optional[int] = None, team_id: Optional[int] = None, player_id: Optional[int] = None, - token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to recalculate stats') - - all_players = FieldingSeason.select() - - if season: - all_players = all_players.where(FieldingSeason.season == season) - if team_id: - try: - this_team = Team.get_by_id(team_id) - all_players = all_players.join(Player).where(FieldingSeason.player.team == this_team) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team id {team_id} not found') - if player_id: - try: - this_player = Player.get_by_id(player_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - - all_players = all_players.where(FieldingSeason.player == this_player) - if all_players.count() == 0: - search_query = BattingStat.select().where( - (BattingStat.player == this_player) & (BattingStat.xch + BattingStat.sbc > 0) - ) - if search_query.count() > 0: - pos_list = [] - for x in search_query: - pos_list.append(x.pos) - for x in pos_list: - this_season = FieldingSeason(player=this_player, season=this_player.season, pos=x) - this_season.save() - else: - db.close() - raise HTTPException(status_code=404, detail=f'No fielding stats found for player id {player_id}') - - for line in all_players: - count = line.recalculate() - logging.info(count) - - db.close() - raise HTTPException(status_code=200, detail=f'Recalculated {all_players.count()} fielding seasons') - - -# @app.post('/api/v1/seasonstats/recalculate') -# async def v1_seasonstats_recalculate( -# which: str, season_start: int, season_end: int, mgr_start: int, mgr_end: int, -# token: str = Depends(oauth2_scheme)): -# if not valid_token(token): -# db.close() -# raise HTTPException(status_code=401, detail='You are not authorized to recalculate stats') -# -# if mgr_start > mgr_end: -# db.close() -# raise HTTPException(status_code=404, detail=f'mgr_start may not be greater than mgr_end') -# if season_start > season_end: -# db.close() -# raise HTTPException(status_code=404, detail=f'season_start may not be greater than season_end') -# if which not in ['batting', 'fielding', 'pitching']: -# db.close() -# raise HTTPException(status_code=404, detail=f'Invalid which value') -# -# x = season_start -# while x <= season_end: -# y = mgr_start -# while y <= mgr_end: -# if which == 'batting': -# BattingSeason.recalculate(x, y) -# elif which == 'pitching': -# PitchingSeason.recalculate(x, y) -# elif which == 'fielding': -# FieldingSeason.recalculate(x, y) -# -# db.close() -# raise HTTPException(status_code=200, detail='Season stats have been recalculated') - - -@app.post('/api/v1/careerstats/recalculate') -async def v1_careerstats_recalculate(which: str, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to recalculate stats') - - if which == 'all': - BattingCareer.recalculate() - PitchingCareer.recalculate() - FieldingCareer.recalculate() - elif which == 'batting': - BattingCareer.recalculate() - elif which == 'pitching': - PitchingCareer.recalculate() - elif which == 'fielding': - FieldingCareer.recalculate() - - db.close() - raise HTTPException(status_code=200, detail='Career stats have been recalculated') - - -@app.get('/api/v1/standings') -async def v1_standings( - season: Optional[int] = SEASON_DEFAULT, team_abbrev: Optional[str] = None, return_type: Optional[str] = 'json', - league_abbrev: Optional[str] = None, division_abbrev: Optional[str] = None, csv: Optional[bool] = False): - """ - :param season: int - :param team_abbrev: string, overrides league/division_abbrev - :param league_abbrev: string - :param division_abbrev: string - """ - standings = Standings.select_season(season) - - if standings.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for season {season}') - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - db.close() - return model_to_dict(Standings.get_or_none(Standings.team == this_team)) - - if league_abbrev: - these_divisions = Division.select().where(fn.Lower(Division.league_abbrev) == league_abbrev.lower()) - if these_divisions.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for league {league_abbrev}') - - standings = standings.where(Standings.team.division << these_divisions) - - if division_abbrev: - this_division = Division.select().where(fn.Lower(Division.division_abbrev) == division_abbrev.lower()) - if not this_division: - db.close() - raise HTTPException(status_code=404, detail=f'No output for division {division_abbrev}') - - standings = standings.where(Standings.team.division << this_division) - - def win_pct(this_team_stan): - if this_team_stan.wins + this_team_stan.losses == 0: - return 0 - else: - return (this_team_stan.wins / (this_team_stan.wins + this_team_stan.losses)) + \ - (this_team_stan.run_diff * .000001) - - div_teams = [team_stan for team_stan in standings] - div_teams.sort(key=lambda team: win_pct(team), reverse=True) - - if return_type == 'csv' or csv: - standings_list = [ - ['season', 'team', 'league', 'division', 'wins', 'losses', 'run diff', 'div gb', 'div enum', 'wc gb', - 'wc enum', 'home wins', 'home losses', 'away wins', 'away losses', 'last 8 wins', 'last 8 losses', - 'streak wl', 'streak num', 'one run wins', 'one run losses', 'pythag_wins', 'pythag losses', - 'wins v bote', 'losses v bote', 'wins v dc', 'losses v dc', 'wins v nlw', 'losses v nlw'] - ] - for line in div_teams: - standings_list.append( - [line.team.season, line.team.abbrev, line.team.division.league_abbrev, line.team.division.division_name, - line.wins, line.losses, line.run_diff, line.div_gb, line.div_e_num, line.wc_gb, line.wc_e_num, - line.home_wins, line.home_losses, line.away_wins, line.away_losses, line.last8_wins, line.last8_losses, - line.streak_wl, line.streak_num, line.one_run_wins, line.one_run_losses, line.pythag_wins, - line.pythag_losses, line.div1_wins, line.div1_losses, line.div2_wins, line.div2_losses, line.div3_wins, - line.div3_losses] - ) - return_stats = DataFrame(standings_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_stats, media_type='text/csv') - else: - return_standings = {} - for line in div_teams: - return_standings[f'{line.team.abbrev}'] = model_to_dict(line) - - db.close() - return return_standings - - -@app.patch('/api/v1/standings/{stan_id}') -async def v1_standings_patch( - stan_id, wins: Optional[int] = None, losses: Optional[int] = None, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch standings') - - try: - this_stan = Standings.get_by_id(stan_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {stan_id}') - - if wins: - this_stan.wins = wins - if losses: - this_stan.losses = losses - - this_stan.save() - db.close() - - return model_to_dict(this_stan) - - -@app.post('/api/v1/standings/s{season}/recalculate') -async def v1_standings_recalculate(season: int, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to calculate stats') - - code = Standings.recalculate(season) - db.close() - if code == 69: - HTTPException(status_code=500, detail=f'Error recreating Standings rows') - raise HTTPException(status_code=200, detail=f'Just recalculated standings for season {season}') - - -@app.get('/api/v1/battingseasons') -async def v1_battingseasons_get( - season: Optional[int] = SEASON_DEFAULT, team_abbrev: Optional[str] = None, sort: Optional[str] = None, - season_type: Optional[str] = None, return_type: Optional[str] = 'json', csv: Optional[bool] = False): - """ - :param season: int - :param player_id: int, overrides other args - :param player_name: int, overrides team_abbrev - :param team_abbrev: str, lowest priority arg - :param sort: str, pa-desc; wara-desc - """ - all_stats = BattingSeason.select().where(BattingSeason.pa > 0) - - if season: - all_stats = all_stats.where(BattingSeason.season == season) - - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for season {season}') - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_players = Player.select_season(season).where(Player.team == this_team) - all_stats = all_stats.where(BattingSeason.player << all_players) - - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for team {team_abbrev}') - - if season_type: - all_stats = all_stats.where(fn.Lower(BattingSeason.season_type) == season_type.lower()) - - if sort: - if sort == 'pa-desc': - all_stats = all_stats.order_by(-BattingSeason.pa) - elif sort == 'wara-desc': - all_stats = all_stats.order_by(-BattingSeason.player.wara) - - if return_type == 'csv' or csv: - stat_list = [ - ['season', 'season_type', 'player', 'pa', 'ab', 'run', 'hit', 'rbi', 'double', 'triple', - 'hr', 'bb', 'so', 'hbp', 'sac', 'ibb', 'gidp', 'sb', 'cs', 'bphr', 'bpfo', 'bp1b', 'bplo', - 'xba', 'xbt'] - ] - for line in all_stats: - stat_list.append( - [line.player.season, line.season_type, line.player.name, line.pa, line.ab, line.run, line.hit, - line.rbi, line.double, line.triple, line.hr, line.bb, line.so, line.hbp, line.sac, line.ibb, line.gidp, - line.sb, line.cs, line.bphr, line.bpfo, line.bp1b, line.bplo, line.xba, line.xbt] - ) - return_stats = DataFrame(stat_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_stats, media_type='text/csv') - else: - return_stats = {} - for line in all_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.get('/api/v1/battingseasons/{id_or_name}') -async def v1_battingseasons_get_player(id_or_name): - try: - this_player = Player.get_by_id(id_or_name) - except Exception as e: - this_player = None - - if this_player: - these_stats = BattingSeason.get_or_none(BattingSeason.player == this_player) - if these_stats: - db.close() - return model_to_dict(these_stats) - else: - db.close() - return {} - else: - these_players = Player.select().where(fn.Lower(Player.name) == id_or_name.lower()) - if these_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Player {id_or_name} not found') - - these_stats = BattingSeason.select().where(BattingSeason.player << these_players) - return_stats = {} - for line in these_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.get('/api/v1/pitchingseasons') -async def v1_pitchingseasons_get( - season: int = SEASON_DEFAULT, team_abbrev: Optional[str] = None, sort: Optional[str] = None, - season_type: Optional[str] = None, return_type: Optional[str] = 'json', csv: Optional[bool] = False): - """ - :param season: int - :param team_abbrev: str, lowest priority arg - :param sort: str, ip-desc; wara-desc - """ - all_stats = PitchingSeason.select_season(season) - - if season: - all_stats = all_stats.where(PitchingSeason.season == season) - - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for season {season}') - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_players = Player.select_season(season).where(Player.team == this_team) - all_stats = all_stats.where(PitchingSeason.player << all_players) - - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for team {team_abbrev}') - - if season_type: - all_stats = all_stats.where(fn.Lower(PitchingSeason.season_type) == season_type.lower()) - - if sort: - logging.warning('In sort!') - if sort == 'ip-desc': - logging.warning('Matched ip-desc') - all_stats = all_stats.order_by(-PitchingSeason.ip) - logging.warning(all_stats) - elif sort == 'wara-desc': - all_stats = all_stats.order_by(-PitchingSeason.player.wara) - - if return_type == 'csv' or csv: - stat_list = [ - ['season', 'season_type', 'player', 'ip', 'hit', 'run', 'erun', 'so', 'bb', 'hbp', - 'wp', 'balk', 'hr', 'ir', 'irs', 'gs', 'win', 'loss', 'hold', 'sv', 'bsv', 'games'] - ] - for line in all_stats: - stat_list.append( - [line.player.season, line.season_type, line.player.name, line.ip, line.hit, line.run, line.erun, - line.so, line.bb, line.hbp, line.wp, line.balk, line.hr, line.ir, line.irs, line.gs, line.win, - line.loss, line.hold, line.sv, line.bsv, line.game] - ) - return_stats = DataFrame(stat_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_stats, media_type='text/csv') - else: - return_stats = {} - for line in all_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.get('/api/v1/pitchingseasons/{id_or_name}') -async def v1_pitchingseasons_get_player(id_or_name): - try: - this_player = Player.get_by_id(id_or_name) - except Exception as e: - this_player = None - - if this_player: - these_stats = PitchingSeason.get_or_none(PitchingSeason.player == this_player) - if these_stats: - db.close() - return model_to_dict(these_stats) - else: - db.close() - return {} - else: - these_players = Player.select().where(fn.Lower(Player.name) == id_or_name.lower()) - if these_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Player {id_or_name} not found') - - these_stats = PitchingSeason.select().where(PitchingSeason.player << these_players) - return_stats = {} - for line in these_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.get('/api/v1/fieldingseasons') -async def v1_fieldingseasons_get( - season: int = SEASON_DEFAULT, team_abbrev: Optional[str] = None, position: Optional[str] = None, - season_type: Optional[str] = None, sort: Optional[str] = None, return_type: Optional[str] = 'json', - csv: Optional[bool] = False): - """ - :param season: int - :param player_id: int, overrides other args - :param player_name: int, overrides team_abbrev - :param team_abbrev: str, lowest priority arg - :param position: str - :param sort: str, pa-desc; wara-desc - """ - all_stats = FieldingSeason.select_season(season).where((FieldingSeason.xch + FieldingSeason.sbc) > 0) - - if season: - all_stats = all_stats.where(FieldingSeason.season == season) - - if position: - all_stats = all_stats.where(FieldingSeason.pos == position.upper()) - - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for season {season}') - - if team_abbrev: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {team_abbrev} not found') - - all_players = Player.select_season(season).where(Player.team == this_team) - all_stats = all_stats.where(FieldingSeason.player << all_players) - - if all_stats.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for team {team_abbrev}') - - if season_type: - all_stats = all_stats.where(fn.Lower(FieldingSeason.season_type) == season_type.lower()) - - if sort: - if sort == 'xch-desc': - all_stats = all_stats.order_by(-(FieldingSeason.xch + FieldingSeason.sbc)) - elif sort == 'wara-desc': - all_stats = all_stats.order_by(-FieldingSeason.player.wara) - - if return_type == 'csv' or csv: - stat_list = [ - ['season', 'season_type', 'player', 'pos', 'xch', 'xhit', 'error', 'pb', 'sbc', 'csc', 'roba', 'robs', - 'raa', 'rto'] - ] - for line in all_stats: - stat_list.append( - [line.player.season, line.season_type, line.player.name, line.pos, line.xch, line.xhit, line.error, - line.pb, line.sbc, line.csc, line.roba, line.robs, line.raa, line.rto] - ) - return_stats = DataFrame(stat_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_stats, media_type='text/csv') - else: - return_stats = {} - for line in all_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.get('/api/v1/fieldingseasons/{id_or_name}') -async def v1_fieldingseasons_get_player(id_or_name): - try: - this_player = Player.get_by_id(id_or_name) - except Exception as e: - this_player = None - - if this_player: - these_stats = FieldingSeason.get_or_none(FieldingSeason.player == this_player) - if these_stats: - db.close() - return model_to_dict(these_stats) - else: - db.close() - return {} - else: - these_players = Player.select().where(fn.Lower(Player.name) == id_or_name.lower()) - if these_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Player {id_or_name} not found') - - these_stats = FieldingSeason.select().where(FieldingSeason.player << these_players) - return_stats = {} - for line in these_stats: - return_stats[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_stats - - -@app.get('/api/v1/draftpicks') -async def v1_draftpicks_get( - season: int = SEASON_DEFAULT, owner_team_abbrev: Optional[str] = None, - orig_team_abbrev: Optional[str] = None, pick_round_start: Optional[int] = None, - pick_round_end: Optional[int] = None, traded: Optional[bool] = None, overall: Optional[int] = None, - team_season: Optional[int] = None, overall_start: Optional[int] = None, overall_end: Optional[int] = None, - return_type = 'json', csv: Optional[bool] = False): - """ - :param season: int - :param owner_team_abbrev: string - :param orig_team_abbrev: string - :param pick_round_start: int - :param pick_round_end: int - :param traded: bool - :param overall: int - """ - all_picks = DraftPick.select_season(season) - if all_picks.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No picks found for season {season}') - - if owner_team_abbrev: - if not team_season: - team_season = season - this_team = Team.get_season(owner_team_abbrev, team_season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {owner_team_abbrev} not found') - - all_picks = all_picks.where(DraftPick.owner == this_team) - if all_picks.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for team {owner_team_abbrev}') - - if orig_team_abbrev: - if not team_season: - team_season = season - this_team = Team.get_season(orig_team_abbrev, team_season) - if not this_team: - db.close() - raise HTTPException(status_code=404, detail=f'Team {orig_team_abbrev} not found') - - all_picks = all_picks.where(DraftPick.origowner == this_team) - if all_picks.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No output for team {orig_team_abbrev}') - - if pick_round_start and pick_round_end: - if pick_round_start > pick_round_end: - db.close() - raise HTTPException(status_code=400, detail=f'Cannot search for pick with end round before start round') - - if pick_round_start: - all_picks = all_picks.where(DraftPick.round >= pick_round_start) - if all_picks.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No picks found beginning in round {pick_round_start}') - - if pick_round_end: - all_picks = all_picks.where(DraftPick.round <= pick_round_end) - if all_picks.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'No picks found ending with round {pick_round_end}') - - if traded: - all_picks = all_picks.where(DraftPick.origowner != DraftPick.owner) - - if overall is not None: - all_picks = all_picks.where(DraftPick.overall == overall) - - if overall_start: - all_picks = all_picks.where(DraftPick.overall >= overall_start) - - if overall_end: - all_picks = all_picks.where(DraftPick.overall <= overall_end) - - logging.info('Trying to spit out draft picks') - if return_type == 'csv' or csv: - logging.info('Working on csv') - pick_list = [ - ['season', 'overall', 'round', 'orig_owner', 'owner', 'player', 'swar'] - ] - logging.info(f'built the pick_list / len(all_picks): {len(all_picks)}') - for line in all_picks: - logging.info(f'line: {line}') - pick_list.append( - [line.season, line.overall, line.round, line.origowner.abbrev, line.owner.abbrev, - f'{line.player.name if line.player else ""}', f'{line.player.wara if line.player else ""}'] - ) - logging.info('filled the pick_list') - return_picks = DataFrame(pick_list).to_csv(header=False, index=False) - - db.close() - return Response(content=return_picks, media_type='text/csv') - else: - return_picks = {} - for line in all_picks: - return_picks[f'{line.id}'] = model_to_dict(line) - - db.close() - return return_picks - - -@app.post('/api/v1/draftpicks') -async def v1_draftpicks_post(picks: DraftPickModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post draft picks') - all_picks = [] - - for x in picks.picks: - this_origowner = None - if x.origowner_id: - try: - this_origowner = Team.get_by_id(x.origowner_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'No owner found with id {x.origowner_id}') - - this_owner = None - if x.owner_id: - try: - this_owner = Team.get_by_id(x.owner_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'No owner found with id {x.owner_id}') - else: - this_owner = this_origowner - - this_player = None - if x.player_id: - try: - this_player = Player.get_by_id(x.player_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'No player found with id {x.player_id}') - - this_pick = DraftPick( - season=x.season, - overall=x.overall, - round=x.round, - origowner=this_origowner, - owner=this_owner, - player=this_player - ) - - all_picks.append(this_pick) - - with db.atomic(): - DraftPick.bulk_create(all_picks, batch_size=15) - db.close() - - raise HTTPException(status_code=200, detail=f'Created {len(all_picks)} draft picks') - - -# player_id is not checked for [int] to enable False as a clear parameter -@app.patch('/api/v1/draftpicks/{pick_id}') -async def v1_draftpicks_patch( - pick_id: int, overall: Optional[int] = None, round: Optional[int] = None, orig_owner_id: Optional[int] = None, - owner_id: Optional[int] = None, season: Optional[int] = None, player_id=None, - token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch draft picks') - - try: - this_pick = DraftPick.get_by_id(pick_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {pick_id}') - - if overall: - this_pick.overall = overall - if season: - this_pick.season = season - if round: - this_pick.round = round - if orig_owner_id: - try: - orig_owner = Team.get_by_id(orig_owner_id) - this_pick.origowner = orig_owner - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {orig_owner_id}') - if owner_id: - try: - new_owner = Team.get_by_id(owner_id) - this_pick.owner = new_owner - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No team found with id {owner_id}') - if player_id is not None: - if player_id.lower() == 'false': - this_pick.player = None - else: - try: - this_player = Player.get_by_id(player_id) - this_pick.player = this_player - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'No player found with id {player_id}') - - this_pick.save() - db.close() - return model_to_dict(this_pick) - - -@app.get('/api/v1/draftpicks/{pick_id}') -async def v1_draftpicks_get_one(pick_id): - try: - this_pick = DraftPick.get_or_none(DraftPick.id == pick_id) - except Exception as e: - db.close() - raise HTTPException(status_code=404, detail=f'Draft pick id {pick_id} not found') - - db.close() - return model_to_dict(this_pick) - - -@app.get('/api/v1/draftdata') -async def v1_draftdata(): - draft_data = DraftData.get_or_none() - db.close() - - if not draft_data: - db.close() - raise HTTPException(status_code=404, detail=f'No draft data found') - else: - db.close() - return model_to_dict(draft_data) - - -@app.patch('/api/v1/draftdata') -async def v1_draftdata_patch( - currentpick: Optional[int] = None, timer: Optional[bool] = None, - pick_deadline: Optional[datetime.datetime] = None, result_channel: Optional[int] = None, - ping_channel: Optional[int] = None, pick_minutes: Optional[int] = None, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch draftdata') - - draft_data = DraftData.get_or_none() - - if not draft_data: - db.close() - raise HTTPException(status_code=404, detail=f'No draft data found') - - if currentpick is not None: - draft_data.currentpick = currentpick - if timer is not None: - draft_data.timer = timer - if pick_deadline is not None: - draft_data.pick_deadline = pick_deadline - if result_channel is not None: - draft_data.result_channel = result_channel - if ping_channel is not None: - draft_data.ping_channel = ping_channel - if pick_minutes is not None: - draft_data.pick_minutes = pick_minutes - - saved = draft_data.save() - db.close() - - if saved == 1: - return model_to_dict(draft_data) - else: - raise HTTPException(status_code=500, detail='Updating draft data failed') - - -@app.get('/api/v1/leaders') -async def v1_leaders( - group: str = 'batting', season=SEASON_DEFAULT, team_abbrev: Optional[str] = None, - league_abbrev: Optional[str] = None, division_abbrev: Optional[str] = None): - current = Current.get_or_none(season=season) - all_leaders = None - if season == 1: - min_ip = 68 - min_pa = 204 - min_ch_high = 34 - min_ch_mid = 17 - min_ch_low = 8 - min_ch_pit = 4 - elif season == 2: - min_ip = 76 - min_pa = 228 - min_ch_high = 38 - min_ch_mid = 19 - min_ch_low = 9 - min_ch_pit = 4 - elif int(season) < SEASON_DEFAULT: - min_ip = 88 - min_pa = 264 - min_ch_high = 44 - min_ch_mid = 22 - min_ch_low = 11 - min_ch_pit = 5 - else: - min_ip = ((current.week - 1) * 4) if current.week > 5 else current.week * 2 - min_pa = ((current.week - 1) * 12) if current.week > 5 else current.week * 6 - min_ch_high = ((current.week - 1) * 2) if current.week > 5 else current.week - min_ch_mid = (min_ch_high / 2) if (min_ch_high / 2) > 1 else 1 - min_ch_low = (min_ch_high / 4) if (min_ch_high / 3) > 1 else 1 - min_ch_pit = (min_ch_high / 8) if (min_ch_high / 6) > 1 else 1 - - if group == 'pitching': - all_leaders = { - 'Starter Wins': {'abbrev': 'W', 'leaders': []}, - 'Wins': {'abbrev': 'W', 'leaders': []}, - 'Earned Run Average': {'abbrev': 'ERA', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Innings Pitched': {'abbrev': 'IP', 'leaders': []}, - 'Strikeouts per Nine': {'abbrev': 'K/9', 'leaders': []}, - 'Walks + Hits / IP': {'abbrev': 'WHIP', 'leaders': []}, - 'Saves': {'abbrev': 'SV', 'leaders': []}, - 'Walks Allowed': {'abbrev': 'BB', 'leaders': []}, - 'Runs Allowed': {'abbrev': 'R', 'leaders': []}, - 'Earned Runs Allowed': {'abbrev': 'ER', 'leaders': []}, - 'Blown Saves': {'abbrev': 'BSV', 'leaders': []}, - 'Hit By Pitches Allowed': {'abbrev': 'HBP', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'H', 'leaders': []}, - 'Home Runs Allowed': {'abbrev': 'HR', 'leaders': []}, - 'Wild Pitches': {'abbrev': 'WP', 'leaders': []}, - 'Holds': {'abbrev': 'HD', 'leaders': []}, - 'Walks Per Nine': {'abbrev': 'BB/9', 'leaders': []}, - 'Strikeouts Per Walk': {'abbrev': 'K/BB', 'leaders': []}, - 'Losses': {'abbrev': 'L', 'leaders': []}, - 'Inherited Runners': {'abbrev': 'IR', 'leaders': []}, - 'Inherited Runners Scored': {'abbrev': 'IRS', 'leaders': []}, - 'Runners Stranded %': {'abbrev': 'RS%', 'leaders': []}, - } - - top_swin = (PitchingStat - .select(PitchingStat.player, fn.COUNT(PitchingStat.win).alias('swin')) - .where(PitchingStat.season == season, PitchingStat.gs == 1, PitchingStat.win == 1) - .order_by(-fn.COUNT(PitchingStat.win), PitchingStat.player) - .group_by(PitchingStat.player) - .limit(10)) - top_win = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.win) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.win, PitchingSeason.player) - .limit(10)) - top_ip = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.ip) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.ip, PitchingSeason.player) - .limit(10)) - top_so = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.so) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.so, PitchingSeason.player) - .limit(10)) - top_era = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.erun, PitchingSeason.ip) - .where(PitchingSeason.season == season, PitchingSeason.ip >= min_ip) - .order_by(((PitchingSeason.erun * 9) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_kpn = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.so, PitchingSeason.ip) - .where(PitchingSeason.season == season, PitchingSeason.ip >= min_ip) - .order_by(-((PitchingSeason.so * 9) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_whip = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb, PitchingSeason.hit, PitchingSeason.ip) - .where(PitchingSeason.season == season, PitchingSeason.ip >= min_ip) - .order_by(+((PitchingSeason.bb + PitchingSeason.hit) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_sv = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.sv) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.sv, PitchingSeason.player) - .limit(10)) - top_bb = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.bb, PitchingSeason.player) - .limit(10)) - top_run = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.run) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.run, PitchingSeason.player) - .limit(10)) - top_erun = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.erun) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.erun, PitchingSeason.player) - .limit(10)) - top_bsv = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bsv) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.bsv, PitchingSeason.player) - .limit(10)) - top_hbp = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hbp) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.hbp, PitchingSeason.player) - .limit(10)) - top_hit = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hit) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.hit, PitchingSeason.player) - .limit(10)) - top_hr = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hr) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.hr, PitchingSeason.player) - .limit(10)) - top_wp = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.wp) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.wp, PitchingSeason.player) - .limit(10)) - top_hd = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hold) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.hold, PitchingSeason.player) - .limit(10)) - top_bpn = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb, PitchingSeason.ip) - .where(PitchingSeason.season == season, PitchingSeason.ip >= min_ip) - .order_by(((PitchingSeason.bb * 9) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_kpw = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb, PitchingSeason.so) - .where(PitchingSeason.season == season, PitchingSeason.ip >= min_ip) - .order_by(-(PitchingSeason.so / PitchingSeason.bb), PitchingSeason.player) - .limit(10)) - top_los = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.loss) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.loss, PitchingSeason.player) - .limit(10)) - top_ir = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.ir) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.ir, PitchingSeason.player) - .limit(10)) - top_irs = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.irs) - .where(PitchingSeason.season == season) - .order_by(-PitchingSeason.irs, PitchingSeason.player) - .limit(10)) - top_irp = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.ir, PitchingSeason.irs) - .where(PitchingSeason.season == season, PitchingSeason.ir >= current.week) - .order_by(-((PitchingSeason.ir - PitchingSeason.irs) / PitchingSeason.ir), PitchingSeason.player) - .limit(10)) - - db.close() - - for x in top_swin: - all_leaders['Starter Wins']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.swin)} - ) - for x in top_win: - all_leaders['Wins']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.win)} - ) - for x in top_ip: - all_leaders['Innings Pitched']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{x.ip:.1f}'} - ) - for x in top_so: - all_leaders['Strikeouts']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.so)} - ) - for x in top_era: - all_leaders['Earned Run Average']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{((x.erun * 9) / x.ip):.2f}'} - ) - for x in top_kpn: - all_leaders['Strikeouts per Nine']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{((x.so * 9) / x.ip):.2f}'} - ) - for x in top_whip: - all_leaders['Walks + Hits / IP']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{((x.bb + x.hit) / x.ip):.2f}'} - ) - for x in top_sv: - all_leaders['Saves']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.sv)} - ) - for x in top_bb: - all_leaders['Walks Allowed']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.bb)} - ) - for x in top_run: - all_leaders['Runs Allowed']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.run)} - ) - for x in top_erun: - all_leaders['Earned Runs Allowed']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.erun)} - ) - for x in top_bsv: - all_leaders['Blown Saves']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.bsv)} - ) - for x in top_hbp: - all_leaders['Hit By Pitches Allowed']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.hbp)} - ) - for x in top_hit: - all_leaders['Hits Allowed']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.hit)} - ) - for x in top_hr: - all_leaders['Home Runs Allowed']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.hr)} - ) - for x in top_wp: - all_leaders['Wild Pitches']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.wp)} - ) - for x in top_hd: - all_leaders['Holds']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.hold)} - ) - for x in top_bpn: - all_leaders['Walks Per Nine']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{((x.bb * 9) / x.ip):.2f}'} - ) - for x in top_kpw: - all_leaders['Strikeouts Per Walk']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{(x.so / x.bb):.2f}'} - ) - for x in top_los: - all_leaders['Losses']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.loss)} - ) - for x in top_ir: - all_leaders['Inherited Runners']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.ir)} - ) - for x in top_irs: - all_leaders['Inherited Runners Scored']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.irs)} - ) - for x in top_irp: - all_leaders['Runners Stranded %']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{((x.ir - x.irs) / x.ir) * 100:.1f}'} - ) - elif group == 'fielding': - all_leaders = { - 'Fielding Chances': {'abbrev': 'X-Ch', 'leaders': []}, - 'Weighted Fielding % (RF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (CF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (LF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (SS)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (3B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (2B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (1B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (C)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (P)': {'abbrev': 'wF%', 'leaders': []}, - 'Errors': {'abbrev': 'E', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'X-Hit', 'leaders': []}, - 'Passed Balls': {'abbrev': 'PB', 'leaders': []}, - 'Steal Attempts Against': {'abbrev': 'SBa', 'leaders': []}, - 'Runners Thrown Out (C)': {'abbrev': 'CSc', 'leaders': []}, - 'Caught Stealing % (Catchers)': {'abbrev': 'CS%', 'leaders': []}, - } - - top_xch = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.sbc) - .where(FieldingSeason.season == season) - .order_by(-(FieldingSeason.xch + FieldingSeason.sbc), FieldingSeason.player) - .limit(10)) - raw_ss = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'SS') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_high))) - raw_cf = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'CF') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_mid))) - raw_2b = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == '2B') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_high))) - raw_3b = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == '3B') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_mid))) - raw_1b = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == '1B') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_mid))) - raw_lf = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'LF') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_low))) - raw_rf = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'RF') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_low))) - raw_ca = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'C') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_mid))) - raw_pi = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'P') & (FieldingSeason.season == season) & (FieldingSeason.xch >= min_ch_pit))) - top_err = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.error) - .where(FieldingSeason.season == season) - .order_by(-FieldingSeason.error, FieldingSeason.player) - .limit(10)) - top_hit = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xhit) - .where(FieldingSeason.season == season) - .order_by(-FieldingSeason.xhit, FieldingSeason.player) - .limit(10)) - top_sbc = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.sbc) - .where((FieldingSeason.season == season) & (FieldingSeason.sbc > 0)) - .order_by(-FieldingSeason.sbc, FieldingSeason.player) - .limit(10)) - top_csc = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.csc) - .where((FieldingSeason.season == season) & (FieldingSeason.csc > 0)) - .order_by(-FieldingSeason.csc, FieldingSeason.player) - .limit(10)) - top_csp = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.sbc, FieldingSeason.csc) - .where((FieldingSeason.season == season) & (FieldingSeason.sbc >= min_ch_low)) - .order_by(-(FieldingSeason.csc / FieldingSeason.sbc), FieldingSeason.player) - .limit(10)) - top_pb = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.pb) - .where((FieldingSeason.season == season) & (FieldingSeason.pb > 0)) - .order_by(-FieldingSeason.pb, FieldingSeason.player) - .limit(10)) - # Removed for season 5 - # top_roba = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.roba) - # .where((FieldingSeason.season == season) & (FieldingSeason.roba > 0)) - # .order_by(-FieldingSeason.roba, FieldingSeason.player) - # .limit(10)) - # top_robs = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.robs) - # .where((FieldingSeason.season == season) & (FieldingSeason.robs > 0)) - # .order_by(-FieldingSeason.robs, FieldingSeason.player) - # .limit(10)) - # top_raa = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.raa) - # .where((FieldingSeason.season == season) & (FieldingSeason.raa > 0)) - # .order_by(-FieldingSeason.raa, FieldingSeason.player) - # .limit(10)) - # top_rto = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.rto) - # .where((FieldingSeason.season == season) & (FieldingSeason.rto > 0)) - # .order_by(-FieldingSeason.rto, FieldingSeason.player) - # .limit(10)) - - db.close() - - for x in top_xch: - all_leaders['Fielding Chances']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.xch + x.sbc} - ) - for x in top_err: - all_leaders['Errors']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.error} - ) - for x in top_sbc: - all_leaders['Steal Attempts Against']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.sbc} - ) - for x in top_csc: - all_leaders['Runners Thrown Out (C)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.csc} - ) - for x in top_csp: - all_leaders['Caught Stealing % (Catchers)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{x.csc * 100 / x.sbc:.1f}'} - ) - for x in top_hit: - all_leaders['Hits Allowed']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.xhit} - ) - for x in top_pb: - all_leaders['Passed Balls']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.pb} - ) - # for x in top_roba: - # all_leaders['Rob Attempts']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.roba} - # ) - # for x in top_robs: - # all_leaders['Rob Successes']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.robs} - # ) - # for x in top_raa: - # all_leaders['Runner Advance Attempts']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.raa} - # ) - # for x in top_rto: - # all_leaders['Runners Thrown Out (OF)']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': x.rto} - # ) - - for x in raw_ss: - all_leaders['Weighted Fielding % (SS)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_cf: - all_leaders['Weighted Fielding % (CF)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_2b: - all_leaders['Weighted Fielding % (2B)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_3b: - all_leaders['Weighted Fielding % (3B)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_1b: - all_leaders['Weighted Fielding % (1B)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_lf: - all_leaders['Weighted Fielding % (LF)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_rf: - all_leaders['Weighted Fielding % (RF)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_ca: - all_leaders['Weighted Fielding % (C)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_pi: - all_leaders['Weighted Fielding % (P)']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for stat in all_leaders: - if 'Weighted Fielding' in stat: - all_leaders[stat]['leaders'] = sorted( - all_leaders[stat]['leaders'], - key=lambda leader: leader['stat'], - reverse=True - ) - all_leaders[stat]['leaders'] = all_leaders[stat]['leaders'][:10] - else: - # return batting leaders - all_leaders = { - 'Home Runs': {'abbrev': 'HR', 'leaders': []}, - 'Batting Average': {'abbrev': 'AVG', 'leaders': []}, - 'On Base Percentage': {'abbrev': 'OBP', 'leaders': []}, - 'Slugging Percentage': {'abbrev': 'SLG', 'leaders': []}, - 'On Base Plus Slugging': {'abbrev': 'OPS', 'leaders': []}, - 'Weighted On Base Avg': {'abbrev': 'wOBA', 'leaders': []}, - 'Avg on Balls in Play': {'abbrev': 'BABIP', 'leaders': []}, - 'Runs Batted In': {'abbrev': 'RBI', 'leaders': []}, - 'Doubles': {'abbrev': '2B', 'leaders': []}, - 'Triples': {'abbrev': '3B', 'leaders': []}, - 'Hits': {'abbrev': 'H', 'leaders': []}, - 'Plate Appearances': {'abbrev': 'PA', 'leaders': []}, - 'Ground Into Double Play': {'abbrev': 'GIDP', 'leaders': []}, - 'Walks': {'abbrev': 'BB', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Hit By Pitch': {'abbrev': 'HBP', 'leaders': []}, - 'Intentional Walks': {'abbrev': 'IBB', 'leaders': []}, - 'Stolen Bases': {'abbrev': 'SB', 'leaders': []}, - 'Caught Stealing': {'abbrev': 'CS', 'leaders': []}, - 'Runs Scored': {'abbrev': 'R', 'leaders': []}, - 'At Bats': {'abbrev': 'AB', 'leaders': []}, - 'No-Doubt Home Runs': {'abbrev': 'NDHR', 'leaders': []}, - 'Ballpark Home Runs': {'abbrev': 'BPHR', 'leaders': []}, - 'Ballpark Flyouts': {'abbrev': 'BPFO', 'leaders': []}, - 'Ballpark Singles': {'abbrev': 'BP1B', 'leaders': []}, - 'Ballpark Lineouts': {'abbrev': 'BPLO', 'leaders': []}, - } - - top_avg = (BattingSeason - .select() - .where((BattingSeason.pa >= min_pa) & (BattingSeason.season == season)) - .order_by(-(BattingSeason.hit / BattingSeason.ab), BattingSeason.player) - .limit(10)) - top_hr = (BattingSeason - .select(BattingSeason.player, BattingSeason.hr) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.hr, BattingSeason.player) - .limit(10)) - top_obp = (BattingSeason - .select() - .where((BattingSeason.pa >= min_pa) & (BattingSeason.season == season)) - .order_by( - -((BattingSeason.hit + BattingSeason.bb + BattingSeason.hbp + BattingSeason.ibb) / BattingSeason.pa), - BattingSeason.player) - .limit(10)) - top_slg = (BattingSeason - .select() - .where((BattingSeason.pa >= min_pa) & (BattingSeason.season == season)) - .order_by(-(((BattingSeason.hr * 4) + (BattingSeason.triple * 3) + (BattingSeason.double * 2) + ( - BattingSeason.hit - BattingSeason.hr - BattingSeason.triple - BattingSeason.double)) / BattingSeason.ab)) - .limit(10)) - top_ops = (BattingSeason - .select() - .where((BattingSeason.pa >= min_pa) & (BattingSeason.season == season)) - .order_by(-((BattingSeason.ab * ( - BattingSeason.hit + BattingSeason.bb + BattingSeason.ibb + BattingSeason.hbp) + ( - (BattingSeason.hr * 4) + (BattingSeason.triple * 3) + ( - BattingSeason.double * 2) + ( - BattingSeason.hit - BattingSeason.double - BattingSeason.triple - BattingSeason.hr)) * ( - BattingSeason.ab + BattingSeason.bb + BattingSeason.ibb + BattingSeason.sac + BattingSeason.hbp)) / - (BattingSeason.ab * ( - BattingSeason.ab + BattingSeason.bb + BattingSeason.ibb + BattingSeason.sac + BattingSeason.hbp)))) - .limit(10)) - top_wob = (BattingSeason - .select() - .where((BattingSeason.pa >= min_pa) & (BattingSeason.season == season)) - .order_by(-(((BattingSeason.bb * .69) + (BattingSeason.hbp * .72) + (BattingSeason.hr * 2.1) + ( - BattingSeason.triple * 1.62) + (BattingSeason.double * 1.27) + (( - BattingSeason.hit - BattingSeason.double - BattingSeason.triple - BattingSeason.hr) * .89)) / - ( - BattingSeason.ab + BattingSeason.bb - BattingSeason.ibb + BattingSeason.sac + BattingSeason.hbp))) - .limit(10)) - top_bab = (BattingSeason - .select() - .where((BattingSeason.pa >= min_pa) & (BattingSeason.season == season)) - .order_by(-((BattingSeason.hit - BattingSeason.hr) / - (BattingSeason.ab - BattingSeason.so - BattingSeason.hr + BattingSeason.sac))) - .limit(10)) - top_rbi = (BattingSeason - .select(BattingSeason.player, BattingSeason.rbi) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.rbi, BattingSeason.player) - .limit(10)) - top_dbl = (BattingSeason - .select(BattingSeason.player, BattingSeason.double) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.double, BattingSeason.player) - .limit(10)) - top_trp = (BattingSeason - .select(BattingSeason.player, BattingSeason.triple) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.triple, BattingSeason.player) - .limit(10)) - top_hit = (BattingSeason - .select(BattingSeason.player, BattingSeason.hit) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.hit, BattingSeason.player) - .limit(10)) - top_pa = (BattingSeason - .select(BattingSeason.player, BattingSeason.pa) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.pa, BattingSeason.player) - .limit(10)) - top_gdp = (BattingSeason - .select(BattingSeason.player, BattingSeason.gidp) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.gidp, BattingSeason.player) - .limit(10)) - top_bb = (BattingSeason - .select(BattingSeason.player, BattingSeason.bb) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.bb, BattingSeason.player) - .limit(10)) - top_so = (BattingSeason - .select(BattingSeason.player, BattingSeason.so) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.so, BattingSeason.player) - .limit(10)) - top_hbp = (BattingSeason - .select(BattingSeason.player, BattingSeason.hbp) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.hbp, BattingSeason.player) - .limit(10)) - top_ibb = (BattingSeason - .select(BattingSeason.player, BattingSeason.ibb) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.ibb, BattingSeason.player) - .limit(10)) - top_sb = (BattingSeason - .select(BattingSeason.player, BattingSeason.sb) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.sb, BattingSeason.player) - .limit(10)) - top_cs = (BattingSeason - .select(BattingSeason.player, BattingSeason.cs) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.cs, BattingSeason.player) - .limit(10)) - top_run = (BattingSeason - .select(BattingSeason.player, BattingSeason.run) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.run, BattingSeason.player) - .limit(10)) - top_ab = (BattingSeason - .select(BattingSeason.player, BattingSeason.ab) - .where(BattingSeason.season == season) - .order_by(-BattingSeason.ab, BattingSeason.player) - .limit(10)) - top_bphr = (BattingSeason - .select(BattingSeason.player, BattingSeason.bphr) - .where((BattingSeason.season == season) & (BattingSeason.bphr > 0)) - .order_by(-BattingSeason.bphr, BattingSeason.player) - .limit(10)) - top_bpfo = (BattingSeason - .select(BattingSeason.player, BattingSeason.bpfo) - .where((BattingSeason.season == season) & (BattingSeason.bpfo > 0)) - .order_by(-BattingSeason.bpfo, BattingSeason.player) - .limit(10)) - top_bp1b = (BattingSeason - .select(BattingSeason.player, BattingSeason.bp1b) - .where((BattingSeason.season == season) & (BattingSeason.bp1b > 0)) - .order_by(-BattingSeason.bp1b, BattingSeason.player) - .limit(10)) - top_bplo = (BattingSeason - .select(BattingSeason.player, BattingSeason.bplo) - .where((BattingSeason.season == season) & (BattingSeason.bplo > 0)) - .order_by(-BattingSeason.bplo, BattingSeason.player) - .limit(10)) - # Removed for season 5 - # top_xba = (BattingSeason - # .select(BattingSeason.player, BattingSeason.xba) - # .where((BattingSeason.season == season) & (BattingSeason.xba > 0)) - # .order_by(-BattingSeason.xba, BattingSeason.player) - # .limit(10)) - # top_xbt = (BattingSeason - # .select(BattingSeason.player, BattingSeason.xbt) - # .where((BattingSeason.season == season) & (BattingSeason.xbt > 0)) - # .order_by(-BattingSeason.xbt, BattingSeason.player) - # .limit(10)) - top_ndhr = (BattingSeason - .select(BattingSeason.player, BattingSeason.bphr, BattingSeason.hr) - .where((BattingSeason.season == season) & (BattingSeason.hr > 0)) - .order_by(-(BattingSeason.hr - BattingSeason.bphr), BattingSeason.player) - .limit(10)) - db.close() - - for x in top_avg: - all_leaders['Batting Average']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{x.hit / x.ab:.3f}'} - ) - for x in top_hr: - all_leaders['Home Runs']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.hr)} - ) - for x in top_obp: - all_leaders['On Base Percentage']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.hit + x.bb + x.hbp + x.ibb) / x.pa:.3f}'} - ) - for x in top_slg: - all_leaders['Slugging Percentage']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{((x.hr * 4) + (x.triple * 3) + (x.double * 2) + (x.hit - x.hr - x.triple - x.double)) / x.ab:.3f}'} - ) - for x in top_ops: - all_leaders['On Base Plus Slugging']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(x.ab * (x.hit + x.bb + x.ibb + x.hbp) + ((x.hr * 4) + (x.triple * 3) + (x.double * 2) + (x.hit - x.double - x.triple - x.hr)) * (x.ab + x.bb + x.ibb + x.sac + x.hbp)) / (x.ab * (x.ab + x.bb + x.ibb + x.sac + x.hbp)):.3f}'} - ) - for x in top_wob: - all_leaders['Weighted On Base Avg']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{(((x.bb * .69) + (x.hbp * .72) + (x.hr * 2.1) + (x.triple * 1.62) + (x.double * 1.27) + ((x.hit - x.double - x.triple - x.hr) * .89)) / (x.ab + x.bb - x.ibb + x.sac + x.hbp)):.3f}'} - ) - for x in top_bab: - all_leaders['Avg on Balls in Play']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, - 'stat': f'{((x.hit - x.hr) / (x.ab - x.so - x.hr + x.sac)):.3f}'} - ) - for x in top_rbi: - all_leaders['Runs Batted In']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.rbi)} - ) - for x in top_dbl: - all_leaders['Doubles']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.double)} - ) - for x in top_trp: - all_leaders['Triples']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.triple)} - ) - for x in top_hit: - all_leaders['Hits']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.hit)} - ) - for x in top_pa: - all_leaders['Plate Appearances']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.pa)} - ) - for x in top_gdp: - all_leaders['Ground Into Double Play']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.gidp)} - ) - for x in top_bb: - all_leaders['Walks']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.bb)} - ) - for x in top_so: - all_leaders['Strikeouts']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.so)} - ) - for x in top_hbp: - all_leaders['Hit By Pitch']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.hbp)} - ) - for x in top_ibb: - all_leaders['Intentional Walks']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.ibb)} - ) - for x in top_sb: - all_leaders['Stolen Bases']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.sb)} - ) - for x in top_cs: - all_leaders['Caught Stealing']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.cs)} - ) - for x in top_run: - all_leaders['Runs Scored']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.run)} - ) - for x in top_ab: - all_leaders['At Bats']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.ab)} - ) - for x in top_bphr: - all_leaders['Ballpark Home Runs']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.bphr)} - ) - for x in top_bpfo: - all_leaders['Ballpark Flyouts']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.bpfo)} - ) - for x in top_bp1b: - all_leaders['Ballpark Singles']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.bp1b)} - ) - for x in top_bplo: - all_leaders['Ballpark Lineouts']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.bplo)} - ) - # for x in top_xba: - # all_leaders['Extra Base Attempts']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.xba)} - # ) - # for x in top_xbt: - # all_leaders['Extra Bases Taken']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.xbt)} - # ) - for x in top_ndhr: - all_leaders['No-Doubt Home Runs']['leaders'].append( - {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': f'{x.hr - x.bphr:.0f}'} - ) - - db.close() - return all_leaders - - -@app.get('/api/v1/single-season-leaders') -async def v1_single_season_leaders_get( - group: str = 'batting', team_abbrev: Optional[str] = None, - league_abbrev: Optional[str] = None, division_abbrev: Optional[str] = None): - all_leaders = None - min_ip = 76 - min_pa = 228 - min_ch_high = 38 - min_ch_mid = 19 - min_ch_low = 9 - min_ch_pit = 5 - weeks = 20 - - if group == 'pitching': - all_leaders = { - # 'Starter Wins': {'abbrev': 'W', 'leaders': []}, - 'Wins': {'abbrev': 'W', 'leaders': []}, - 'Earned Run Average': {'abbrev': 'ERA', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Innings Pitched': {'abbrev': 'IP', 'leaders': []}, - 'Strikeouts per Nine': {'abbrev': 'K/9', 'leaders': []}, - 'Walks + Hits / IP': {'abbrev': 'WHIP', 'leaders': []}, - 'Saves': {'abbrev': 'SV', 'leaders': []}, - 'Walks Allowed': {'abbrev': 'BB', 'leaders': []}, - 'Runs Allowed': {'abbrev': 'R', 'leaders': []}, - 'Earned Runs Allowed': {'abbrev': 'ER', 'leaders': []}, - 'Blown Saves': {'abbrev': 'BSV', 'leaders': []}, - 'Hit By Pitches Allowed': {'abbrev': 'HBP', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'H', 'leaders': []}, - 'Home Runs Allowed': {'abbrev': 'HR', 'leaders': []}, - 'Wild Pitches': {'abbrev': 'WP', 'leaders': []}, - 'Holds': {'abbrev': 'HD', 'leaders': []}, - 'Walks Per Nine': {'abbrev': 'BB/9', 'leaders': []}, - 'Strikeouts Per Walk': {'abbrev': 'K/BB', 'leaders': []}, - 'Losses': {'abbrev': 'L', 'leaders': []}, - 'Inherited Runners': {'abbrev': 'IR', 'leaders': []}, - 'Inherited Runners Scored': {'abbrev': 'IRS', 'leaders': []}, - 'Runners Stranded %': {'abbrev': 'RS%', 'leaders': []}, - } - - # top_swin = (PitchingStat - # .select(PitchingStat.player, fn.COUNT(PitchingStat.win).alias('swin')) - # .where(PitchingStat.gs == 1, PitchingStat.win == 1) - # .order_by(-fn.COUNT(PitchingStat.win), PitchingStat.player) - # .group_by(PitchingStat.player) - # .limit(10)) - top_win = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.win) - .order_by(-PitchingSeason.win, PitchingSeason.player) - .limit(10)) - top_ip = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.ip) - .order_by(-PitchingSeason.ip, PitchingSeason.player) - .limit(10)) - top_so = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.so) - .order_by(-PitchingSeason.so, PitchingSeason.player) - .limit(10)) - top_era = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.erun, PitchingSeason.ip) - .where(PitchingSeason.ip >= min_ip) - .order_by(((PitchingSeason.erun * 9) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_kpn = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.so, PitchingSeason.ip) - .where(PitchingSeason.ip >= min_ip) - .order_by(-((PitchingSeason.so * 9) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_whip = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb, PitchingSeason.hit, PitchingSeason.ip) - .where(PitchingSeason.ip >= min_ip) - .order_by(+((PitchingSeason.bb + PitchingSeason.hit) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_sv = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.sv) - .order_by(-PitchingSeason.sv, PitchingSeason.player) - .limit(10)) - top_bb = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb) - .order_by(-PitchingSeason.bb, PitchingSeason.player) - .limit(10)) - top_run = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.run) - .order_by(-PitchingSeason.run, PitchingSeason.player) - .limit(10)) - top_erun = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.erun) - .order_by(-PitchingSeason.erun, PitchingSeason.player) - .limit(10)) - top_bsv = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bsv) - .order_by(-PitchingSeason.bsv, PitchingSeason.player) - .limit(10)) - top_hbp = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hbp) - .order_by(-PitchingSeason.hbp, PitchingSeason.player) - .limit(10)) - top_hit = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hit) - .order_by(-PitchingSeason.hit, PitchingSeason.player) - .limit(10)) - top_hr = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hr) - .order_by(-PitchingSeason.hr, PitchingSeason.player) - .limit(10)) - top_wp = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.wp) - .order_by(-PitchingSeason.wp, PitchingSeason.player) - .limit(10)) - top_hd = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.hold) - .order_by(-PitchingSeason.hold, PitchingSeason.player) - .limit(10)) - top_bpn = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb, PitchingSeason.ip) - .where(PitchingSeason.ip >= min_ip) - .order_by(((PitchingSeason.bb * 9) / PitchingSeason.ip), PitchingSeason.player) - .limit(10)) - top_kpw = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.bb, PitchingSeason.so) - .where(PitchingSeason.ip >= min_ip) - .order_by(-(PitchingSeason.so / PitchingSeason.bb), PitchingSeason.player) - .limit(10)) - top_los = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.loss) - .order_by(-PitchingSeason.loss, PitchingSeason.player) - .limit(10)) - top_ir = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.ir) - .order_by(-PitchingSeason.ir, PitchingSeason.player) - .limit(10)) - top_irs = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.irs) - .order_by(-PitchingSeason.irs, PitchingSeason.player) - .limit(10)) - top_irp = (PitchingSeason - .select(PitchingSeason.player, PitchingSeason.ir, PitchingSeason.irs) - .where(PitchingSeason.ir >= weeks) - .order_by(-((PitchingSeason.ir - PitchingSeason.irs) / PitchingSeason.ir), PitchingSeason.player) - .limit(10)) - - db.close() - - # for x in top_swin: - # all_leaders['Starter Wins']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.swin)} - # ) - for x in top_win: - all_leaders['Wins']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.win)} - ) - for x in top_ip: - all_leaders['Innings Pitched']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{x.ip:.1f}'} - ) - for x in top_so: - all_leaders['Strikeouts']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.so)} - ) - for x in top_era: - all_leaders['Earned Run Average']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{((x.erun * 9) / x.ip):.2f}'} - ) - for x in top_kpn: - all_leaders['Strikeouts per Nine']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{((x.so * 9) / x.ip):.2f}'} - ) - for x in top_whip: - all_leaders['Walks + Hits / IP']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{((x.bb + x.hit) / x.ip):.2f}'} - ) - for x in top_sv: - all_leaders['Saves']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.sv)} - ) - for x in top_bb: - all_leaders['Walks Allowed']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.bb)} - ) - for x in top_run: - all_leaders['Runs Allowed']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.run)} - ) - for x in top_erun: - all_leaders['Earned Runs Allowed']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.erun)} - ) - for x in top_bsv: - all_leaders['Blown Saves']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.bsv)} - ) - for x in top_hbp: - all_leaders['Hit By Pitches Allowed']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.hbp)} - ) - for x in top_hit: - all_leaders['Hits Allowed']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.hit)} - ) - for x in top_hr: - all_leaders['Home Runs Allowed']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.hr)} - ) - for x in top_wp: - all_leaders['Wild Pitches']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.wp)} - ) - for x in top_hd: - all_leaders['Holds']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.hold)} - ) - for x in top_bpn: - all_leaders['Walks Per Nine']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{((x.bb * 9) / x.ip):.2f}'} - ) - for x in top_kpw: - all_leaders['Strikeouts Per Walk']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.so / x.bb):.2f}'} - ) - for x in top_los: - all_leaders['Losses']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.loss)} - ) - for x in top_ir: - all_leaders['Inherited Runners']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.ir)} - ) - for x in top_irs: - all_leaders['Inherited Runners Scored']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.irs)} - ) - for x in top_irp: - all_leaders['Runners Stranded %']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{((x.ir - x.irs) / x.ir) * 100:.1f}'} - ) - elif group == 'fielding': - all_leaders = { - 'Fielding Chances': {'abbrev': 'X-Ch', 'leaders': []}, - 'Weighted Fielding % (RF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (CF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (LF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (SS)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (3B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (2B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (1B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (C)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (P)': {'abbrev': 'wF%', 'leaders': []}, - 'Errors': {'abbrev': 'E', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'X-Hit', 'leaders': []}, - 'Passed Balls': {'abbrev': 'PB', 'leaders': []}, - 'Steal Attempts Against': {'abbrev': 'SBa', 'leaders': []}, - 'Runners Thrown Out (C)': {'abbrev': 'CSc', 'leaders': []}, - 'Caught Stealing % (Catchers)': {'abbrev': 'CS%', 'leaders': []}, - # 'Rob Attempts': {'abbrev': 'RobA', 'leaders': []}, - # 'Rob Successes': {'abbrev': 'RobS', 'leaders': []}, - # 'Runner Advance Attempts': {'abbrev': 'RAA', 'leaders': []}, - # 'Runners Thrown Out (OF)': {'abbrev': 'RTO', 'leaders': []}, - } - - top_xch = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.sbc) - .order_by(-(FieldingSeason.xch + FieldingSeason.sbc), FieldingSeason.player) - .limit(10)) - raw_ss = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'SS') & (FieldingSeason.xch >= min_ch_high))) - raw_cf = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'CF') & (FieldingSeason.xch >= min_ch_mid))) - raw_2b = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == '2B') & (FieldingSeason.xch >= min_ch_high))) - raw_3b = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == '3B') & (FieldingSeason.xch >= min_ch_mid))) - raw_1b = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == '1B') & (FieldingSeason.xch >= min_ch_mid))) - raw_lf = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'LF') & (FieldingSeason.xch >= min_ch_low))) - raw_rf = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'RF') & (FieldingSeason.xch >= min_ch_low))) - raw_ca = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'C') & (FieldingSeason.xch >= min_ch_mid))) - raw_pi = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xch, FieldingSeason.xhit, FieldingSeason.error) - .where( - (FieldingSeason.pos == 'P') & (FieldingSeason.xch >= min_ch_pit))) - top_err = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.error) - .order_by(-FieldingSeason.error, FieldingSeason.player) - .limit(10)) - top_hit = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.xhit) - .order_by(-FieldingSeason.xhit, FieldingSeason.player) - .limit(10)) - top_sbc = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.sbc) - .where((FieldingSeason.sbc > 0)) - .order_by(-FieldingSeason.sbc, FieldingSeason.player) - .limit(10)) - top_csc = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.csc) - .where((FieldingSeason.csc > 0)) - .order_by(-FieldingSeason.csc, FieldingSeason.player) - .limit(10)) - top_csp = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.sbc, FieldingSeason.csc) - .where((FieldingSeason.sbc >= min_ch_mid)) - .order_by(-(FieldingSeason.csc / FieldingSeason.sbc), FieldingSeason.player) - .limit(10)) - top_pb = (FieldingSeason - .select(FieldingSeason.player, FieldingSeason.pb) - .where((FieldingSeason.pb > 0)) - .order_by(-FieldingSeason.pb, FieldingSeason.player) - .limit(10)) - # Removed for season 5 - # top_roba = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.roba) - # .where((FieldingSeason.roba > 0)) - # .order_by(-FieldingSeason.roba, FieldingSeason.player) - # .limit(10)) - # top_robs = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.robs) - # .where((FieldingSeason.robs > 0)) - # .order_by(-FieldingSeason.robs, FieldingSeason.player) - # .limit(10)) - # top_raa = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.raa) - # .where((FieldingSeason.raa > 0)) - # .order_by(-FieldingSeason.raa, FieldingSeason.player) - # .limit(10)) - # top_rto = (FieldingSeason - # .select(FieldingSeason.player, FieldingSeason.rto) - # .where((FieldingSeason.rto > 0)) - # .order_by(-FieldingSeason.rto, FieldingSeason.player) - # .limit(10)) - - db.close() - - for x in top_xch: - all_leaders['Fielding Chances']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': x.xch + x.sbc} - ) - for x in top_err: - all_leaders['Errors']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.error} - ) - for x in top_sbc: - all_leaders['Steal Attempts Against']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.sbc} - ) - for x in top_csc: - all_leaders['Runners Thrown Out (C)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.csc} - ) - for x in top_csp: - all_leaders['Caught Stealing % (Catchers)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{x.csc * 100 / x.sbc:.1f}'} - ) - for x in top_hit: - all_leaders['Hits Allowed']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.xhit} - ) - for x in top_pb: - all_leaders['Passed Balls']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.pb} - ) - # for x in top_roba: - # all_leaders['Rob Attempts']['leaders'].append( - # {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.roba} - # ) - # for x in top_robs: - # all_leaders['Rob Successes']['leaders'].append( - # {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.robs} - # ) - # for x in top_raa: - # all_leaders['Runner Advance Attempts']['leaders'].append( - # {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.raa} - # ) - # for x in top_rto: - # all_leaders['Runners Thrown Out (OF)']['leaders'].append( - # {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': x.rto} - # ) - - for x in raw_ss: - all_leaders['Weighted Fielding % (SS)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_cf: - all_leaders['Weighted Fielding % (CF)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_2b: - all_leaders['Weighted Fielding % (2B)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_3b: - all_leaders['Weighted Fielding % (3B)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_1b: - all_leaders['Weighted Fielding % (1B)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_lf: - all_leaders['Weighted Fielding % (LF)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_rf: - all_leaders['Weighted Fielding % (RF)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_ca: - all_leaders['Weighted Fielding % (C)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_pi: - all_leaders['Weighted Fielding % (P)']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for stat in all_leaders: - if 'Weighted Fielding' in stat: - all_leaders[stat]['leaders'] = sorted( - all_leaders[stat]['leaders'], - key=lambda leader: leader['stat'], - reverse=True - ) - all_leaders[stat]['leaders'] = all_leaders[stat]['leaders'][:10] - else: - # return batting leaders - all_leaders = { - 'Home Runs': {'abbrev': 'HR', 'leaders': []}, - 'Batting Average': {'abbrev': 'AVG', 'leaders': []}, - 'On Base Percentage': {'abbrev': 'OBP', 'leaders': []}, - 'Slugging Percentage': {'abbrev': 'SLG', 'leaders': []}, - 'On Base Plus Slugging': {'abbrev': 'OPS', 'leaders': []}, - 'Weighted On Base Avg': {'abbrev': 'wOBA', 'leaders': []}, - 'Avg on Balls in Play': {'abbrev': 'BABIP', 'leaders': []}, - 'Runs Batted In': {'abbrev': 'RBI', 'leaders': []}, - 'Doubles': {'abbrev': '2B', 'leaders': []}, - 'Triples': {'abbrev': '3B', 'leaders': []}, - 'Hits': {'abbrev': 'H', 'leaders': []}, - 'Plate Appearances': {'abbrev': 'PA', 'leaders': []}, - 'Ground Into Double Play': {'abbrev': 'GIDP', 'leaders': []}, - 'Walks': {'abbrev': 'BB', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Hit By Pitch': {'abbrev': 'HBP', 'leaders': []}, - 'Intentional Walks': {'abbrev': 'IBB', 'leaders': []}, - 'Stolen Bases': {'abbrev': 'SB', 'leaders': []}, - 'Caught Stealing': {'abbrev': 'CS', 'leaders': []}, - 'Runs Scored': {'abbrev': 'R', 'leaders': []}, - 'At Bats': {'abbrev': 'AB', 'leaders': []}, - 'No-Doubt Home Runs': {'abbrev': 'NDHR', 'leaders': []}, - 'Ballpark Home Runs': {'abbrev': 'BPHR', 'leaders': []}, - 'Ballpark Flyouts': {'abbrev': 'BPFO', 'leaders': []}, - 'Ballpark Singles': {'abbrev': 'BP1B', 'leaders': []}, - 'Ballpark Lineouts': {'abbrev': 'BPLO', 'leaders': []}, - # 'Extra Base Attempts': {'abbrev': 'XBA', 'leaders': []}, - # 'Extra Bases Taken': {'abbrev': 'XBT', 'leaders': []}, - } - - top_avg = (BattingSeason - .select() - .where((BattingSeason.pa >= min_pa)) - .order_by(-(BattingSeason.hit / BattingSeason.ab), BattingSeason.player) - .limit(10)) - top_hr = (BattingSeason - .select(BattingSeason.player, BattingSeason.hr) - .order_by(-BattingSeason.hr, BattingSeason.player) - .limit(10)) - top_obp = (BattingSeason - .select() - .where(BattingSeason.pa >= min_pa) - .order_by( - -((BattingSeason.hit + BattingSeason.bb + BattingSeason.hbp + BattingSeason.ibb) / BattingSeason.pa), - BattingSeason.player) - .limit(10)) - top_slg = (BattingSeason - .select() - .where(BattingSeason.pa >= min_pa) - .order_by(-(((BattingSeason.hr * 4) + (BattingSeason.triple * 3) + (BattingSeason.double * 2) + ( - BattingSeason.hit - BattingSeason.hr - BattingSeason.triple - BattingSeason.double)) / BattingSeason.ab)) - .limit(10)) - top_ops = (BattingSeason - .select() - .where(BattingSeason.pa >= min_pa) - .order_by(-((BattingSeason.ab * ( - BattingSeason.hit + BattingSeason.bb + BattingSeason.ibb + BattingSeason.hbp) + ( - (BattingSeason.hr * 4) + (BattingSeason.triple * 3) + ( - BattingSeason.double * 2) + ( - BattingSeason.hit - BattingSeason.double - BattingSeason.triple - BattingSeason.hr)) * ( - BattingSeason.ab + BattingSeason.bb + BattingSeason.ibb + BattingSeason.sac + BattingSeason.hbp)) / - (BattingSeason.ab * ( - BattingSeason.ab + BattingSeason.bb + BattingSeason.ibb + BattingSeason.sac + BattingSeason.hbp)))) - .limit(10)) - top_wob = (BattingSeason - .select() - .where(BattingSeason.pa >= min_pa) - .order_by(-(((BattingSeason.bb * .69) + (BattingSeason.hbp * .72) + (BattingSeason.hr * 2.1) + ( - BattingSeason.triple * 1.62) + (BattingSeason.double * 1.27) + (( - BattingSeason.hit - BattingSeason.double - BattingSeason.triple - BattingSeason.hr) * .89)) / - ( - BattingSeason.ab + BattingSeason.bb - BattingSeason.ibb + BattingSeason.sac + BattingSeason.hbp))) - .limit(10)) - top_bab = (BattingSeason - .select() - .where(BattingSeason.pa >= min_pa) - .order_by(-((BattingSeason.hit - BattingSeason.hr) / - (BattingSeason.ab - BattingSeason.so - BattingSeason.hr + BattingSeason.sac))) - .limit(10)) - top_rbi = (BattingSeason - .select(BattingSeason.player, BattingSeason.rbi) - .order_by(-BattingSeason.rbi, BattingSeason.player) - .limit(10)) - top_dbl = (BattingSeason - .select(BattingSeason.player, BattingSeason.double) - .order_by(-BattingSeason.double, BattingSeason.player) - .limit(10)) - top_trp = (BattingSeason - .select(BattingSeason.player, BattingSeason.triple) - .order_by(-BattingSeason.triple, BattingSeason.player) - .limit(10)) - top_hit = (BattingSeason - .select(BattingSeason.player, BattingSeason.hit) - .order_by(-BattingSeason.hit, BattingSeason.player) - .limit(10)) - top_pa = (BattingSeason - .select(BattingSeason.player, BattingSeason.pa) - .order_by(-BattingSeason.pa, BattingSeason.player) - .limit(10)) - top_gdp = (BattingSeason - .select(BattingSeason.player, BattingSeason.gidp) - .order_by(-BattingSeason.gidp, BattingSeason.player) - .limit(10)) - top_bb = (BattingSeason - .select(BattingSeason.player, BattingSeason.bb) - .order_by(-BattingSeason.bb, BattingSeason.player) - .limit(10)) - top_so = (BattingSeason - .select(BattingSeason.player, BattingSeason.so) - .order_by(-BattingSeason.so, BattingSeason.player) - .limit(10)) - top_hbp = (BattingSeason - .select(BattingSeason.player, BattingSeason.hbp) - .order_by(-BattingSeason.hbp, BattingSeason.player) - .limit(10)) - top_ibb = (BattingSeason - .select(BattingSeason.player, BattingSeason.ibb) - .order_by(-BattingSeason.ibb, BattingSeason.player) - .limit(10)) - top_sb = (BattingSeason - .select(BattingSeason.player, BattingSeason.sb) - .order_by(-BattingSeason.sb, BattingSeason.player) - .limit(10)) - top_cs = (BattingSeason - .select(BattingSeason.player, BattingSeason.cs) - .order_by(-BattingSeason.cs, BattingSeason.player) - .limit(10)) - top_run = (BattingSeason - .select(BattingSeason.player, BattingSeason.run) - .order_by(-BattingSeason.run, BattingSeason.player) - .limit(10)) - top_ab = (BattingSeason - .select(BattingSeason.player, BattingSeason.ab) - .order_by(-BattingSeason.ab, BattingSeason.player) - .limit(10)) - top_bphr = (BattingSeason - .select(BattingSeason.player, BattingSeason.bphr) - .where(BattingSeason.bphr > 0) - .order_by(-BattingSeason.bphr, BattingSeason.player) - .limit(10)) - top_bpfo = (BattingSeason - .select(BattingSeason.player, BattingSeason.bpfo) - .where(BattingSeason.bpfo > 0) - .order_by(-BattingSeason.bpfo, BattingSeason.player) - .limit(10)) - top_bp1b = (BattingSeason - .select(BattingSeason.player, BattingSeason.bp1b) - .where(BattingSeason.bp1b > 0) - .order_by(-BattingSeason.bp1b, BattingSeason.player) - .limit(10)) - top_bplo = (BattingSeason - .select(BattingSeason.player, BattingSeason.bplo) - .where(BattingSeason.bplo > 0) - .order_by(-BattingSeason.bplo, BattingSeason.player) - .limit(10)) - # top_xba = (BattingSeason - # .select(BattingSeason.player, BattingSeason.xba) - # .where(BattingSeason.xba > 0) - # .order_by(-BattingSeason.xba, BattingSeason.player) - # .limit(10)) - # top_xbt = (BattingSeason - # .select(BattingSeason.player, BattingSeason.xbt) - # .where(BattingSeason.xbt > 0) - # .order_by(-BattingSeason.xbt, BattingSeason.player) - # .limit(10)) - top_ndhr = (BattingSeason - .select(BattingSeason.player, BattingSeason.bphr, BattingSeason.hr) - .where(BattingSeason.hr > 0) - .order_by(-(BattingSeason.hr - BattingSeason.bphr), BattingSeason.player) - .limit(10)) - db.close() - - for x in top_avg: - all_leaders['Batting Average']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{x.hit / x.ab:.3f}'} - ) - for x in top_hr: - all_leaders['Home Runs']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.hr)} - ) - for x in top_obp: - all_leaders['On Base Percentage']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.hit + x.bb + x.hbp + x.ibb) / x.pa:.3f}'} - ) - for x in top_slg: - all_leaders['Slugging Percentage']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{((x.hr * 4) + (x.triple * 3) + (x.double * 2) + (x.hit - x.hr - x.triple - x.double)) / x.ab:.3f}'} - ) - for x in top_ops: - all_leaders['On Base Plus Slugging']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(x.ab * (x.hit + x.bb + x.ibb + x.hbp) + ((x.hr * 4) + (x.triple * 3) + (x.double * 2) + (x.hit - x.double - x.triple - x.hr)) * (x.ab + x.bb + x.ibb + x.sac + x.hbp)) / (x.ab * (x.ab + x.bb + x.ibb + x.sac + x.hbp)):.3f}'} - ) - for x in top_wob: - all_leaders['Weighted On Base Avg']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{(((x.bb * .69) + (x.hbp * .72) + (x.hr * 2.1) + (x.triple * 1.62) + (x.double * 1.27) + ((x.hit - x.double - x.triple - x.hr) * .89)) / (x.ab + x.bb - x.ibb + x.sac + x.hbp)):.3f}'} - ) - for x in top_bab: - all_leaders['Avg on Balls in Play']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{((x.hit - x.hr) / (x.ab - x.so - x.hr + x.sac)):.3f}'} - ) - for x in top_rbi: - all_leaders['Runs Batted In']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.rbi)} - ) - for x in top_dbl: - all_leaders['Doubles']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.double)} - ) - for x in top_trp: - all_leaders['Triples']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.triple)} - ) - for x in top_hit: - all_leaders['Hits']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.hit)} - ) - for x in top_pa: - all_leaders['Plate Appearances']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.pa)} - ) - for x in top_gdp: - all_leaders['Ground Into Double Play']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.gidp)} - ) - for x in top_bb: - all_leaders['Walks']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.bb)} - ) - for x in top_so: - all_leaders['Strikeouts']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.so)} - ) - for x in top_hbp: - all_leaders['Hit By Pitch']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.hbp)} - ) - for x in top_ibb: - all_leaders['Intentional Walks']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.ibb)} - ) - for x in top_sb: - all_leaders['Stolen Bases']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.sb)} - ) - for x in top_cs: - all_leaders['Caught Stealing']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.cs)} - ) - for x in top_run: - all_leaders['Runs Scored']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.run)} - ) - for x in top_ab: - all_leaders['At Bats']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.ab)} - ) - for x in top_bphr: - all_leaders['Ballpark Home Runs']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.bphr)} - ) - for x in top_bpfo: - all_leaders['Ballpark Flyouts']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.bpfo)} - ) - for x in top_bp1b: - all_leaders['Ballpark Singles']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.bp1b)} - ) - for x in top_bplo: - all_leaders['Ballpark Lineouts']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': round(x.bplo)} - ) - # for x in top_xba: - # all_leaders['Extra Base Attempts']['leaders'].append( - # {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.xba)} - # ) - # for x in top_xbt: - # all_leaders['Extra Bases Taken']['leaders'].append( - # {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, 'stat': round(x.xbt)} - # ) - for x in top_ndhr: - all_leaders['No-Doubt Home Runs']['leaders'].append( - {'player': x.player.name, 'season': x.player.season, 'team': x.player.team.abbrev, - 'stat': f'{x.hr - x.bphr:.0f}'} - ) - - db.close() - return all_leaders - - -@app.get('/api/v1/career-leaders') -async def v1_career_leaders_get(group: str = 'batting'): - min_ip = 300 - min_pa = 1000 - min_ch_high = 200 - min_ch_mid = 80 - min_ch_low = 40 - all_leaders = None - - if group == 'pitching': - all_leaders = { - # 'Starter Wins': {'abbrev': 'W', 'leaders': []}, - 'Wins': {'abbrev': 'W', 'leaders': []}, - 'Earned Run Average': {'abbrev': 'ERA', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Innings Pitched': {'abbrev': 'IP', 'leaders': []}, - 'Strikeouts per Nine': {'abbrev': 'K/9', 'leaders': []}, - 'Walks + Hits / IP': {'abbrev': 'WHIP', 'leaders': []}, - 'Saves': {'abbrev': 'SV', 'leaders': []}, - 'Walks Allowed': {'abbrev': 'BB', 'leaders': []}, - 'Runs Allowed': {'abbrev': 'R', 'leaders': []}, - 'Earned Runs Allowed': {'abbrev': 'ER', 'leaders': []}, - 'Blown Saves': {'abbrev': 'BSV', 'leaders': []}, - 'Hit By Pitches Allowed': {'abbrev': 'HBP', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'H', 'leaders': []}, - 'Home Runs Allowed': {'abbrev': 'HR', 'leaders': []}, - 'Wild Pitches': {'abbrev': 'WP', 'leaders': []}, - 'Holds': {'abbrev': 'HD', 'leaders': []}, - 'Walks Per Nine': {'abbrev': 'BB/9', 'leaders': []}, - 'Strikeouts Per Walk': {'abbrev': 'K/BB', 'leaders': []}, - 'Losses': {'abbrev': 'L', 'leaders': []}, - } - - # top_swin = (PitchingStat - # .select(PitchingStat.player, fn.COUNT(PitchingStat.win).alias('swin')) - # .where(PitchingStat.gs == 1, PitchingStat.win == 1) - # .order_by(-fn.COUNT(PitchingStat.win), PitchingStat.player) - # .group_by(PitchingStat.player) - # .limit(10)) - top_win = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.win) - .order_by(-PitchingCareer.win, PitchingCareer.name) - .limit(10)) - top_ip = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.ip) - .order_by(-PitchingCareer.ip, PitchingCareer.name) - .limit(10)) - top_so = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.so) - .order_by(-PitchingCareer.so, PitchingCareer.name) - .limit(10)) - top_era = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.erun, PitchingCareer.ip) - .where(PitchingCareer.ip >= min_ip) - .order_by(((PitchingCareer.erun * 9) / PitchingCareer.ip), PitchingCareer.name) - .limit(10)) - top_kpn = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.so, PitchingCareer.ip) - .where(PitchingCareer.ip >= min_ip) - .order_by(-((PitchingCareer.so * 9) / PitchingCareer.ip), PitchingCareer.name) - .limit(10)) - top_whip = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.bb, PitchingCareer.hit, PitchingCareer.ip) - .where(PitchingCareer.ip >= min_ip) - .order_by(+((PitchingCareer.bb + PitchingCareer.hit) / PitchingCareer.ip), PitchingCareer.name) - .limit(10)) - top_sv = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.sv) - .order_by(-PitchingCareer.sv, PitchingCareer.name) - .limit(10)) - top_bb = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.bb) - .order_by(-PitchingCareer.bb, PitchingCareer.name) - .limit(10)) - top_run = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.run) - .order_by(-PitchingCareer.run, PitchingCareer.name) - .limit(10)) - top_erun = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.erun) - .order_by(-PitchingCareer.erun, PitchingCareer.name) - .limit(10)) - top_bsv = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.bsv) - .order_by(-PitchingCareer.bsv, PitchingCareer.name) - .limit(10)) - top_hbp = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.hbp) - .order_by(-PitchingCareer.hbp, PitchingCareer.name) - .limit(10)) - top_hit = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.hit) - .order_by(-PitchingCareer.hit, PitchingCareer.name) - .limit(10)) - top_hr = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.hr) - .order_by(-PitchingCareer.hr, PitchingCareer.name) - .limit(10)) - top_wp = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.wp) - .order_by(-PitchingCareer.wp, PitchingCareer.name) - .limit(10)) - top_hd = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.hold) - .order_by(-PitchingCareer.hold, PitchingCareer.name) - .limit(10)) - top_bpn = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.bb, PitchingCareer.ip) - .where(PitchingCareer.ip >= min_ip) - .order_by(((PitchingCareer.bb * 9) / PitchingCareer.ip), PitchingCareer.name) - .limit(10)) - top_kpw = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.bb, PitchingCareer.so) - .where(PitchingCareer.ip >= min_ip) - .order_by(-(PitchingCareer.so / PitchingCareer.bb), PitchingCareer.name) - .limit(10)) - top_los = (PitchingCareer - .select(PitchingCareer.name, PitchingCareer.loss) - .order_by(-PitchingCareer.loss, PitchingCareer.name) - .limit(10)) - - db.close() - - # for x in top_swin: - # all_leaders['Starter Wins']['leaders'].append( - # {'player': x.player.name, 'team': x.player.team.abbrev, 'stat': round(x.swin)} - # ) - for x in top_win: - all_leaders['Wins']['leaders'].append( - {'player': x.name, 'stat': round(x.win)} - ) - for x in top_ip: - all_leaders['Innings Pitched']['leaders'].append( - {'player': x.name, 'stat': f'{x.ip:.1f}'} - ) - for x in top_so: - all_leaders['Strikeouts']['leaders'].append( - {'player': x.name, 'stat': round(x.so)} - ) - for x in top_era: - all_leaders['Earned Run Average']['leaders'].append( - {'player': x.name, 'stat': f'{((x.erun * 9) / x.ip):.2f}'} - ) - for x in top_kpn: - all_leaders['Strikeouts per Nine']['leaders'].append( - {'player': x.name, 'stat': f'{((x.so * 9) / x.ip):.2f}'} - ) - for x in top_whip: - all_leaders['Walks + Hits / IP']['leaders'].append( - {'player': x.name, 'stat': f'{((x.bb + x.hit) / x.ip):.2f}'} - ) - for x in top_sv: - all_leaders['Saves']['leaders'].append( - {'player': x.name, 'stat': round(x.sv)} - ) - for x in top_bb: - all_leaders['Walks Allowed']['leaders'].append( - {'player': x.name, 'stat': round(x.bb)} - ) - for x in top_run: - all_leaders['Runs Allowed']['leaders'].append( - {'player': x.name, 'stat': round(x.run)} - ) - for x in top_erun: - all_leaders['Earned Runs Allowed']['leaders'].append( - {'player': x.name, 'stat': round(x.erun)} - ) - for x in top_bsv: - all_leaders['Blown Saves']['leaders'].append( - {'player': x.name, 'stat': round(x.bsv)} - ) - for x in top_hbp: - all_leaders['Hit By Pitches Allowed']['leaders'].append( - {'player': x.name, 'stat': round(x.hbp)} - ) - for x in top_hit: - all_leaders['Hits Allowed']['leaders'].append( - {'player': x.name, 'stat': round(x.hit)} - ) - for x in top_hr: - all_leaders['Home Runs Allowed']['leaders'].append( - {'player': x.name, 'stat': round(x.hr)} - ) - for x in top_wp: - all_leaders['Wild Pitches']['leaders'].append( - {'player': x.name, 'stat': round(x.wp)} - ) - for x in top_hd: - all_leaders['Holds']['leaders'].append( - {'player': x.name, 'stat': round(x.hold)} - ) - for x in top_bpn: - all_leaders['Walks Per Nine']['leaders'].append( - {'player': x.name, 'stat': f'{((x.bb * 9) / x.ip):.2f}'} - ) - for x in top_kpw: - all_leaders['Strikeouts Per Walk']['leaders'].append( - {'player': x.name, 'stat': f'{(x.so / x.bb):.2f}'} - ) - for x in top_los: - all_leaders['Losses']['leaders'].append( - {'player': x.name, 'stat': round(x.loss)} - ) - elif group == 'fielding': - all_leaders = { - 'Fielding Chances': {'abbrev': 'X-Ch', 'leaders': []}, - 'Weighted Fielding % (RF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (CF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (LF)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (SS)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (3B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (2B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (1B)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (C)': {'abbrev': 'wF%', 'leaders': []}, - 'Weighted Fielding % (P)': {'abbrev': 'wF%', 'leaders': []}, - 'Errors': {'abbrev': 'E', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'X-Hit', 'leaders': []}, - 'Passed Balls': {'abbrev': 'PB', 'leaders': []}, - 'Steal Attempts Against': {'abbrev': 'SBa', 'leaders': []}, - 'Runners Thrown Out': {'abbrev': 'CSc', 'leaders': []}, - 'Caught Stealing % (Catchers)': {'abbrev': 'CS%', 'leaders': []}, - } - - top_xch = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.sbc) - .order_by(-(FieldingCareer.xch + FieldingCareer.sbc), FieldingCareer.name) - .limit(10)) - raw_ss = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == 'SS') & (FieldingCareer.xch >= min_ch_high))) - raw_cf = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == 'CF') & (FieldingCareer.xch >= min_ch_mid))) - raw_2b = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == '2B') & (FieldingCareer.xch >= min_ch_high))) - raw_3b = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == '3B') & (FieldingCareer.xch >= min_ch_mid))) - raw_1b = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == '1B') & (FieldingCareer.xch >= min_ch_mid))) - raw_lf = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == 'LF') & (FieldingCareer.xch >= min_ch_low))) - raw_rf = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == 'RF') & (FieldingCareer.xch >= min_ch_low))) - raw_ca = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == 'C') & (FieldingCareer.xch >= min_ch_mid))) - raw_pi = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xch, FieldingCareer.xhit, FieldingCareer.error) - .where( - (FieldingCareer.pos == 'P') & (FieldingCareer.xch >= (min_ch_low / 3)))) - top_err = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.error) - .order_by(-FieldingCareer.error, FieldingCareer.name) - .limit(10)) - top_hit = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.xhit) - .order_by(-FieldingCareer.xhit, FieldingCareer.name) - .limit(10)) - top_sbc = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.sbc) - .order_by(-FieldingCareer.sbc, FieldingCareer.name) - .limit(10)) - top_csc = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.csc) - .order_by(-FieldingCareer.csc, FieldingCareer.name) - .limit(10)) - top_csp = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.sbc, FieldingCareer.csc) - .where(FieldingCareer.sbc >= min_ch_mid) - .order_by(-((FieldingCareer.csc * 100) / FieldingCareer.sbc), FieldingCareer.name) - .limit(10)) - top_pb = (FieldingCareer - .select(FieldingCareer.name, FieldingCareer.pb) - .where(FieldingCareer.pb > 0) - .order_by(-FieldingCareer.pb, FieldingCareer.name) - .limit(10)) - - db.close() - - for x in top_xch: - all_leaders['Fielding Chances']['leaders'].append( - {'player': x.name, 'stat': x.xch + x.sbc} - ) - for x in top_err: - all_leaders['Errors']['leaders'].append( - {'player': x.name, 'stat': x.error} - ) - for x in top_sbc: - all_leaders['Steal Attempts Against']['leaders'].append( - {'player': x.name, 'stat': x.sbc} - ) - for x in top_csc: - all_leaders['Runners Thrown Out']['leaders'].append( - {'player': x.name, 'stat': x.csc} - ) - for x in top_csp: - all_leaders['Caught Stealing % (Catchers)']['leaders'].append( - {'player': x.name, 'stat': f'{x.csc * 100 / x.sbc:.1f}'} - ) - for x in top_hit: - all_leaders['Hits Allowed']['leaders'].append( - {'player': x.name, 'stat': x.xhit} - ) - for x in top_pb: - all_leaders['Passed Balls']['leaders'].append( - {'player': x.name, 'stat': x.pb} - ) - - for x in raw_ss: - all_leaders['Weighted Fielding % (SS)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_cf: - all_leaders['Weighted Fielding % (CF)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_2b: - all_leaders['Weighted Fielding % (2B)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_3b: - all_leaders['Weighted Fielding % (3B)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_1b: - all_leaders['Weighted Fielding % (1B)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_lf: - all_leaders['Weighted Fielding % (LF)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_rf: - all_leaders['Weighted Fielding % (RF)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_ca: - all_leaders['Weighted Fielding % (C)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for x in raw_pi: - all_leaders['Weighted Fielding % (P)']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.xch - (x.error * .5) - (x.xhit * .75)) / x.xch:.3f}'} - ) - for stat in all_leaders: - if 'Weighted Fielding' in stat: - all_leaders[stat]['leaders'] = sorted( - all_leaders[stat]['leaders'], - key=lambda leader: leader['stat'], - reverse=True - ) - all_leaders[stat]['leaders'] = all_leaders[stat]['leaders'][:10] - else: - # return batting leaders - all_leaders = { - 'Home Runs': {'abbrev': 'HR', 'leaders': []}, - 'Batting Average': {'abbrev': 'AVG', 'leaders': []}, - 'On Base Percentage': {'abbrev': 'OBP', 'leaders': []}, - 'Slugging Percentage': {'abbrev': 'SLG', 'leaders': []}, - 'Runs Batted In': {'abbrev': 'RBI', 'leaders': []}, - 'Doubles': {'abbrev': '2B', 'leaders': []}, - 'Triples': {'abbrev': '3B', 'leaders': []}, - 'Hits': {'abbrev': 'H', 'leaders': []}, - 'Plate Appearances': {'abbrev': 'PA', 'leaders': []}, - 'Ground Into Double Play': {'abbrev': 'GIDP', 'leaders': []}, - 'Walks': {'abbrev': 'BB', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Hit By Pitch': {'abbrev': 'HBP', 'leaders': []}, - 'Intentional Walks': {'abbrev': 'IBB', 'leaders': []}, - 'Stolen Bases': {'abbrev': 'SB', 'leaders': []}, - 'Caught Stealing': {'abbrev': 'CS', 'leaders': []}, - 'Runs Scored': {'abbrev': 'R', 'leaders': []}, - 'At Bats': {'abbrev': 'AB', 'leaders': []}, - } - - top_avg = (BattingCareer - .select() - .where(BattingCareer.pa >= min_pa) - .order_by(-(BattingCareer.hit / BattingCareer.ab), BattingCareer.name) - .limit(10)) - top_hr = (BattingCareer - .select(BattingCareer.name, BattingCareer.hr) - .order_by(-BattingCareer.hr, BattingCareer.name) - .limit(10)) - top_obp = (BattingCareer - .select() - .where(BattingCareer.pa >= min_pa) - .order_by( - -((BattingCareer.hit + BattingCareer.bb + BattingCareer.hbp + BattingCareer.ibb) / BattingCareer.pa), - BattingCareer.name) - .limit(10)) - top_slg = (BattingCareer - .select() - .where(BattingCareer.pa >= min_pa) - .order_by(-(((BattingCareer.hr * 4) + (BattingCareer.triple * 3) + (BattingCareer.double * 2) + ( - BattingCareer.hit - BattingCareer.hr - BattingCareer.triple - BattingCareer.double)) / BattingCareer.ab)) - .limit(10)) - top_rbi = (BattingCareer - .select(BattingCareer.name, BattingCareer.rbi) - .order_by(-BattingCareer.rbi, BattingCareer.name) - .limit(10)) - top_dbl = (BattingCareer - .select(BattingCareer.name, BattingCareer.double) - .order_by(-BattingCareer.double, BattingCareer.name) - .limit(10)) - top_trp = (BattingCareer - .select(BattingCareer.name, BattingCareer.triple) - .order_by(-BattingCareer.triple, BattingCareer.name) - .limit(10)) - top_hit = (BattingCareer - .select(BattingCareer.name, BattingCareer.hit) - .order_by(-BattingCareer.hit, BattingCareer.name) - .limit(10)) - top_pa = (BattingCareer - .select(BattingCareer.name, BattingCareer.pa) - .order_by(-BattingCareer.pa, BattingCareer.name) - .limit(10)) - top_gdp = (BattingCareer - .select(BattingCareer.name, BattingCareer.gidp) - .order_by(-BattingCareer.gidp, BattingCareer.name) - .limit(10)) - top_bb = (BattingCareer - .select(BattingCareer.name, BattingCareer.bb) - .order_by(-BattingCareer.bb, BattingCareer.name) - .limit(10)) - top_so = (BattingCareer - .select(BattingCareer.name, BattingCareer.so) - .order_by(-BattingCareer.so, BattingCareer.name) - .limit(10)) - top_hbp = (BattingCareer - .select(BattingCareer.name, BattingCareer.hbp) - .order_by(-BattingCareer.hbp, BattingCareer.name) - .limit(10)) - top_ibb = (BattingCareer - .select(BattingCareer.name, BattingCareer.ibb) - .order_by(-BattingCareer.ibb, BattingCareer.name) - .limit(10)) - top_sb = (BattingCareer - .select(BattingCareer.name, BattingCareer.sb) - .order_by(-BattingCareer.sb, BattingCareer.name) - .limit(10)) - top_cs = (BattingCareer - .select(BattingCareer.name, BattingCareer.cs) - .order_by(-BattingCareer.cs, BattingCareer.name) - .limit(10)) - top_run = (BattingCareer - .select(BattingCareer.name, BattingCareer.run) - .order_by(-BattingCareer.run, BattingCareer.name) - .limit(10)) - top_ab = (BattingCareer - .select(BattingCareer.name, BattingCareer.ab) - .order_by(-BattingCareer.ab, BattingCareer.name) - .limit(10)) - db.close() - - for x in top_avg: - all_leaders['Batting Average']['leaders'].append( - {'player': x.name, 'stat': f'{x.hit / x.ab:.3f}'} - ) - for x in top_hr: - all_leaders['Home Runs']['leaders'].append( - {'player': x.name, 'stat': round(x.hr)} - ) - for x in top_obp: - all_leaders['On Base Percentage']['leaders'].append( - {'player': x.name, - 'stat': f'{(x.hit + x.bb + x.hbp + x.ibb) / x.pa:.3f}'} - ) - for x in top_slg: - all_leaders['Slugging Percentage']['leaders'].append( - {'player': x.name, - 'stat': f'{((x.hr * 4) + (x.triple * 3) + (x.double * 2) + (x.hit - x.hr - x.triple - x.double)) / x.ab:.3f}'} - ) - for x in top_rbi: - all_leaders['Runs Batted In']['leaders'].append( - {'player': x.name, 'stat': round(x.rbi)} - ) - for x in top_dbl: - all_leaders['Doubles']['leaders'].append( - {'player': x.name, 'stat': round(x.double)} - ) - for x in top_trp: - all_leaders['Triples']['leaders'].append( - {'player': x.name, 'stat': round(x.triple)} - ) - for x in top_hit: - all_leaders['Hits']['leaders'].append( - {'player': x.name, 'stat': round(x.hit)} - ) - for x in top_pa: - all_leaders['Plate Appearances']['leaders'].append( - {'player': x.name, 'stat': round(x.pa)} - ) - for x in top_gdp: - all_leaders['Ground Into Double Play']['leaders'].append( - {'player': x.name, 'stat': round(x.gidp)} - ) - for x in top_bb: - all_leaders['Walks']['leaders'].append( - {'player': x.name, 'stat': round(x.bb)} - ) - for x in top_so: - all_leaders['Strikeouts']['leaders'].append( - {'player': x.name, 'stat': round(x.so)} - ) - for x in top_hbp: - all_leaders['Hit By Pitch']['leaders'].append( - {'player': x.name, 'stat': round(x.hbp)} - ) - for x in top_ibb: - all_leaders['Intentional Walks']['leaders'].append( - {'player': x.name, 'stat': round(x.ibb)} - ) - for x in top_sb: - all_leaders['Stolen Bases']['leaders'].append( - {'player': x.name, 'stat': round(x.sb)} - ) - for x in top_cs: - all_leaders['Caught Stealing']['leaders'].append( - {'player': x.name, 'stat': round(x.cs)} - ) - for x in top_run: - all_leaders['Runs Scored']['leaders'].append( - {'player': x.name, 'stat': round(x.run)} - ) - for x in top_ab: - all_leaders['At Bats']['leaders'].append( - {'player': x.name, 'stat': round(x.ab)} - ) - - db.close() - return all_leaders - - -@app.get('/api/v1/leaders/{stat}') # Not implemented -async def v1_leaders_stat( - stat: str, season: int = Current.get().season, team_abbrev: Optional[str] = None, - league_abbrev: Optional[str] = None, division_abbrev: Optional[str] = None): - db.close() - raise HTTPException(501, detail='Function not implemented, yet') - - -@app.get('/api/v1/single-game-leaders') -async def v1_single_game_leaders_get( - group: str = 'batting', season: Optional[int] = None, team_abbrev: Optional[str] = None): - all_leaders = None - - if group == 'pitching': - all_leaders = { - 'Perfect Games': {'abbrev': 'PG', 'leaders': []}, - 'Complete Games': {'abbrev': 'PG', 'leaders': []}, - # 'Innings Pitched': {'abbrev': 'IP', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Scoreless Innings': {'abbrev': 'SI', 'leaders': []}, - 'Zero Baserunners': {'abbrev': 'ZB', 'leaders': []}, - 'Earned Runs Allowed': {'abbrev': 'ER', 'leaders': []}, - 'Hit By Pitches Allowed': {'abbrev': 'HBP', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'H', 'leaders': []}, - 'Home Runs Allowed': {'abbrev': 'HR', 'leaders': []}, - 'Wild Pitches': {'abbrev': 'WP', 'leaders': []}, - } - all_stats = PitchingStat.select().join(Team).where( - (PitchingStat.team.abbrev != 'SRS') & (PitchingStat.ip <= 10) - ) - if season: - all_stats = all_stats.where(PitchingStat.season == season) - if team_abbrev and season: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - raise HTTPException(404, f'Team {team_abbrev} not found in season {season}') - all_stats = all_stats.where(PitchingStat.team == this_team) - - # top_ip = (all_stats - # .order_by(-PitchingStat.ip, PitchingStat.season, PitchingStat.player) - # .limit(10)) - top_so = (all_stats - .order_by(-PitchingStat.so, PitchingStat.season, PitchingStat.player) - .limit(10)) - top_si = (all_stats.where(PitchingStat.run == 0) - .order_by(-PitchingStat.ip, PitchingStat.season, PitchingStat.player) - .limit(10)) - top_zb = (all_stats - .where((PitchingStat.hit == 0) & (PitchingStat.bb == 0) & (PitchingStat.hbp == 0)) - .order_by(-PitchingStat.ip, PitchingStat.season, PitchingStat.player) - .limit(10)) - top_erun = (all_stats - .order_by(-PitchingStat.erun, PitchingStat.season, PitchingStat.player) - .limit(10)) - top_hbp = (all_stats - .order_by(-PitchingStat.hbp, PitchingStat.season, PitchingStat.player) - .limit(10)) - top_hit = (all_stats - .order_by(-PitchingStat.hit, PitchingStat.season, PitchingStat.player) - .limit(10)) - top_hr = (all_stats - .order_by(-PitchingStat.hr, PitchingStat.season, PitchingStat.player) - .limit(10)) - top_wp = (all_stats - .order_by(-PitchingStat.wp, PitchingStat.season, PitchingStat.player) - .limit(10)) - - db.close() - return all_leaders - - # for x in top_ip: - # this_result = Result.select().where( - # (Result.season == x.season) & (Result.week == x.week) & - # ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - # ).limit(1) - # - # opponent = None - # home_team = None - # away_team = None - # if this_result.count() > 0: - # # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # # f'This Team: {x.player.team}') - # home_team = this_result[0].hometeam - # away_team = this_result[0].awayteam - # if this_result[0].hometeam == x.player.team: - # opponent = this_result[0].awayteam - # else: - # opponent = this_result[0].hometeam - # # logging.info(f'Opponent: {opponent}') - # - # all_leaders['Innings Pitched']['leaders'].append( - # { - # 'player': x.player.name, - # 'team': x.team.abbrev, - # 'stat': f'{x.ip:.1f}', - # 'season': x.player.season, - # 'week': x.week, - # 'game_num': x.game, - # 'opponent': opponent.abbrev if opponent else '???', - # 'home_team': home_team.abbrev if home_team else '???', - # 'away_team': away_team.abbrev if away_team else '???' - # } - # ) - for x in top_so: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Strikeouts']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': round(x.so), - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_si: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Scoreless Innings']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': f'{x.ip:.1f}', - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_zb: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Zero Baserunners']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': f'{x.ip:.1f}', - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_erun: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Earned Runs Allowed']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': round(x.erun), - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_hbp: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Hit By Pitches Allowed']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': round(x.hbp), - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_hit: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Hits Allowed']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': round(x.hit), - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_hr: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Home Runs Allowed']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': round(x.hr), - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_wp: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Wild Pitches']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': round(x.wp), - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - - elif group == 'fielding': - all_leaders = { - 'Fielding Chances': {'abbrev': 'xch', 'leaders': []}, - 'Errors': {'abbrev': 'E', 'leaders': []}, - 'Hits Allowed': {'abbrev': 'H', 'leaders': []}, - 'Passed Balls': {'abbrev': 'PB', 'leaders': []}, - 'Steal Attempts Against': {'abbrev': 'SBa', 'leaders': []}, - 'Runners Thrown Out (C)': {'abbrev': 'CSc', 'leaders': []}, - # 'Rob Attempts': {'abbrev': 'ROBa', 'leaders': []}, - # 'Rob Successes': {'abbrev': 'ROBs', 'leaders': []}, - } - all_stats = BattingStat.select().join(Team).where(BattingStat.team.abbrev != 'SRS') - if season: - all_stats = all_stats.where(BattingStat.season == season) - if team_abbrev and season: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - raise HTTPException(404, f'Team {team_abbrev} not found in season {season}') - all_stats = all_stats.where(BattingStat.team == this_team) - - top_xch = (all_stats - .where(BattingStat.xch > 1) - .order_by(-BattingStat.xch, BattingStat.season, BattingStat.week) - .limit(10)) - top_err = (all_stats - .where(BattingStat.error > 1) - .order_by(-BattingStat.error, BattingStat.season, BattingStat.week) - .limit(10)) - top_hit = (all_stats - .where(BattingStat.hit > 1) - .order_by(-BattingStat.xhit, BattingStat.season, BattingStat.week) - .limit(10)) - top_sbc = (all_stats - .where(BattingStat.sbc > 1) - .order_by(-BattingStat.sbc, BattingStat.season, BattingStat.week) - .limit(10)) - top_csc = (all_stats - .where(BattingStat.csc > 1) - .order_by(-BattingStat.csc, BattingStat.season, BattingStat.week) - .limit(10)) - top_pb = (all_stats - .where(BattingStat.pb > 1) - .order_by(-BattingStat.pb, BattingStat.season, BattingStat.week) - .limit(10)) - # top_roba = (all_stats - # .where(BattingStat.roba > 1) - # .order_by(-BattingStat.roba, BattingStat.season, BattingStat.week) - # .limit(10)) - # top_robs = (all_stats - # .where(BattingStat.robs > 1) - # .order_by(-BattingStat.robs, BattingStat.season, BattingStat.week) - # .limit(10)) - - db.close() - - for x in top_xch: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Fielding Chances']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': x.xch, - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_err: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Errors']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': x.error, - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_sbc: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Steal Attempts Against']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': x.sbc, - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_csc: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Runners Thrown Out (C)']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': x.csc, - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_hit: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Hits Allowed']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': x.xhit, - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - for x in top_pb: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Passed Balls']['leaders'].append( - { - 'player': x.player.name, - 'team': x.team.abbrev, - 'stat': x.pb, - 'season': x.player.season, - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???' - } - ) - # for x in top_roba: - # this_result = Result.select().where( - # (Result.season == x.season) & (Result.week == x.week) & - # ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - # ).limit(1) - # - # opponent = None - # home_team = None - # away_team = None - # if this_result.count() > 0: - # # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # # f'This Team: {x.player.team}') - # home_team = this_result[0].hometeam - # away_team = this_result[0].awayteam - # if this_result[0].hometeam == x.player.team: - # opponent = this_result[0].awayteam - # else: - # opponent = this_result[0].hometeam - # # logging.info(f'Opponent: {opponent}') - # - # all_leaders['Rob Attempts']['leaders'].append( - # { - # 'player': x.player.name, - # 'team': x.team.abbrev, - # 'stat': x.roba, - # 'season': x.player.season, - # 'week': x.week, - # 'game_num': x.game, - # 'opponent': opponent.abbrev if opponent else '???', - # 'home_team': home_team.abbrev if home_team else '???', - # 'away_team': away_team.abbrev if away_team else '???' - # } - # ) - # for x in top_robs: - # this_result = Result.select().where( - # (Result.season == x.season) & (Result.week == x.week) & - # ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - # ).limit(1) - # - # opponent = None - # home_team = None - # away_team = None - # if this_result.count() > 0: - # # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # # f'This Team: {x.player.team}') - # home_team = this_result[0].hometeam - # away_team = this_result[0].awayteam - # if this_result[0].hometeam == x.player.team: - # opponent = this_result[0].awayteam - # else: - # opponent = this_result[0].hometeam - # # logging.info(f'Opponent: {opponent}') - # - # all_leaders['Rob Successes']['leaders'].append( - # { - # 'player': x.player.name, - # 'team': x.team.abbrev, - # 'stat': x.robs, - # 'season': x.player.season, - # 'week': x.week, - # 'game_num': x.game, - # 'opponent': opponent.abbrev if opponent else '???', - # 'home_team': home_team.abbrev if home_team else '???', - # 'away_team': away_team.abbrev if away_team else '???' - # } - # ) - - else: - all_leaders = { - 'Home Runs': {'abbrev': 'HR', 'leaders': []}, - 'Hits': {'abbrev': 'H', 'leaders': []}, - 'RBI': {'abbrev': 'RBI', 'leaders': []}, - 'Hit for Cycle': {'abbrev': 'H', 'leaders': []}, - 'Stolen Bases': {'abbrev': 'SB', 'leaders': []}, - 'Doubles': {'abbrev': '2B', 'leaders': []}, - 'Triples': {'abbrev': '3B', 'leaders': []}, - 'Walks': {'abbrev': 'BB', 'leaders': []}, - # 'Extra Bases Taken': {'abbrev': 'XBT', 'leaders': []}, - 'Strikeouts': {'abbrev': 'K', 'leaders': []}, - 'Hit by Pitch': {'abbrev': 'HBP', 'leaders': []}, - } - all_stats = BattingStat.select().join(Team).where(BattingStat.team.abbrev != 'SRS') - if season: - all_stats = all_stats.where(BattingStat.season == season) - if team_abbrev and season: - this_team = Team.get_season(team_abbrev, season) - if not this_team: - raise HTTPException(404, f'Team {team_abbrev} not found in season {season}') - all_stats = all_stats.where(BattingStat.team == this_team) - - top_hr = (all_stats.where(BattingStat.hr > 1).order_by(-BattingStat.hr, BattingStat.season).limit(10)) - logging.info(f'top_hr: {top_hr}') - top_hit = (all_stats.where(BattingStat.hit > 2).order_by( - -BattingStat.hit, BattingStat.season, BattingStat.week - ).limit(10)) - top_rbi = (all_stats.where(BattingStat.rbi > 3).order_by( - -BattingStat.rbi, BattingStat.season, BattingStat.week - ).limit(10)) - top_sb = (all_stats.where(BattingStat.sb > 1).order_by( - -BattingStat.sb, BattingStat.season, BattingStat.week - ).limit(10)) - top_dbl = (all_stats.where(BattingStat.double > 1).order_by( - -BattingStat.double, BattingStat.season, BattingStat.week - ).limit(10)) - top_tri = (all_stats.where(BattingStat.triple > 1).order_by( - -BattingStat.triple, BattingStat.season, BattingStat.week - ).limit(10)) - top_bb = (all_stats.where(BattingStat.bb > 2).order_by( - -BattingStat.bb, BattingStat.season, BattingStat.week - ).limit(10)) - # top_xbt = (all_stats.where(BattingStat.xbt > 1).order_by( - # -BattingStat.xbt, BattingStat.season, BattingStat.week - # ).limit(10)) - top_k = (all_stats.where(BattingStat.so > 2).order_by( - -BattingStat.so, BattingStat.season, BattingStat.week - ).limit(10)) - top_hbp = (all_stats.where(BattingStat.hbp > 1).order_by( - -BattingStat.hbp, BattingStat.season, BattingStat.week - ).limit(10)) - top_ccl = (all_stats.where( - (BattingStat.hr > 0) & (BattingStat.triple > 0) & (BattingStat.double > 0) & - ((BattingStat.hit - BattingStat.double - BattingStat.triple - BattingStat.hr) > 0) - ).order_by(-BattingStat.hit, BattingStat.season, BattingStat.week).limit(10)) - - for x in top_hr: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Home Runs']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.hr}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_hit: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Hits']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.hit}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_rbi: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['RBI']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.rbi}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_sb: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Stolen Bases']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.sb}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_dbl: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Doubles']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.double}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_tri: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Triples']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.triple}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_bb: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Walks']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.bb}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - # for x in top_xbt: - # this_result = Result.select().where( - # (Result.season == x.season) & (Result.week == x.week) & - # ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - # ).limit(1) - # - # opponent = None - # home_team = None - # away_team = None - # if this_result.count() > 0: - # # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # # f'This Team: {x.player.team}') - # home_team = this_result[0].hometeam - # away_team = this_result[0].awayteam - # if this_result[0].hometeam == x.player.team: - # opponent = this_result[0].awayteam - # else: - # opponent = this_result[0].hometeam - # # logging.info(f'Opponent: {opponent}') - # - # all_leaders['Extra Bases Taken']['leaders'].append( - # { - # 'player': x.player.name, - # 'season': x.player.season, - # 'team': x.team.abbrev, - # 'stat': f'{x.xbt}', - # 'week': x.week, - # 'game_num': x.game, - # 'opponent': opponent.abbrev if opponent else '???', - # 'home_team': home_team.abbrev if home_team else '???', - # 'away_team': away_team.abbrev if away_team else '???', - # } - # ) - for x in top_k: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Strikeouts']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.so}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_hbp: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Hit by Pitch']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.hbp}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - for x in top_ccl: - this_result = Result.select().where( - (Result.season == x.season) & (Result.week == x.week) & - ((Result.awayteam == x.team) | (Result.hometeam == x.team)) - ).limit(1) - - opponent = None - home_team = None - away_team = None - if this_result.count() > 0: - # logging.info(f'Query: {this_result} / Result: {this_result[0]}') - # logging.info(f'Home Team: {this_result[0].hometeam} / Away Team: {this_result[0].awayteam} / ' - # f'This Team: {x.player.team}') - home_team = this_result[0].hometeam - away_team = this_result[0].awayteam - if this_result[0].hometeam == x.player.team: - opponent = this_result[0].awayteam - else: - opponent = this_result[0].hometeam - # logging.info(f'Opponent: {opponent}') - - all_leaders['Hit for Cycle']['leaders'].append( - { - 'player': x.player.name, - 'season': x.player.season, - 'team': x.team.abbrev, - 'stat': f'{x.hit}', - 'week': x.week, - 'game_num': x.game, - 'opponent': opponent.abbrev if opponent else '???', - 'home_team': home_team.abbrev if home_team else '???', - 'away_team': away_team.abbrev if away_team else '???', - } - ) - - db.close() - return all_leaders - - -@app.get('/api/v1/teamstats') -async def v1_teamstats( - group: str = 'batting', season: int = SEASON_DEFAULT, team_abbrev: Optional[str] = None): - team_stats = {} - if team_abbrev: - all_teams = Team.select_season(season).where(Team.abbrev == team_abbrev) - else: - all_teams = Team.select_season(season).where(Team.division.is_null(False)).order_by(Team.sname) - - if group == 'batting': - for team in all_teams: - if team.abbrev[:2] != 'FA': - team_stats[team.abbrev] = { - 'team': model_to_dict(team), - 'stats': BattingStat.team_season(team, season) - } - elif group == 'pitching': - for team in all_teams: - if team.abbrev[:2] != 'FA': - team_stats[team.abbrev] = { - 'team': model_to_dict(team), - 'stats': PitchingStat.team_season(team, season) - } - else: - for team in all_teams: - if team.abbrev[:2] != 'FA': - team_stats[team.abbrev] = { - 'team': model_to_dict(team), - 'stats': BattingStat.team_fielding_season(team, season) - } - - db.close() - return team_stats - - -@app.get('/api/v1/managers') -async def v1_managers_get(): - all_managers = Manager.select() - - return_managers = {} - for x in all_managers: - return_managers[f'{x.id}'] = model_to_dict(x) - - db.close() - return return_managers - - -@app.get('/api/v1/managers/{name_or_id}') -async def v1_managers_get_one(name_or_id): - try: - this_manager = Manager.get_by_id(name_or_id) - except: - this_manager = Manager.get_or_none(fn.Lower(Manager.name) == name_or_id.lower()) - - if not this_manager: - db.close() - raise HTTPException(status_code=404, detail=f'Manager {name_or_id} not found') - - db.close() - return model_to_dict(this_manager) - - -@app.patch('/api/v1/managers/{name_or_id}') -async def v1_managers_patch( - name_or_id, image: Optional[str] = None, headline: Optional[str] = None, bio: Optional[str] = None, - token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch managers') - - try: - this_manager = Manager.get_by_id(name_or_id) - except: - this_manager = Manager.get_or_none(fn.Lower(Manager.name) == name_or_id.lower()) - - if not this_manager: - db.close() - raise HTTPException(status_code=404, detail=f'Manager {name_or_id} not found') - - if image: - this_manager.image = image - - if headline: - this_manager.headline = headline - - if bio: - this_manager.bio = bio - - saved = this_manager.save() - db.close() - - if saved == 1: - return model_to_dict(this_manager) - else: - raise HTTPException(status_code=500, detail='Manager update has failed') - - -@app.post('/api/v1/managers') -async def v1_managers_post(manager: ManagerModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post managers') - - this_manager = Manager(name=manager.name) - this_manager.save() - - if manager.image: - this_manager.image = manager.image - if manager.headline: - this_manager.headline = manager.headline - if manager.bio: - this_manager.bio = manager.bio - - this_manager.save() - db.close() - - return model_to_dict(this_manager) - - -@app.get('/api/v1/awards') -async def v1_awards_get( - name: Optional[str] = None, season: Optional[int] = None, timing: Optional[str] = None, - manager_id: Optional[int] = None, player_id: Optional[int] = None, team_id: Optional[int] = None, - player_name: Optional[str] = None): - all_awards = Award.select() - - if name: - all_awards = all_awards.where(Award.name == name) - if season: - all_awards = all_awards.where(Award.season == season) - if timing: - all_awards = all_awards.where(Award.timing == timing) - if manager_id: - try: - this_manager = Manager.get_by_id(manager_id) - all_awards = all_awards.where( - ((Award.manager1 == this_manager) | (Award.manager2 == this_manager)) - ) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager id {manager_id} not found') - if player_id or player_name: - if player_id: - try: - this_player = Player.get_by_id(player_id) - all_awards = all_awards.where(Award.player == this_player) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - else: - these_players = Player.select().where(fn.Lower(Player.name) == player_name.lower()) - if these_players.count() == 0: - db.close() - raise HTTPException(status_code=404, detail=f'Player {player_name} not found') - - all_awards = all_awards.where(Award.player << these_players) - if team_id: - try: - this_team = Team.get_by_id(team_id) - all_awards = all_awards.where(Award.team == this_team) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team id {team_id} not found') - - return_awards = {} - for x in all_awards: - return_awards[f'{x.id}'] = model_to_dict(x) - - db.close() - return return_awards - - -@app.get('/api/v1/awards/{award_id}') -async def v1_awards_get_one(award_id): - try: - this_award = Award.get_by_id(award_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Award {award_id} not found') - - db.close() - return model_to_dict(this_award) - - -@app.patch('/api/v1/awards/{award_id}') -async def v1_awards_patch( - award_id, name: Optional[str] = None, season: Optional[int] = None, timing: Optional[str] = None, - image: Optional[str] = None, manager1_id: Optional[int] = None, manager2_id: Optional[int] = None, - player_id: Optional[int] = None, team_id: Optional[int] = None, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to patch awards') - - try: - this_award = Award.get_by_id(award_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Award {award_id} not found') - - if name: - this_award.name = name - if image: - this_award.image = image - if timing: - this_award.timing = timing - if season: - this_award.season = season - if manager1_id: - try: - this_manager = Manager.get_by_id(manager1_id) - this_award.manager1 = this_manager - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager id {manager1_id} not found') - if manager2_id: - try: - this_manager = Manager.get_by_id(manager2_id) - this_award.manager2 = this_manager - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager id {manager2_id} not found') - if player_id: - try: - this_player = Player.get_by_id(player_id) - this_award.player = this_player - except: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {player_id} not found') - if team_id: - try: - this_team = Team.get_by_id(team_id) - this_award.team = this_team - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team id {team_id} not found') - - saved = this_award.save() - db.close() - - if saved == 1: - return model_to_dict(this_award) - else: - raise HTTPException(status_code=500, detail='Award update has failed') - - -@app.post('/api/v1/awards') -async def v1_awards_post(awards: AwardModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post awards') - - all_awards = [] - - for award in awards.awards: - this_award = Award( - name=award.name, - season=award.season - ) - - if award.image: - this_award.image = award.image - if award.timing: - this_award.timing = award.timing - if award.manager1_id: - try: - this_manager = Manager.get_by_id(award.manager1_id) - this_award.manager1 = this_manager - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager id {award.manager1_id} not found') - if award.manager2_id: - try: - this_manager = Manager.get_by_id(award.manager2_id) - this_award.manager2 = this_manager - except: - db.close() - raise HTTPException(status_code=404, detail=f'Manager id {award.manager2_id} not found') - if award.player_id: - try: - this_player = Player.get_by_id(award.player_id) - this_award.player = this_player - except: - db.close() - raise HTTPException(status_code=404, detail=f'Player id {award.player_id} not found') - if award.team_id: - try: - this_team = Team.get_by_id(award.team_id) - this_award.team = this_team - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team id {award.team_id} not found') - - all_awards.append(this_award) - - with db.atomic(): - Award.bulk_create(all_awards, batch_size=15) - db.close() - - raise HTTPException(status_code=200, detail=f'Created {len(all_awards)} awards') - - -@app.delete('/api/v1/awards/{id}') -async def v1_awards_delete(id): - try: - this_award = Award.get_by_id(id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Award {id} not found') - - count = this_award.delete_instance() - db.close() - if count == 1: - raise HTTPException(status_code=200, detail=f'Award {id} has been deleted') - else: - raise HTTPException(status_code=500, detail=f'Award was not deleted') - - -@app.get('/api/v1/dice') -async def v1_dice_get( - season: Optional[int] = None, week_start: Optional[int] = None, week_end: Optional[int] = None, - team_id: Optional[int] = None, roller: Optional[int] = None): - all_dice = DiceRoll.select() - - if season: - all_dice = all_dice.where(DiceRoll.season == season) - - if (week_start and not week_end) or (week_end and not week_start): - if week_start: - all_dice = all_dice.where(DiceRoll.week >= week_start) - else: - all_dice = all_dice.where(DiceRoll.week <= week_start) - if week_start and week_end: - if week_end >= week_start: - all_dice = all_dice.where((DiceRoll.week >= week_start) & (DiceRoll.week <= week_end)) - else: - db.close() - raise HTTPException(status_code=400, detail='Week end must be greater than or equal to week start') - if team_id: - try: - this_team = Team.get_by_id(team_id) - all_dice = all_dice.where(DiceRoll.team == this_team) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team ID {team_id} not found') - if roller: - all_dice = all_dice.where(DiceRoll.roller == roller) - - return_dice = {} - for x in all_dice: - return_dice[f'{x.id}'] = model_to_dict(x) - - db.close() - return return_dice - - -@app.post('/api/v1/dice') -async def v1_dice_post(dice: DiceModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post dice rolls') - all_dice = [] - - for x in dice.rolls: - try: - this_team = Team.get_by_id(x.team_id) - this_die = DiceRoll( - season=x.season, - week=x.week, - team=this_team, - roller=x.roller, - dsix=x.dsix, - twodsix=x.twodsix, - threedsix=x.threedsix, - dtwenty=x.dtwenty - ) - all_dice.append(this_die) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team ID {x.team_id} not found') - - with db.atomic(): - DiceRoll.bulk_create(all_dice, batch_size=20) - - db.close() - raise HTTPException(status_code=200, detail=f'Posted {len(all_dice)} dice rolls') - - -@app.delete('/api/v1/dice') -async def v1_dice_delete( - season: int, week_start: Optional[int] = None, week_end: Optional[int] = None, - team_id: Optional[int] = None, roller: Optional[int] = None): - delete_query = DiceRoll.delete().where(DiceRoll.season == season) - - if (week_start and not week_end) or (week_end and not week_start): - if week_start: - delete_query = delete_query.where(DiceRoll.week >= week_start) - else: - delete_query = delete_query.where(DiceRoll.week <= week_start) - if week_start and week_end: - if week_end >= week_start: - delete_query = delete_query.where((DiceRoll.week >= week_start) & (DiceRoll.week <= week_end)) - else: - db.close() - raise HTTPException(status_code=400, detail='Week end must be greater than or equal to week start') - if team_id: - try: - this_team = Team.get_by_id(team_id) - delete_query = delete_query.where(DiceRoll.team == this_team) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team ID {team_id} not found') - if roller: - delete_query = delete_query.where(DiceRoll.roller == roller) - - print(f'delete_query: {delete_query}') - - count = delete_query.execute() - db.close() - if count > 0: - raise HTTPException(status_code=200, detail=f'Removed {count} batting stat lines') - else: - raise HTTPException(status_code=418, detail=f'Well slap my ass and call me a teapot; ' - f'I did not delete any records') - - -@app.post('/api/v1/draft-list') -async def v1_draft_list_post(draft_list: DraftListModel, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post dice rolls') - all_draft_list = [] - - try: - this_team = Team.get_by_id(draft_list.draft_list[0].team_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Team ID {draft_list.draft_list[0].team_id} not found') - - old_list = DraftList.delete().where( - DraftList.team == this_team - ) - old_list.execute() - - for x in draft_list.draft_list: - try: - this_player = Player.get_by_id(x.player_id) - except: - db.close() - raise HTTPException(status_code=404, detail=f'Player ID {x.player_id} not found') - - this_list = DraftList( - season=x.season, - team=this_team, - rank=x.rank, - player=this_player - ) - all_draft_list.append(this_list) - - with db.atomic(): - DraftList.bulk_create(all_draft_list, batch_size=20) - - db.close() - raise HTTPException(status_code=200, detail=f'Posted {len(all_draft_list)} dice rolls') - - -@app.get('/api/v1/draft-list/{team_id}') -async def v1_draft_list_get( - team_id, return_type: Optional[str] = 'json', csv: Optional[bool] = False, token: str = Depends(oauth2_scheme)): - if not valid_token(token): - logging.warning(f'Bad Token: {token}') - db.close() - raise HTTPException(status_code=401, detail='You are not authorized to post dice rolls') - - this_team = Team.get_by_id(team_id) - team_list = DraftList.select().where(DraftList.team == this_team) - - if return_type == 'csv' or csv: - return_list = [['season', 'team', 'rank', 'player']] - for x in team_list: - return_list.append([x.season, x.team.abbrev, x.rank, x.player.name]) - else: - return_list = {} - for x in team_list: - return_list[f'{x.id}'] = model_to_dict(x) - - db.close() - return return_list diff --git a/migrations.py b/migrations.py deleted file mode 100644 index 7942b22..0000000 --- a/migrations.py +++ /dev/null @@ -1,50 +0,0 @@ -from playhouse.migrate import * -import app.db_engine as db_engine - -migrator = SqliteMigrator(db_engine.db) - - -# pubdate_field = DateTimeField(null=True) -# comment_field = TextField(default='') - - -# pitcher_injury = IntegerField(null=True) -# pos_1 = CharField(default='None') -# pos_2 = CharField(null=True) -# hand_batting = CharField(null=True) -# hand_pitching = CharField(null=True) -# re24_primary = FloatField(null=True) -# re24_running = FloatField(null=True) -# last_game2 = CharField(null=True) -# division = ForeignKeyField(db_engine.Division, field=db_engine.Division.id, null=True) # for division migration -# manager = ForeignKeyField(db_engine.Manager, field=db_engine.Manager.id, null=True) # for manager table -# p_career = ForeignKeyField(db_engine.PitchingCareer, field=db_engine.PitchingCareer.id, null=True) # for careers -# b_career = ForeignKeyField(db_engine.BattingCareer, field=db_engine.BattingCareer.id, null=True) # for careers -# f_career = ForeignKeyField(db_engine.FieldingCareer, field=db_engine.FieldingCareer.id, null=True) # for careers -away_manager = ForeignKeyField(db_engine.Manager, field=db_engine.Manager.id, null=True) # to add Manager to games -home_manager = ForeignKeyField(db_engine.Manager, field=db_engine.Manager.id, null=True) # to add Manager to games -team = ForeignKeyField(db_engine.Team, field=db_engine.Team.id, null=True) # to add Team to decisions - -migrate( - # migrator.add_column('team', 'division_id', division), # for division migration - # migrator.add_column('team', 'manager1_id', manager), # for manager table - # migrator.add_column('team', 'manager2_id', manager), # for manager table - # migrator.add_column('battingseason', 'career_id', b_career), # for career stats - # migrator.add_column('pitchingseason', 'career_id', p_career), # for career stats - # migrator.add_column('fieldingseason', 'career_id', f_career), # for career stats - # migrator.add_column('player', 'last_game2', last_game2), - # migrator.add_column('player', 'pos_1', pos_1), - # migrator.add_column('comment_tbl', 'comment', comment_field), - # migrator.rename_column('team', 'division', 'division_legacy'), - # migrator.drop_column('story', 'some_old_field'), - # migrator.drop_not_null('team', 'abbrev'), - # migrator.add_not_null('story', 'modified_date'), - # migrator.rename_table('story', 'stories_tbl'), - # migrator.drop_index('team', 'team_abbrev'), - # migrator.drop_index('player', 'player_name') - migrator.add_column('decision', 'team', team), - # migrator.add_column('stratplay', 'hand_batting', hand_batting), - # migrator.add_column('stratplay', 'hand_pitching', hand_pitching), - # migrator.add_column('stratplay', 're24_primary', re24_primary), - # migrator.add_column('stratplay', 're24_running', re24_running) -) \ No newline at end of file diff --git a/pd_master.db b/pd_master.db deleted file mode 100644 index f510bac..0000000 Binary files a/pd_master.db and /dev/null differ diff --git a/test-storage/migrate_custom_commands.py b/test-storage/migrate_custom_commands.py deleted file mode 100644 index 4de14ab..0000000 --- a/test-storage/migrate_custom_commands.py +++ /dev/null @@ -1,458 +0,0 @@ -#!/usr/bin/env python3 -""" -Migration script to transfer custom commands from old database to new schema. - -This script: -1. Reads existing commands and creators from sba_is_fun.db -2. Maps the old schema to the new custom_commands schema -3. Migrates all data preserving relationships and metadata -4. Provides detailed logging and validation - -Usage: - python migrate_custom_commands.py --source /path/to/sba_is_fun.db --target /path/to/sba_master.db [--dry-run] -""" - -import sqlite3 -import json -import logging -import argparse -from datetime import datetime -from typing import Dict, List, Tuple, Optional - - -class CustomCommandMigrator: - def __init__(self, source_db: str, target_db: str, dry_run: bool = False): - self.source_db = source_db - self.target_db = target_db - self.dry_run = dry_run - self.setup_logging() - - def setup_logging(self): - """Setup logging configuration""" - logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[ - logging.FileHandler(f'migration_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log'), - logging.StreamHandler() - ] - ) - self.logger = logging.getLogger('migrate_custom_commands.CustomCommandMigrator') - - def validate_source_database(self) -> bool: - """Validate that source database has expected tables and structure""" - try: - conn = sqlite3.connect(self.source_db) - cursor = conn.cursor() - - # Check for required tables - cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name IN ('command', 'creator');") - tables = [row[0] for row in cursor.fetchall()] - - if 'command' not in tables or 'creator' not in tables: - self.logger.error(f"Required tables missing. Found: {tables}") - return False - - # Check command table structure - cursor.execute("PRAGMA table_info(command);") - command_cols = [row[1] for row in cursor.fetchall()] - required_command_cols = ['id', 'name', 'message', 'creator_id', 'createtime'] - - for col in required_command_cols: - if col not in command_cols: - self.logger.error(f"Required column '{col}' missing from command table") - return False - - # Check creator table structure - cursor.execute("PRAGMA table_info(creator);") - creator_cols = [row[1] for row in cursor.fetchall()] - required_creator_cols = ['id', 'name', 'discordid'] - - for col in required_creator_cols: - if col not in creator_cols: - self.logger.error(f"Required column '{col}' missing from creator table") - return False - - conn.close() - self.logger.info("Source database validation passed") - return True - - except Exception as e: - self.logger.error(f"Error validating source database: {e}") - return False - - def validate_target_database(self) -> bool: - """Validate that target database has the new custom_commands tables""" - try: - conn = sqlite3.connect(self.target_db) - cursor = conn.cursor() - - # Check for required tables - cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name IN ('custom_commands', 'custom_command_creators');") - tables = [row[0] for row in cursor.fetchall()] - - if 'custom_commands' not in tables or 'custom_command_creators' not in tables: - self.logger.error(f"Target tables missing. Found: {tables}") - self.logger.error("Please ensure the new custom_commands schema has been created first") - return False - - conn.close() - self.logger.info("Target database validation passed") - return True - - except Exception as e: - self.logger.error(f"Error validating target database: {e}") - return False - - def load_source_data(self) -> Tuple[List[Dict], List[Dict]]: - """Load creators and commands from source database""" - conn = sqlite3.connect(self.source_db) - cursor = conn.cursor() - - # Load creators - self.logger.info("Loading creators from source database...") - cursor.execute("SELECT id, name, discordid FROM creator ORDER BY id;") - creators_raw = cursor.fetchall() - - creators = [] - for row in creators_raw: - creators.append({ - 'old_id': row[0], - 'name': row[1], - 'discord_id': row[2] - }) - - self.logger.info(f"Loaded {len(creators)} creators") - - # Load commands - self.logger.info("Loading commands from source database...") - cursor.execute(""" - SELECT c.id, c.name, c.message, c.creator_id, c.createtime, c.last_used, c.sent_warns, - cr.name as creator_name, cr.discordid as creator_discord_id - FROM command c - LEFT JOIN creator cr ON c.creator_id = cr.id - ORDER BY c.id; - """) - commands_raw = cursor.fetchall() - - commands = [] - for row in commands_raw: - # Parse last_used datetime - last_used = None - if row[5]: # last_used - try: - last_used = datetime.fromisoformat(row[5]).isoformat() - except: - last_used = row[5] # Keep original if parsing fails - - # Parse createtime - created_at = None - if row[4]: # createtime - try: - created_at = datetime.fromisoformat(row[4]).isoformat() - except: - created_at = row[4] # Keep original if parsing fails - - commands.append({ - 'old_id': row[0], - 'name': row[1], - 'content': row[2], # message -> content - 'old_creator_id': row[3], - 'created_at': created_at, - 'last_used': last_used, - 'sent_warns': row[6], - 'creator_name': row[7], - 'creator_discord_id': row[8] - }) - - self.logger.info(f"Loaded {len(commands)} commands") - - conn.close() - return creators, commands - - def migrate_creators(self, creators: List[Dict]) -> Dict[int, int]: - """Migrate creators and return mapping of old_id -> new_id""" - if self.dry_run: - self.logger.info(f"[DRY RUN] Would migrate {len(creators)} creators") - return {creator['old_id']: creator['old_id'] for creator in creators} # Mock mapping - - conn = sqlite3.connect(self.target_db) - cursor = conn.cursor() - - creator_id_mapping = {} - now = datetime.now().isoformat() - - for creator in creators: - try: - # Check if creator already exists by discord_id - cursor.execute("SELECT id FROM custom_command_creators WHERE discord_id = ?", (creator['discord_id'],)) - existing = cursor.fetchone() - - if existing: - creator_id_mapping[creator['old_id']] = existing[0] - self.logger.info(f"Creator '{creator['name']}' (Discord: {creator['discord_id']}) already exists with ID {existing[0]}") - continue - - # Insert new creator - cursor.execute(""" - INSERT INTO custom_command_creators - (discord_id, username, display_name, created_at, total_commands, active_commands) - VALUES (?, ?, ?, ?, 0, 0) - """, (creator['discord_id'], creator['name'], creator['name'], now)) - - new_id = cursor.lastrowid - creator_id_mapping[creator['old_id']] = new_id - - self.logger.info(f"Migrated creator '{creator['name']}': {creator['old_id']} -> {new_id}") - - except Exception as e: - self.logger.error(f"Error migrating creator {creator}: {e}") - raise - - conn.commit() - conn.close() - - self.logger.info(f"Successfully migrated {len(creator_id_mapping)} creators") - return creator_id_mapping - - def migrate_commands(self, commands: List[Dict], creator_id_mapping: Dict[int, int]) -> None: - """Migrate commands using the creator ID mapping""" - if self.dry_run: - self.logger.info(f"[DRY RUN] Would migrate {len(commands)} commands") - return - - conn = sqlite3.connect(self.target_db) - cursor = conn.cursor() - - migrated_count = 0 - skipped_count = 0 - - for command in commands: - try: - # Map old creator_id to new creator_id - if command['old_creator_id'] not in creator_id_mapping: - self.logger.warning(f"Skipping command '{command['name']}' - creator ID {command['old_creator_id']} not found in mapping") - skipped_count += 1 - continue - - new_creator_id = creator_id_mapping[command['old_creator_id']] - - # Check if command already exists by name - cursor.execute("SELECT id FROM custom_commands WHERE name = ?", (command['name'],)) - existing = cursor.fetchone() - - if existing: - self.logger.warning(f"Command '{command['name']}' already exists with ID {existing[0]} - skipping") - skipped_count += 1 - continue - - # Determine if command was warned/inactive based on sent_warns - warning_sent = bool(command['sent_warns'] and command['sent_warns'] != 0) - - # For migrated commands, ensure last_used is at least the migration date - # to prevent immediate deletion eligibility - migration_date = datetime.now().isoformat() - last_used = command['last_used'] - - # If command hasn't been used recently, set last_used to migration date - # to give it a grace period - if last_used: - try: - last_used_dt = datetime.fromisoformat(last_used.replace('Z', '+00:00')) - # If last used more than 60 days ago, update to migration date - if (datetime.now() - last_used_dt).days > 60: - last_used = migration_date - self.logger.info(f"Updated last_used for command '{command['name']}' to migration date") - except: - # If we can't parse the date, use migration date - last_used = migration_date - else: - # If no last_used date, use migration date - last_used = migration_date - - # Add migration tag to indicate this is a migrated command - tags = '["migrated"]' - - # Insert command - cursor.execute(""" - INSERT INTO custom_commands - (name, content, creator_id, created_at, updated_at, last_used, use_count, warning_sent, is_active, tags) - VALUES (?, ?, ?, ?, ?, ?, 0, ?, 1, ?) - """, ( - command['name'], - command['content'], - new_creator_id, - command['created_at'], - None, # updated_at - last_used, - warning_sent, - tags - )) - - migrated_count += 1 - if migrated_count % 10 == 0: - self.logger.info(f"Migrated {migrated_count} commands...") - - except Exception as e: - self.logger.error(f"Error migrating command {command}: {e}") - raise - - conn.commit() - conn.close() - - self.logger.info(f"Successfully migrated {migrated_count} commands, skipped {skipped_count}") - - def update_creator_stats(self) -> None: - """Update creator statistics after migration""" - if self.dry_run: - self.logger.info("[DRY RUN] Would update creator statistics") - return - - conn = sqlite3.connect(self.target_db) - cursor = conn.cursor() - - # Update creator stats - cursor.execute(""" - UPDATE custom_command_creators SET - total_commands = ( - SELECT COUNT(*) FROM custom_commands - WHERE creator_id = custom_command_creators.id - ), - active_commands = ( - SELECT COUNT(*) FROM custom_commands - WHERE creator_id = custom_command_creators.id AND is_active = 1 - ) - """) - - conn.commit() - conn.close() - self.logger.info("Updated creator statistics") - - def generate_migration_report(self) -> None: - """Generate a detailed migration report""" - if self.dry_run: - conn_source = sqlite3.connect(self.source_db) - cursor_source = conn_source.cursor() - - cursor_source.execute("SELECT COUNT(*) FROM creator") - source_creators = cursor_source.fetchone()[0] - - cursor_source.execute("SELECT COUNT(*) FROM command") - source_commands = cursor_source.fetchone()[0] - - conn_source.close() - - self.logger.info(f""" -=== DRY RUN MIGRATION REPORT === -Source Database: {self.source_db} -Target Database: {self.target_db} - -Would migrate: -- {source_creators} creators -- {source_commands} commands - -No actual changes made (dry run mode). - """.strip()) - return - - # Real migration report - conn_source = sqlite3.connect(self.source_db) - conn_target = sqlite3.connect(self.target_db) - - cursor_source = conn_source.cursor() - cursor_target = conn_target.cursor() - - # Source counts - cursor_source.execute("SELECT COUNT(*) FROM creator") - source_creators = cursor_source.fetchone()[0] - - cursor_source.execute("SELECT COUNT(*) FROM command") - source_commands = cursor_source.fetchone()[0] - - # Target counts - cursor_target.execute("SELECT COUNT(*) FROM custom_command_creators") - target_creators = cursor_target.fetchone()[0] - - cursor_target.execute("SELECT COUNT(*) FROM custom_commands") - target_commands = cursor_target.fetchone()[0] - - # Get sample of migrated data - cursor_target.execute(""" - SELECT cc.name, cc.content, ccc.username - FROM custom_commands cc - JOIN custom_command_creators ccc ON cc.creator_id = ccc.id - LIMIT 5 - """) - sample_commands = cursor_target.fetchall() - - conn_source.close() - conn_target.close() - - self.logger.info(f""" -=== MIGRATION REPORT === -Source Database: {self.source_db} -Target Database: {self.target_db} - -Migration Results: -- Source creators: {source_creators} -> Target creators: {target_creators} -- Source commands: {source_commands} -> Target commands: {target_commands} - -Sample migrated commands: -""".strip()) - - for cmd in sample_commands: - self.logger.info(f" '{cmd[0]}' by {cmd[2]}: {cmd[1][:50]}...") - - def run_migration(self) -> bool: - """Execute the full migration process""" - self.logger.info(f"Starting custom commands migration {'(DRY RUN)' if self.dry_run else ''}") - self.logger.info(f"Source: {self.source_db}") - self.logger.info(f"Target: {self.target_db}") - - try: - # Validate databases - if not self.validate_source_database(): - return False - - if not self.validate_target_database(): - return False - - # Load source data - creators, commands = self.load_source_data() - - # Migrate creators first - creator_id_mapping = self.migrate_creators(creators) - - # Migrate commands - self.migrate_commands(commands, creator_id_mapping) - - # Update statistics - self.update_creator_stats() - - # Generate report - self.generate_migration_report() - - self.logger.info("Migration completed successfully!") - return True - - except Exception as e: - self.logger.error(f"Migration failed: {e}") - return False - - -def main(): - parser = argparse.ArgumentParser(description='Migrate custom commands from old database to new schema') - parser.add_argument('--source', required=True, help='Path to source database (sba_is_fun.db)') - parser.add_argument('--target', required=True, help='Path to target database (sba_master.db)') - parser.add_argument('--dry-run', action='store_true', help='Run in dry-run mode (no actual changes)') - - args = parser.parse_args() - - migrator = CustomCommandMigrator(args.source, args.target, args.dry_run) - success = migrator.run_migration() - - exit(0 if success else 1) - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/test-storage/pd_master.db b/test-storage/pd_master.db deleted file mode 100644 index f510bac..0000000 Binary files a/test-storage/pd_master.db and /dev/null differ diff --git a/test-storage/sba_is_fun.db b/test-storage/sba_is_fun.db deleted file mode 100644 index 44505c5..0000000 Binary files a/test-storage/sba_is_fun.db and /dev/null differ