Close #21 Some forecast data has benn changed to json in the download site.
Such cases are now handled
This commit is contained in:
@@ -64,7 +64,7 @@ import loggingconf # noqa 401
|
|||||||
# import default_imgs_rc
|
# import default_imgs_rc
|
||||||
|
|
||||||
|
|
||||||
__LATEST_VERSION__ = "3.2.0"
|
__LATEST_VERSION__ = "3.2.1"
|
||||||
|
|
||||||
if IS_BINARY:
|
if IS_BINARY:
|
||||||
__VERSION__ = __LATEST_VERSION__
|
__VERSION__ = __LATEST_VERSION__
|
||||||
|
|||||||
@@ -113,8 +113,8 @@ class Constants:
|
|||||||
UPDATING_STR = "Updating..."
|
UPDATING_STR = "Updating..."
|
||||||
ACF_DOCS = "https://aresvalley.com/documentation/"
|
ACF_DOCS = "https://aresvalley.com/documentation/"
|
||||||
FORECAST_PROBABILITIES = "https://services.swpc.noaa.gov/text/sgarf.txt"
|
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_XRAY = "https://services.swpc.noaa.gov/json/goes/primary/xrays-1-day.json"
|
||||||
SPACE_WEATHER_PROT_EL = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt"
|
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_AK_INDEX = "https://services.swpc.noaa.gov/text/wwv.txt"
|
||||||
SPACE_WEATHER_SGAS = "https://services.swpc.noaa.gov/text/sgas.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"
|
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_AVAILABLE = "New software version"
|
||||||
NEW_VERSION_MSG = lambda v: f"The software version {v} is available." # noqa: E731
|
NEW_VERSION_MSG = lambda v: f"The software version {v} is available." # noqa: E731
|
||||||
DOWNLOAD_SUGG_MSG = "Download new version now?"
|
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:
|
class ThemeConstants:
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ import logging.config
|
|||||||
from constants import __BASE_FOLDER__
|
from constants import __BASE_FOLDER__
|
||||||
import os.path
|
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 = {
|
_LOGGING_CONFIG = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'formatters': {
|
'formatters': {
|
||||||
'general': {
|
'general': {
|
||||||
'format': '%(asctime)s::%(levelname)s::%(module)s::%(funcName)s::%(message)s',
|
'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': {
|
'handlers': {
|
||||||
'console': {
|
'console': {
|
||||||
@@ -26,20 +29,15 @@ _LOGGING_CONFIG = {
|
|||||||
'filename': os.path.join(__BASE_FOLDER__, 'info.log'),
|
'filename': os.path.join(__BASE_FOLDER__, 'info.log'),
|
||||||
'mode': 'w',
|
'mode': 'w',
|
||||||
'encoding': 'utf8',
|
'encoding': 'utf8',
|
||||||
'formatter': 'general'
|
'formatter': 'general',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
'root': {
|
'root': {
|
||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
'handlers': ['console', 'file']
|
'handlers': ['console', 'file'],
|
||||||
},
|
},
|
||||||
'loggers': {
|
# Add loggers if required
|
||||||
'root.sublogger': {
|
# 'loggers': {}
|
||||||
'propagate': False,
|
|
||||||
'level': 'DEBUG',
|
|
||||||
'handlers': ['console', 'file']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.config.dictConfig(_LOGGING_CONFIG)
|
logging.config.dictConfig(_LOGGING_CONFIG)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import logging
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from PyQt5.QtCore import QObject, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtSlot
|
||||||
from constants import Constants, Messages
|
from constants import Constants, Messages
|
||||||
from switchable_label import SwitchableLabelsIterable
|
from switchable_label import SwitchableLabelsIterable
|
||||||
from weatherdata import SpaceWeatherData
|
from weatherdata import SpaceWeatherData
|
||||||
from utilities import safe_cast, pop_up
|
from utilities import pop_up
|
||||||
|
|
||||||
|
|
||||||
class SpaceWeatherManager(QObject):
|
class SpaceWeatherManager(QObject):
|
||||||
@@ -136,7 +137,8 @@ class SpaceWeatherManager(QObject):
|
|||||||
"""
|
"""
|
||||||
self._owner.update_now_bar.set_idle()
|
self._owner.update_now_bar.set_idle()
|
||||||
if status_ok:
|
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):
|
def format_text(letter, power):
|
||||||
return letter + f"{xray_long * 10**power:.1f}"
|
return letter + f"{xray_long * 10**power:.1f}"
|
||||||
@@ -171,7 +173,7 @@ class SpaceWeatherManager(QObject):
|
|||||||
elif xray_long == -1.00e+05:
|
elif xray_long == -1.00e+05:
|
||||||
self._switchable_r_labels.switch_off_all()
|
self._switchable_r_labels.switch_off_all()
|
||||||
|
|
||||||
pro10 = safe_cast(self._owner.space_weather_data.prot_el[-1][8], float)
|
pro10 = float(self._owner.space_weather_data.prot_el)
|
||||||
if pro10 < 10 and pro10 != -1.00e+05:
|
if pro10 < 10 and pro10 != -1.00e+05:
|
||||||
self._switchable_s_labels.switch_on(self._owner.s0_now_lbl)
|
self._switchable_s_labels.switch_on(self._owner.s0_now_lbl)
|
||||||
elif pro10 >= 10 and pro10 < 100:
|
elif pro10 >= 10 and pro10 < 100:
|
||||||
@@ -187,13 +189,9 @@ class SpaceWeatherManager(QObject):
|
|||||||
elif pro10 == -1.00e+05:
|
elif pro10 == -1.00e+05:
|
||||||
self._switchable_s_labels.switch_off_all()
|
self._switchable_s_labels.switch_off_all()
|
||||||
|
|
||||||
k_index = safe_cast(
|
k_index = int(self._owner.space_weather_data.ak_index[8][11].replace('.', ''))
|
||||||
self._owner.space_weather_data.ak_index[8][11].replace('.', ''), int
|
|
||||||
)
|
|
||||||
self._owner.k_index_lbl.setText(str(k_index))
|
self._owner.k_index_lbl.setText(str(k_index))
|
||||||
a_index = safe_cast(
|
a_index = int(self._owner.space_weather_data.ak_index[7][7].replace('.', ''))
|
||||||
self._owner.space_weather_data.ak_index[7][7].replace('.', ''), int
|
|
||||||
)
|
|
||||||
self._owner.a_index_lbl.setText(str(a_index))
|
self._owner.a_index_lbl.setText(str(a_index))
|
||||||
|
|
||||||
if k_index == 0:
|
if k_index == 0:
|
||||||
@@ -252,9 +250,7 @@ class SpaceWeatherManager(QObject):
|
|||||||
self._a_storm_labels.switch_on(self._owner.a_sev_storm_lbl)
|
self._a_storm_labels.switch_on(self._owner.a_sev_storm_lbl)
|
||||||
|
|
||||||
index = self._owner.space_weather_data.geo_storm[6].index("was") + 1
|
index = self._owner.space_weather_data.geo_storm[6].index("was") + 1
|
||||||
k_index_24_hmax = safe_cast(
|
k_index_24_hmax = int(self._owner.space_weather_data.geo_storm[6][index])
|
||||||
self._owner.space_weather_data.geo_storm[6][index], int
|
|
||||||
)
|
|
||||||
if k_index_24_hmax == 0:
|
if k_index_24_hmax == 0:
|
||||||
self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl)
|
self._switchable_g_today_labels.switch_on(self._owner.g0_today_lbl)
|
||||||
elif k_index_24_hmax == 1:
|
elif k_index_24_hmax == 1:
|
||||||
@@ -276,13 +272,10 @@ class SpaceWeatherManager(QObject):
|
|||||||
elif k_index_24_hmax == 9:
|
elif k_index_24_hmax == 9:
|
||||||
self._switchable_g_today_labels.switch_on(self._owner.g5_today_lbl)
|
self._switchable_g_today_labels.switch_on(self._owner.g5_today_lbl)
|
||||||
|
|
||||||
val = safe_cast(
|
val = int(self._owner.space_weather_data.ak_index[7][2].replace('.', ''))
|
||||||
self._owner.space_weather_data.ak_index[7][2].replace('.', ''), int
|
|
||||||
)
|
|
||||||
self._owner.sfi_lbl.setText(f"{val}")
|
self._owner.sfi_lbl.setText(f"{val}")
|
||||||
val = safe_cast(
|
val = int(
|
||||||
[x[4] for x in self._owner.space_weather_data.sgas
|
[x[4] for x in self._owner.space_weather_data.sgas if "SSN" in x][0]
|
||||||
if "SSN" in x][0], int
|
|
||||||
)
|
)
|
||||||
self._owner.sn_lbl.setText(f"{val:d}")
|
self._owner.sn_lbl.setText(f"{val:d}")
|
||||||
|
|
||||||
@@ -291,6 +284,14 @@ class SpaceWeatherManager(QObject):
|
|||||||
label.pixmap = pixmap
|
label.pixmap = pixmap
|
||||||
label.make_transparent()
|
label.make_transparent()
|
||||||
label.apply_pixmap()
|
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()
|
||||||
|
|
||||||
elif not self._owner.closing:
|
elif not self._owner.closing:
|
||||||
pop_up(self._owner, title=Messages.BAD_DOWNLOAD,
|
pop_up(self._owner, title=Messages.BAD_DOWNLOAD,
|
||||||
text=Messages.BAD_DOWNLOAD_MSG).show()
|
text=Messages.BAD_DOWNLOAD_MSG).show()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from time import perf_counter
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot
|
||||||
from constants import Constants
|
from constants import Constants
|
||||||
from utilities import checksum_ok
|
from utilities import checksum_ok, get_file_extension
|
||||||
from web_utilities import (
|
from web_utilities import (
|
||||||
get_cacert_file,
|
get_cacert_file,
|
||||||
get_pool_manager,
|
get_pool_manager,
|
||||||
@@ -234,7 +234,7 @@ class UpdateSpaceWeatherThread(BaseDownloadThread):
|
|||||||
"""Download the data conteining the information of a specific property."""
|
"""Download the data conteining the information of a specific property."""
|
||||||
link = getattr(Constants, "SPACE_WEATHER_" + property_name.upper())
|
link = getattr(Constants, "SPACE_WEATHER_" + property_name.upper())
|
||||||
data = await _download_resource(session, link)
|
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):
|
async def _download_image(self, session, n):
|
||||||
"""Download the data corresponding the n-th image displayed in the screen."""
|
"""Download the data corresponding the n-th image displayed in the screen."""
|
||||||
|
|||||||
@@ -197,3 +197,21 @@ def safe_cast(value, cast_type, default=-1):
|
|||||||
r = default
|
r = default
|
||||||
finally:
|
finally:
|
||||||
return r
|
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]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
|
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
|
||||||
@@ -10,7 +11,7 @@ from threads import (
|
|||||||
)
|
)
|
||||||
from constants import Constants
|
from constants import Constants
|
||||||
from switchable_label import MultiColorSwitchableLabel
|
from switchable_label import MultiColorSwitchableLabel
|
||||||
from utilities import safe_cast
|
from utilities import safe_cast, get_value_from_list_of_dicts
|
||||||
|
|
||||||
|
|
||||||
class _BaseWeatherData(QObject):
|
class _BaseWeatherData(QObject):
|
||||||
@@ -90,12 +91,35 @@ class SpaceWeatherData(_BaseWeatherData):
|
|||||||
"""Override _BaseWeatherData._parse_data.
|
"""Override _BaseWeatherData._parse_data.
|
||||||
|
|
||||||
Set all the data."""
|
Set all the data."""
|
||||||
self.xray = self._double_split(self.xray)
|
if self.xray is not None:
|
||||||
self.prot_el = self._double_split(self.prot_el)
|
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)
|
self.ak_index = self._double_split(self.ak_index)
|
||||||
|
if self.sgas is not None:
|
||||||
self.sgas = self._double_split(self.sgas)
|
self.sgas = self._double_split(self.sgas)
|
||||||
|
if self.geo_storm is not None:
|
||||||
self.geo_storm = self._double_split(self.geo_storm)
|
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):
|
def remove_data(self):
|
||||||
"""Remove the reference to all the data."""
|
"""Remove the reference to all the data."""
|
||||||
self.xray = ''
|
self.xray = ''
|
||||||
|
|||||||
Reference in New Issue
Block a user