diff --git a/src/artemis.py b/src/artemis.py index dec8ff0..31572c6 100644 --- a/src/artemis.py +++ b/src/artemis.py @@ -64,7 +64,7 @@ import loggingconf # noqa 401 # import default_imgs_rc -__LATEST_VERSION__ = "3.2.0" +__LATEST_VERSION__ = "3.2.1" if IS_BINARY: __VERSION__ = __LATEST_VERSION__ diff --git a/src/constants.py b/src/constants.py index cbc5b8c..ef5f262 100644 --- a/src/constants.py +++ b/src/constants.py @@ -113,8 +113,8 @@ class Constants: UPDATING_STR = "Updating..." ACF_DOCS = "https://aresvalley.com/documentation/" FORECAST_PROBABILITIES = "https://services.swpc.noaa.gov/text/sgarf.txt" - SPACE_WEATHER_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt" - SPACE_WEATHER_PROT_EL = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt" + SPACE_WEATHER_XRAY = "https://services.swpc.noaa.gov/json/goes/primary/xrays-1-day.json" + SPACE_WEATHER_PROT_EL = "https://services.swpc.noaa.gov/json/goes/primary/integral-protons-1-day.json" SPACE_WEATHER_AK_INDEX = "https://services.swpc.noaa.gov/text/wwv.txt" SPACE_WEATHER_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt" SPACE_WEATHER_GEO_STORM = "https://services.swpc.noaa.gov/text/3-day-forecast.txt" @@ -209,6 +209,8 @@ class Messages: NEW_VERSION_AVAILABLE = "New software version" NEW_VERSION_MSG = lambda v: f"The software version {v} is available." # noqa: E731 DOWNLOAD_SUGG_MSG = "Download new version now?" + SCREEN_UPDATE_FAIL = "Unable to update the data" + SCREEN_UPDATE_FAIL_MSG = "Downloaded data currupted or invalid" class ThemeConstants: diff --git a/src/loggingconf.py b/src/loggingconf.py index 5238922..ca8b3c0 100644 --- a/src/loggingconf.py +++ b/src/loggingconf.py @@ -3,15 +3,18 @@ import logging.config from constants import __BASE_FOLDER__ import os.path -"""Import the module to initialize the logging configuration""" +"""Import the module to initialize the logging configuration. + +It is imported only for its side effects.""" + _LOGGING_CONFIG = { 'version': 1, 'formatters': { 'general': { 'format': '%(asctime)s::%(levelname)s::%(module)s::%(funcName)s::%(message)s', - 'datefmt': '%d/%m/%Y %I:%M:%S %p' - } + 'datefmt': '%d/%m/%Y %I:%M:%S %p', + }, }, 'handlers': { 'console': { @@ -26,20 +29,15 @@ _LOGGING_CONFIG = { 'filename': os.path.join(__BASE_FOLDER__, 'info.log'), 'mode': 'w', 'encoding': 'utf8', - 'formatter': 'general' - } + 'formatter': 'general', + }, }, 'root': { 'level': 'DEBUG', - 'handlers': ['console', 'file'] + 'handlers': ['console', 'file'], }, - 'loggers': { - 'root.sublogger': { - 'propagate': False, - 'level': 'DEBUG', - 'handlers': ['console', 'file'] - } - } + # Add loggers if required + # 'loggers': {} } logging.config.dictConfig(_LOGGING_CONFIG) diff --git a/src/spaceweathermanager.py b/src/spaceweathermanager.py index dc5f5f9..98ce784 100644 --- a/src/spaceweathermanager.py +++ b/src/spaceweathermanager.py @@ -1,9 +1,10 @@ +import logging import webbrowser from PyQt5.QtCore import QObject, pyqtSlot from constants import Constants, Messages from switchable_label import SwitchableLabelsIterable from weatherdata import SpaceWeatherData -from utilities import safe_cast, pop_up +from utilities import pop_up class SpaceWeatherManager(QObject): @@ -136,161 +137,161 @@ class SpaceWeatherManager(QObject): """ self._owner.update_now_bar.set_idle() if status_ok: - xray_long = safe_cast(self._owner.space_weather_data.xray[-1][7], float) + try: + xray_long = float(self._owner.space_weather_data.xray) - def format_text(letter, power): - return letter + f"{xray_long * 10**power:.1f}" + def format_text(letter, power): + return letter + f"{xray_long * 10**power:.1f}" - if xray_long < 1e-8 and xray_long != -1.00e+05: - self._owner.peak_flux_lbl.setText(format_text("= 1e-8 and xray_long < 1e-7: - self._owner.peak_flux_lbl.setText(format_text("A", 8)) - elif xray_long >= 1e-7 and xray_long < 1e-6: - self._owner.peak_flux_lbl.setText(format_text("B", 7)) - elif xray_long >= 1e-6 and xray_long < 1e-5: - self._owner.peak_flux_lbl.setText(format_text("C", 6)) - elif xray_long >= 1e-5 and xray_long < 1e-4: - self._owner.peak_flux_lbl.setText(format_text("M", 5)) - elif xray_long >= 1e-4: - self._owner.peak_flux_lbl.setText(format_text("X", 4)) - elif xray_long == -1.00e+05: - self._owner.peak_flux_lbl.setText("No Data") + if xray_long < 1e-8 and xray_long != -1.00e+05: + self._owner.peak_flux_lbl.setText("= 1e-8 and xray_long < 1e-7: + self._owner.peak_flux_lbl.setText(format_text("A", 8)) + elif xray_long >= 1e-7 and xray_long < 1e-6: + self._owner.peak_flux_lbl.setText(format_text("B", 7)) + elif xray_long >= 1e-6 and xray_long < 1e-5: + self._owner.peak_flux_lbl.setText(format_text("C", 6)) + elif xray_long >= 1e-5 and xray_long < 1e-4: + self._owner.peak_flux_lbl.setText(format_text("M", 5)) + elif xray_long >= 1e-4: + self._owner.peak_flux_lbl.setText(format_text("X", 4)) + elif xray_long == -1.00e+05: + self._owner.peak_flux_lbl.setText("No Data") - if xray_long < 1e-5 and xray_long != -1.00e+05: - self._switchable_r_labels.switch_on(self._owner.r0_now_lbl) - elif xray_long >= 1e-5 and xray_long < 5e-5: - self._switchable_r_labels.switch_on(self._owner.r1_now_lbl) - elif xray_long >= 5e-5 and xray_long < 1e-4: - self._switchable_r_labels.switch_on(self._owner.r2_now_lbl) - elif xray_long >= 1e-4 and xray_long < 1e-3: - self._switchable_r_labels.switch_on(self._owner.r3_now_lbl) - elif xray_long >= 1e-3 and xray_long < 2e-3: - self._switchable_r_labels.switch_on(self._owner.r4_now_lbl) - elif xray_long >= 2e-3: - self._switchable_r_labels.switch_on(self._owner.r5_now_lbl) - elif xray_long == -1.00e+05: - self._switchable_r_labels.switch_off_all() + if xray_long < 1e-5 and xray_long != -1.00e+05: + self._switchable_r_labels.switch_on(self._owner.r0_now_lbl) + elif xray_long >= 1e-5 and xray_long < 5e-5: + self._switchable_r_labels.switch_on(self._owner.r1_now_lbl) + elif xray_long >= 5e-5 and xray_long < 1e-4: + self._switchable_r_labels.switch_on(self._owner.r2_now_lbl) + elif xray_long >= 1e-4 and xray_long < 1e-3: + self._switchable_r_labels.switch_on(self._owner.r3_now_lbl) + elif xray_long >= 1e-3 and xray_long < 2e-3: + self._switchable_r_labels.switch_on(self._owner.r4_now_lbl) + elif xray_long >= 2e-3: + self._switchable_r_labels.switch_on(self._owner.r5_now_lbl) + elif xray_long == -1.00e+05: + self._switchable_r_labels.switch_off_all() - pro10 = safe_cast(self._owner.space_weather_data.prot_el[-1][8], float) - if pro10 < 10 and pro10 != -1.00e+05: - self._switchable_s_labels.switch_on(self._owner.s0_now_lbl) - elif pro10 >= 10 and pro10 < 100: - self._switchable_s_labels.switch_on(self._owner.s1_now_lbl) - elif pro10 >= 100 and pro10 < 1000: - self._switchable_s_labels.switch_on(self._owner.s2_now_lbl) - elif pro10 >= 1000 and pro10 < 10000: - self._switchable_s_labels.switch_on(self._owner.s3_now_lbl) - elif pro10 >= 10000 and pro10 < 100000: - self._switchable_s_labels.switch_on(self._owner.s4_now_lbl) - elif pro10 >= 100000: - self._switchable_s_labels.switch_on(self._owner.s5_now_lbl) - elif pro10 == -1.00e+05: - self._switchable_s_labels.switch_off_all() + pro10 = float(self._owner.space_weather_data.prot_el) + if pro10 < 10 and pro10 != -1.00e+05: + self._switchable_s_labels.switch_on(self._owner.s0_now_lbl) + elif pro10 >= 10 and pro10 < 100: + self._switchable_s_labels.switch_on(self._owner.s1_now_lbl) + elif pro10 >= 100 and pro10 < 1000: + self._switchable_s_labels.switch_on(self._owner.s2_now_lbl) + elif pro10 >= 1000 and pro10 < 10000: + self._switchable_s_labels.switch_on(self._owner.s3_now_lbl) + elif pro10 >= 10000 and pro10 < 100000: + self._switchable_s_labels.switch_on(self._owner.s4_now_lbl) + elif pro10 >= 100000: + self._switchable_s_labels.switch_on(self._owner.s5_now_lbl) + elif pro10 == -1.00e+05: + self._switchable_s_labels.switch_off_all() - k_index = safe_cast( - self._owner.space_weather_data.ak_index[8][11].replace('.', ''), int - ) - self._owner.k_index_lbl.setText(str(k_index)) - a_index = safe_cast( - self._owner.space_weather_data.ak_index[7][7].replace('.', ''), int - ) - self._owner.a_index_lbl.setText(str(a_index)) + k_index = int(self._owner.space_weather_data.ak_index[8][11].replace('.', '')) + self._owner.k_index_lbl.setText(str(k_index)) + a_index = int(self._owner.space_weather_data.ak_index[7][7].replace('.', '')) + self._owner.a_index_lbl.setText(str(a_index)) - if k_index == 0: - self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_inactive_lbl) - self._owner.expected_noise_lbl.setText(" S0 - S1 (<-120 dBm) ") - elif k_index == 1: - self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_very_quiet_lbl) - self._owner.expected_noise_lbl.setText(" S0 - S1 (<-120 dBm) ") - elif k_index == 2: - self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_quiet_lbl) - self._owner.expected_noise_lbl.setText(" S1 - S2 (-115 dBm) ") - elif k_index == 3: - self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_unsettled_lbl) - self._owner.expected_noise_lbl.setText(" S2 - S3 (-110 dBm) ") - elif k_index == 4: - self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_active_lbl) - self._owner.expected_noise_lbl.setText(" S3 - S4 (-100 dBm) ") - elif k_index == 5: - self._switchable_g_now_labels.switch_on(self._owner.g1_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_min_storm_lbl) - self._owner.expected_noise_lbl.setText(" S4 - S6 (-90 dBm) ") - elif k_index == 6: - self._switchable_g_now_labels.switch_on(self._owner.g2_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_maj_storm_lbl) - self._owner.expected_noise_lbl.setText(" S6 - S9 (-80 dBm) ") - elif k_index == 7: - self._switchable_g_now_labels.switch_on(self._owner.g3_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_sev_storm_lbl) - self._owner.expected_noise_lbl.setText(" S9 - S20 (>-60 dBm) ") - elif k_index == 8: - self._switchable_g_now_labels.switch_on(self._owner.g4_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_very_sev_storm_lbl) - self._owner.expected_noise_lbl.setText(" S20 - S30 (>-60 dBm) ") - elif k_index == 9: - self._switchable_g_now_labels.switch_on(self._owner.g5_now_lbl) - self._k_storm_labels.switch_on(self._owner.k_ex_sev_storm_lbl) - self._owner.expected_noise_lbl.setText(" S30+ (>>-60 dBm) ") - self._owner.expected_noise_lbl.switch_on() + if k_index == 0: + self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_inactive_lbl) + self._owner.expected_noise_lbl.setText(" S0 - S1 (<-120 dBm) ") + elif k_index == 1: + self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_very_quiet_lbl) + self._owner.expected_noise_lbl.setText(" S0 - S1 (<-120 dBm) ") + elif k_index == 2: + self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_quiet_lbl) + self._owner.expected_noise_lbl.setText(" S1 - S2 (-115 dBm) ") + elif k_index == 3: + self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_unsettled_lbl) + self._owner.expected_noise_lbl.setText(" S2 - S3 (-110 dBm) ") + elif k_index == 4: + self._switchable_g_now_labels.switch_on(self._owner.g0_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_active_lbl) + self._owner.expected_noise_lbl.setText(" S3 - S4 (-100 dBm) ") + elif k_index == 5: + self._switchable_g_now_labels.switch_on(self._owner.g1_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_min_storm_lbl) + self._owner.expected_noise_lbl.setText(" S4 - S6 (-90 dBm) ") + elif k_index == 6: + self._switchable_g_now_labels.switch_on(self._owner.g2_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_maj_storm_lbl) + self._owner.expected_noise_lbl.setText(" S6 - S9 (-80 dBm) ") + elif k_index == 7: + self._switchable_g_now_labels.switch_on(self._owner.g3_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_sev_storm_lbl) + self._owner.expected_noise_lbl.setText(" S9 - S20 (>-60 dBm) ") + elif k_index == 8: + self._switchable_g_now_labels.switch_on(self._owner.g4_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_very_sev_storm_lbl) + self._owner.expected_noise_lbl.setText(" S20 - S30 (>-60 dBm) ") + elif k_index == 9: + self._switchable_g_now_labels.switch_on(self._owner.g5_now_lbl) + self._k_storm_labels.switch_on(self._owner.k_ex_sev_storm_lbl) + self._owner.expected_noise_lbl.setText(" S30+ (>>-60 dBm) ") + self._owner.expected_noise_lbl.switch_on() - if a_index >= 0 and a_index < 8: - self._a_storm_labels.switch_on(self._owner.a_quiet_lbl) - elif a_index >= 8 and a_index < 16: - self._a_storm_labels.switch_on(self._owner.a_unsettled_lbl) - elif a_index >= 16 and a_index < 30: - self._a_storm_labels.switch_on(self._owner.a_active_lbl) - elif a_index >= 30 and a_index < 50: - self._a_storm_labels.switch_on(self._owner.a_min_storm_lbl) - elif a_index >= 50 and a_index < 100: - self._a_storm_labels.switch_on(self._owner.a_maj_storm_lbl) - elif a_index >= 100 and a_index < 400: - self._a_storm_labels.switch_on(self._owner.a_sev_storm_lbl) + if a_index >= 0 and a_index < 8: + self._a_storm_labels.switch_on(self._owner.a_quiet_lbl) + elif a_index >= 8 and a_index < 16: + self._a_storm_labels.switch_on(self._owner.a_unsettled_lbl) + elif a_index >= 16 and a_index < 30: + self._a_storm_labels.switch_on(self._owner.a_active_lbl) + elif a_index >= 30 and a_index < 50: + self._a_storm_labels.switch_on(self._owner.a_min_storm_lbl) + elif a_index >= 50 and a_index < 100: + self._a_storm_labels.switch_on(self._owner.a_maj_storm_lbl) + elif a_index >= 100 and a_index < 400: + self._a_storm_labels.switch_on(self._owner.a_sev_storm_lbl) - index = self._owner.space_weather_data.geo_storm[6].index("was") + 1 - k_index_24_hmax = safe_cast( - self._owner.space_weather_data.geo_storm[6][index], int - ) - if k_index_24_hmax == 0: - self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) - elif k_index_24_hmax == 1: - self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) - elif k_index_24_hmax == 2: - self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) - elif k_index_24_hmax == 3: - self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) - elif k_index_24_hmax == 4: - self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) - elif k_index_24_hmax == 5: - self._switchable_g_today_labels.switch_on(self._owner.g1_today_lbl) - elif k_index_24_hmax == 6: - self._switchable_g_today_labels.switch_on(self._owner.g2_today_lbl) - elif k_index_24_hmax == 7: - self._switchable_g_today_labels.switch_on(self._owner.g3_today_lbl) - elif k_index_24_hmax == 8: - self._switchable_g_today_labels.switch_on(self._owner.g4_today_lbl) - elif k_index_24_hmax == 9: - self._switchable_g_today_labels.switch_on(self._owner.g5_today_lbl) + index = self._owner.space_weather_data.geo_storm[6].index("was") + 1 + k_index_24_hmax = int(self._owner.space_weather_data.geo_storm[6][index]) + if k_index_24_hmax == 0: + self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) + elif k_index_24_hmax == 1: + self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) + elif k_index_24_hmax == 2: + self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) + elif k_index_24_hmax == 3: + self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) + elif k_index_24_hmax == 4: + self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl) + elif k_index_24_hmax == 5: + self._switchable_g_today_labels.switch_on(self._owner.g1_today_lbl) + elif k_index_24_hmax == 6: + self._switchable_g_today_labels.switch_on(self._owner.g2_today_lbl) + elif k_index_24_hmax == 7: + self._switchable_g_today_labels.switch_on(self._owner.g3_today_lbl) + elif k_index_24_hmax == 8: + self._switchable_g_today_labels.switch_on(self._owner.g4_today_lbl) + elif k_index_24_hmax == 9: + self._switchable_g_today_labels.switch_on(self._owner.g5_today_lbl) - val = safe_cast( - self._owner.space_weather_data.ak_index[7][2].replace('.', ''), int - ) - self._owner.sfi_lbl.setText(f"{val}") - val = safe_cast( - [x[4] for x in self._owner.space_weather_data.sgas - if "SSN" in x][0], int - ) - self._owner.sn_lbl.setText(f"{val:d}") + val = int(self._owner.space_weather_data.ak_index[7][2].replace('.', '')) + self._owner.sfi_lbl.setText(f"{val}") + val = int( + [x[4] for x in self._owner.space_weather_data.sgas if "SSN" in x][0] + ) + self._owner.sn_lbl.setText(f"{val:d}") + + for label, pixmap in zip(self.space_weather_labels, + self._owner.space_weather_data.images): + label.pixmap = pixmap + label.make_transparent() + label.apply_pixmap() + except Exception as e: # This is a mess, so log an error and give up + logging.error(f"Forecast update failure: {e}") + pop_up( + self._owner, + title=Messages.SCREEN_UPDATE_FAIL, + text=Messages.SCREEN_UPDATE_FAIL_MSG + ).show() - for label, pixmap in zip(self.space_weather_labels, - self._owner.space_weather_data.images): - label.pixmap = pixmap - label.make_transparent() - label.apply_pixmap() elif not self._owner.closing: pop_up(self._owner, title=Messages.BAD_DOWNLOAD, text=Messages.BAD_DOWNLOAD_MSG).show() diff --git a/src/threads.py b/src/threads.py index 10dd55c..f413023 100644 --- a/src/threads.py +++ b/src/threads.py @@ -7,7 +7,7 @@ from time import perf_counter import aiohttp from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot from constants import Constants -from utilities import checksum_ok +from utilities import checksum_ok, get_file_extension from web_utilities import ( get_cacert_file, get_pool_manager, @@ -234,7 +234,7 @@ class UpdateSpaceWeatherThread(BaseDownloadThread): """Download the data conteining the information of a specific property.""" link = getattr(Constants, "SPACE_WEATHER_" + property_name.upper()) data = await _download_resource(session, link) - setattr(self._space_weather_data, property_name, str(data, 'utf-8')) + self._space_weather_data.set_property(property_name, data, get_file_extension(link)) async def _download_image(self, session, n): """Download the data corresponding the n-th image displayed in the screen.""" diff --git a/src/utilities.py b/src/utilities.py index e860c3a..111a103 100644 --- a/src/utilities.py +++ b/src/utilities.py @@ -197,3 +197,21 @@ def safe_cast(value, cast_type, default=-1): r = default finally: return r + + +def get_file_extension(file): + """Return the extension of a file. Return None if there is not such property.""" + components = file.split('.') + if len(components) > 1: + return components[-1] + return None + + +def get_value_from_list_of_dicts(iterable, callable_ok, key_value): + """Return a value from a dict inside a list of dicts. + + The iterable is reversed first, then the value corresponding to the key key_value + is returned from the first dict for which callable_ok(dict) returns True""" + for d in reversed(iterable): + if callable_ok(d): + return d[key_value] diff --git a/src/weatherdata.py b/src/weatherdata.py index 0b562dc..cf1ad00 100644 --- a/src/weatherdata.py +++ b/src/weatherdata.py @@ -1,4 +1,5 @@ import logging +import json import re from PyQt5.QtGui import QPixmap from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject @@ -10,7 +11,7 @@ from threads import ( ) from constants import Constants from switchable_label import MultiColorSwitchableLabel -from utilities import safe_cast +from utilities import safe_cast, get_value_from_list_of_dicts class _BaseWeatherData(QObject): @@ -90,11 +91,34 @@ class SpaceWeatherData(_BaseWeatherData): """Override _BaseWeatherData._parse_data. Set all the data.""" - self.xray = self._double_split(self.xray) - self.prot_el = self._double_split(self.prot_el) - self.ak_index = self._double_split(self.ak_index) - self.sgas = self._double_split(self.sgas) - self.geo_storm = self._double_split(self.geo_storm) + if self.xray is not None: + self.xray = get_value_from_list_of_dicts( + self.xray, + lambda d: d["energy"] == "0.1-0.8nm", + "flux" + ) + if self.prot_el is not None: + self.prot_el = get_value_from_list_of_dicts( + self.prot_el, + lambda d: d["energy"] == ">=10 MeV", + "flux" + ) + if self.ak_index is not None: + self.ak_index = self._double_split(self.ak_index) + if self.sgas is not None: + self.sgas = self._double_split(self.sgas) + if self.geo_storm is not None: + self.geo_storm = self._double_split(self.geo_storm) + + def set_property(self, property_name, data, extension): + """Set a property to the object. Format the data based on the extension.""" + if extension == 'txt': + setattr(self, property_name, str(data, 'utf-8')) + elif extension == 'json': + setattr(self, property_name, json.loads(data)) + else: + logging.error("Invalid file extension") + setattr(self, property_name, None) def remove_data(self): """Remove the reference to all the data."""