Add --create flag to custom submit command
- Add --create/-c flag to create new players directly from YAML profiles - Skip MLBPlayer creation (not needed for custom players) - Auto-populate required API fields (cost, rarity, mlbclub, etc.) - Update YAML profile with player_id and card_id after creation - Add Adm Ball Traits custom player profile 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
0fe549449d
commit
fe0ab5e1bd
@ -6,6 +6,7 @@ Supports both batters and pitchers with their respective schemas.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional, Literal
|
||||
|
||||
@ -282,6 +283,7 @@ def submit(
|
||||
character: str = typer.Argument(..., help="Character profile name"),
|
||||
dry_run: bool = typer.Option(False, "--dry-run", "-n", help="Preview changes without saving"),
|
||||
skip_s3: bool = typer.Option(False, "--skip-s3", help="Skip S3 upload after submit"),
|
||||
create: bool = typer.Option(False, "--create", "-c", help="Create new player in database (requires cardset_id in profile)"),
|
||||
):
|
||||
"""Submit a custom character to the database."""
|
||||
profile = load_profile(character)
|
||||
@ -289,7 +291,8 @@ def submit(
|
||||
|
||||
console.print()
|
||||
console.print("=" * 70)
|
||||
console.print(f"[bold]SUBMITTING {profile['name']} ({player_type})[/bold]")
|
||||
action = "CREATING" if create else "SUBMITTING"
|
||||
console.print(f"[bold]{action} {profile['name']} ({player_type})[/bold]")
|
||||
console.print("=" * 70)
|
||||
|
||||
if dry_run:
|
||||
@ -307,20 +310,202 @@ def submit(
|
||||
console.print(f"[red]ERROR: {vs_hand} ratings total is {total:.2f}, must be 108.0[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# Validate create requirements
|
||||
if create:
|
||||
if not profile.get('cardset_id'):
|
||||
console.print("[red]ERROR: cardset_id required in profile for --create[/red]")
|
||||
raise typer.Exit(1)
|
||||
if profile.get('player_id'):
|
||||
console.print("[red]ERROR: player_id already set - use submit without --create to update[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
if dry_run:
|
||||
console.print("[green]Validation passed - ready to submit[/green]")
|
||||
return
|
||||
|
||||
# Import database functions
|
||||
try:
|
||||
from pd_cards.core.db import db_get, db_put, db_patch
|
||||
from pd_cards.core.db import db_get, db_put, db_patch, db_post
|
||||
except ImportError:
|
||||
# Fallback to old location during migration
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
from db_calls import db_get, db_put, db_patch
|
||||
from db_calls import db_get, db_put, db_patch, db_post
|
||||
|
||||
async def do_create():
|
||||
"""Create a new player in the database."""
|
||||
# Parse name
|
||||
name_parts = profile['name'].split()
|
||||
name_first = name_parts[0]
|
||||
name_last = ' '.join(name_parts[1:]) if len(name_parts) > 1 else name_parts[0]
|
||||
|
||||
# Generate bbref_id for custom player (with timestamp to avoid conflicts)
|
||||
timestamp = int(datetime.now().timestamp())
|
||||
bbref_id = f"custom_{name_last.lower().replace(' ', '')}{name_first[0].lower()}{timestamp}"
|
||||
|
||||
cardset_id = profile['cardset_id']
|
||||
hand = profile.get('hand', 'R')
|
||||
|
||||
console.print(f"Name: {name_first} {name_last}")
|
||||
console.print(f"BBRef ID: {bbref_id}")
|
||||
console.print(f"Cardset: {cardset_id}")
|
||||
console.print()
|
||||
|
||||
# Step 1: Create Player record (custom players don't need MLBPlayer)
|
||||
console.print("Creating Player record...")
|
||||
now = datetime.now()
|
||||
release_date = f"{now.year}-{now.month}-{now.day}"
|
||||
|
||||
# Get first position for pos_1
|
||||
positions = list(profile.get('positions', {}).keys())
|
||||
pos_1 = positions[0] if positions else 'DH'
|
||||
|
||||
player_payload = {
|
||||
'p_name': f"{name_first} {name_last}",
|
||||
'bbref_id': bbref_id,
|
||||
'fangraphs_id': 0,
|
||||
'mlbam_id': 0,
|
||||
'retrosheet_id': '',
|
||||
'hand': hand,
|
||||
'mlb_team_id': 1,
|
||||
'franchise_id': 1, # Default franchise
|
||||
'cardset_id': cardset_id,
|
||||
'description': 'Custom',
|
||||
'is_custom': True,
|
||||
# Required fields
|
||||
'cost': 100, # Default cost
|
||||
'image': '', # Will be patched after
|
||||
'mlbclub': 'Custom Ballplayers',
|
||||
'franchise': 'Custom Ballplayers',
|
||||
'set_num': 9999,
|
||||
'rarity_id': 5, # Common
|
||||
'pos_1': pos_1,
|
||||
}
|
||||
|
||||
new_player = await db_post('players', payload=player_payload)
|
||||
player_id = new_player['player_id']
|
||||
console.print(f"[green] Created Player (ID: {player_id})[/green]")
|
||||
|
||||
# Step 3: Patch Player with image URL
|
||||
card_type = 'batting' if player_type == 'batter' else 'pitching'
|
||||
image_url = f"https://pd.manticorum.com/api/v2/players/{player_id}/{card_type}card?d={release_date}"
|
||||
await db_patch('players', object_id=player_id, params=[('image', image_url)])
|
||||
console.print("[green] Updated Player with image URL[/green]")
|
||||
|
||||
# Step 4: Create Card
|
||||
if player_type == 'batter':
|
||||
console.print("Creating BattingCard...")
|
||||
baserunning = profile.get('baserunning', {})
|
||||
batting_card_payload = {
|
||||
'cards': [{
|
||||
'player_id': player_id,
|
||||
'key_bbref': bbref_id,
|
||||
'key_fangraphs': 0,
|
||||
'key_mlbam': 0,
|
||||
'key_retro': '',
|
||||
'name_first': name_first,
|
||||
'name_last': name_last,
|
||||
'steal_low': baserunning.get('steal_low', 5),
|
||||
'steal_high': baserunning.get('steal_high', 12),
|
||||
'steal_auto': 1 if baserunning.get('steal_auto') else 0,
|
||||
'steal_jump': baserunning.get('steal_jump', 0.15),
|
||||
'hit_and_run': baserunning.get('hit_and_run', 'C'),
|
||||
'running': baserunning.get('running', 10),
|
||||
'bunting': baserunning.get('bunting', 'C'),
|
||||
'hand': hand,
|
||||
}]
|
||||
}
|
||||
await db_put('battingcards', payload=batting_card_payload, timeout=10)
|
||||
|
||||
# Get the card ID
|
||||
bc_query = await db_get('battingcards', params=[('player_id', player_id)])
|
||||
card_id = bc_query['cards'][0]['id']
|
||||
card_id_field = 'battingcard_id'
|
||||
ratings_endpoint = 'battingcardratings'
|
||||
console.print(f"[green] Created BattingCard (ID: {card_id})[/green]")
|
||||
else:
|
||||
console.print("Creating PitchingCard...")
|
||||
pitching = profile.get('pitching', {})
|
||||
pitching_card_payload = {
|
||||
'cards': [{
|
||||
'player_id': player_id,
|
||||
'key_bbref': bbref_id,
|
||||
'key_fangraphs': 0,
|
||||
'key_mlbam': 0,
|
||||
'key_retro': '',
|
||||
'name_first': name_first,
|
||||
'name_last': name_last,
|
||||
'hand': hand,
|
||||
'starter_rating': pitching.get('starter_rating', 5),
|
||||
'relief_rating': pitching.get('relief_rating', 5),
|
||||
'closer_rating': pitching.get('closer_rating'),
|
||||
}]
|
||||
}
|
||||
await db_put('pitchingcards', payload=pitching_card_payload, timeout=10)
|
||||
|
||||
# Get the card ID
|
||||
pc_query = await db_get('pitchingcards', params=[('player_id', player_id)])
|
||||
card_id = pc_query['cards'][0]['id']
|
||||
card_id_field = 'pitchingcard_id'
|
||||
ratings_endpoint = 'pitchingcardratings'
|
||||
console.print(f"[green] Created PitchingCard (ID: {card_id})[/green]")
|
||||
|
||||
# Step 5: Create ratings
|
||||
console.print("Creating ratings...")
|
||||
ratings_list = []
|
||||
for vs_hand, ratings in profile['ratings'].items():
|
||||
hand_char = vs_hand[-1] # 'L' or 'R'
|
||||
rating_data = {
|
||||
card_id_field: card_id,
|
||||
'vs_hand': hand_char,
|
||||
**ratings
|
||||
}
|
||||
ratings_list.append(rating_data)
|
||||
|
||||
await db_put(ratings_endpoint, payload={'ratings': ratings_list}, timeout=10)
|
||||
console.print("[green] Created ratings[/green]")
|
||||
|
||||
# Step 6: Create positions
|
||||
console.print("Creating positions...")
|
||||
positions_list = []
|
||||
for pos, stats in profile.get('positions', {}).items():
|
||||
if isinstance(stats, dict):
|
||||
positions_list.append({
|
||||
'player_id': player_id,
|
||||
'position': pos,
|
||||
**stats
|
||||
})
|
||||
else:
|
||||
positions_list.append({
|
||||
'player_id': player_id,
|
||||
'position': pos,
|
||||
})
|
||||
|
||||
if positions_list:
|
||||
await db_put('cardpositions', payload={'positions': positions_list}, timeout=10)
|
||||
console.print(f"[green] Created {len(positions_list)} position(s)[/green]")
|
||||
|
||||
# Step 7: Update YAML profile with IDs
|
||||
console.print("Updating profile with IDs...")
|
||||
profile['player_id'] = player_id
|
||||
if player_type == 'batter':
|
||||
profile['batting_card_id'] = card_id
|
||||
else:
|
||||
profile['pitching_card_id'] = card_id
|
||||
|
||||
profile_path = get_profile_path(character)
|
||||
with open(profile_path, 'w') as f:
|
||||
yaml.dump(profile, f, default_flow_style=False, sort_keys=False)
|
||||
console.print(f"[green] Updated {profile_path.name}[/green]")
|
||||
|
||||
console.print()
|
||||
console.print(f"[bold green]Successfully created {profile['name']}![/bold green]")
|
||||
console.print(f"Player ID: {player_id}")
|
||||
console.print(f"Card ID: {card_id}")
|
||||
console.print(f"URL: https://pd.manticorum.com/api/v2/players/{player_id}/{card_type}card?d={release_date}")
|
||||
|
||||
async def do_submit():
|
||||
"""Update an existing player in the database."""
|
||||
player_id = profile.get('player_id')
|
||||
|
||||
if player_type == 'pitcher':
|
||||
@ -335,7 +520,7 @@ def submit(
|
||||
if not player_id or not card_id:
|
||||
id_field = 'pitching_card_id' if player_type == 'pitcher' else 'batting_card_id'
|
||||
console.print(f"[red]ERROR: Profile missing player_id or {id_field}[/red]")
|
||||
console.print("Create the player first, then update the profile with IDs.")
|
||||
console.print("Use --create to create a new player, or add IDs to the profile.")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# Update ratings
|
||||
@ -382,6 +567,9 @@ def submit(
|
||||
console.print("[yellow]S3 upload not yet implemented in CLI[/yellow]")
|
||||
console.print("Run manually: python check_cards_and_upload.py")
|
||||
|
||||
if create:
|
||||
asyncio.run(do_create())
|
||||
else:
|
||||
asyncio.run(do_submit())
|
||||
|
||||
|
||||
|
||||
75
pd_cards/custom/profiles/adm_ball_traits.yaml
Normal file
75
pd_cards/custom/profiles/adm_ball_traits.yaml
Normal file
@ -0,0 +1,75 @@
|
||||
name: Adm Ball Traits
|
||||
player_type: batter
|
||||
hand: R
|
||||
target_ops: 0.8
|
||||
cardset_id: 29
|
||||
player_id: 13361
|
||||
batting_card_id: 6244
|
||||
positions:
|
||||
3B:
|
||||
range: 2
|
||||
error: 8
|
||||
SS:
|
||||
range: 3
|
||||
error: 10
|
||||
baserunning:
|
||||
steal_jump: 0.083333
|
||||
steal_high: 15
|
||||
steal_low: 9
|
||||
steal_auto: true
|
||||
running: 13
|
||||
hit_and_run: B
|
||||
bunting: B
|
||||
ratings:
|
||||
vs_L:
|
||||
homerun: 0.0
|
||||
bp_homerun: 1.0
|
||||
triple: 2.75
|
||||
double_three: 0.0
|
||||
double_two: 2.0
|
||||
double_pull: 3.75
|
||||
single_two: 6.5
|
||||
single_one: 5.0
|
||||
single_center: 7.75
|
||||
bp_single: 5.0
|
||||
walk: 12.0
|
||||
hbp: 4.0
|
||||
strikeout: 16.0
|
||||
lineout: 4.0
|
||||
popout: 2.0
|
||||
flyout_a: 0.0
|
||||
flyout_bq: 2.0
|
||||
flyout_lf_b: 4.0
|
||||
flyout_rf_b: 4.0
|
||||
groundout_a: 9.0
|
||||
groundout_b: 11.0
|
||||
groundout_c: 6.25
|
||||
pull_rate: 0.2
|
||||
center_rate: 0.5
|
||||
slap_rate: 0.3
|
||||
vs_R:
|
||||
homerun: 0.0
|
||||
bp_homerun: 1.0
|
||||
triple: 0.5
|
||||
double_three: 0.0
|
||||
double_two: 4.5
|
||||
double_pull: 4.5
|
||||
single_two: 5.0
|
||||
single_one: 8.0
|
||||
single_center: 5.5
|
||||
bp_single: 5.0
|
||||
walk: 11.0
|
||||
hbp: 1.0
|
||||
strikeout: 14.5
|
||||
lineout: 2.0
|
||||
popout: 2.0
|
||||
flyout_a: 0.0
|
||||
flyout_bq: 3.0
|
||||
flyout_lf_b: 5.0
|
||||
flyout_rf_b: 8.0
|
||||
groundout_a: 5.0
|
||||
groundout_b: 12.0
|
||||
groundout_c: 10.5
|
||||
pull_rate: 0.18
|
||||
center_rate: 0.42
|
||||
slap_rate: 0.4
|
||||
Loading…
Reference in New Issue
Block a user