Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pymetar for openSUSE:Factory 
checked in at 2024-01-08 23:44:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pymetar (Old)
 and      /work/SRC/openSUSE:Factory/.python-pymetar.new.21961 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pymetar"

Mon Jan  8 23:44:41 2024 rev:10 rq:1137448 version:1.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pymetar/python-pymetar.changes    
2020-05-26 17:19:06.147946702 +0200
+++ /work/SRC/openSUSE:Factory/.python-pymetar.new.21961/python-pymetar.changes 
2024-01-08 23:44:54.753549030 +0100
@@ -1,0 +2,6 @@
+Sun Jan  7 21:08:41 UTC 2024 - Dirk Müller <dmuel...@suse.com>
+
+- update to 1.4
+  * no changelog available
+
+-------------------------------------------------------------------

Old:
----
  pymetar-1.1.tar.gz

New:
----
  pymetar-1.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pymetar.spec ++++++
--- /var/tmp/diff_new_pack.xALcSu/_old  2024-01-08 23:44:55.521576954 +0100
+++ /var/tmp/diff_new_pack.xALcSu/_new  2024-01-08 23:44:55.525577099 +0100
@@ -1,7 +1,7 @@
 #
-# spec file for package python-pymetar
+# spec file
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 # Copyright (c) 2012 Malcolm J Lewis <malcolmle...@opensuse.org>
 #
 # All modifications and additions to the file contributed by third parties
@@ -18,23 +18,22 @@
 
 
 %define         modname pymetar
-%define         oldpython python
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%define skip_python2 1
+%{?sle15_python_module_pythons}
 Name:           python-%{modname}
-Version:        1.1
+Version:        1.4
 Release:        0
 Summary:        METAR weather report parser
 License:        GPL-2.0-or-later
 Group:          Development/Languages/Python
 URL:            https://www.schwarzvogel.de/software-pymetar.shtml
-Source0:        http://www.schwarzvogel.de/pkgs/pymetar-%{version}.tar.gz
+Source0:        https://www.schwarzvogel.de/pkgs/pymetar-%{version}.tar.gz
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires(post): update-alternatives
-Requires(postun): update-alternatives
-Obsoletes:      %{oldpython}-%{modname}
+Requires(postun):update-alternatives
 BuildArch:      noarch
 %python_subpackages
 
@@ -46,14 +45,11 @@
 %setup -q -n %{modname}-%{version}
 
 %build
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
-%python_clone -a %{buildroot}%{_mandir}/man1/%{modname}.1
+%pyproject_install
 %python_clone -a %{buildroot}%{_bindir}/%{modname}
-# we install docs on our own
-rm -r %{buildroot}%{_datadir}/doc/
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
@@ -64,15 +60,16 @@
 cd -
 
 %post
-%python_install_alternative %{modname} %{modname}.1
+%python_install_alternative %{modname}
 
 %postun
-%python_uninstall_alternative %{modname} %{modname}.1
+%python_uninstall_alternative %{modname}
 
 %files %{python_files}
 %doc README.md
 %license COPYING
 %python_alternative %{_bindir}/%{modname}
-%{python_sitelib}/*
-%python_alternative %{_mandir}/man1/%{modname}.1%{?ext_man}
+%{python_sitelib}/pymetar.py
+%pycache_only %{python_sitelib}/__pycache__/pymetar*
+%{python_sitelib}/pymetar-%{version}.dist-info
 

++++++ pymetar-1.1.tar.gz -> pymetar-1.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/PKG-INFO new/pymetar-1.4/PKG-INFO
--- old/pymetar-1.1/PKG-INFO    2018-12-25 18:55:35.000000000 +0100
+++ new/pymetar-1.4/PKG-INFO    2021-10-15 10:29:53.842224600 +0200
@@ -1,98 +1,97 @@
 Metadata-Version: 2.1
 Name: pymetar
-Version: 1.1
-Summary: 
-PyMETAR is a python module and command line tool designed to fetch Metar
-reports from the NOAA (https://www.noaa.gov) and allow access to the
-included weather information.
-
+Version: 1.4
+Summary: Pymetar is a python module and command line tool that fetches and 
parses METAR reports
 Home-page: http://www.schwarzvogel.de/software-pymetar.shtml
 Author: Tobias Klausmann
 Author-email: klausman-pyme...@schwarzvogel.de
 License: UNKNOWN
-Description: # PyMETAR - a module to fetch and parse METAR reports
-        
-        **NOTE:** If you're looking for information regarding Python 2 and 
PyMETAR, see
-        the end of this document.
-        
-        The National Oceanic and Atmospheric Administration (NOAA, 
http://www.noaa.gov/)
-        provides easy access to the weather reports generated by a large 
number of
-        weather stations (mostly at airports) worldwide. Those reports are 
called METAR
-        reports and are delivered as plain text files that look like this:
-        
-        ```
-        Duesseldorf, Germany (EDDL) 51-18N 006-46E 41M
-        Jul 26, 2002 - 03:50 AM EST / 2002.07.26 0850 UTC
-        Wind: from the SW (220 degrees) at 9 MPH (8 KT):0
-        Visibility: 3 mile(s):0
-        Sky conditions: mostly cloudy
-        Weather: mist
-        Temperature: 60 F (16 C)
-        Dew Point: 57 F (14 C)
-        Relative Humidity: 87%
-        Pressure (altimeter): 30.00 in. Hg (1016 hPa)
-        ob: EDDL 260850Z 22008KT 5000 BR SCT006 BKN012 16/14 Q1016 BECMG BKN015
-        cycle: 9
-        ```
-        
-        While this is convenient if you just want to quickly look up the data, 
there's
-        some effort involved in parsing all of this into a format that is 
digestible by
-        a program. Plus, you have to remember the base URL of the reports and 
fetch the
-        file.
-        
-        This is what this library does. All you have to do is find the station 
you're
-        interested in at http://www.aviationweather.gov/metar and feed the 
4-letter
-        station code to the MetarReport class.
-        
-        On the user end, the library provides a large number of methods to 
fetch the
-        parsed information in a plethora of formats. Those functions are 
described in
-        the file `librarydoc.txt` which was in turn generated using PyDoc.
-        
-        PyMETAR uses `urllib2` (and its successors), which in turn makes it 
easy to honor
-        the environment variable `http_proxy`. This simplifies use of a proxy
-        tremendously. Thanks go to Davide Di Blasi for both suggesting and 
implementing
-        this. The environment variable is easy to use: just set it to:
-        
-        ```
-        http://username:passw...@proxy.yourdomain.com:port 
-        ```
-        
-        You can also specify a proxy (with the same syntax) as an argument to 
the
-        fetching function. This is sometimes easier when using PyMETAR in a web
-        application environment (such as ZopeWeatherApplet by Jerome Alet). See
-        `librarydoc.txt` for details on how to accomplish that. 
-        
-        You can also use IPs instead of hostnames, of course. When in doubt, 
ask your
-        proxy admin.
-        
-        Due to some peculiarities in the METAR format, I can not rule out the
-        possibility that the library barfs on some less common types of 
reports. If you
-        encounter such a report, please save it and the error messages you get 
as
-        completely as possible and send them to me at 
`klausman-pyme...@schwarzvogel.de`
-        --- Thanks a lot!
-        
-        Of course you may send all the other bugs you encounter to me, too. As 
this is a
-        Python library, chances are that you are Python programmer and can 
provide a
-        patch. If you do so, please, by all means use spaces for indentation, 
four per
-        level, that makes merging the patch a lot easier.
-        
-        ## Python 2, 3, PyPy, PyPy3 and so on
-        
-        This version of PyMETAR supports Python 3.x and PyPy3 only. The last 
version to
-        have Python2 as its main target was v0.21.
-        
-        Compatibility with PyPy (2.x), Jython and other interpreters not 
mentioned
-        above is unknown.
-        
-        I maintain a branch (called Python2) on git which is the state of 
Pymetar as it
-        was for the last version supporting Python 2. That branch is in 
maintenance
-        mode, i.e. it will only receive fixes for security issues or bugs that 
can be
-        fixed without too much fuss. That branch will go away in 2020.
-        
-        [0] http://python-future.org/
-        
 Platform: UNKNOWN
 Classifier: Programming Language :: Python :: 3
 Classifier: License :: OSI Approved :: GNU General Public License v2 or later 
(GPLv2+)
 Classifier: Operating System :: OS Independent
 Description-Content-Type: text/markdown
+License-File: COPYING
+
+# PyMETAR - a module to fetch and parse METAR reports
+
+**NOTE:** If you're looking for information regarding Python 2 and PyMETAR, see
+the end of this document.
+
+The National Oceanic and Atmospheric Administration (NOAA, 
http://www.noaa.gov/)
+provides easy access to the weather reports generated by a large number of
+weather stations (mostly at airports) worldwide. Those reports are called METAR
+reports and are delivered as plain text files that look like this:
+
+```
+Duesseldorf, Germany (EDDL) 51-18N 006-46E 41M
+Jul 26, 2002 - 03:50 AM EST / 2002.07.26 0850 UTC
+Wind: from the SW (220 degrees) at 9 MPH (8 KT):0
+Visibility: 3 mile(s):0
+Sky conditions: mostly cloudy
+Weather: mist
+Temperature: 60 F (16 C)
+Dew Point: 57 F (14 C)
+Relative Humidity: 87%
+Pressure (altimeter): 30.00 in. Hg (1016 hPa)
+ob: EDDL 260850Z 22008KT 5000 BR SCT006 BKN012 16/14 Q1016 BECMG BKN015
+cycle: 9
+```
+
+While this is convenient if you just want to quickly look up the data, there's
+some effort involved in parsing all of this into a format that is digestible by
+a program. Plus, you have to remember the base URL of the reports and fetch the
+file.
+
+This is what this library does. All you have to do is find the station you're
+interested in at http://www.aviationweather.gov/metar and feed the 4-letter
+station code to the MetarReport class.
+
+On the user end, the library provides a large number of methods to fetch the
+parsed information in a plethora of formats. Those functions are described in
+the file `librarydoc.txt` which was in turn generated using PyDoc.
+
+PyMETAR uses `urllib2` (and its successors), which in turn makes it easy to 
honor
+the environment variable `http_proxy`. This simplifies use of a proxy
+tremendously. Thanks go to Davide Di Blasi for both suggesting and implementing
+this. The environment variable is easy to use: just set it to:
+
+```
+http://username:passw...@proxy.yourdomain.com:port 
+```
+
+You can also specify a proxy (with the same syntax) as an argument to the
+fetching function. This is sometimes easier when using PyMETAR in a web
+application environment (such as ZopeWeatherApplet by Jerome Alet). See
+`librarydoc.txt` for details on how to accomplish that. 
+
+You can also use IPs instead of hostnames, of course. When in doubt, ask your
+proxy admin.
+
+Due to some peculiarities in the METAR format, I can not rule out the
+possibility that the library barfs on some less common types of reports. If you
+encounter such a report, please save it and the error messages you get as
+completely as possible and send them to me at 
`klausman-pyme...@schwarzvogel.de`
+--- Thanks a lot!
+
+Of course you may send all the other bugs you encounter to me, too. As this is 
a
+Python library, chances are that you are Python programmer and can provide a
+patch. If you do so, please, by all means use spaces for indentation, four per
+level, that makes merging the patch a lot easier.
+
+## Python 2, 3, PyPy, PyPy3 and so on
+
+This version of PyMETAR supports Python 3.x and PyPy3 only. The last version to
+have Python2 as its main target was v0.21.
+
+Compatibility with PyPy (2.x), Jython and other interpreters not mentioned
+above is unknown.
+
+I maintain a branch (called Python2) on git which is the state of Pymetar as it
+was for the last version supporting Python 2. That branch is in maintenance
+mode, i.e. it will only receive fixes for security issues or bugs that can be
+fixed without too much fuss. That branch will go away in 2020.
+
+[0] http://python-future.org/
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/bin/pymetar new/pymetar-1.4/bin/pymetar
--- old/pymetar-1.1/bin/pymetar 2018-12-25 18:44:00.000000000 +0100
+++ new/pymetar-1.4/bin/pymetar 2021-10-15 10:28:30.000000000 +0200
@@ -1,7 +1,7 @@
 #!/usr/bin/python -tt
 # -*- coding: iso-8859-15 -*-
 
-__version__ = "1.1"
+__version__ = "1.4"
 
 import pymetar
 import sys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/bin/pymetar.py 
new/pymetar-1.4/bin/pymetar.py
--- old/pymetar-1.1/bin/pymetar.py      2018-12-25 18:46:34.000000000 +0100
+++ new/pymetar-1.4/bin/pymetar.py      2021-10-15 10:29:50.000000000 +0200
@@ -20,7 +20,6 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA."""
 #
-import math
 import re
 
 import urllib.request  # noqa: E402
@@ -29,12 +28,12 @@
 
 __author__ = "klausman-pyme...@schwarzvogel.de"
 
-__version__ = "1.1"
+__version__ = "1.4"
 
 CLOUD_RE_STR = (r"^(CAVOK|CLR|SKC|BKN|SCT|FEW|OVC|NSC)([0-9]{3})?"
                 r"(TCU|CU|CB|SC|CBMAM|ACC|SCSL|CCSL|ACSL)?$")
-COND_RE_STR = (r"^(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|"
-               r"GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)$")
+COND_RE_STR = (r"^[-+]?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|"
+               r"GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\+?FC)$")
 
 
 class EmptyReportException(Exception):
@@ -398,14 +397,13 @@
 
     coords = coords + float(elements[0])
 
-    if compass_dir in ('W', 'S'):
+    if compass_dir in 'WS':
         coords = -1.0 * coords
 
     return coords
 
 
 class WeatherReport:
-
     """Incorporates both the unparsed textual representation of the
     weather report and the parsed values as soon as they are filled
     in by ReportParser."""
@@ -493,8 +491,7 @@
         """
         Return the wind speed in miles per hour.
         """
-        if self.windspeed is not None:
-            return self.windspeedmph
+        return self.windspeedmph
 
     def getWindSpeedBeaufort(self):
         """
@@ -502,7 +499,7 @@
         cf. https://en.wikipedia.org/wiki/Beaufort_scale
         """
         if self.windspeed is not None:
-            return round(math.pow(self.windspeed / 0.8359648, 2 / 3.0))
+            return round((self.windspeed / 0.8359648) ** (2 / 3.0))
 
     def getWindSpeedKnots(self):
         """
@@ -528,8 +525,7 @@
         """
         Return visibility in km.
         """
-        if self.vis is not None:
-            return self.vis
+        return self.vis
 
     def getVisibilityMiles(self):
         """
@@ -688,7 +684,7 @@
         Return the time when the observation was made in ISO 8601 format
         (e.g. 2002-07-25 15:12:00Z)
         """
-        return(metar_to_iso8601(self.rtime))
+        return metar_to_iso8601(self.rtime)
 
     def getPixmap(self):
         """
@@ -803,12 +799,10 @@
         """
         matches = self.match_WeatherPart(COND_RE_STR)
         for wcond in matches:
-            if ((len(wcond) > 3) and
-                    (wcond.startswith('+') or wcond.startswith('-'))):
-
+            if len(wcond) > 3 and wcond.startswith(('+', '-')):
                 wcond = wcond[1:]
 
-            if wcond.startswith('+') or wcond.startswith('-'):
+            if wcond.startswith(('+', '-')):
                 pphen = 1
             elif len(wcond) < 4:
                 pphen = 0
@@ -835,12 +829,13 @@
         strings, only the first one is taken into account!
         """
         matches = []
+        # FIXME This mixes direct access to the "code" attribute and the 
accessor function "getRawMetarCode" which just returns "code".
         if self.Report.code is not None:
             myre = re.compile(regexp)
             for wpart in self.Report.getRawMetarCode().split():
                 match = myre.match(wpart)
                 if match:
-                    matches.append(match.string[match.start(0): match.end(0)])
+                    matches.append(match.group())
         return matches
 
     def ParseReport(self, MetarReport=None):
@@ -911,14 +906,13 @@
             # The line containing date and time of the report
             # We have to make sure that the station ID is *not*
             # in this line to avoid trying to parse the ob: line
-            elif ((data.find(" UTC")) != -1 and
-                  (data.find(self.Report.givenstationid)) == -1):
+            elif " UTC" in data and self.Report.givenstationid not in data:
                 rtime = data.split("/")[1]
                 self.Report.rtime = rtime.strip()
 
             # temperature
 
-            elif (header == "Temperature"):
+            elif header == "Temperature":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.tempf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -926,7 +920,7 @@
 
             # wind chill
 
-            elif (header == "Windchill"):
+            elif header == "Windchill":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.w_chillf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -934,14 +928,14 @@
 
             # wind dir and speed
 
-            elif (header == "Wind"):
-                if (data.find("Calm") != -1):
+            elif header == "Wind":
+                if "Calm" in data:
                     self.Report.windspeed = 0.0
                     self.Report.windspeedkt = 0.0
                     self.Report.windspeedmph = 0.0
                     self.Report.winddir = None
                     self.Report.windcomp = None
-                elif (data.find("Variable") != -1):
+                elif "Variable" in data:
                     speed = data.split(" ", 3)[2]
                     self.Report.windspeed = (float(speed) * 0.44704)
                     self.Report.windspeedkt = int(data.split(" ", 5)[4][1:])
@@ -962,7 +956,7 @@
 
             # visibility
 
-            elif (header == "Visibility"):
+            elif header == "Visibility":
                 for visgroup in data.split():
                     try:
                         self.Report.vis = float(visgroup) * 1.609344
@@ -973,7 +967,7 @@
 
             # dew point
 
-            elif (header == "Dew Point"):
+            elif header == "Dew Point":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.dewpf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -981,36 +975,36 @@
 
             # humidity
 
-            elif (header == "Relative Humidity"):
+            elif header == "Relative Humidity":
                 h = data.split("%", 1)[0]
                 self.Report.humid = int(h)
 
             # pressure
 
-            elif (header == "Pressure (altimeter)"):
+            elif header == "Pressure (altimeter)":
                 press = data.split(" ", 1)[0]
-                self.Report.press = (float(press) * 33.863886)
+                self.Report.press = float(press) * 33.863886
                 # 1 in = 25.4 mm => 1 inHg = 25.4 mmHg
-                self.Report.pressmmHg = (float(press) * 25.4000)
+                self.Report.pressmmHg = float(press) * 25.4000
 
             # shot weather desc. ("rain", "mist", ...)
 
-            elif (header == "Weather"):
+            elif header == "Weather":
                 self.Report.weather = data
 
             # short desc. of sky conditions
 
-            elif (header == "Sky conditions"):
+            elif header == "Sky conditions":
                 self.Report.sky = data
 
             # the encoded report itself
 
-            elif (header == "ob"):
+            elif header == "ob":
                 self.Report.code = data.strip()
 
             # the cycle value ("time slot")
 
-            elif (header == "cycle"):
+            elif header == "cycle":
                 try:
                     self.Report.cycle = int(data)
                 except ValueError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/pymetar.egg-info/PKG-INFO 
new/pymetar-1.4/pymetar.egg-info/PKG-INFO
--- old/pymetar-1.1/pymetar.egg-info/PKG-INFO   2018-12-25 18:55:35.000000000 
+0100
+++ new/pymetar-1.4/pymetar.egg-info/PKG-INFO   2021-10-15 10:29:53.000000000 
+0200
@@ -1,98 +1,97 @@
 Metadata-Version: 2.1
 Name: pymetar
-Version: 1.1
-Summary: 
-PyMETAR is a python module and command line tool designed to fetch Metar
-reports from the NOAA (https://www.noaa.gov) and allow access to the
-included weather information.
-
+Version: 1.4
+Summary: Pymetar is a python module and command line tool that fetches and 
parses METAR reports
 Home-page: http://www.schwarzvogel.de/software-pymetar.shtml
 Author: Tobias Klausmann
 Author-email: klausman-pyme...@schwarzvogel.de
 License: UNKNOWN
-Description: # PyMETAR - a module to fetch and parse METAR reports
-        
-        **NOTE:** If you're looking for information regarding Python 2 and 
PyMETAR, see
-        the end of this document.
-        
-        The National Oceanic and Atmospheric Administration (NOAA, 
http://www.noaa.gov/)
-        provides easy access to the weather reports generated by a large 
number of
-        weather stations (mostly at airports) worldwide. Those reports are 
called METAR
-        reports and are delivered as plain text files that look like this:
-        
-        ```
-        Duesseldorf, Germany (EDDL) 51-18N 006-46E 41M
-        Jul 26, 2002 - 03:50 AM EST / 2002.07.26 0850 UTC
-        Wind: from the SW (220 degrees) at 9 MPH (8 KT):0
-        Visibility: 3 mile(s):0
-        Sky conditions: mostly cloudy
-        Weather: mist
-        Temperature: 60 F (16 C)
-        Dew Point: 57 F (14 C)
-        Relative Humidity: 87%
-        Pressure (altimeter): 30.00 in. Hg (1016 hPa)
-        ob: EDDL 260850Z 22008KT 5000 BR SCT006 BKN012 16/14 Q1016 BECMG BKN015
-        cycle: 9
-        ```
-        
-        While this is convenient if you just want to quickly look up the data, 
there's
-        some effort involved in parsing all of this into a format that is 
digestible by
-        a program. Plus, you have to remember the base URL of the reports and 
fetch the
-        file.
-        
-        This is what this library does. All you have to do is find the station 
you're
-        interested in at http://www.aviationweather.gov/metar and feed the 
4-letter
-        station code to the MetarReport class.
-        
-        On the user end, the library provides a large number of methods to 
fetch the
-        parsed information in a plethora of formats. Those functions are 
described in
-        the file `librarydoc.txt` which was in turn generated using PyDoc.
-        
-        PyMETAR uses `urllib2` (and its successors), which in turn makes it 
easy to honor
-        the environment variable `http_proxy`. This simplifies use of a proxy
-        tremendously. Thanks go to Davide Di Blasi for both suggesting and 
implementing
-        this. The environment variable is easy to use: just set it to:
-        
-        ```
-        http://username:passw...@proxy.yourdomain.com:port 
-        ```
-        
-        You can also specify a proxy (with the same syntax) as an argument to 
the
-        fetching function. This is sometimes easier when using PyMETAR in a web
-        application environment (such as ZopeWeatherApplet by Jerome Alet). See
-        `librarydoc.txt` for details on how to accomplish that. 
-        
-        You can also use IPs instead of hostnames, of course. When in doubt, 
ask your
-        proxy admin.
-        
-        Due to some peculiarities in the METAR format, I can not rule out the
-        possibility that the library barfs on some less common types of 
reports. If you
-        encounter such a report, please save it and the error messages you get 
as
-        completely as possible and send them to me at 
`klausman-pyme...@schwarzvogel.de`
-        --- Thanks a lot!
-        
-        Of course you may send all the other bugs you encounter to me, too. As 
this is a
-        Python library, chances are that you are Python programmer and can 
provide a
-        patch. If you do so, please, by all means use spaces for indentation, 
four per
-        level, that makes merging the patch a lot easier.
-        
-        ## Python 2, 3, PyPy, PyPy3 and so on
-        
-        This version of PyMETAR supports Python 3.x and PyPy3 only. The last 
version to
-        have Python2 as its main target was v0.21.
-        
-        Compatibility with PyPy (2.x), Jython and other interpreters not 
mentioned
-        above is unknown.
-        
-        I maintain a branch (called Python2) on git which is the state of 
Pymetar as it
-        was for the last version supporting Python 2. That branch is in 
maintenance
-        mode, i.e. it will only receive fixes for security issues or bugs that 
can be
-        fixed without too much fuss. That branch will go away in 2020.
-        
-        [0] http://python-future.org/
-        
 Platform: UNKNOWN
 Classifier: Programming Language :: Python :: 3
 Classifier: License :: OSI Approved :: GNU General Public License v2 or later 
(GPLv2+)
 Classifier: Operating System :: OS Independent
 Description-Content-Type: text/markdown
+License-File: COPYING
+
+# PyMETAR - a module to fetch and parse METAR reports
+
+**NOTE:** If you're looking for information regarding Python 2 and PyMETAR, see
+the end of this document.
+
+The National Oceanic and Atmospheric Administration (NOAA, 
http://www.noaa.gov/)
+provides easy access to the weather reports generated by a large number of
+weather stations (mostly at airports) worldwide. Those reports are called METAR
+reports and are delivered as plain text files that look like this:
+
+```
+Duesseldorf, Germany (EDDL) 51-18N 006-46E 41M
+Jul 26, 2002 - 03:50 AM EST / 2002.07.26 0850 UTC
+Wind: from the SW (220 degrees) at 9 MPH (8 KT):0
+Visibility: 3 mile(s):0
+Sky conditions: mostly cloudy
+Weather: mist
+Temperature: 60 F (16 C)
+Dew Point: 57 F (14 C)
+Relative Humidity: 87%
+Pressure (altimeter): 30.00 in. Hg (1016 hPa)
+ob: EDDL 260850Z 22008KT 5000 BR SCT006 BKN012 16/14 Q1016 BECMG BKN015
+cycle: 9
+```
+
+While this is convenient if you just want to quickly look up the data, there's
+some effort involved in parsing all of this into a format that is digestible by
+a program. Plus, you have to remember the base URL of the reports and fetch the
+file.
+
+This is what this library does. All you have to do is find the station you're
+interested in at http://www.aviationweather.gov/metar and feed the 4-letter
+station code to the MetarReport class.
+
+On the user end, the library provides a large number of methods to fetch the
+parsed information in a plethora of formats. Those functions are described in
+the file `librarydoc.txt` which was in turn generated using PyDoc.
+
+PyMETAR uses `urllib2` (and its successors), which in turn makes it easy to 
honor
+the environment variable `http_proxy`. This simplifies use of a proxy
+tremendously. Thanks go to Davide Di Blasi for both suggesting and implementing
+this. The environment variable is easy to use: just set it to:
+
+```
+http://username:passw...@proxy.yourdomain.com:port 
+```
+
+You can also specify a proxy (with the same syntax) as an argument to the
+fetching function. This is sometimes easier when using PyMETAR in a web
+application environment (such as ZopeWeatherApplet by Jerome Alet). See
+`librarydoc.txt` for details on how to accomplish that. 
+
+You can also use IPs instead of hostnames, of course. When in doubt, ask your
+proxy admin.
+
+Due to some peculiarities in the METAR format, I can not rule out the
+possibility that the library barfs on some less common types of reports. If you
+encounter such a report, please save it and the error messages you get as
+completely as possible and send them to me at 
`klausman-pyme...@schwarzvogel.de`
+--- Thanks a lot!
+
+Of course you may send all the other bugs you encounter to me, too. As this is 
a
+Python library, chances are that you are Python programmer and can provide a
+patch. If you do so, please, by all means use spaces for indentation, four per
+level, that makes merging the patch a lot easier.
+
+## Python 2, 3, PyPy, PyPy3 and so on
+
+This version of PyMETAR supports Python 3.x and PyPy3 only. The last version to
+have Python2 as its main target was v0.21.
+
+Compatibility with PyPy (2.x), Jython and other interpreters not mentioned
+above is unknown.
+
+I maintain a branch (called Python2) on git which is the state of Pymetar as it
+was for the last version supporting Python 2. That branch is in maintenance
+mode, i.e. it will only receive fixes for security issues or bugs that can be
+fixed without too much fuss. That branch will go away in 2020.
+
+[0] http://python-future.org/
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/pymetar.py new/pymetar-1.4/pymetar.py
--- old/pymetar-1.1/pymetar.py  2018-12-25 18:46:34.000000000 +0100
+++ new/pymetar-1.4/pymetar.py  2021-10-15 10:29:50.000000000 +0200
@@ -20,7 +20,6 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA."""
 #
-import math
 import re
 
 import urllib.request  # noqa: E402
@@ -29,12 +28,12 @@
 
 __author__ = "klausman-pyme...@schwarzvogel.de"
 
-__version__ = "1.1"
+__version__ = "1.4"
 
 CLOUD_RE_STR = (r"^(CAVOK|CLR|SKC|BKN|SCT|FEW|OVC|NSC)([0-9]{3})?"
                 r"(TCU|CU|CB|SC|CBMAM|ACC|SCSL|CCSL|ACSL)?$")
-COND_RE_STR = (r"^(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|"
-               r"GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)$")
+COND_RE_STR = (r"^[-+]?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|"
+               r"GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\+?FC)$")
 
 
 class EmptyReportException(Exception):
@@ -398,14 +397,13 @@
 
     coords = coords + float(elements[0])
 
-    if compass_dir in ('W', 'S'):
+    if compass_dir in 'WS':
         coords = -1.0 * coords
 
     return coords
 
 
 class WeatherReport:
-
     """Incorporates both the unparsed textual representation of the
     weather report and the parsed values as soon as they are filled
     in by ReportParser."""
@@ -493,8 +491,7 @@
         """
         Return the wind speed in miles per hour.
         """
-        if self.windspeed is not None:
-            return self.windspeedmph
+        return self.windspeedmph
 
     def getWindSpeedBeaufort(self):
         """
@@ -502,7 +499,7 @@
         cf. https://en.wikipedia.org/wiki/Beaufort_scale
         """
         if self.windspeed is not None:
-            return round(math.pow(self.windspeed / 0.8359648, 2 / 3.0))
+            return round((self.windspeed / 0.8359648) ** (2 / 3.0))
 
     def getWindSpeedKnots(self):
         """
@@ -528,8 +525,7 @@
         """
         Return visibility in km.
         """
-        if self.vis is not None:
-            return self.vis
+        return self.vis
 
     def getVisibilityMiles(self):
         """
@@ -688,7 +684,7 @@
         Return the time when the observation was made in ISO 8601 format
         (e.g. 2002-07-25 15:12:00Z)
         """
-        return(metar_to_iso8601(self.rtime))
+        return metar_to_iso8601(self.rtime)
 
     def getPixmap(self):
         """
@@ -803,12 +799,10 @@
         """
         matches = self.match_WeatherPart(COND_RE_STR)
         for wcond in matches:
-            if ((len(wcond) > 3) and
-                    (wcond.startswith('+') or wcond.startswith('-'))):
-
+            if len(wcond) > 3 and wcond.startswith(('+', '-')):
                 wcond = wcond[1:]
 
-            if wcond.startswith('+') or wcond.startswith('-'):
+            if wcond.startswith(('+', '-')):
                 pphen = 1
             elif len(wcond) < 4:
                 pphen = 0
@@ -835,12 +829,13 @@
         strings, only the first one is taken into account!
         """
         matches = []
+        # FIXME This mixes direct access to the "code" attribute and the 
accessor function "getRawMetarCode" which just returns "code".
         if self.Report.code is not None:
             myre = re.compile(regexp)
             for wpart in self.Report.getRawMetarCode().split():
                 match = myre.match(wpart)
                 if match:
-                    matches.append(match.string[match.start(0): match.end(0)])
+                    matches.append(match.group())
         return matches
 
     def ParseReport(self, MetarReport=None):
@@ -911,14 +906,13 @@
             # The line containing date and time of the report
             # We have to make sure that the station ID is *not*
             # in this line to avoid trying to parse the ob: line
-            elif ((data.find(" UTC")) != -1 and
-                  (data.find(self.Report.givenstationid)) == -1):
+            elif " UTC" in data and self.Report.givenstationid not in data:
                 rtime = data.split("/")[1]
                 self.Report.rtime = rtime.strip()
 
             # temperature
 
-            elif (header == "Temperature"):
+            elif header == "Temperature":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.tempf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -926,7 +920,7 @@
 
             # wind chill
 
-            elif (header == "Windchill"):
+            elif header == "Windchill":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.w_chillf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -934,14 +928,14 @@
 
             # wind dir and speed
 
-            elif (header == "Wind"):
-                if (data.find("Calm") != -1):
+            elif header == "Wind":
+                if "Calm" in data:
                     self.Report.windspeed = 0.0
                     self.Report.windspeedkt = 0.0
                     self.Report.windspeedmph = 0.0
                     self.Report.winddir = None
                     self.Report.windcomp = None
-                elif (data.find("Variable") != -1):
+                elif "Variable" in data:
                     speed = data.split(" ", 3)[2]
                     self.Report.windspeed = (float(speed) * 0.44704)
                     self.Report.windspeedkt = int(data.split(" ", 5)[4][1:])
@@ -962,7 +956,7 @@
 
             # visibility
 
-            elif (header == "Visibility"):
+            elif header == "Visibility":
                 for visgroup in data.split():
                     try:
                         self.Report.vis = float(visgroup) * 1.609344
@@ -973,7 +967,7 @@
 
             # dew point
 
-            elif (header == "Dew Point"):
+            elif header == "Dew Point":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.dewpf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -981,36 +975,36 @@
 
             # humidity
 
-            elif (header == "Relative Humidity"):
+            elif header == "Relative Humidity":
                 h = data.split("%", 1)[0]
                 self.Report.humid = int(h)
 
             # pressure
 
-            elif (header == "Pressure (altimeter)"):
+            elif header == "Pressure (altimeter)":
                 press = data.split(" ", 1)[0]
-                self.Report.press = (float(press) * 33.863886)
+                self.Report.press = float(press) * 33.863886
                 # 1 in = 25.4 mm => 1 inHg = 25.4 mmHg
-                self.Report.pressmmHg = (float(press) * 25.4000)
+                self.Report.pressmmHg = float(press) * 25.4000
 
             # shot weather desc. ("rain", "mist", ...)
 
-            elif (header == "Weather"):
+            elif header == "Weather":
                 self.Report.weather = data
 
             # short desc. of sky conditions
 
-            elif (header == "Sky conditions"):
+            elif header == "Sky conditions":
                 self.Report.sky = data
 
             # the encoded report itself
 
-            elif (header == "ob"):
+            elif header == "ob":
                 self.Report.code = data.strip()
 
             # the cycle value ("time slot")
 
-            elif (header == "cycle"):
+            elif header == "cycle":
                 try:
                     self.Report.cycle = int(data)
                 except ValueError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/setup.py new/pymetar-1.4/setup.py
--- old/pymetar-1.1/setup.py    2018-12-25 18:48:03.000000000 +0100
+++ new/pymetar-1.4/setup.py    2021-07-06 13:19:31.000000000 +0200
@@ -24,16 +24,13 @@
     version=pymetar.__version__,
     author="Tobias Klausmann",
     author_email="klausman-pyme...@schwarzvogel.de",
-    description=pymetar.__doc__,
+    description="Pymetar is a python module and command line tool that fetches 
and parses METAR reports",
     long_description=long_description,
     long_description_content_type="text/markdown",
     url="http://www.schwarzvogel.de/software-pymetar.shtml";,
     packages=setuptools.find_packages(),
     py_modules=["pymetar"],
     scripts=["bin/pymetar"],
-    data_files=[("share/doc/pymetar-%s" % pymetar.__version__,
-                 ['README.md', 'COPYING', 'THANKS']),
-                ("share/man/man1", ['pymetar.1'])],
     classifiers=(
     "Programming Language :: Python :: 3",
     "License :: OSI Approved :: GNU General Public License v2 or later 
(GPLv2+)", 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/testing/smoketest/pymetar.py 
new/pymetar-1.4/testing/smoketest/pymetar.py
--- old/pymetar-1.1/testing/smoketest/pymetar.py        2018-12-25 
18:46:34.000000000 +0100
+++ new/pymetar-1.4/testing/smoketest/pymetar.py        2021-10-15 
10:29:50.000000000 +0200
@@ -20,7 +20,6 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA."""
 #
-import math
 import re
 
 import urllib.request  # noqa: E402
@@ -29,12 +28,12 @@
 
 __author__ = "klausman-pyme...@schwarzvogel.de"
 
-__version__ = "1.1"
+__version__ = "1.4"
 
 CLOUD_RE_STR = (r"^(CAVOK|CLR|SKC|BKN|SCT|FEW|OVC|NSC)([0-9]{3})?"
                 r"(TCU|CU|CB|SC|CBMAM|ACC|SCSL|CCSL|ACSL)?$")
-COND_RE_STR = (r"^(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|"
-               r"GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)$")
+COND_RE_STR = (r"^[-+]?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|"
+               r"GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\+?FC)$")
 
 
 class EmptyReportException(Exception):
@@ -398,14 +397,13 @@
 
     coords = coords + float(elements[0])
 
-    if compass_dir in ('W', 'S'):
+    if compass_dir in 'WS':
         coords = -1.0 * coords
 
     return coords
 
 
 class WeatherReport:
-
     """Incorporates both the unparsed textual representation of the
     weather report and the parsed values as soon as they are filled
     in by ReportParser."""
@@ -493,8 +491,7 @@
         """
         Return the wind speed in miles per hour.
         """
-        if self.windspeed is not None:
-            return self.windspeedmph
+        return self.windspeedmph
 
     def getWindSpeedBeaufort(self):
         """
@@ -502,7 +499,7 @@
         cf. https://en.wikipedia.org/wiki/Beaufort_scale
         """
         if self.windspeed is not None:
-            return round(math.pow(self.windspeed / 0.8359648, 2 / 3.0))
+            return round((self.windspeed / 0.8359648) ** (2 / 3.0))
 
     def getWindSpeedKnots(self):
         """
@@ -528,8 +525,7 @@
         """
         Return visibility in km.
         """
-        if self.vis is not None:
-            return self.vis
+        return self.vis
 
     def getVisibilityMiles(self):
         """
@@ -688,7 +684,7 @@
         Return the time when the observation was made in ISO 8601 format
         (e.g. 2002-07-25 15:12:00Z)
         """
-        return(metar_to_iso8601(self.rtime))
+        return metar_to_iso8601(self.rtime)
 
     def getPixmap(self):
         """
@@ -803,12 +799,10 @@
         """
         matches = self.match_WeatherPart(COND_RE_STR)
         for wcond in matches:
-            if ((len(wcond) > 3) and
-                    (wcond.startswith('+') or wcond.startswith('-'))):
-
+            if len(wcond) > 3 and wcond.startswith(('+', '-')):
                 wcond = wcond[1:]
 
-            if wcond.startswith('+') or wcond.startswith('-'):
+            if wcond.startswith(('+', '-')):
                 pphen = 1
             elif len(wcond) < 4:
                 pphen = 0
@@ -835,12 +829,13 @@
         strings, only the first one is taken into account!
         """
         matches = []
+        # FIXME This mixes direct access to the "code" attribute and the 
accessor function "getRawMetarCode" which just returns "code".
         if self.Report.code is not None:
             myre = re.compile(regexp)
             for wpart in self.Report.getRawMetarCode().split():
                 match = myre.match(wpart)
                 if match:
-                    matches.append(match.string[match.start(0): match.end(0)])
+                    matches.append(match.group())
         return matches
 
     def ParseReport(self, MetarReport=None):
@@ -911,14 +906,13 @@
             # The line containing date and time of the report
             # We have to make sure that the station ID is *not*
             # in this line to avoid trying to parse the ob: line
-            elif ((data.find(" UTC")) != -1 and
-                  (data.find(self.Report.givenstationid)) == -1):
+            elif " UTC" in data and self.Report.givenstationid not in data:
                 rtime = data.split("/")[1]
                 self.Report.rtime = rtime.strip()
 
             # temperature
 
-            elif (header == "Temperature"):
+            elif header == "Temperature":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.tempf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -926,7 +920,7 @@
 
             # wind chill
 
-            elif (header == "Windchill"):
+            elif header == "Windchill":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.w_chillf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -934,14 +928,14 @@
 
             # wind dir and speed
 
-            elif (header == "Wind"):
-                if (data.find("Calm") != -1):
+            elif header == "Wind":
+                if "Calm" in data:
                     self.Report.windspeed = 0.0
                     self.Report.windspeedkt = 0.0
                     self.Report.windspeedmph = 0.0
                     self.Report.winddir = None
                     self.Report.windcomp = None
-                elif (data.find("Variable") != -1):
+                elif "Variable" in data:
                     speed = data.split(" ", 3)[2]
                     self.Report.windspeed = (float(speed) * 0.44704)
                     self.Report.windspeedkt = int(data.split(" ", 5)[4][1:])
@@ -962,7 +956,7 @@
 
             # visibility
 
-            elif (header == "Visibility"):
+            elif header == "Visibility":
                 for visgroup in data.split():
                     try:
                         self.Report.vis = float(visgroup) * 1.609344
@@ -973,7 +967,7 @@
 
             # dew point
 
-            elif (header == "Dew Point"):
+            elif header == "Dew Point":
                 fnht, cels = data.split(None, 3)[0:3:2]
                 self.Report.dewpf = float(fnht)
                 # The string we have split is "(NN C)", hence the slice
@@ -981,36 +975,36 @@
 
             # humidity
 
-            elif (header == "Relative Humidity"):
+            elif header == "Relative Humidity":
                 h = data.split("%", 1)[0]
                 self.Report.humid = int(h)
 
             # pressure
 
-            elif (header == "Pressure (altimeter)"):
+            elif header == "Pressure (altimeter)":
                 press = data.split(" ", 1)[0]
-                self.Report.press = (float(press) * 33.863886)
+                self.Report.press = float(press) * 33.863886
                 # 1 in = 25.4 mm => 1 inHg = 25.4 mmHg
-                self.Report.pressmmHg = (float(press) * 25.4000)
+                self.Report.pressmmHg = float(press) * 25.4000
 
             # shot weather desc. ("rain", "mist", ...)
 
-            elif (header == "Weather"):
+            elif header == "Weather":
                 self.Report.weather = data
 
             # short desc. of sky conditions
 
-            elif (header == "Sky conditions"):
+            elif header == "Sky conditions":
                 self.Report.sky = data
 
             # the encoded report itself
 
-            elif (header == "ob"):
+            elif header == "ob":
                 self.Report.code = data.strip()
 
             # the cycle value ("time slot")
 
-            elif (header == "cycle"):
+            elif header == "cycle":
                 try:
                     self.Report.cycle = int(data)
                 except ValueError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pymetar-1.1/testing/smoketest/runtests.sh 
new/pymetar-1.4/testing/smoketest/runtests.sh
--- old/pymetar-1.1/testing/smoketest/runtests.sh       2018-08-13 
19:23:54.000000000 +0200
+++ new/pymetar-1.4/testing/smoketest/runtests.sh       2021-10-15 
10:25:44.000000000 +0200
@@ -4,6 +4,7 @@
 SETDIR="reports/"
 SETS="set-2007-10-14  set-2010-01-17 set-2010-10-31 set-2017-07-29"
 
+mkdir -p logs
 for TEST in $TESTS; do
        for SET in $SETS; do
                echo "Running $TEST on $SETDIR/$SET"

Reply via email to