Coverage for celery_tasks/validation_tasks.py: 7.53%

59 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2026-04-13 14:11 +0000

1""" 

2Validation Tasks 

3 

4Tasks for validating match data before processing. 

5These ensure data quality and prevent invalid data from entering the database. 

6""" 

7 

8import logging 

9from datetime import datetime 

10from typing import Any 

11 

12from celery_app import app 

13 

14logger = logging.getLogger(__name__) 

15 

16 

17@app.task(name="celery_tasks.validation_tasks.validate_match_data") 

18def validate_match_data(match_data: dict[str, Any]) -> dict[str, Any]: 

19 """ 

20 Validate match data structure and contents. 

21 

22 Checks: 

23 - Required fields are present 

24 - Data types are correct 

25 - Values are within acceptable ranges 

26 - Dates are valid 

27 - Team names are not empty 

28 

29 Args: 

30 match_data: Dictionary containing match information 

31 

32 Returns: 

33 Dict containing: 

34 - valid: bool - Whether the data is valid 

35 - errors: List[str] - List of validation errors (empty if valid) 

36 - warnings: List[str] - List of warnings (data is still valid) 

37 """ 

38 errors: list[str] = [] 

39 warnings: list[str] = [] 

40 

41 # Required fields 

42 required_fields = ["home_team", "away_team", "match_date", "season"] 

43 for field in required_fields: 

44 if field not in match_data or not match_data[field]: 

45 errors.append(f"Missing required field: {field}") 

46 

47 # If required fields are missing, return early 

48 if errors: 

49 return {"valid": False, "errors": errors, "warnings": warnings} 

50 

51 # Validate team names 

52 home_team = match_data["home_team"] 

53 away_team = match_data["away_team"] 

54 

55 if not isinstance(home_team, str) or len(home_team.strip()) == 0: 

56 errors.append("home_team must be a non-empty string") 

57 

58 if not isinstance(away_team, str) or len(away_team.strip()) == 0: 

59 errors.append("away_team must be a non-empty string") 

60 

61 if home_team == away_team: 

62 errors.append("home_team and away_team cannot be the same") 

63 

64 # Validate date 

65 try: 

66 match_date = match_data["match_date"] 

67 if isinstance(match_date, str): 

68 # Try to parse ISO format date 

69 datetime.fromisoformat(match_date.replace("Z", "+00:00")) 

70 elif not isinstance(match_date, datetime): 

71 errors.append("match_date must be a string in ISO format or datetime object") 

72 except (ValueError, AttributeError) as e: 

73 errors.append(f"Invalid match_date format: {e}") 

74 

75 # Validate scores (if provided) 

76 if "home_score" in match_data and match_data["home_score"] is not None: 

77 try: 

78 score = int(match_data["home_score"]) 

79 if score < 0: 

80 errors.append("home_score cannot be negative") 

81 except (ValueError, TypeError): 

82 errors.append("home_score must be an integer") 

83 

84 if "away_score" in match_data and match_data["away_score"] is not None: 

85 try: 

86 score = int(match_data["away_score"]) 

87 if score < 0: 

88 errors.append("away_score cannot be negative") 

89 except (ValueError, TypeError): 

90 errors.append("away_score must be an integer") 

91 

92 # Validate match status 

93 valid_statuses = ["scheduled", "tbd", "live", "completed", "cancelled", "postponed"] 

94 if "match_status" in match_data: 

95 status = match_data["match_status"] 

96 if status and status not in valid_statuses: 

97 warnings.append(f"Unusual match_status: {status}. Expected one of: {valid_statuses}") 

98 

99 # Validate season format 

100 season = match_data["season"] 

101 if not isinstance(season, str): 

102 errors.append("season must be a string") 

103 elif len(season) < 4: 

104 warnings.append(f"Unusual season format: {season}") 

105 

106 # Log validation result 

107 if errors: 

108 logger.warning(f"Validation failed for match {home_team} vs {away_team}: {errors}") 

109 elif warnings: 

110 logger.info(f"Validation passed with warnings for {home_team} vs {away_team}: {warnings}") 

111 else: 

112 logger.debug(f"Validation passed for {home_team} vs {away_team}") 

113 

114 return {"valid": len(errors) == 0, "errors": errors, "warnings": warnings}