diff --git a/assignments/a3/a3.tex b/assignments/a3/a3.tex index e7ae115..52bb324 100644 --- a/assignments/a3/a3.tex +++ b/assignments/a3/a3.tex @@ -114,13 +114,14 @@ Do \textbf{not} include your solution in this file. \begin{enumerate} \item[a.] -TODO: Write your answer here. +The precipitation attribute is a float, and in Python floats are immutable. In \texttt{calculate\_mr}, if ever the \texttt{precipitation} parameter is changed, it will be a variable reassignment, which will change the id of \texttt{precipitation}. This does not change the id of \texttt{wm.precipitation}, which is why \texttt{calculate\_mr} can never mutate the \texttt{precipitation} attribute of \texttt{wm}. \item [b.] -TODO: Write your answer here. +The function wants to use the given temperature or $-2.8$, whichever is higher. If the \texttt{wm.temperature} attribute is below $-2.8$ and gets reassigned to $-2.8$, then it will mutate the \texttt{wm} object, which is unwanted. However, if it is first stored into a different variable \texttt{temperature}, then any change to \texttt{temperature} won't affect \texttt{wm.temperature}, and therefore \texttt{wm} won't get mutated, which is good. \item[c.] -TODO: Write your answer here. +The elements of a tuple themselves can be mutated, as stated in the question. However, they cannot be reassigned, the id's of the elements will all stay the same, and elements cannot be added or removed, which makes tuples immutable. + \end{enumerate} \end{enumerate} diff --git a/assignments/a3/a3_part4_tests.py b/assignments/a3/a3_part4_tests.py index 2342433..c4288c6 100644 --- a/assignments/a3/a3_part4_tests.py +++ b/assignments/a3/a3_part4_tests.py @@ -28,11 +28,11 @@ class TestCalculateMr: def test_equation_3a_branch(self) -> None: """Test the branch calculate_mr that contains Equation 3a.""" - assert 123.82 == pytest.approx(ffwi.calculate_mr(2.4, 80)) + assert 123.823 == pytest.approx(ffwi.calculate_mr(2.4, 80)) def test_equation_3b_branch(self) -> None: """Test the branch calculate_mr that contains Equation 3b.""" - assert 182.80 == pytest.approx(ffwi.calculate_mr(2.4, 155)) + assert 182.803 == pytest.approx(ffwi.calculate_mr(2.4, 155)) class TestCalculateM: @@ -40,19 +40,31 @@ class TestCalculateM: def test_no_mutation_mo_equals_ed(self) -> None: """Test that calculate_m does not mutate the WeatherMetrics argument when mo == ed.""" - # TODO: Complete this unit test and remove this TODO + wm_old = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + wm_new = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + ffwi.calculate_m(wm_new, 0.5, 0.5) + assert wm_old == wm_new def test_no_mutation_mo_leq_ew(self) -> None: """Test that calculate_m does not mutate the WeatherMetrics argument when mo <= ew.""" - # TODO: Complete this unit test and remove this TODO + wm_old = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + wm_new = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + ffwi.calculate_m(wm_new, 0.5, 0.1) + assert wm_old == wm_new def test_no_mutation_mo_greater_than_ew(self) -> None: """Test that calculate_m does not mutate the WeatherMetrics argument when mo > ew.""" - # TODO: Complete this unit test and remove this TODO + wm_old = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + wm_new = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + ffwi.calculate_m(wm_new, 5.0, 3.0) + assert wm_old == wm_new def test_no_mutation_mo_greater_than_ed(self) -> None: """Test that calculate_m does not mutate the WeatherMetrics argument when mo > ed.""" - # TODO: Complete this unit test and remove this TODO + wm_old = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + wm_new = WeatherMetrics(1, 2, 3.0, 4.0, 5.0, 6.0) + ffwi.calculate_m(wm_new, 0.01, 0.1) + assert wm_old == wm_new @pytest.fixture @@ -69,9 +81,9 @@ def test_ffmc_against_ground_truth(sample_data) -> None: """Test the correctness of calculate_ffmc, calculate_dmc, calculate_dc, calculate_isi, calculate_bui, and calculate_fwi based on sample_data. - Ensure that, for every WeatherMetric element in sample_data[0] passed to each of the calculate_ + Ensure that, for every WeatherMetric element in inputs passed to each of the calculate_ functions mentioned above, the return value, rounded to the nearest decimal, matches the - corresponding value from the FfwiOutput element in sample_data[1]. + corresponding value from the FfwiOutput element in outputs. Hints: - You will need to use the built-in function round. @@ -82,7 +94,20 @@ def test_ffmc_against_ground_truth(sample_data) -> None: dc = ffwi.INITIAL_DC inputs, outputs = sample_data - # TODO: Complete this test and remove this TODO. + for i in range(len(sample_data)): + ffmc = ffwi.calculate_ffmc(inputs[i], ffmc) + dmc = ffwi.calculate_dmc(inputs[i], dmc) + dc = ffwi.calculate_dc(inputs[i], dc) + isi = ffwi.calculate_isi(inputs[i], ffmc) + bui = ffwi.calculate_bui(dmc, dc) + fwi = ffwi.calculate_fwi(isi, bui) + + assert round(ffmc, 1) == pytest.approx(outputs[i].ffmc) + assert round(dmc, 1) == pytest.approx(outputs[i].dmc) + assert round(dc, 1) == pytest.approx(outputs[i].dc) + assert round(isi, 1)== pytest.approx(outputs[i].isi) + assert round(bui, 1) == pytest.approx(outputs[i].bui) + assert round(fwi, 1) == pytest.approx(outputs[i].fwi) if __name__ == '__main__': @@ -91,15 +116,15 @@ if __name__ == '__main__': # When you are ready to check your work with python_ta, uncomment the following lines. # (Delete the "#" and space before each line.) # IMPORTANT: keep this code indented inside the "if __name__ == '__main__'" block - # import python_ta - # import python_ta.contracts - # python_ta.contracts.DEBUG_CONTRACTS = False - # python_ta.contracts.check_all_contracts() - # python_ta.check_all(config={ - # 'allowed-io': ['load_data'], - # 'extra-imports': ['a3_ffwi_system', 'a3_part4', 'pytest'], - # 'max-line-length': 100, - # 'max-args': 6, - # 'max-locals': 25, - # 'disable': ['R1705', 'R0201', 'C0103', 'W0621', 'E9970'], - # }) + import python_ta + import python_ta.contracts + python_ta.contracts.DEBUG_CONTRACTS = False + python_ta.contracts.check_all_contracts() + python_ta.check_all(config={ + 'allowed-io': ['load_data'], + 'extra-imports': ['a3_ffwi_system', 'a3_part4', 'pytest'], + 'max-line-length': 100, + 'max-args': 6, + 'max-locals': 25, + 'disable': ['R1705', 'R0201', 'C0103', 'W0621', 'E9970'], + })