Repository: python-metar/python-metar

Issue:
Allow `ParserErrors` to not raise
If you're like me and get most of your METAR codes from FAA's ASOS program, you get a *lot* of parser errors.

The `MetarParser` subclass in [cloudside](https://github.com/Geosyntec/cloudside/blob/master/cloudside/station.py#L149) gets around this by simply logging the error and moving on. 

It'd be nice to have this as an *option* upstream.

Discussion:
akrherz: Adding a test here that actually generates an exception is rather funny, since if we have parsing code that raises exceptions, we should fix that bug! :slightly_smiling_face: 
akrherz: I have a test in and realize now that known Exceptions can come from other places than just Metar, this all will take some consideration for the API.
akrherz: Thanks @phobson , I'd like to see if @WeatherGod chimes in on this prior to merging.  Will wait a bit while I work on a PR for a formal release.  Or are we still not close enough for what you need for cloudside to use?
phobson: To clear: strictly speaking, this change is not necessary for cloudside to function as intended, but may help preventing ASOS's weirder codes from being completely ignored.

Punting on this in favor of more robust error handling would be fine by me.
akrherz: Thanks @phobson , this change does not impact previous code behavior, so will take this PR now so to proceed with a release.

Patch:
diff --git a/metar/Metar.py b/metar/Metar.py
index b682d2c..766c485 100755
--- a/metar/Metar.py
+++ b/metar/Metar.py
@@ -324,13 +324,11 @@ class Metar(object):
         provided, then the month and year are guessed from the current date.
       utcdelta : int or datetime.timedelta, optional
         An int of hours or a timedelta object used to specify the timezone.
-      strict : bool (default is True) or str {'raise', 'warn', 'log'}
-        When unparsed or unparseable groups exist in a METAR code, a
-        ``ParserError`` will be raised. Setting this to False will suppress that
-        behavior and will use the standard library's logging module to record
-        all supressed errors. One can then detect if decoding is complete by
-        checking the :attr:`decode_completed` attribute.
-
+      strict : bool (default is True)
+        This option determines if a ``ParserError`` is raised when
+        unparsable groups are found or an unexpected exception is encountered.
+        Setting this to `False` will prevent exceptions from being raised and
+        only generate warning messages.
       """
 
       self.code = metarcode              # original METAR code
@@ -439,9 +437,13 @@ class Metar(object):
 
       except Exception as err:
           message = (
-              "%s failed while processing '%s'\n\t%s" % (handler.__name__, code, "\n\t".join(err.args))
+              ("%s failed while processing '%s'\n\t%s"
+               ) % (handler.__name__, code, "\n\t".join(err.args))
           )
-          raise ParserError(message)
+          if strict:
+              raise ParserError(message)
+          else:
+              warnings.warn(message, RuntimeWarning)
 
       if self._unparsed_groups:
           code = ' '.join(self._unparsed_groups)


Test patch:
diff --git a/test/test_metar.py b/test/test_metar.py
index d358061..269cf02 100644
--- a/test/test_metar.py
+++ b/test/test_metar.py
@@ -267,6 +267,13 @@ class MetarTest(unittest.TestCase):
     self.assertEqual( report("MMMMMGMMKT").wind(), "missing" )
     self.assertEqual( report("MMMMMG01KT").wind(), "missing" )
 
+  def test_issue51_strict(self):
+    """Check that setting strict=False prevents a ParserError"""
+    with warnings.catch_warnings(record=True) as w:
+        report = Metar.Metar(sta_time+"90010KT", strict=False)
+    assert len(w) == 1
+    assert report.wind_speed is None
+
   def test_142_parseWind_illegal(self):
     """Check rejection of illegal wind groups."""
     self.raisesParserError( sta_time+"90010KT" )