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 ""
示例#5
0
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 ""