Description: Fixes crash after changes of the received data (xml structure) * backported from current upstream * some minor string changes * reflect changed openweathermap datastructure * fix crash when wind direction is not available * shows UV when available * handle download errors and missing values * fix logging handling * fix crash when 6 days forcast is not available * fix crash if applying settings and start minimized * catch unhandled exceptions and write them into log file * fix crash when UV index has two decimals
Author: Alf Gaida <aga...@siduction.org> --- Bug-Debian: https://bugs.debian.org/939651 Forwarded: not-needed Last-Update: 2019-09-07 --- meteo-qt-1.0.0.orig/CHANGELOG +++ meteo-qt-1.0.0/CHANGELOG @@ -1,3 +1,11 @@ +1.1 +- Option to show the window at start-up +- Fixes for crashes +- Show wind info when Bft unit option is unchecked +- Use unicode arrows for hPa and T° trend +- Wrap weather information of the day on panel +- Update translations [German, Slovak, Czech] + 1.0.0 - Automatic detection of the geolocation - Reenable UV Ozone in weather information --- meteo-qt-1.0.0.orig/meteo_qt/about_dlg.py +++ meteo-qt-1.0.0/meteo_qt/about_dlg.py @@ -102,7 +102,8 @@ class AboutDialog(QDialog): '', '<p>werthad <a href="mailto:wert...@gmail.com">' 'wert...@gmail.com</a>' - '<br/> [hu] Hungarian translation', '' + '<br/> [hu] Hungarian translation', + '' ) + QCoreApplication.translate( '', @@ -129,27 +130,44 @@ class AboutDialog(QDialog): '<a href="mailto:rw4...@yandex.ru">rw4...@yandex.ru</a>' '<br/>Alexey Zakaldaev ' '<a href="mailto:nelex...@gmail.com">nelex...@gmail.com</a>' - '<br/>Liliya Panova<br/> [ru] Russian translation', '' + '<br/>Liliya Panova<br/> [ru] Russian translation', + '' + ) + + QCoreApplication.translate( + '', + '<p>jose1711 ' + '<a href="mailto:jose1...@gmail.com">' + 'jose1...@gmail.com</a>' + '<br> [sk] Slovak translation, Project', + '' ) + QCoreApplication.translate( '', '<p>Atilla Öntaş ' '<a href="mailto:tarakbu...@gmail.com">' 'tarakbu...@gmail.com</a>' - '<br/> [tr] Turkish translation', '' + '<br/> [tr] Turkish translation', + '' ) + QCoreApplication.translate( '', '<p>Yuri Chornoivan ' '<a href="mailto:yurc...@ukr.net">yurc...@ukr.net</a>' - '<br/> [uk] Ukrainian translation', '' + '<br/> [uk] Ukrainian translation', + '' ) + QCoreApplication.translate( '', '<p>You-Cheng Hsieh ' '<a href="mailto:yochenhs...@gmail.com">' 'yochenhs...@gmail.com</a>' - '<br/> [zh_TW] Chinese (Taiwan) translation', '' + '<br/> [zh_TW] Chinese (Taiwan) translation', + '' + ) + + QCoreApplication.translate( + '', + '<p>pmav99<br/> Project', + '' ) - + QCoreApplication.translate('', '<p>pmav99<br/> Project', '')) + ) return contributors --- meteo-qt-1.0.0.orig/meteo_qt/citylistdlg.py +++ meteo-qt-1.0.0/meteo_qt/citylistdlg.py @@ -127,7 +127,7 @@ class CityListDlg(QDialog): QCoreApplication.translate( 'Message when trying to remove the' 'last and unique city in the list', - 'This is the default city !', + 'This is the default city!', 'Cities list dialogue' ) ) --- meteo-qt-1.0.0.orig/meteo_qt/meteo_qt.py +++ meteo-qt-1.0.0/meteo_qt/meteo_qt.py @@ -17,6 +17,9 @@ from lxml import etree import json import time import datetime +import traceback +from io import StringIO +import gc from PyQt5.QtCore import ( PYQT_VERSION_STR, QT_VERSION_STR, QCoreApplication, QByteArray, @@ -143,17 +146,6 @@ class SystemTrayIcon(QMainWindow): # The traycolor has to be initialized here for the case when we cannot # reach the tray method (case: set the color at first time usage) self.traycolor = '' - self.refresh() - - def overviewcity(self): - temp_trend = '' - if self.temp_trend == " ↗": - temp_trend = " " - elif self.temp_trend == " ↘": - temp_trend = "" - - self.overviewcitydlg = QDialog() - self.setCentralWidget(self.overviewcitydlg) self.days_dico = {'0': self.tr('Mon'), '1': self.tr('Tue'), '2': self.tr('Wed'), @@ -169,14 +161,21 @@ class SystemTrayIcon(QMainWindow): self.hpa_indications = self.cond.pressure self.uv_risk = self.cond.uv_risk self.uv_recommend = self.cond.uv_recommend + + self.refresh() + + def overviewcity(self): + self.overviewcitydlg = QDialog() + self.setCentralWidget(self.overviewcitydlg) self.forecast_weather_list = [] self.dayforecast_weather_list = [] self.icon_list = [] self.dayforecast_icon_list = [] self.unit_temp = self.units_dico[self.unit] - self.total_layout = QVBoxLayout() + total_layout = QVBoxLayout() + # ----First part overview day ----- - self.over_layout = QVBoxLayout() + over_layout = QVBoxLayout() self.dayforecast_layout = QHBoxLayout() self.dayforecast_temp_layout = QHBoxLayout() # Check for city translation @@ -197,27 +196,28 @@ class SystemTrayIcon(QMainWindow): self.city_label = QLabel( '<font size="4"><b>' + city_label + '<\b><\font>' ) - self.over_layout.addWidget(self.city_label) - self.icontemp_layout = QHBoxLayout() - self.icon_label = QLabel() - self.icon_label.setPixmap(self.wIcon) - self.icontemp_layout.addWidget(self.icon_label) - self.temp_label = QLabel( + over_layout.addWidget(self.city_label) + icontemp_layout = QHBoxLayout() + icon_label = QLabel() + icon_label.setPixmap(self.wIcon) + icontemp_layout.addWidget(icon_label) + temp_label = QLabel( '<font size="5"><b>' + '{0:.1f}' .format(float(self.weatherDataDico['Temp'][:-1])) + ' ' - + self.unit_temp + temp_trend + '<\b><\font>' + + self.unit_temp + self.temp_trend + '<\b><\font>' ) - self.icontemp_layout.addWidget(self.temp_label) - self.over_layout.addLayout(self.icontemp_layout) - self.weather = QLabel( + icontemp_layout.addWidget(temp_label) + over_layout.addLayout(icontemp_layout) + weather = QLabel( '<font size="4"><b>' + self.weatherDataDico['Meteo'] + '<\b><\font>' ) - self.icontemp_layout.addWidget(self.weather) - self.icontemp_layout.addStretch() - self.over_layout.addLayout(self.dayforecast_layout) - self.over_layout.addLayout(self.dayforecast_temp_layout) + weather.setWordWrap(True) + icontemp_layout.addWidget(weather) + icontemp_layout.addStretch() + over_layout.addLayout(self.dayforecast_layout) + over_layout.addLayout(self.dayforecast_temp_layout) # ------Second part overview day--------- self.over_grid = QGridLayout() # Wind @@ -233,20 +233,23 @@ class SystemTrayIcon(QMainWindow): if wind_unit == 'imperial': self.unit_system = ' mph ' self.unit_system_wind = ' mph ' - self.windLabelDescr = QLabel('None') + windLabelDescr = QLabel('None') wind_speed = '{0:.1f}'.format(float(self.weatherDataDico['Wind'][0])) windTobeaufort = str(self.convertToBeaufort(wind_speed)) if self.bft_bool is True: wind_speed = windTobeaufort - self.unit_system_wind = ' Bft. ' + unit_system_wind = ' Bft. ' + else: + unit_system_wind = self.unit_system_wind + try: - self.windLabelDescr = QLabel( + windLabelDescr = QLabel( '<font color=>' + self.weatherDataDico['Wind'][4] + ' ' + self.weatherDataDico['Wind'][2] + '° ' + '<br/>' - + wind_speed + self.unit_system_wind + + wind_speed + unit_system_wind + self.weatherDataDico['Wind'][1] + '<\font>' ) - self.windLabelDescr.setToolTip( + windLabelDescr.setToolTip( self.beaufort_sea_land[windTobeaufort] ) except: @@ -262,7 +265,7 @@ class SystemTrayIcon(QMainWindow): self.clouds_label = QLabel( '<font size="3" color=><b>' + self.tr('Cloudiness') + '<\b><\font>' ) - self.clouds_name = QLabel( + clouds_name = QLabel( '<font color=>' + self.weatherDataDico['Clouds'] + '<\font>' ) # Pressure @@ -270,26 +273,26 @@ class SystemTrayIcon(QMainWindow): '<font size="3" color=><b>' + self.tr('Pressure') + '<\b><\font>' ) if self.hPaTrend == 0: - hpa = "" + hpa = "→" elif self.hPaTrend < 0: - hpa = "" + hpa = "↘" elif self.hPaTrend > 0: - hpa = "" - self.pressure_value = QLabel( + hpa = "↗" + pressure_value = QLabel( '<font color=>' + str(float(self.weatherDataDico['Pressure'][0])) + ' ' + self.weatherDataDico['Pressure'][1] + " " + hpa + '<\font>' ) - self.pressure_value.setToolTip(self.hpa_indications['hpa']) + pressure_value.setToolTip(self.hpa_indications['hpa']) # Humidity self.humidity_label = QLabel( '<font size="3" color=><b>' + self.tr('Humidity') + '<\b><\font>' ) - self.humidity_value = QLabel( + humidity_value = QLabel( '<font color=>' + self.weatherDataDico['Humidity'][0] + ' ' + self.weatherDataDico['Humidity'][1] + '<\font>' ) # Precipitation - self.precipitation_label = QLabel( + precipitation_label = QLabel( '<font size="3" color=><b>' + QCoreApplication.translate( 'Precipitation type (no/rain/snow)', @@ -311,24 +314,24 @@ class SystemTrayIcon(QMainWindow): rain_value = "{0:.4f}".format(float(rain_value)) else: rain_value = "{0:.2f}".format(float(rain_value)) - self.precipitation_value = QLabel( + precipitation_value = QLabel( '<font color=>' + rain_mode + ' ' + rain_value + ' ' + rain_unit + '</font>' ) # Sunrise Sunset Daylight - self.sunrise_label = QLabel( + sunrise_label = QLabel( '<font color=><b>' + self.tr('Sunrise') + '</b></font>' ) - self.sunset_label = QLabel( + sunset_label = QLabel( '<font color=><b>' + self.tr('Sunset') + '</b></font>' ) rise_str = self.utc('Sunrise', 'weatherdata') set_str = self.utc('Sunset', 'weatherdata') - self.sunrise_value = QLabel( + sunrise_value = QLabel( '<font color=>' + rise_str[:-3] + '</font>' ) - self.sunset_value = QLabel('<font color=>' + set_str[:-3] + '</font>') - self.daylight_label = QLabel( + sunset_value = QLabel('<font color=>' + set_str[:-3] + '</font>') + daylight_label = QLabel( '<font color=><b>' + QCoreApplication.translate( 'Daylight duration', 'Daylight', @@ -337,7 +340,7 @@ class SystemTrayIcon(QMainWindow): + '</b></font>' ) daylight_value = self.daylight_delta(rise_str[:-3], set_str[:-3]) - self.daylight_value_label = QLabel( + daylight_value_label = QLabel( '<font color=>' + daylight_value + '</font>' ) # --UV--- @@ -374,32 +377,34 @@ class SystemTrayIcon(QMainWindow): self.ozone_value_label = QLabel() self.ozone_value_label.setText(fetching_text) self.over_grid.addWidget(self.wind_label, 0, 0) - self.over_grid.addWidget(self.windLabelDescr, 0, 1) + self.over_grid.addWidget(windLabelDescr, 0, 1) self.over_grid.addWidget(self.wind_icon_label, 0, 2) self.over_grid.addWidget(self.clouds_label, 1, 0) - self.over_grid.addWidget(self.clouds_name, 1, 1) + self.over_grid.addWidget(clouds_name, 1, 1) self.over_grid.addWidget(self.pressure_label, 2, 0) - self.over_grid.addWidget(self.pressure_value, 2, 1) + self.over_grid.addWidget(pressure_value, 2, 1) self.over_grid.addWidget(self.humidity_label, 3, 0) - self.over_grid.addWidget(self.humidity_value, 3, 1, 1, 3) # align left - self.over_grid.addWidget(self.precipitation_label, 4, 0) - self.over_grid.addWidget(self.precipitation_value, 4, 1) - self.over_grid.addWidget(self.sunrise_label, 5, 0) - self.over_grid.addWidget(self.sunrise_value, 5, 1) - self.over_grid.addWidget(self.sunset_label, 6, 0) - self.over_grid.addWidget(self.sunset_value, 6, 1) - self.over_grid.addWidget(self.daylight_label, 7, 0) - self.over_grid.addWidget(self.daylight_value_label, 7, 1) + self.over_grid.addWidget(humidity_value, 3, 1, 1, 3) # align left + self.over_grid.addWidget(precipitation_label, 4, 0) + self.over_grid.addWidget(precipitation_value, 4, 1) + self.over_grid.addWidget(sunrise_label, 5, 0) + self.over_grid.addWidget(sunrise_value, 5, 1) + self.over_grid.addWidget(sunset_label, 6, 0) + self.over_grid.addWidget(sunset_value, 6, 1) + self.over_grid.addWidget(daylight_label, 7, 0) + self.over_grid.addWidget(daylight_value_label, 7, 1) + self.over_grid.addWidget(self.uv_label, 8, 0) + self.over_grid.addWidget(self.uv_value_label, 8, 1) # -------------Forecast------------- self.forecast_days_layout = QHBoxLayout() self.forecast_icons_layout = QHBoxLayout() self.forecast_minmax_layout = QHBoxLayout() # ---------------------------------- - self.total_layout.addLayout(self.over_layout) - self.total_layout.addLayout(self.over_grid) - self.total_layout.addLayout(self.forecast_icons_layout) - self.total_layout.addLayout(self.forecast_days_layout) - self.total_layout.addLayout(self.forecast_minmax_layout) + total_layout.addLayout(over_layout) + total_layout.addLayout(self.over_grid) + total_layout.addLayout(self.forecast_icons_layout) + total_layout.addLayout(self.forecast_days_layout) + total_layout.addLayout(self.forecast_minmax_layout) if self.forcast6daysBool: self.forecast6data() @@ -416,10 +421,16 @@ class SystemTrayIcon(QMainWindow): self.ozone_fetch() logging.debug('Fetched ozone data') - self.overviewcitydlg.setLayout(self.total_layout) + self.overviewcitydlg.setLayout(total_layout) self.setWindowTitle(self.tr('Weather status')) self.restoreGeometry(self.settings.value("MainWindow/Geometry", QByteArray())) + ## Option to start with the panel closed, true by defaut + # starting with the panel open can be useful for users who don't have plasma + # installed (to set keyboard shortcuts or other default window behaviours) + start_minimized = self.settings.value('StartMinimized') or 'True' + if start_minimized == 'False': + self.showpanel() def daylight_delta(self, s1, s2): FMT = '%H:%M' @@ -520,8 +531,15 @@ class SystemTrayIcon(QMainWindow): return 12 def wind_icon_direction(self): - transf = QTransform() angle = self.weatherDataDico['Wind'][2] + if angle == '': + if self.wind_icon_label.isVisible is True: + self.wind_icon_label.hide() + return + else: + if self.wind_icon_label.isVisible is False: + self.wind_icon_label.show() + transf = QTransform() logging.debug('Wind degrees direction: ' + angle) transf.rotate(int(float(angle))) rotated = self.wind_icon.transformed( @@ -568,13 +586,13 @@ class SystemTrayIcon(QMainWindow): uv = float(uv) except: return ('grey', 'None') - if uv <= 2.9: + if uv <= 2.99: return ('green', 'Low') - elif uv <= 5.9: + elif uv <= 5.99: return ('yellow', 'Moderate') - elif uv <= 7.9: + elif uv <= 7.99: return ('orange', 'High') - elif uv <= 10.9: + elif uv <= 10.99: return ('red', 'Very high') elif uv >= 11: return ('purple', 'Extreme') @@ -633,106 +651,143 @@ class SystemTrayIcon(QMainWindow): fetched_file_periods = (len(self.forecast6_data.xpath('//time'))) if fetched_file_periods < periods: periods = fetched_file_periods - logging.warn('Reduce forecast for the next 6 days to {0}'.format( + logging.warning('Reduce forecast for the next 6 days to {0}'.format( periods - 1)) - for d in range(1, periods): - date_list = self.forecast6_data[4][d].get('day').split('-') - day_of_week = str(datetime.date( - int(date_list[0]), int(date_list[1]), - int(date_list[2])).weekday()) - label = QLabel('' + self.days_dico[day_of_week] + '') - label.setToolTip(self.forecast6_data[4][d].get('day')) - label.setAlignment(Qt.AlignHCenter) - self.forecast_days_layout.addWidget(label) - mlabel = QLabel( - '<font color=>' + '{0:.0f}' - .format(float(self.forecast6_data[4][d][4].get('min'))) - + '°<br/>' + '{0:.0f}' - .format(float(self.forecast6_data[4][d][4].get('max'))) - + '°</font>' - ) - mlabel.setAlignment(Qt.AlignHCenter) - mlabel.setToolTip(self.tr('Min Max Temperature of the day')) - self.forecast_minmax_layout.addWidget(mlabel) - # icon - self.icon_list.append(self.forecast6_data[4][d][0].get('var')) - weather_cond = self.forecast6_data[4][d][0].get('name') - try: - weather_cond = ( - self.conditions[self.forecast6_data[4][d][0].get('number')] - ) - except: - logging.warn( - 'Cannot find localisation string for :' - + weather_cond - ) - pass - try: - # Take the label translated text and remove the html tags - doc.setHtml(self.precipitation_label.text()) - precipitation_label = doc.toPlainText() + ': ' - precipitation_type = self.forecast6_data[4][d][1].get('type') - precipitation_type = ( - self.precipitation[precipitation_type] + ' ' - ) - precipitation_value = self.forecast6_data[4][d][1].get('value') - rain_unit = ' mm' - if self.unit_system == ' mph ': - rain_unit = ' inch' - precipitation_value = ( - str(float(precipitation_value) / 25.4) + ' ' + counter_day = 0 + forecast_data = False + + for element in self.forecast6_data.iter(): + + if element.tag == 'time': + forecast_data = True + if forecast_data is False: + continue + + if element.tag == 'time': + counter_day += 1 + if counter_day == periods: + break + + weather_end = False + date_list = element.get('day').split('-') + day_of_week = str(datetime.date( + int(date_list[0]), int(date_list[1]), + int(date_list[2])).weekday() + ) + label = QLabel('' + self.days_dico[day_of_week] + '') + label.setToolTip(element.get('day')) + label.setAlignment(Qt.AlignHCenter) + self.forecast_days_layout.addWidget(label) + + if element.tag == 'temperature': + mlabel = QLabel( + '<font color=>' + '{0:.0f}' + .format(float(element.get('min'))) + + '°<br/>' + '{0:.0f}' + .format(float(element.get('max'))) + + '°</font>' + ) + mlabel.setAlignment(Qt.AlignHCenter) + mlabel.setToolTip(self.tr('Min Max Temperature of the day')) + self.forecast_minmax_layout.addWidget(mlabel) + + if element.tag == 'symbol': + # icon + self.icon_list.append(element.get('var')) + weather_cond = element.get('name') + try: + weather_cond = ( + self.conditions[element.get('number')] ) - precipitation_value = ( - "{0:.2f}".format(float(precipitation_value)) + except KeyError: + logging.warning( + 'Cannot find localisation string for: ' + + weather_cond ) - else: - precipitation_value = ( - "{0:.1f}".format(float(precipitation_value)) + pass + + if element.tag == 'precipitation': + + try: + # Take the label translated text and remove the html tags + doc.setHtml(self.precipitation_label.text()) + precipitation_label = doc.toPlainText() + ': ' + precipitation_type = element.get('type') + precipitation_type = ( + self.precipitation[precipitation_type] + ' ' ) - weather_cond += ( - '\n' + precipitation_label + precipitation_type - + precipitation_value + rain_unit - ) - except: - pass - doc.setHtml(self.wind_label.text()) - wind = doc.toPlainText() + ': ' - try: - wind_direction = ( - self.wind_direction[ - self.forecast6_data[4][d][2].get('code') - ] + precipitation_value = element.get('value') + rain_unit = ' mm' + if self.unit_system == ' mph ': + rain_unit = ' inch' + precipitation_value = ( + str(float(precipitation_value) / 25.4) + ' ' + ) + precipitation_value = ( + "{0:.2f}".format(float(precipitation_value)) + ) + else: + precipitation_value = ( + "{0:.1f}".format(float(precipitation_value)) + ) + weather_cond += ( + '\n' + precipitation_label + precipitation_type + + precipitation_value + rain_unit + ) + except: + pass + + if element.tag == 'windDirection': + doc.setHtml(self.wind_label.text()) + wind = doc.toPlainText() + ': ' + try: + wind_direction = ( + self.wind_direction[element.get('code')] + ) + except KeyError: + wind_direction = '' + + if element.tag == 'windSpeed': + wind_speed = ( + '{0:.1f}'.format(float(element.get('mps'))) ) - except: - wind_direction = '' - wind_speed = ( - '{0:.1f}'.format( - float(self.forecast6_data[4][d][3].get('mps')) + if self.bft_bool: + wind_speed = str(self.convertToBeaufort(wind_speed)) + weather_cond += ( + '\n' + + wind + + wind_speed + + self.unit_system_wind + + wind_direction ) - ) - if self.bft_bool: - wind_speed = str(self.convertToBeaufort(wind_speed)) - weather_cond += ( - '\n' + wind + wind_speed + self.unit_system_wind - + wind_direction - ) - doc.setHtml(self.pressure_label.text()) - pressure_label = doc.toPlainText() + ': ' - pressure = ( - '{0:.1f}'.format( - float(self.forecast6_data[4][d][5].get('value')) + + if element.tag == 'pressure': + + doc.setHtml(self.pressure_label.text()) + pressure_label = doc.toPlainText() + ': ' + pressure = ( + '{0:.1f}'.format( + float(element.get('value')) + ) ) - ) - weather_cond += '\n' + pressure_label + pressure + ' hPa' - humidity = self.forecast6_data[4][d][6].get('value') - doc.setHtml(self.humidity_label.text()) - humidity_label = doc.toPlainText() + ': ' - weather_cond += '\n' + humidity_label + humidity + ' %' - clouds = self.forecast6_data[4][d][7].get('all') - doc.setHtml(self.clouds_label.text()) - clouds_label = doc.toPlainText() + ': ' - weather_cond += '\n' + clouds_label + clouds + ' %' - self.forecast_weather_list.append(weather_cond) + weather_cond += '\n' + pressure_label + pressure + ' hPa' + + if element.tag == 'humidity': + humidity = element.get('value') + doc.setHtml(self.humidity_label.text()) + humidity_label = doc.toPlainText() + ': ' + weather_cond += '\n' + humidity_label + humidity + ' %' + + if element.tag == 'clouds': + clouds = element.get('all') + doc.setHtml(self.clouds_label.text()) + clouds_label = doc.toPlainText() + ': ' + weather_cond += '\n' + clouds_label + clouds + ' %' + weather_end = True + + if weather_end is True: + self.forecast_weather_list.append(weather_cond) + weather_end = False def forecastdata(self): '''Forecast for the next 4 days''' @@ -777,8 +832,8 @@ class SystemTrayIcon(QMainWindow): ] ) except: - logging.warn( - 'Cannot find localisation string for :' + logging.warning( + 'Cannot find localisation string for: ' + weather_cond ) pass @@ -886,7 +941,7 @@ class SystemTrayIcon(QMainWindow): if fetched_file_periods < periods: # Some times server sends less data periods = fetched_file_periods - logging.warn( + logging.warning( 'Reduce forecast of the day to {0}'.format(periods - 1) ) for d in range(start, periods): @@ -919,7 +974,7 @@ class SystemTrayIcon(QMainWindow): ) wind += wind_name_translated except KeyError: - logging.warn('Cannot find wind name :' + str(wind_name)) + logging.warning('Cannot find wind name: ' + str(wind_name)) logging.info('Set wind name to None') wind = '' finally: @@ -1002,7 +1057,7 @@ class SystemTrayIcon(QMainWindow): if winddircode != '': wind = self.wind_direction[winddircode] + ' ' else: - logging.warn( + logging.warning( 'Wind direction code is missing: ' + str(winddircode) ) @@ -1013,12 +1068,12 @@ class SystemTrayIcon(QMainWindow): self.conditions[self.clouds_name_dic[clouds.lower()]] ) except KeyError: - logging.warn( + logging.warning( 'The clouding description in json is not relevant' ) clouds_translated = '' else: - logging.warn('Clouding name is missing: ' + str(clouds)) + logging.warning('Clouding name is missing: ' + str(clouds)) clouds_cond = clouds_translated + ' ' + str(cloudspercent) + '%' ttip = ttip + wind + clouds_cond daytime.setToolTip(ttip) @@ -1094,9 +1149,12 @@ class SystemTrayIcon(QMainWindow): self.uv_value_label.setText('<font color=>' + uv_gauge + '</font>') logging.debug('UV gauge ◼: ' + uv_gauge) self.uv_value_label.setToolTip(self.uv_recommend[uv_color[1]]) - if uv_gauge != '-': - self.over_grid.addWidget(self.uv_label, 8, 0) - self.over_grid.addWidget(self.uv_value_label, 8, 1) + if uv_gauge == '-': + self.uv_label.hide() + self.uv_value_label.hide() + else: + self.uv_label.show() + self.uv_value_label.show() def dayiconfetch(self): '''Icons for the forecast of the day''' @@ -1164,7 +1222,7 @@ class SystemTrayIcon(QMainWindow): or self.download_thread.isRunning() ): logging.debug( - 'WheelEvent : Downloading icons - remaining thread...' + 'WheelEvent: Downloading icons - remaining thread...' ) return self.icon_city_loading() @@ -1217,8 +1275,8 @@ class SystemTrayIcon(QMainWindow): ) except: logging.debug( - 'Cities menu : firsttime run,' - 'if clic cancel in settings without any city configured' + 'Cities menu: firsttime run,' + 'if clicked cancel in settings without any city configured' ) pass # Prevent duplicate entries @@ -1300,7 +1358,7 @@ class SystemTrayIcon(QMainWindow): self.icon_city_loading() self.inerror = False self.systray.setIcon(QIcon(':/noicon')) - self.systray.setToolTip(self.tr('Fetching weather data ...')) + self.systray.setToolTip(self.tr('Fetching weather data...')) self.city = self.settings.value('City') or '' self.id_ = self.settings.value('ID') or None if self.id_ is None: @@ -1373,7 +1431,7 @@ class SystemTrayIcon(QMainWindow): self.inerror = False elif done == 1: self.inerror = True - logging.debug('Trying to retrieve data ...') + logging.debug('Trying to retrieve data...') self.timer.singleShot(10000, self.try_again) return if hasattr(self, 'updateicon'): @@ -1414,62 +1472,107 @@ class SystemTrayIcon(QMainWindow): def weatherdata(self, tree): if self.inerror: return - self.tempFloat = tree[1].get('value') - self.temp = ' ' + str(round(float(self.tempFloat))) + '°' - self.temp_decimal = '{0:.1f}'.format(float(self.tempFloat)) + '°' - self.meteo = tree[8].get('value') - meteo_condition = tree[8].get('number') - try: - self.meteo = self.conditions[meteo_condition] - except: - logging.debug('Cannot find localisation string for' - 'meteo_condition:' + str(meteo_condition)) - pass - clouds = tree[5].get('name') - clouds_percent = tree[5].get('value') + '%' - try: - clouds = self.clouds[clouds] - clouds = self.conditions[clouds] - except: - logging.debug( - 'Cannot find localisation string for clouds:' - + str(clouds) - ) - pass - wind = tree[4][0].get('name').lower() - try: - wind = self.wind[wind] - wind = self.conditions[wind] - except: - logging.debug( - 'Cannot find localisation string for wind:' - + str(wind) - ) - pass - try: - wind_codes = tree[4][2].get('code') - wind_dir_value = tree[4][2].get('value') - wind_dir = tree[4][2].get('name') - except: - wind_codes = tree[4][1].get('code') - wind_dir_value = tree[4][1].get('value') - wind_dir = tree[4][1].get('name') - try: - wind_codes = self.wind_codes[wind_codes] - except: - logging.debug( - 'Cannot find localisation string for wind_codes:' - + str(wind_codes) - ) - pass - try: - wind_dir = self.wind_dir[tree[4][2].get('code')] - except: - logging.debug( - 'Cannot find localisation string for wind_dir:' - + str(wind_dir) - ) - pass + + for element in tree.iter(): + + if element.tag == 'sun': + self.weatherDataDico['Sunrise'] = element.get('rise') + self.weatherDataDico['Sunset'] = element.get('set') + + if element.tag == 'temperature': + self.tempFloat = element.get('value') + self.temp = ' ' + str(round(float(self.tempFloat))) + '°' + self.temp_decimal = '{0:.1f}'.format(float(self.tempFloat)) + '°' + + if element.tag == 'weather': + self.meteo = element.get('value') + meteo_condition = element.get('number') + try: + self.meteo = self.conditions[meteo_condition] + except KeyError: + logging.debug( + 'Cannot find localisation string for' + ' meteo_condition:' + + str(meteo_condition) + ) + pass + + if element.tag == 'clouds': + clouds = element.get('name') + clouds_percent = element.get('value') + '%' + try: + clouds = self.clouds[clouds] + clouds = self.conditions[clouds] + except KeyError: + logging.debug( + 'Cannot find localisation string for clouds:' + + str(clouds) + ) + pass + + if element.tag == 'speed': + wind_value = element.get('value') + wind = element.get('name').lower() + try: + wind = self.wind[wind] + wind = self.conditions[wind] + except KeyError: + logging.debug( + 'Cannot find localisation string for wind:' + + str(wind) + ) + pass + if element.tag == 'direction': + wind_codes_english = element.get('code') + wind_dir_value = element.get('value') + wind_dir = element.get('name') + + try: + wind_dir_value = str(int(float(wind_dir_value))) + except TypeError: + wind_dir_value = '' + + try: + wind_codes = self.wind_codes[wind_codes_english] + except (KeyError, UnboundLocalError): + logging.debug( + 'Cannot find localisation string for wind_codes:' + + str(wind_codes_english) + ) + wind_codes = wind_codes_english + + if wind_codes is None: + wind_codes = '' + + try: + wind_dir = self.wind_dir[wind_codes_english] + except KeyError: + logging.debug( + 'Cannot find localisation string for wind_dir:' + + str(wind_dir) + ) + if wind_dir is None: + wind_dir = '' + + if element.tag == 'humidity': + self.weatherDataDico['Humidity'] = ( + element.get('value'), element.get('unit') + ) + + if element.tag == 'pressure': + self.weatherDataDico['Pressure'] = ( + element.get('value'), element.get('unit') + ) + + if element.tag == 'precipitation': + rain_mode = element.get('mode') + rain_value = element.get('value') + if rain_value is None: + rain_value = '' + self.weatherDataDico['Precipitation'] = ( + rain_mode, rain_value + ) + self.city_weather_info = ( self.city + ' ' + self.country + ' ' + self.temp_decimal + ' ' + self.meteo @@ -1481,24 +1584,16 @@ class SystemTrayIcon(QMainWindow): self.weatherDataDico['Country'] = self.country self.weatherDataDico['Temp'] = self.tempFloat + '°' self.weatherDataDico['Meteo'] = self.meteo - self.weatherDataDico['Humidity'] = (tree[2].get('value'), - tree[2].get('unit')) + self.weatherDataDico['Wind'] = ( - tree[4][0].get('value'), wind, str(int(float(wind_dir_value))), - wind_codes, wind_dir) - self.weatherDataDico['Clouds'] = (clouds_percent + ' ' + clouds) - self.weatherDataDico['Pressure'] = (tree[3].get('value'), - tree[3].get('unit')) - self.weatherDataDico['Humidity'] = (tree[2].get('value'), - tree[2].get('unit')) - self.weatherDataDico['Sunrise'] = tree[0][2].get('rise') - self.weatherDataDico['Sunset'] = tree[0][2].get('set') - rain_value = tree[7].get('value') - if rain_value is None: - rain_value = '' - self.weatherDataDico['Precipitation'] = ( - tree[7].get('mode'), rain_value + wind_value, + wind, + wind_dir_value, + wind_codes, + wind_dir ) + self.weatherDataDico['Clouds'] = (clouds_percent + ' ' + clouds) + if self.id_ not in self.trendCities_dic: # dict {'id': 'hPa', , '', 'T°', 'temp_trend', 'weather changedBool'} self.trendCities_dic[self.id_] = [''] * 5 @@ -1655,10 +1750,14 @@ class SystemTrayIcon(QMainWindow): self.activate(3) def activate(self, reason): + ## Option to start with the panel closed, true by defaut + # starting with the panel open can be useful for users who don't have plasma + # installed (to set keyboard shortcuts or other default window behaviours) + start_minimized = self.settings.value('StartMinimized') or 'True' if reason == 3: if self.inerror or self.id_ is None or self.id_ == '': return - if self.isVisible(): + if self.isVisible() and start_minimized == 'True': self.hide() else: self.show() @@ -1840,22 +1939,33 @@ class Download(QThread): done = 0 logging.debug( - 'Fetching url for 6 days :' + self.forecast6_url + 'Fetching url for 6 days: ' + self.forecast6_url + self.id_ + self.suffix + '&cnt=7' ) + reqforecast6 = ( + self.forecast6_url + self.id_ + + self.suffix + '&cnt=7' + ) try: reqforecast6 = urllib.request.urlopen( self.forecast6_url + self.id_ + self.suffix + '&cnt=7', timeout=5 ) pageforecast6 = reqforecast6.read() + if str(pageforecast6).count('ClientError') > 0: + raise TypeError treeforecast6 = etree.fromstring(pageforecast6) forcast6days = True except ( - urllib.error.HTTPError, urllib.error.URLError, etree.XMLSyntaxError + timeout, + urllib.error.HTTPError, + urllib.error.URLError, + etree.XMLSyntaxError, + TypeError ) as e: forcast6days = False - logging.error('6 days forcast not available : ' + str(e)) + logging.error('Url of 6 days forcast not available: ' + str(reqforecast6)) + logging.error('6 days forcast not available: ' + str(e)) try: logging.debug( @@ -1877,7 +1987,7 @@ class Download(QThread): elif self.html404(pagedayforecast, 'day_forecast'): # Try with json logging.debug( - 'Fetching json url for forecast of the day :' + 'Fetching json url for forecast of the day: ' + self.day_forecast_url + self.id_ + self.suffix.replace('xml', 'json') ) @@ -1914,13 +2024,16 @@ class Download(QThread): self.day_forecast_rawpage['PyQt_PyObject'].emit(treedayforecast) self.done.emit(int(done)) except ( - urllib.error.HTTPError, urllib.error.URLError, TypeError + ConnectionResetError, + urllib.error.HTTPError, + urllib.error.URLError, + TypeError ) as error: if self.tentatives >= 10: done = 1 try: m_error = ( - self.tr('Error :\n') + str(error.code) + self.tr('Error:\n') + str(error.code) + ' ' + str(error.reason) ) except: @@ -1931,7 +2044,7 @@ class Download(QThread): return else: self.tentatives += 1 - logging.warn('Error: ' + str(error)) + logging.warning('Error: ' + str(error)) logging.info('Try again...' + str(self.tentatives)) self.run() except timeout: @@ -1942,7 +2055,7 @@ class Download(QThread): return else: self.tentatives += 1 - logging.warn( + logging.warning( '5 secondes timeout, new tentative: ' + str(self.tentatives) ) @@ -2225,7 +2338,7 @@ def main(): loggerStream = logging.getLogger() handlerStream = logging.StreamHandler() loggerStreamFormatter = logging.Formatter( - '%(levelname)s: %(message)s - %(lineno)s :%(module)s' + '%(levelname)s: %(message)s - %(lineno)s: %(module)s' ) handlerStream.setFormatter(loggerStreamFormatter) loggerStream.addHandler(handlerStream) @@ -2234,5 +2347,42 @@ def main(): app.exec_() +def excepthook(exc_type, exc_value, tracebackobj): + """ + Global function to catch unhandled exceptions. + + Parameters + ---------- + exc_type : str + exception type + exc_value : int + exception value + tracebackobj : traceback + traceback object + """ + separator = '-' * 80 + + now = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + ' CRASH:' + + info = StringIO() + traceback.print_tb(tracebackobj, None, info) + info.seek(0) + info = info.read() + + errmsg = '{}\t \n{}'.format(exc_type, exc_value) + sections = [now, separator, errmsg, separator, info] + msg = '\n'.join(sections) + + print(msg) + + settings = QSettings() + logPath = os.path.dirname(settings.fileName()) + logFile = logPath + '/meteo-qt.log' + with open(logFile, 'a') as logfile: + logfile.write(msg) + + +sys.excepthook = excepthook + if __name__ == '__main__': main() --- meteo-qt-1.0.0.orig/meteo_qt/searchcity.py +++ meteo-qt-1.0.0/meteo_qt/searchcity.py @@ -327,7 +327,7 @@ class WorkThread(QThread): + self.suffix ) logging.debug( - 'City before utf8 encode :' + self.accurate_url + 'City before utf8 encode: ' + self.accurate_url + self.city + self.suffix ) req = urllib.request.urlopen( --- meteo-qt-1.0.0.orig/meteo_qt/settings.py +++ meteo-qt-1.0.0/meteo_qt/settings.py @@ -290,6 +290,21 @@ class MeteoSettings(QDialog): self.owmkey_text = QLineEdit() self.owmkey_text.setText(apikey) self.owmkey_text.textChanged.connect(self.apikey_changed) + + self.start_minimized_label = QLabel( + QCoreApplication.translate( + 'Checkable option to show or not the window at startup', + 'Start minimized', + 'Settings dialogue' + ) + ) + self.start_minimized_chbx = QCheckBox() + start_minimized_bool = self.settings.value('StartMinimized') or 'True' + self.start_minimized_bool = eval(start_minimized_bool) + self.start_minimized_chbx.setChecked(self.start_minimized_bool) + self.start_minimized_chbx.stateChanged.connect(self.start_minimized) + self.start_minimized_changed = False + # ---------- self.panel = QGridLayout() self.panel.addWidget(self.city_title, 0, 0) @@ -323,6 +338,8 @@ class MeteoSettings(QDialog): self.panel.addWidget(self.owmkey_label, 11, 0) self.panel.addWidget(self.owmkey_text, 11, 1) self.panel.addWidget(self.owmkey_create, 11, 2) + self.panel.addWidget(self.start_minimized_label, 12, 0) + self.panel.addWidget(self.start_minimized_chbx, 12, 1) self.layout.addLayout(self.panel) self.layout.addLayout(self.buttonLayout) @@ -513,6 +530,18 @@ class MeteoSettings(QDialog): bold = 'False' self.settings.setValue('Bold', str(bold)) + def start_minimized(self, state): + self.start_minimized_state = state + self.start_minimized_changed = True + self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) + + def start_minimized_apply(self): + if self.start_minimized_state == 2: + start_minimized = 'True' + else: + start_minimized = 'False' + self.settings.setValue('StartMinimized', start_minimized) + def beaufort(self, state): self.bft_state = state self.bft_changed = True @@ -630,6 +659,8 @@ class MeteoSettings(QDialog): self.bold_apply() if self.bft_changed: self.beaufort_apply() + if self.start_minimized_changed: + self.start_minimized_apply() proxy_url = self.settings.value('Proxy_url') or '' if proxy_url == '': self.proxy_bool = False --- meteo-qt-1.0.0.orig/share/meteo-qt.desktop +++ meteo-qt-1.0.0/share/meteo-qt.desktop @@ -1,23 +1,29 @@ [Desktop Entry] Type=Application Name=Meteo-qt +Name[cs]=Meteo-qt Name[el]=Meteo-qt Name[pl]=Meteo-qt Name[ru]=Meteo-qt +Name[sk]=Meteo-qt Name[uk]=Meteo-qt Name[es]=Meteo-qt GenericName=Weather status information +GenericName[cs]=Informace o počasí GenericName[de]=Informationen zur Wetterlage GenericName[el]=Μετεωρολογικές πληροφορίες GenericName[pl]=Informacje pogodowe GenericName[ru]=Сведения о погоде +GenericName[sk]=Informácie o počasí GenericName[uk]=Дані щодо погоди GenericName[es]=Información meteorológica Comment=A Qt system tray application for weather information +Comment[cs]=Qt aplikace, která zobrazuje informace o počasí v systémové liště Comment[de]=Qt Anwendung für die Benachrichtungsfläche von Taskleisten, die Informationen zur Wetterlage anzeigt Comment[el]=Μια Qt εφαρμογή πλαισίου συστήματος για τις καιρικές συνθήκες Comment[pl]=Aplikacja Qt z informacjami pogodowymi zasobniku systemowym Comment[ru]=Отображает сведения о погоде в системном лотке +Comment[sk]=Qt aplikácia, ktorá zobrazuje informácie o počasí v systémovej lište Comment[uk]=Програма на Qt, що показує дані щодо погоди у системному лотку Comment[es]=Una aplicación de icono de bandeja para información meteorológica Exec=meteo-qt