-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvgde.py
190 lines (156 loc) · 6.47 KB
/
vgde.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import os
import requests
import logging
import re
from argparse import ArgumentParser
from typing import Optional, Dict, Any
# Constants
MAX_GAME_NAME_LENGTH = 100
GAME_NAME_PATTERN = r"^[a-zA-Z0-9\s]+$"
DEFAULT_REQUEST_TIMEOUT = 10
BASE_URL = 'https://api.rawg.io/api'
GAMES_ENDPOINT = '/games'
# Handle non-integer REQUEST_TIMEOUT values gracefully
try:
REQUEST_TIMEOUT = int(os.getenv('REQUEST_TIMEOUT', DEFAULT_REQUEST_TIMEOUT))
except ValueError:
logging.warning(f"Invalid REQUEST_TIMEOUT value. Using default: {DEFAULT_REQUEST_TIMEOUT}")
REQUEST_TIMEOUT = DEFAULT_REQUEST_TIMEOUT
def configure_logging() -> logging.Logger:
"""Configure logging for the script."""
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
# Configure logging
logger = configure_logging()
# Retrieve the RAWG API key from environment variables
API_KEY = os.getenv('RAWG_API_KEY')
# Exit if the API key is not set
if not API_KEY:
logger.error("RAWG API key not found in environment variables.")
exit(1)
class MissingAPIKeyError(Exception):
"""Custom exception for missing API key."""
pass
class InvalidInputError(Exception):
"""Custom exception for invalid user input."""
pass
def validate_game_name(game_name: str) -> str:
"""
Validates the game name.
Args:
game_name (str): The name of the game to validate.
Returns:
str: The validated game name.
Raises:
InvalidInputError: If the game name is invalid.
"""
if not game_name:
raise InvalidInputError("Invalid input. Please enter a non-empty game name.")
if len(game_name) > MAX_GAME_NAME_LENGTH:
raise InvalidInputError("Invalid input. Game name is too long.")
if not re.match(GAME_NAME_PATTERN, game_name):
raise InvalidInputError("Invalid input. Game name contains invalid characters.")
return game_name
def check_api_key() -> None:
"""
Checks if the RAWG API key is set.
Raises:
MissingAPIKeyError: If the API key is not found.
"""
if not API_KEY or API_KEY.strip() == "":
logger.error("API key not found. Please set the RAWG_API_KEY environment variable.")
raise MissingAPIKeyError("API key not found. Please set the RAWG_API_KEY environment variable.")
def fetch_game_data(game_name: str) -> Optional[Dict[str, Any]]:
"""
Fetches game data from the RAWG API and returns the first result.
Args:
game_name (str): The name of the game to fetch data for.
Returns:
Optional[Dict[str, Any]]: The fetched game data or None if not found.
"""
game_name = validate_game_name(game_name)
url = f"{BASE_URL}{GAMES_ENDPOINT}"
params = {'key': API_KEY, 'search': game_name}
try:
response = requests.get(url, params=params, timeout=REQUEST_TIMEOUT)
response.raise_for_status()
data = response.json()
if 'results' in data and len(data['results']) > 0:
return data['results'][0]
else:
logger.error(f"No results found for game '{game_name}'.")
return None
except requests.exceptions.Timeout:
logger.error(f"The request timed out while trying to fetch game information for '{game_name}'.")
except requests.exceptions.ConnectionError:
logger.error(f"A network problem occurred while trying to fetch game information for '{game_name}'.")
except requests.exceptions.HTTPError as e:
logger.error(f"HTTP error occurred while trying to fetch game information for '{game_name}': {e.response.status_code} - {e.response.reason}")
logger.error(f"Response content: {e.response.content}")
except requests.exceptions.RequestException as e:
logger.error(f"An unexpected error occurred while trying to fetch game information for '{game_name}': {e}")
except ValueError as e:
logger.error(f"Error parsing the response JSON for game '{game_name}': {e}")
return None
def parse_game_info(data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""
Parses the game information from the API response.
Args:
data (Dict[str, Any]): The raw game data from the API.
Returns:
Optional[Dict[str, Any]]: The parsed game information or None if data format is unexpected.
"""
required_keys = ['name', 'released', 'rating', 'description', 'background_image']
if all(key in data for key in required_keys):
return {key: data[key] for key in required_keys}
logger.error("Unexpected data format in API response for game information.")
return None
def display_game_info(game_info: Optional[Dict[str, Any]]) -> None:
"""
Displays information about a game.
Args:
game_info (Optional[Dict[str, Any]]): The game information to display.
"""
if game_info:
logger.info(f"Name: {game_info['name']}")
logger.info(f"Released: {game_info['released']}")
logger.info(f"Rating: {game_info['rating']}")
logger.info(f"Description: {game_info['description']}")
logger.info(f"Background Image URL: {game_info['background_image']}")
else:
logger.warning("No game information to display.")
def main() -> Optional[Dict[str, Any]]:
"""
Main function to run the script.
Prompts the user to enter the name of a game and displays its information.
Returns:
Optional[Dict[str, Any]]: The game information or None if an error occurred.
"""
parser = ArgumentParser(description="Fetch game information from RAWG API.")
parser.add_argument('game_name', type=str, help="The name of the game to search for.")
args = parser.parse_args()
try:
check_api_key()
except MissingAPIKeyError as e:
logger.error(f"API key error: {e}")
exit(1)
try:
sanitized_game_name = validate_game_name(args.game_name)
raw_data = fetch_game_data(sanitized_game_name)
game_info = parse_game_info(raw_data)
display_game_info(game_info)
return game_info
except InvalidInputError as e:
logger.error(f"Input validation error: {e}")
except requests.exceptions.RequestException as e:
logger.error(f"Request error: {e}")
except Exception as e:
logger.error(f"An unexpected error occurred: {e}")
return None
if __name__ == "__main__":
main()