Coverage for C:\Users\svjatoslavsmatvejevs\AppData\Local\Programs\Python\Python39\Lib\site-packages\report\report.py: 0%
112 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-13 09:58 +0200
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-13 09:58 +0200
1"""Command-line interface for report of Monaco race.
3Class:
4 OrderedNamespace
5 Cli
6"""
7import os
8import sys
9import argparse
10from dataclasses import dataclass, field
11from typing import Any
13from tabulate import tabulate
15import constant as c
16from race import Race
19class OrderedNamespace(argparse.Namespace):
20 """Namespace with ordered arguments.
22 Adds dictionary which saves order of input arguments in cli.
23 """
25 def __init__(self, **kwargs):
26 """Initialize with new attribute
28 Args:
29 kwargs: arguments in parser
30 """
31 # _order will save input arguments in given order
32 self.__dict__["_order"] = [None]
33 super().__init__(**kwargs)
35 def __setattr__(self, attr: str, value: Any):
36 """Set attributes.
38 _order will contain only attribute names, that was
39 provided in cli in preserved order.
41 Args:
42 attr: Attributes in Namespace.
43 value: Values of attributes in Namespace.
44 """
45 super().__setattr__(attr, value)
46 if attr in self._order:
47 self.__dict__["_order"].clear()
48 self.__dict__["_order"].append(attr)
50 def ordered(self) -> list[tuple]:
51 """Generate values for attributes in _order.
53 Returns:
54 Return _order pairs of attributes and values.
55 """
56 return [(attr, getattr(self, attr)) for attr in self._order
57 if attr != "files"]
59 def only_file_path(self):
60 """Checks argument quantity.
62 Checks if any argument was given beside files path argument.
64 Raises:
65 UserWarning: If only files path was given as argument.
66 """
67 if len(self.__dict__["_order"]) == 1:
68 raise UserWarning("Application should use at least one command argument!")
71@dataclass
72class Cli:
73 print_func: dict = field(default_factory=dict)
74 args: argparse.Namespace = field(init=False)
75 race: Race = field(init=False)
77 def __post_init__(self):
78 # Save all print functions in dictionary in order to make execution simpler.
79 self.print_func = {"report": self.print_report,
80 "time": self.print_time,
81 "date": self.print_date_of_the_race,
82 "racers_number": self.print_number_of_racers,
83 "driver": self.print_driver,
84 "racers": self.print_racers,
85 "teams": self.print_teams,
86 "team_racers": self.print_racers_in_team,
87 "full_report": self.print_full_report}
89 @staticmethod
90 def get_path_to_files(path: str) -> dict[str: str]:
91 """Get path to the log files.
93 Args:
94 path: Path of the folder where log files are located.
96 Returns:
97 Dictionary with file name as key and path to the file as value.
99 Raises:
100 UserWarning: if not all files where found in passed path.
101 NotADirectoryError: if directory name is file name.
102 """
103 # Get path of the log files from directory if file name is in lookup list
104 files = {os.path.splitext(f)[0]: os.path.join(path, f)
105 for f in os.listdir(path)
106 if f.lower() in c.REPORT_FILES}
107 # Check if dictionary has all necessary files.
108 if len(files) != len(c.REPORT_FILES):
109 raise UserWarning("File missing. Make sure that folder contains files:"
110 f" {c.REPORT_FILES}")
111 return files
113 def print_date_of_the_race(self):
114 """Print date of the race."""
115 print("\nDate of the race:")
116 print(f"\t{self.race.get_data_of_race()}")
118 def print_time(self):
119 """Print start time of the 1st qualification."""
120 print("\n1st qualification round started at:")
121 print(f"\t{self.race.get_start_time_of_q1()}")
123 def print_number_of_racers(self):
124 """Print number of racers in the race."""
125 print("\nNumber of the racers in the race:")
126 print(f"\t{self.race.get_number_of_racers()}")
128 def print_report(self):
129 """Print race report.
131 Prints race report in nice table look.
132 """
133 # Build report of the race.
134 race_report = self.race.build_report()
135 racers = []
136 print("\nReport of the race:")
137 # Loop through report sorted by lap time
138 for num, racer in enumerate(sorted(race_report, key=lambda x: x[2])):
139 # Convert time lap to appropriate string format.
140 racer[2] = str(racer[2])[3: -3]
141 # Insert racer's place.
142 racer.insert(0, str(num + 1))
143 racers.append(racer)
144 # Separate first 15 places.
145 if num + 1 == 15:
146 sep = "-" * len(racer[3])
147 racers.append(["--", sep, sep, sep])
148 print(tabulate(racers,
149 headers=["", "Full Name", "Team", "Q1 Time"],
150 tablefmt=c.TABLE_FORMAT))
152 def print_driver(self, driver: str):
153 """Print driver information.
155 Args:
156 driver: Driver full name.
157 """
158 try:
159 driver = self.race.get_racer(driver)
160 print(f"\nInformation about {driver[1]}:")
161 print(tabulate([driver],
162 headers=["Abbr", "Full Name", "Team", "Q1 Time"],
163 tablefmt=c.TABLE_FORMAT))
164 except UserWarning as err:
165 print(err)
167 def print_racers(self, order: str):
168 """Print list of racers in the race.
170 Args:
171 order: Flag for racers order.
172 """
173 racers = [[racer] for racer in
174 self.race.get_names_of_racers(reverse=c.ORDER[order])]
175 print(tabulate(racers,
176 headers=["List of racers in the race:"],
177 tablefmt=c.TABLE_FORMAT))
179 def print_teams(self, order: str):
180 """Print list of teams in the race.
182 Args:
183 order: Flag for racers order.
184 """
185 teams = [[team] for team in self.race.get_teams(reverse=c.ORDER[order])]
186 print(tabulate(teams,
187 headers=["List of teams:"],
188 tablefmt=c.TABLE_FORMAT))
190 def print_racers_in_team(self, team: str):
191 """Print racers in specific team.
193 Args:
194 team: Name of the team.
195 """
196 try:
197 racers = self.race.get_racers_in_team(team.upper())
198 print(f"\nRacers from {team.upper()} team:")
199 print(tabulate(racers,
200 headers=["Abbr", "Full Name", "Team", "Q1 Time"],
201 tablefmt=c.TABLE_FORMAT, ))
202 except UserWarning as err:
203 print(err)
205 def print_full_report(self):
206 """Print full report of the race.
208 Full report consists of date of the race, time of the 1st qualification,
209 number of racers in the race and report of 1st qualification.
210 """
211 self.print_date_of_the_race()
212 self.print_time()
213 self.print_number_of_racers()
214 self.print_report()
216 def cli(self):
217 """Implement command-line interface
219 Uses argparse to get input from command-line
220 and print according result.
221 """
222 parser = argparse.ArgumentParser(
223 prog="Report of Monaco 2018 racing:",
224 description="Get information about the race from the log files."
225 )
226 parser.add_argument(
227 "-f", "--files", required=True,
228 help="directory path where the race log files are located (required argument)"
229 )
230 parser.add_argument(
231 "-r", "--report", action="store_true",
232 help="report of the 1st qualification result"
233 )
234 parser.add_argument(
235 "-d", "--date", action="store_true",
236 help="date of the 1st qualification"
237 )
238 parser.add_argument(
239 "-t", "--time", action="store_true",
240 help="start time of the 1st qualifications"
241 )
242 parser.add_argument(
243 "--racers-number", action="store_true",
244 help="number of the racers in the race"
245 )
246 parser.add_argument(
247 "--driver",
248 help="information about specific driver"
249 )
250 parser.add_argument(
251 "--racers",
252 const=c.ORDER_CHOICES[0],
253 nargs="?",
254 choices=c.ORDER_CHOICES,
255 help="""list of all racers in the race in asc or"
256 desc order (default is asc)"""
257 )
258 parser.add_argument(
259 "--teams",
260 const=c.ORDER_CHOICES[0],
261 nargs="?",
262 choices=c.ORDER_CHOICES,
263 help="""list of all teams in the race in asc "
264 or desc order (default is asc)"""
265 )
266 parser.add_argument(
267 "--team-racers",
268 help="list of all racers from specific team"
269 )
270 parser.add_argument(
271 "--full-report", action="store_true",
272 help="combines --date, --time --racers-number and --report"
273 )
275 self.args = parser.parse_args(namespace=OrderedNamespace())
277 try:
278 # Check if only files argument was passed
279 self.args.only_file_path()
280 except UserWarning as err:
281 print(err)
282 parser.print_usage()
283 sys.exit()
285 try:
286 # Get log files from file directory
287 file_path = self.get_path_to_files(self.args.files)
288 except (FileNotFoundError, NotADirectoryError, UserWarning) as err:
289 sys.exit(err)
291 # Create instance with log files passed as parameter.
292 self.race = Race(log_files=file_path)
294 # Go through passed arguments and execute according print functions.
295 for arg, value in self.args.ordered():
296 if arg in ["driver", "racers", "teams", "team_racers"]:
297 self.print_func[arg](value)
298 else:
299 self.print_func[arg]()
302if __name__ == "__main__":
303 cli = Cli()
304 cli.cli()