def renameClass(self, class_properties: Dict[str, str]) -> str: old_class_name: str = class_properties["old_class_name"] new_class_name: str = class_properties["new_class_name"] if not uml_utilities.parse_class_identifier(old_class_name): return "Old class name is invalid.<br>(Cannot contain whitespace or quotes, and cannot be surrounded by brackets.)" if not uml_utilities.parse_class_identifier(new_class_name): return "New class name is invalid.<br>(Cannot contain whitespace or quotes, and cannot be surrounded by brackets.)" if not self.__diagram.rename_class(old_class_name, new_class_name): return "Class " + new_class_name + " already exists in the diagram." return ""
def do_set(self, arg: str) -> None: """Usage: set <identifier> <attribute_name> <attribute_value> Adds or modifies the attribute for the specified class For help with identifiers, type in 'help identifiers'""" # Check the number of arguments args: List[str] = arg.split() if len(args) != 3: print("Please provide a valid number of arguments.") print(self.do_set.__doc__) return # Grab arguments identifier: str = args[0] attr_name: str = args[1] attr_value: str = args[2] # Classify what kind of identifier was provided identifier_class: Optional[str] = uml_utilities.classify_identifier( identifier) # Ensure attribute name is valid if not uml_utilities.parse_class_identifier(attr_name): print( "Please provide a valid attribute name (no whitespace, quotes, or surrounding brackets)." ) return # Handle class identifiers if identifier_class == "class": class_id: Optional[str] = uml_utilities.parse_class_identifier( identifier) if class_id is not None: self.__set_class_attribute(class_id, attr_name, attr_value) return # Handle relationship identifiers elif identifier_class == "relationship": rel_id: Optional[Tuple[ str, str]] = uml_utilities.parse_relationship_identifier(identifier) if rel_id is not None: self.__set_relationship_attribute(rel_id, attr_name, attr_value) return # If we don't return before we get here, the user provided a bad argument print("Invalid argument provided.") print(self.do_set.__doc__)
def do_rename(self, arg: str) -> None: """Usage: rename <class name> <new class name> Changes the name of a class if it exists and the new name is not taken For help with identifiers, type in 'help identifiers""" # Check the number of arguments args: List[str] = arg.split() if len(args) != 2: print("Please provide a valid number of arguments.") print(self.do_rename.__doc__) return # Grab arguments old_class_name: str = args[0] new_class_name: str = args[1] # Parse the class IDs class_ids: List[Optional[str]] = [ uml_utilities.parse_class_identifier(old_class_name), uml_utilities.parse_class_identifier(new_class_name), ] # Make sure that the class ids are valid if not class_ids[0] or not class_ids[1]: print("Please provide two valid class class_ids as arguments.") print(self.do_rename.__doc__) return # Make sure that the old class name is in the diagram if class_ids[0] not in self.__diagram.get_all_class_names(): print("Class '{}' does not exist in the diagram".format( class_ids[0])) return # Rename the class, checking for an error if not self.__diagram.rename_class(str(class_ids[0]), str( class_ids[1])): print("Class with name '{}' already exists in the diagram".format( class_ids[1])) return else: print("Renamed class '{}' to '{}'".format(class_ids[0], class_ids[1])) # If we don't return before we get here, the user provided a bad argument print("Invalid argument provided.") print(self.do_rename.__doc__)
def addClass(self, class_properties: Dict[str, str]) -> str: class_name: str = class_properties["class_name"] x: str = class_properties["x"] y: str = class_properties["y"] if not uml_utilities.parse_class_identifier(class_properties["class_name"]): return "Class name is invalid.<br>(Cannot contain whitespace or quotes, and cannot be surrounded by brackets.)" if not self.__diagram.add_class(class_name): return "Class " + class_name + " already exists in the diagram." self.__diagram.set_class_attribute(class_name, "[x]", x) self.__diagram.set_class_attribute(class_name, "[y]", y) return ""
def test_parse_class_identifier() -> None: assert uml_utilities.parse_class_identifier("Alpha") == "Alpha" assert not uml_utilities.parse_class_identifier("") assert not uml_utilities.parse_class_identifier(" ") assert not uml_utilities.parse_class_identifier("Bad Name") assert not uml_utilities.parse_class_identifier("'Bad'Name") assert not uml_utilities.parse_class_identifier("[BadName]")
def do_remove(self, arg: str) -> None: """Usage: remove <identifier> Removes a class or relationship if one with that identifier exists in the diagram For help with identifiers, type in 'help identifiers'""" # Check the number of arguments args: List[str] = arg.split() if len(args) != 1: print( "Please provide a valid class or relationship identifier as an argument." ) print(self.do_remove.__doc__) return # Grab arguments identifier: str = args[0] # Classify what kind of identifier was provided identifier_class: Optional[str] = uml_utilities.classify_identifier( identifier) # Handle class identifiers if identifier_class == "class": class_id: Optional[str] = uml_utilities.parse_class_identifier( identifier) if class_id is not None: self.__remove_class(arg) return # Handle relationship identifiers elif identifier_class == "relationship": rel_id: Optional[Tuple[ str, str]] = uml_utilities.parse_relationship_identifier(identifier) if rel_id is not None: self.__remove_relationship(rel_id) return # If we don't return before we get here, the user provided a bad argument print("Invalid argument provided.") print(self.do_remove.__doc__)
def setRelationshipAttribute(self, attribute_data: Dict[str, str]) -> str: attr_key: str = attribute_data["attr_key"] attr_value: str = attribute_data["attr_key"] relationship_id: str = attribute_data["relationship_id"] relationship_id_tuple: Optional[ Tuple[str, str] ] = uml_utilities.parse_relationship_identifier(relationship_id) if not relationship_id_tuple: raise Exception( "Invalid relationship identifier provided: " + relationship_id ) class_name_a: str = relationship_id_tuple[0] class_name_b: str = relationship_id_tuple[1] if not class_name_a in self.__diagram.get_all_class_names(): return "Class " + class_name_a + " not found in the diagram." if not class_name_b in self.__diagram.get_all_class_names(): return "Class " + class_name_b + " not found in the diagram." if ( not "ignore_naming_rules" in attribute_data and not uml_utilities.parse_class_identifier(attr_key) ): return "Attribute name is invalid. (Cannot contain whitespace or quotes, and cannot be surrounded by brackets.)" if not self.__diagram.set_relationship_attribute( relationship_id_tuple[0], relationship_id_tuple[1], attr_key, attr_value ): return "Relationship not found in diagram: {}".format( uml_utilities.stringify_relationship_identifier( class_name_a, class_name_b ) ) return ""
def do_variable(self, arg: str) -> None: """Usage: variable [set|remove] <class name> <variable name> [-v VISIBILITY] [-t TYPE] Adds, modifies, or removes a member variable for the specified class""" # Check the number of arguments args: List[str] = arg.split() if len(args) < 3: print("Please provide a valid number of arguments.") print(self.do_variable.__doc__) return # Grab arguments subcommand: str = args[0] class_name: str = args[1] var_name: str = args[2] # Parse the class ID and variable name class_id: Optional[str] = uml_utilities.parse_class_identifier( class_name) var_id: Optional[str] = uml_utilities.parse_class_identifier(var_name) # Make sure that the class ID is valid if class_id is None: print( "Please provide a valid class name (no whitespace, quotes, or surrounding brackets)." ) return # Make sure that the variable ID is valid if var_id is None: print( "Please provide a valid variable name (no whitespace, quotes, or surrounding brackets)." ) return # Make sure that the class name is in the diagram if class_id not in self.__diagram.get_all_class_names(): print("Class '{}' does not exist in the diagram".format(class_id)) return # Handle set subcommand if subcommand == "set": # Set up argument parser for optional flags arg_parser: ArgumentParser = ArgumentParser(add_help=False, usage="") arg_parser.add_argument("-v", "--visibility") arg_parser.add_argument("-t", "--type") try: extra_args: Namespace = arg_parser.parse_args( args[3:len(args)]) except: print("Invalid argument provided.") print(self.do_function.__doc__) return # Grab and verify any optional flag values var_visibility: Optional[str] = "" var_type: Optional[str] = "" if extra_args.visibility: var_visibility = uml_utilities.parse_class_identifier( extra_args.visibility) if extra_args.type: var_type = uml_utilities.parse_class_identifier( extra_args.type) if var_visibility is None or var_type is None: print( "Please ensure all values provided are valid (no whitespace, quotes, or surrounding brackets)." ) return # Dispatch self.__variable_set(class_id, var_id, var_visibility, var_type) return # Handle remove subcommand if subcommand == "remove": self.__variable_remove(class_id, var_id) return # If we don't return before we get here, the user provided a bad argument print("Invalid argument provided.") print(self.do_variable.__doc__)
def do_function(self, arg: str) -> None: """Usage: function [set|remove] <class name> <function name> [-v VISIBILITY] [-t TYPE] [-p PARAMETERS] Adds, modifies, or removes a member function for the specified class For help with formatting parameter lists, type in 'help parameters'""" # Check the number of arguments args: List[str] = arg.split() if len(args) < 3: print("Please provide a valid number of arguments.") print(self.do_function.__doc__) return # Grab arguments subcommand: str = args[0] class_name: str = args[1] func_name: str = args[2] # Parse the class ID and function name class_id: Optional[str] = uml_utilities.parse_class_identifier( class_name) func_id: Optional[str] = uml_utilities.parse_class_identifier( func_name) # Make sure that the class ID is valid if class_id is None: print( "Please provide a valid class name (no whitespace, quotes, or surrounding brackets)." ) return # Make sure that the function ID is valid if func_id is None: print( "Please provide a valid function name (no whitespace, quotes, or surrounding brackets)." ) return # Make sure that the class name is in the diagram if class_id not in self.__diagram.get_all_class_names(): print("Class '{}' does not exist in the diagram".format(class_id)) return # Handle set subcommand if subcommand == "set": # Set up argument parser for optional flags arg_parser: ArgumentParser = ArgumentParser(add_help=False, usage="") arg_parser.add_argument("-v", "--visibility") arg_parser.add_argument("-t", "--type") arg_parser.add_argument("-p", "--parameters") try: extra_args: Namespace = arg_parser.parse_args( args[3:len(args)]) except: print("Invalid argument provided.") print(self.do_function.__doc__) return # Grab and verify any optional flag values func_visibility: Optional[str] = "" func_type: Optional[str] = "" param_list: Optional[List[str]] = [] if extra_args.visibility: func_visibility = uml_utilities.parse_class_identifier( extra_args.visibility) if extra_args.type: func_type = uml_utilities.parse_class_identifier( extra_args.type) if extra_args.parameters: param_list = uml_utilities.parse_param_list( extra_args.parameters) if func_visibility is None or func_type is None or param_list is None: print( "Please ensure all values provided are valid (no whitespace, quotes, or surrounding brackets)." ) return # Dispatch self.__function_set(class_id, func_id, func_visibility, func_type, param_list) return # Handle remove subcommand if subcommand == "remove": self.__function_remove(class_id, func_id) return # If we don't return before we get here, the user provided a bad argument print("Invalid argument provided.") print(self.do_function.__doc__)
def setClassAttribute(self, attribute_data: Dict[str, str]) -> str: attr_key: str = "" attr_value: str = "" attr_name: str = "" class_name: str = attribute_data["class_name"] attr_category: str = attribute_data["attribute_category"] # Prepare the member function for storage if attr_category == "function": param_list: List[str] = [] # Leave param_list empty if no parameters were given if attribute_data["func_params"] != "": param_list = attribute_data["func_params"].split(",") # Remove whitespace from each parameter param_list = [p.strip() for p in param_list] # Ensure that each parameter has a type and name for param in param_list: if len(param.split(" ")) != 2: return f'Invalid parameter: "{param}".\n(Parameters must follow the format "[type1] [name1], [type2] [name2], ..." \nor leave the field blank for a void parameter list.' serial_func_pair: Tuple[str, str] = uml_utilities.serialize_function( attribute_data["func_visibility"].strip(), attribute_data["func_return_type"].strip(), attribute_data["func_name"].strip(), param_list, ) attr_name = attribute_data["func_name"] attr_key = serial_func_pair[0] attr_value = serial_func_pair[1] # Prepare the member variable for storage elif attr_category == "variable": serial_var_pair: Tuple[str, str] = uml_utilities.serialize_variable( attribute_data["var_visibility"].strip(), attribute_data["var_type"].strip(), attribute_data["var_name"].strip(), ) attr_name = attribute_data["var_name"] attr_key = serial_var_pair[0] attr_value = serial_var_pair[1] # Metadata attributes do not need to be serialized elif attr_category == "metadata": attr_name = attribute_data["attribute_name"] attr_key = attribute_data["attribute_name"] attr_value = attribute_data["attribute_value"] else: raise Exception("Unrecognized attribute category: " + attr_category) if ( not "ignore_naming_rules" in attribute_data and not uml_utilities.parse_class_identifier(attr_name) ): return "Attribute name is invalid. (Cannot contain whitespace or quotes, and cannot be surrounded by brackets.)" if not self.__diagram.set_class_attribute(class_name, attr_key, attr_value): return ( "Class " + class_name + " does not exist in the diagram. Unable to add attribute: " + attr_key ) return ""