diff --git a/src/weather/constants.py b/src/weather/constants.py index f28690a..2ed80ad 100644 --- a/src/weather/constants.py +++ b/src/weather/constants.py @@ -3,8 +3,9 @@ # # Every value that the day-25 lectures fix lives here, so that no other module # contains a magic string or number: the name of the data file, the names of -# its columns, the factors of the Fahrenheit conversion and the name of the -# exported file. +# its columns, the factors of the Fahrenheit conversion, the name of the +# exported file, the table that is created from a dictionary and the message +# for a missing optional dependency. """Constants of the weather data project, as fixed by the day-25 lectures.""" @@ -46,3 +47,24 @@ FAHRENHEIT_DENOMINATOR: Final[int] = 5 ## @brief Offset of the Celsius to Fahrenheit conversion: `temp * 9 / 5 + 32`. FAHRENHEIT_OFFSET: Final[int] = 32 + +## @brief Name of the column that holds the student names of the lecture's table. +COLUMN_STUDENTS: Final[str] = "students" + +## @brief Name of the column that holds the scores of the lecture's table. +COLUMN_SCORES: Final[str] = "scores" + +## @brief Student names of the table that the lecture creates from a dictionary. +STUDENTS: Final[tuple[str, ...]] = ("Amy", "James", "Angela") + +## @brief Scores of the students, in the order of `STUDENTS`. +SCORES: Final[tuple[int, ...]] = (76, 56, 65) + +## @brief Name of the day that the main flow selects and converts. +MONDAY: Final[str] = "Monday" + +## @brief Message printed when `pandas`, an optional extra, is not installed. +PANDAS_MISSING_MESSAGE: Final[str] = ( + "pandas is not installed; the pandas part needs the extra: " + 'pip install "weather[pandas]"' +) diff --git a/src/weather/export.py b/src/weather/export.py new file mode 100644 index 0000000..2b60ed1 --- /dev/null +++ b/src/weather/export.py @@ -0,0 +1,39 @@ +## @file export.py +# @brief Creates a `DataFrame` from a dictionary and exports it to a CSV file. +# +# This is the end of the second lecture: the table of students and scores is +# built from a dictionary and written with `DataFrame.to_csv`. Nothing is +# written unless `export_frame` is called with a path or its default name. + +"""Creates a DataFrame from a dictionary and exports it to a CSV file.""" + +from pathlib import Path + +import pandas + +from weather.constants import ( + COLUMN_SCORES, + COLUMN_STUDENTS, + EXPORT_FILE_NAME, + SCORES, + STUDENTS, +) + + +def create_scores_frame() -> pandas.DataFrame: + """! @brief Create the table of students and scores from a dictionary. + + @return A table with the columns `students` and `scores`, one row per student. + """ + data_dict = {COLUMN_STUDENTS: list(STUDENTS), COLUMN_SCORES: list(SCORES)} + return pandas.DataFrame(data_dict) + + +def export_frame(frame: pandas.DataFrame, path: Path | str = EXPORT_FILE_NAME) -> None: + """! @brief Write a table to a CSV file, the row index included. + + @param frame The table to write. + @param path Path of the file to write; `new_data.csv` in the working folder + by default. + """ + frame.to_csv(path) diff --git a/tests/test_constants.py b/tests/test_constants.py index c9872de..c8cff38 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -34,3 +34,18 @@ def test_fahrenheit_factors_give_the_lecture_formula() -> None: def test_exported_file_has_the_name_of_the_lecture() -> None: assert constants.EXPORT_FILE_NAME == "new_data.csv" + + +def test_scores_table_has_the_columns_and_values_of_the_lecture() -> None: + assert constants.COLUMN_STUDENTS == "students" + assert constants.COLUMN_SCORES == "scores" + assert constants.STUDENTS == ("Amy", "James", "Angela") + assert constants.SCORES == (76, 56, 65) + + +def test_main_flow_uses_monday() -> None: + assert constants.MONDAY == "Monday" + + +def test_missing_pandas_message_names_the_extra() -> None: + assert 'pip install "weather[pandas]"' in constants.PANDAS_MISSING_MESSAGE