예제 #1
0
    def test_correct_write(self):
        """Tests that the function correctly updates the chemical library with the new nicknames."""
        temp_file = NamedTemporaryFile("w+")

        file_contents = "100.0 salt pepper\n0.5 Arg Arginine\n54.55 NaCl\n"
        with open(temp_file.name, "w") as file:
            file.write(file_contents)

        with mock.patch("buf.commands.chemical.chemical_library_file",
                        temp_file.name):
            read_chemical_dict = chemical.load_chemicals()

            chemical_object = read_chemical_dict["salt"]

            chemical_object.names.append("new_name_1")
            chemical_object.names.append("new_name_2")

            read_chemical_dict["new_name_1"] = chemical_object
            read_chemical_dict["new_name_2"] = chemical_object

            chemical.nickname_chemical("salt", ["new_name_1", "new_name_2"])

            new_dict = chemical.load_chemicals()

            self.assertEqual(read_chemical_dict, new_dict)
예제 #2
0
    def test_incomplete_delete(self):
        """Tests that when the --complete option is not specified, only the chemical name specified is removed from \
        the library (and not its nicknames)."""

        temp_file = NamedTemporaryFile("w+")

        test_salt_and_pepper = chemical.Chemical(200, ["salt", "pepper"])
        test_kcl = chemical.Chemical(123.4, ["KCl"])

        test_pepper = chemical.Chemical(200, ["pepper"])

        initial_library = {
            "salt": test_salt_and_pepper,
            "pepper": test_salt_and_pepper,
            "KCl": test_kcl
        }

        after_delete = {"KCl": test_kcl, "pepper": test_pepper}

        with mock.patch("buf.commands.chemical.chemical_library_file",
                        temp_file.name):
            chemical.save_chemical_library(initial_library)

            chemical.delete_chemical("salt",
                                     complete_deletion=False,
                                     prompt_for_confirmation=False)

            self.assertEqual(after_delete, chemical.load_chemicals())
예제 #3
0
    def test_read_write(self):
        """Tests that the loading, saving, and again loading the chemical library leaves it unchanged."""
        temp_file = NamedTemporaryFile("w+")

        file_contents = "100.0 salt pepper\n0.5 Arg Arginine\n54.55 NaCl\n"
        with open(temp_file.name, "w") as file:
            file.write(file_contents)

        with mock.patch("buf.commands.chemical.chemical_library_file",
                        temp_file.name):
            read_chemical_dict = chemical.load_chemicals()

            chemical.save_chemical_library(read_chemical_dict)

            read_again = chemical.load_chemicals()

            self.assertEqual(read_chemical_dict, read_again)
예제 #4
0
 def test_correct_read(self):
     """Tests that the function correctly parses a file into a dictionary."""
     one_chemical = chemical.Chemical(123.4, ["name1", "name2"])
     other_chemical = chemical.Chemical(567.8, ["name3", "name4"])
     chemical_dict = {
         "name1": one_chemical,
         "name2": one_chemical,
         "name3": other_chemical,
         "name4": other_chemical
     }
     with mock.patch("buf.commands.chemical.open") as mock_open:
         mock_open.return_value.__enter__.return_value = StringIO(
             str(one_chemical) + "\n" + str(other_chemical))
         returned_dict = chemical.load_chemicals()
         self.assertEqual(chemical_dict, returned_dict)
예제 #5
0
def assert_recipe_validity(recipe_object: Recipe,
                           chemical_library: dict = None,
                           recipe_library: dict = None,
                           check_existing_chemicals: bool = True):
    """Checks that a given Recipe object is valid (i.e. all concentration have both valid magnitudes and units,
     the chemicals specified in the recipe are in the chemical library if their concentration is specified in molar,
     and that a recipe with the same name doesn't already exist in the recipe library)."""

    if chemical_library == None and check_existing_chemicals == True:
        chemical_library = chemical.load_chemicals()
    if recipe_library == None:
        recipe_library = load_recipes()

    if recipe_object.name in recipe_library:
        error_messages.recipe_already_exists(recipe_object.name)

    if " " in recipe_object.name:
        error_messages.spaces_in_recipe_name(recipe_object.name)

    for concentration, chemical_name in zip(recipe_object.concentrations,
                                            recipe_object.chemical_names):

        magnitude, symbol = unit.split_unit_quantity(concentration)

        if symbol not in unit.valid_units:
            error_messages.invalid_concentration_unit(symbol)

        if check_existing_chemicals:
            if symbol in unit.concentration_units and chemical_name not in chemical_library:
                error_messages.chemical_not_found(chemical_name)

        try:
            float_magnitude = float(magnitude)
        except:
            error_messages.non_number_concentration_magnitude(magnitude)

        if float_magnitude <= 0:
            error_messages.non_positive_concentration_magnitude(
                float_magnitude)
예제 #6
0
def add_recipes_from_file(filename: str):
    """Parses specified file, adding a recipe to the library for each line in the file.
    Each line in the file should first contain the recipe's name, followed by a list of contents.
    All words should be separated by spaces. Example file:

    recipe_a 10% glycerol 2M NaCl
    recipe_b 20mM KCl 4g DTT
    """
    if os.path.isfile(filename) == False:
        error_messages.file_not_found(filename)

    try:
        with open(filename, "r") as file:
            lines = file.readlines()
    except:
        error_messages.file_read_error(filename)

    existing_chemical_library = chemical.load_chemicals()
    existing_recipe_library = load_recipes()

    new_recipe_library = {}

    for line_number, line in enumerate(lines):

        try:
            words = line.split()
            if len(words) == 0:
                continue
            elif len(words) < 3:
                error_messages.line_too_short_in_recipe_file(line_number)
            elif len(words) % 2 == 0:
                error_messages.line_has_inequal_contents_in_recipe_file(
                    line_number)

            recipe_name = words[0]

            concentrations = words[1::2]
            chemical_names = words[2::2]

            new_recipe_object = make_safe_recipe(
                recipe_name,
                concentrations,
                chemical_names,
                chemical_library=existing_chemical_library,
                recipe_library=existing_recipe_library)

            if recipe_name in new_recipe_library:
                error_messages.duplicate_file_entry(recipe_name)

            new_recipe_library[recipe_name] = new_recipe_object

        except:
            error_messages.add_from_file_termination(
                line_number,
                erroneous_line=line.strip("\n"),
                upper_case_data_type="Recipes")

    with open(recipe_library_file, "a") as file:
        # Note: dict.values() can be used here but not in chemical.add_chemicals_from_file, since chemicals can
        # have multiple names, and therefore will appear multiple times in values()
        for new_recipe in list(new_recipe_library.values()):
            file.write(str(new_recipe) + "\n")

    print("Added the following recipes to your library:",
          *list(new_recipe_library.keys()))