def sort_parse(self, command, reverse=False): """ Parses and validates the sort command Input: command - the user command reverse - the order of the sort Return: True on valid and False otherwise """ self.set_command(command) # simple sort no type use total expense pattern_sort = self._regex_search(self._PATTERN_SORT) if pattern_sort: self._parsed_command = {"type": None, "reverse": reverse} return True # use an expense type for the sort pattern_sort_by_type = self._regex_search(self._PATTERN_SORT_BY_TYPE) if pattern_sort_by_type: expense_type = pattern_sort_by_type.group(1) if not Apartment.is_expense_type(expense_type): UI.set_message(UI.get_error_types()) return False self._parsed_command = {"type": expense_type, "reverse": reverse} return True UI.set_message(UI.get_error_sort()) return False
def filter(self): """ Filter the list of apartments on specific criteria """ self._validate_parsed_command(["greater", "type"]) # filter by type if self._parsed_command["type"]: expense_type = self._parsed_command["type"] filtered_bloc_dict = {} for apartment_id in self._bloc_dict.keys(): if self._bloc_dict[apartment_id].expenses[expense_type]: filtered_bloc_dict[apartment_id] = self._bloc_dict[apartment_id] self._bloc_dict = filtered_bloc_dict # filter by total greater than if self._parsed_command["greater"]: amount_greater = float(self._parsed_command["greater"]) filtered_bloc_dict = {} for apartment_id in self._bloc_dict.keys(): if self._bloc_dict[apartment_id].get_total_expenses() > amount_greater: filtered_bloc_dict[apartment_id] = self._bloc_dict[apartment_id] self._bloc_dict = filtered_bloc_dict # print(filtered_bloc_dict) if not filtered_bloc_dict: UI.set_message("No apartment fits the criteria") else: UI.set_message("Apartments filtered successfully")
def filter_parse(self, command): """ Parses and validates the filter command Input: command - the user command Return: True on valid and False otherwise """ self.set_command(command) # filter by total amount greater than pattern_total_greater = self._regex_search(self._PATTERN_FILTER_GREATER_THAN_TOTAL) if pattern_total_greater: greater = pattern_total_greater.group(1) self._parsed_command = {"greater": greater, "type": None} return True # filter by only apartments having that type pattern_by_type = self._regex_search(self._PATTERN_FILTER_BY_TYPE) if pattern_by_type: expense_type = pattern_by_type.group(1) if not Apartment.is_expense_type(expense_type): UI.set_message(UI.get_error_types()) return False self._parsed_command = {"greater": None, "type": expense_type} return True UI.set_message(UI.get_error_filter()) return False
def list_total_apartment(self): """ Displays the total expenses for an apartment """ self._validate_parsed_command(["id"]) apartment_id = self._parsed_command["id"] UI.set_message("Total expenses = " + str(self._bloc_dict[apartment_id].get_total_expenses()))
def _insert_or_replace_apartment_parse(self, command, command_type): """ Protected parse method for insert and replace Input: command - the user command command_type - the command_type, can be insert or replace Return: True on valid and False otherwise Raises: Exception on invalid command_type """ self.set_command(command) # get the correct pattern if command_type is "insert": pattern = self._regex_search(self._PATTERN_INSERT) if not pattern: UI.set_message(UI.get_error("insert <amount>, <expense_type> at <apartment_id>")) return False elif command_type is "replace": pattern = self._regex_search(self._PATTERN_REPLACE) if not pattern: UI.set_message(UI.get_error("replace <amount>, <expense_type> at <apartment_id>")) return False else: raise Exception("command type is incorrect") # get the data amount = pattern.group(1) expense_type = pattern.group(2) apartment_id = pattern.group(3) # wrong type if not Apartment.is_expense_type(expense_type): UI.set_message(UI.get_error_types()) return False if command_type is "insert": # apartment does exist in the list if self.is_apartment(apartment_id): UI.set_message("Apartment " + apartment_id + " does exist in the list. " "Use this command to replace: replace " + amount + ", " + expense_type + " at " + apartment_id) return False elif command_type is "replace": # apartment does not exist in the list if not self.is_apartment(apartment_id): UI.set_message("Apartment " + apartment_id + " does not exist in the list. " "Use this command to add: insert " + amount + ", " + expense_type + " at " + apartment_id) return False # all good self._parsed_command = {"type": expense_type, "amount": amount, "id": apartment_id} return True
def stat_total_type(self): """ Displays the total for an expense type """ self._validate_parsed_command(["expense_type"]) sum_type = self._parsed_command["expense_type"] total = sum([self._bloc_dict[i].expenses[sum_type] for i in self._bloc_dict]) # for apartment_id in self._bloc_dict: # total += self._bloc_dict[apartment_id].expenses[sum_type] UI.set_message("Total expenses for " + sum_type + " = " + str(total))
def stat_max_apartment(self): """ Displays the biggest expense in an apartment """ self._validate_parsed_command(["id"]) apartment_id = self._parsed_command["id"] biggest_types = self._bloc_dict[apartment_id].get_max_expenses_type() if biggest_types: UI.set_message("Biggest expense is " + biggest_types.__str__() + " = " + str( self._bloc_dict[apartment_id].expenses[biggest_types[0]])) else: UI.set_message("Apartment has all expenses = 0")
def list_by_type(self): """ Displays only the apartments having a specific expense type """ self._validate_parsed_command(["expense_type"]) expense_type = self._parsed_command["expense_type"] filtered_bloc_dict = {} for apartment_id in self._bloc_dict.keys(): if self._bloc_dict[apartment_id].expenses[expense_type] != 0: filtered_bloc_dict[apartment_id] = self._bloc_dict[apartment_id] if filtered_bloc_dict: UI.set_message(UI.get_bloc_table(filtered_bloc_dict)) else: UI.set_message("There are no apartments with " + expense_type)
def list_greater_than(self): """ Displays only the apartments with an overall expense greater than the given amount """ self._validate_parsed_command(["greater"]) greater_than = float(self._parsed_command["greater"]) filtered_bloc_dict = {} for apartment_id in self._bloc_dict.keys(): if self._bloc_dict[apartment_id].get_total_expenses() > greater_than: filtered_bloc_dict[apartment_id] = self._bloc_dict[apartment_id] # check if empty if filtered_bloc_dict: UI.set_message(UI.get_bloc_table(filtered_bloc_dict)) else: UI.set_message("There are no apartments with overall expenses greater than " + str(greater_than))
def list_greater_than_parse(self, command): """ Parses and validates the 'list greater than' command Input: command - the user command Return: True on valid and False otherwise """ # list greater than <amount> self.set_command(command) pattern_greater = self._regex_search(self._PATTERN_LIST_GREATER) if pattern_greater: greater = pattern_greater.group(1) self._parsed_command = {"greater": greater} return True UI.set_message(UI.get_error("list greater than <amount>")) return False
def list_less_than(self): """ Displays only the apartments with an overall expense less than the given amount """ self._validate_parsed_command(["less"]) less_than = float(self._parsed_command["less"]) upper_id_limit = self._parsed_command["upper_id_limit"] filtered_bloc_dict = {} for apartment_id in range(1, int(upper_id_limit) + 1): apartment_id = str(apartment_id) if self.is_apartment(apartment_id): if self._bloc_dict[apartment_id].get_total_expenses() < less_than: filtered_bloc_dict[apartment_id] = self._bloc_dict[apartment_id] # check if empty if filtered_bloc_dict: UI.set_message(UI.get_bloc_table(filtered_bloc_dict)) else: UI.set_message("There are no apartments with overall expenses less than " + str(less_than))
def list_less_than_parse(self, command): """ Parses and validates the 'list less than' command Input: command - the user command Return: True on valid and False otherwise """ # less than <amount> before <id> self.set_command(command) pattern_less = self._regex_search(self._PATTERN_LIST_LESS) if pattern_less: less = pattern_less.group(1) upper_id_limit = pattern_less.group(2) self._parsed_command = {"less": less, "upper_id_limit": upper_id_limit} return True UI.set_message(UI.get_error("list less than <amount> before <apartment_id>")) return False
def remove_apartment(self): """ Remove the expenses from an apartment or from a list of apartments. """ if "id" in self._parsed_command: # remove only from one apartments apartment_id = self._parsed_command["id"] self._bloc_dict[apartment_id] = Apartment() UI.set_message("Removed all expenses from apartment " + apartment_id) elif "type" in self._parsed_command: # remove all types expense_type = self._parsed_command["type"] for apartment_id in self._bloc_dict.keys(): self._bloc_dict[apartment_id].expenses[expense_type] = 0 UI.set_message("Removed " + self._parsed_command["type"] + " from all apartments ") elif ("id_min" in self._parsed_command) and ("id_max" in self._parsed_command): # remove from range removed_from = [] # keep track of all removed for apartment_id in range(int(self._parsed_command["id_min"]), int(self._parsed_command["id_max"]) + 1): apartment_id = str(apartment_id) if self.is_apartment(apartment_id): removed_from.append(apartment_id) self._bloc_dict[apartment_id] = Apartment() UI.set_message("Removed all expenses from apartments " + removed_from.__str__()) else: raise Exception("Incorrect parsed_command")
def sort(self): """ Displays the list of apartments sorted """ self._validate_parsed_command(["type", "reverse"]) reverse_sort = self._parsed_command["reverse"] if reverse_sort is True: header_message = " sorted descending" else: header_message = " sorted ascending" # simple sort by total expense if self._parsed_command["type"] is None: # we create a list of tuples consisting of (id, apartment_obj, total_expense) list_of_tuples = [ (apartment_id, self._bloc_dict[apartment_id], self._bloc_dict[apartment_id].get_total_expenses()) for apartment_id in self._bloc_dict] # set message header_message += " by total expenses" else: # sort by type expense_type = self._parsed_command["type"] # we create a list of tuples consisting of (id, apartment_obj, expense_type_amount) list_of_tuples = [ (apartment_id, self._bloc_dict[apartment_id], self._bloc_dict[apartment_id].expenses[expense_type]) for apartment_id in self._bloc_dict] # set message header_message += " by expense '" + expense_type + "'" # print("raw_list: ", list_of_tuples) # use the last key of the tuple for the value sorted_list_of_tuples = sorted(list_of_tuples, key=lambda item: item[2], reverse=reverse_sort) # print("sorted_list: ", sorted_sort_it) UI.set_message(UI.get_bloc_table(sorted_list_of_tuples, header_message))
def stat_max_apartment_parse(self, command): """ Parses and validates the 'max id' command Input: command - the user command Return: True on valid and False otherwise """ self.set_command(command) # max <id> pattern_max = self._regex_search(self._PATTERN_STAT_MAX_APARTMENT) if pattern_max: apartment_id = pattern_max.group(1) if not self.is_apartment(apartment_id): UI.set_message("Apartment " + apartment_id + " does not exist in the list") return False self._parsed_command = {"id": apartment_id} return True UI.set_message(UI.get_error("max <apartment_number>")) return False
def stat_total_type_parse(self, command): """ Parses and validates the 'sum type' command Input: command - the user command Return: True on valid and False otherwise """ self.set_command(command) # sum <type> pattern_sum = self._regex_search(self._PATTERN_STAT_TOTAL_TYPE) if pattern_sum: expense_type = pattern_sum.group(1) if not Apartment.is_expense_type(expense_type): UI.set_message(UI.get_error_types()) return False self._parsed_command = {"expense_type": expense_type} return True UI.set_message(UI.get_error("sum <type>")) return False
def list_by_type_parse(self, command): """ Parses and validates the list command Input: command - the user command Return: True on valid and False otherwise """ self.set_command(command) # list <type> pattern_type = self._regex_search(self._PATTERN_LIST_BY_TYPE) if pattern_type: expense_type = pattern_type.group(1) if not Apartment.is_expense_type(expense_type): UI.set_message(UI.get_error_types()) return False self._parsed_command = {"expense_type": expense_type} return True UI.set_message(UI.get_error("list <expense_type>")) return False
def list_total_apartment_parse(self, command): """ Parses and validates the 'list total' command Input: command - the user command Return: True on valid and False otherwise """ self.set_command(command) # sold|total <apartment_number> pattern_total = self._regex_search(self._PATTERN_LIST_TOTAL_APARTMENT) if pattern_total: apartment_id = pattern_total.group(1) if not self.is_apartment(apartment_id): UI.set_message("Apartment " + apartment_id + " does not exist in the list") return False self._parsed_command = {"id": apartment_id} return True UI.set_message(UI.get_error("list total <apartment_id>")) return False
def remove_apartment_parse(self, command): """ Parses and validates the remove command Input: command - the user command Return: True on valid and False otherwise """ self.set_command(command) # first case by apartment id pattern_remove_by_id = self._regex_search(self._PATTERN_REMOVE_BY_ID) if pattern_remove_by_id: apartment_id = pattern_remove_by_id.group(1) if not self.is_apartment(apartment_id): UI.set_message( "Apartment " + apartment_id + " does not exist in this list so all the expenses are by default 0") return False self._parsed_command = {"id": apartment_id} return True # second case remove from interval pattern_remove_by_interval = self._regex_search(self._PATTERN_REMOVE_BY_INTERVAL) if pattern_remove_by_interval: id_min = pattern_remove_by_interval.group(1) id_max = pattern_remove_by_interval.group(2) self._parsed_command = {"id_min": id_min, "id_max": id_max} return True # third case by type pattern_remove_by_type = self._regex_search(self._PATTERN_REMOVE_BY_TYPE) if pattern_remove_by_type: expense_type = pattern_remove_by_type.group(1) if not Apartment.is_expense_type(expense_type): UI.set_message(UI.get_error_types()) return False self._parsed_command = {"type": expense_type} return True UI.set_message(UI.get_error("remove <apartment_id> \n\tremove from 5 to 10 \n\tremove type")) return False
def run(self): """ Main loop of the application """ print(UI.get_help_menu()) while True: # get the command from the user command = UI.get_command() # find out the command type and handle each command correctly if "help" in command: UI.set_message(UI.get_help_menu()) elif ("quit" in command) or ("exit" in command): self.exit() elif "insert" in command: if self.bloc.insert_apartment_parse(command): self._undo_start("insert") self.bloc.insert_apartment() elif "replace" in command: if self.bloc.replace_apartment_parse(command): self._undo_start("replace") self.bloc.insert_apartment() elif "remove" in command: if self.bloc.remove_apartment_parse(command): self._undo_start("remove") self.bloc.remove_apartment() elif "list" in command: if "list" == command: self.bloc.list_all() elif "greater" in command: if self.bloc.list_greater_than_parse(command): self.bloc.list_greater_than() elif "less" in command: if self.bloc.list_less_than_parse(command): self.bloc.list_less_than() elif ("sold" in command) or ("total" in command): if self.bloc.list_total_apartment_parse(command): self.bloc.list_total_apartment() else: # check list by type if self.bloc.list_by_type_parse(command): self.bloc.list_by_type() elif "sum" in command: if self.bloc.stat_total_type_parse(command): self.bloc.stat_total_type() elif "max" in command: if self.bloc.stat_max_apartment_parse(command): self.bloc.stat_max_apartment() elif "filter" in command: if self.bloc.filter_parse(command): self._undo_start("filter") self.bloc.filter() elif "sort" in command: if "asc" in command: if self.bloc.sort_parse(command, reverse=False): self.bloc.sort() elif "desc" in command: if self.bloc.sort_parse(command, reverse=True): self.bloc.sort() else: UI.set_message(UI.get_error_sort()) elif "undo" in command: if self._undo_last_operation: UI.set_message("Undo operation '" + self._undo_last_operation + "' finished") self._undo_end() else: UI.set_message("Nothing to undo") elif "save" == command: self.save() UI.set_message("Current bloc state saved to file.") else: UI.set_message("Command unknown. type help for a list of commands") # print all messages print(UI.get_message())
def list_all(self): """ Displays all the apartments in the bloc """ UI.set_message(UI.get_bloc_table(self._bloc_dict))