Complete Phase 2: Card import, deck building, and full API
- Add card import feature with fuzzy matching - Implement deck CRUD and management endpoints - Add user data APIs for groups, networks, preferences, activity, replays - Create comprehensive API documentation (API_DOCUMENTATION.md) - Add ENDPOINT_AUDIT.md for endpoint verification - Update documentation (README, ROADMAP, state.json) - Update architecture blueprint and Cockatrice analysis - All Phase 2 deliverables complete and documented
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
"""File parser service for card import."""
|
||||
import csv
|
||||
import json
|
||||
from typing import List, Union
|
||||
from pathlib import Path
|
||||
import openpyxl
|
||||
import pandas as pd
|
||||
|
||||
|
||||
class FileParser:
|
||||
"""Parse various file formats for card import."""
|
||||
|
||||
SUPPORTED_FORMATS = ['xlsx', 'csv', 'json', 'ods']
|
||||
|
||||
@staticmethod
|
||||
async def parse_file(file_path: Path) -> List[str]:
|
||||
"""
|
||||
Parse a file and extract card names.
|
||||
|
||||
Args:
|
||||
file_path: Path to the file to parse
|
||||
|
||||
Returns:
|
||||
List of card names extracted from the file
|
||||
|
||||
Raises:
|
||||
ValueError: If file format is not supported
|
||||
FileNotFoundError: If file does not exist
|
||||
Exception: If file cannot be parsed
|
||||
"""
|
||||
file_type = file_path.suffix.lower().lstrip('.')
|
||||
|
||||
if file_type not in FileParser.SUPPORTED_FORMATS:
|
||||
raise ValueError(f"Unsupported file format: {file_type}. Supported formats: {FileParser.SUPPORTED_FORMATS}")
|
||||
|
||||
if not file_path.exists():
|
||||
raise FileNotFoundError(f"File not found: {file_path}")
|
||||
|
||||
if file_type == 'csv':
|
||||
return FileParser._parse_csv(file_path)
|
||||
elif file_type == 'json':
|
||||
return FileParser._parse_json(file_path)
|
||||
elif file_type == 'xlsx':
|
||||
return FileParser._parse_xlsx(file_path)
|
||||
elif file_type == 'ods':
|
||||
return FileParser._parse_ods(file_path)
|
||||
|
||||
@staticmethod
|
||||
def _parse_csv(file_path: Path) -> List[str]:
|
||||
"""Parse CSV file and extract card names."""
|
||||
card_names = []
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
reader = csv.reader(f)
|
||||
for row in reader:
|
||||
# Take first non-empty column as card name
|
||||
for cell in row:
|
||||
cell = cell.strip()
|
||||
if cell:
|
||||
card_names.append(cell)
|
||||
break
|
||||
return card_names
|
||||
|
||||
@staticmethod
|
||||
def _parse_json(file_path: Path) -> List[str]:
|
||||
"""Parse JSON file and extract card names."""
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if isinstance(data, list):
|
||||
return [str(item).strip() for item in data if str(item).strip()]
|
||||
elif isinstance(data, dict):
|
||||
# Try common keys
|
||||
for key in ['cards', 'card_names', 'cards_list', 'list']:
|
||||
if key in data and isinstance(data[key], list):
|
||||
return [str(item).strip() for item in data[key] if str(item).strip()]
|
||||
# If no common key found, try first list value
|
||||
for value in data.values():
|
||||
if isinstance(value, list):
|
||||
return [str(item).strip() for item in value if str(item).strip()]
|
||||
raise ValueError("Invalid JSON format: expected list or dict with card names")
|
||||
|
||||
@staticmethod
|
||||
def _parse_xlsx(file_path: Path) -> List[str]:
|
||||
"""Parse XLSX file and extract card names from first column."""
|
||||
card_names = []
|
||||
try:
|
||||
workbook = openpyxl.load_workbook(file_path, read_only=True)
|
||||
worksheet = workbook.active
|
||||
|
||||
for row in worksheet.iter_rows(values_only=True):
|
||||
if row and row[0]:
|
||||
cell_value = str(row[0]).strip()
|
||||
if cell_value:
|
||||
card_names.append(cell_value)
|
||||
finally:
|
||||
if 'workbook' in locals():
|
||||
workbook.close()
|
||||
return card_names
|
||||
|
||||
@staticmethod
|
||||
def _parse_ods(file_path: Path) -> List[str]:
|
||||
"""Parse ODS file and extract card names from first column."""
|
||||
try:
|
||||
df = pd.read_excel(file_path, engine='odf')
|
||||
card_names = df.iloc[:, 0].dropna().astype(str).str.strip().tolist()
|
||||
return [name for name in card_names if name]
|
||||
except ImportError:
|
||||
raise ImportError("pandas with odf engine required for ODS parsing. Install with: pip install pandas odfpy")
|
||||
Reference in New Issue
Block a user