]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Substitute a failing get_localzone()
authorFrank Brehm <frank.brehm@pixelpark.com>
Tue, 9 Apr 2024 16:07:12 +0000 (18:07 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Tue, 9 Apr 2024 16:07:12 +0000 (18:07 +0200)
lib/pp_admintools/__init__.py
lib/pp_admintools/handler/pflogparse.py
lib/pp_admintools/postfix_chain.py
test/test_25_postfix_logparser.py

index f98a578d37ff3a670aa3856f334816a94a882151..1c7875f96d887496d53b0be416f09389997e4d48 100644 (file)
@@ -15,12 +15,13 @@ import shutil
 # Own modules
 import fb_tools.common
 
-__version__ = '1.0.2'
+__version__ = '1.0.3'
 
 MAX_PORT_NUMBER = (2 ** 16) - 1
 DEFAULT_CONFIG_DIR = 'pixelpark'
 DEFAULT_TERMINAL_WIDTH = 99
 DEFAULT_TERMINAL_HEIGHT = 40
+DEFAULT_TZ_OFFSET = '+2h'
 
 
 # =============================================================================
index 75e6790b84f878f42d4f8e12568eb3aa6e3c12d6..9ae7ee846f809ac030abeaea2f5412194ca7d957 100644 (file)
@@ -66,6 +66,8 @@ class PostfixLogfileParser(HandlingObject):
         r'^\s*from=<(?P<from>[^>]*)>,\s+size=(?P<size>\d+),\s+nrcpt=(?P<nrcpt>\d+)',
         re.IGNORECASE)
 
+    warn_on_parse_error = True
+
     # -------------------------------------------------------------------------
     def __init__(
         self, appname=None, verbose=0, version=__version__, base_dir=None,
@@ -82,6 +84,10 @@ class PostfixLogfileParser(HandlingObject):
             terminal_has_colors=terminal_has_colors, initialized=False,
         )
 
+        if not self.warn_on_parse_error:
+            SmtpAction.warn_on_parse_error = False
+            PostfixLogchainInfo.warn_on_parse_error = False
+
         self.reset(no_warnings=True)
 
         if initialized:
@@ -323,7 +329,11 @@ class PostfixLogfileParser(HandlingObject):
             self, postfix_id, timestamp=None, host=None, pid=None, message=None):
         """Evaluate a postfix/smtp action log line."""
         if postfix_id not in self.chain:
-            LOG.warn(_('Postfix transaction {!r} does not exists.').format(postfix_id))
+            msg = _('Postfix transaction {!r} does not exists.').format(postfix_id)
+            if self.warn_on_parse_error:
+                LOG.warn(msg)
+            else:
+                LOG.debug(msg)
             return
 
         action = SmtpAction.from_log_entry(
index df54b5796079749abfed94d091153389a9752e4e..861fae7346f1a2aa4943c868b23ee56c8b1aebd4 100644 (file)
@@ -18,21 +18,29 @@ from collections.abc import Sequence
 
 # Third party modules
 from fb_tools.common import pp
+from fb_tools.common import timeinterval2delta
 from fb_tools.common import to_bool
 from fb_tools.errors import InvalidMailAddressError
 from fb_tools.mailaddress import MailAddress
 from fb_tools.obj import FbGenericBaseObject
 
 # Own modules
+from . import DEFAULT_TZ_OFFSET
 from .errors import DateFormatError
 from .errors import WrongDateIsoformatError
-from .tzlocal import get_localzone
 from .xlate import XLATOR
 
+HAS_GET_LOCALZONE = False
+try:
+    from .tzlocal import get_localzone
+    HAS_GET_LOCALZONE = True
+except ImportError:
+    pass
+
 _ = XLATOR.gettext
 ngettext = XLATOR.ngettext
 
-__version__ = '0.7.2'
+__version__ = '0.7.3'
 
 LOG = logging.getLogger(__name__)
 
@@ -45,6 +53,55 @@ PATTERN_ISOTIMEZONE = r'((?P<utc>Z)|(?P<tz_hours>[+-][01]\d)(?::?(?P<tz_mins>[0-
 
 RE_ISODATETIME = re.compile(PATTERN_ISODATE + r'[T\s]' + PATTERN_ISOTIME + PATTERN_ISOTIMEZONE)
 
+PATTERN_DEFAULT_TZ = r'^\s*(?P<sign>[+-])\s*(?P<offset>.*)'
+RE_DEFAULT_TZ = re.compile(PATTERN_DEFAULT_TZ)
+
+RE_TZ = re.compile(r'^\s*(?P<tz_hours>[01]\d)(?::?(?P<tz_mins>[0-5]\d))?')
+
+DEFAULT_TZ = UTC
+
+# =============================================================================
+def get_default_tz_from_offset(offset=None):
+    """Return the given offset in seconds as a datetime.timezone object."""
+    if offset is None:
+        offset = DEFAULT_TZ_OFFSET
+
+    default_tz = datetime.timedelta()
+
+    if not offset:
+        return default_tz
+
+    if isinstance(offset, (int, float)):
+        return datetime.timezone(datetime.timedelta(seconds=float(offset)))
+
+    offset = str(offset)
+    omatch = RE_DEFAULT_TZ.match(offset)
+    if not omatch:
+        msg = _('Could not interprete {!r} as a timezone offset.').format(offset)
+        raise ValueError(msg)
+
+    sign = omatch['sign']
+    offset_abs = omatch['offset']
+
+    tz_match = RE_TZ.match(offset_abs)
+    if tz_match:
+        res_offset = 0
+        if tz_match['tz_mins']:
+            res_offset = int(tz_match['tz_mins']) * 60
+        res_offset += int(tz_match['tz_hours']) * 3600
+        if sign == '-':
+            res_offset *= -1
+        return datetime.timezone(datetime.timedelta(seconds=res_offset))
+
+    delta = timeinterval2delta(offset_abs)
+    if sign == '-':
+        delta *= -1
+    return datetime.timezone(delta)
+
+
+# =============================================================================
+DEFAULT_TZ = get_default_tz_from_offset(DEFAULT_TZ_OFFSET)
+
 
 # =============================================================================
 def fromisoformat(datestr):
@@ -85,7 +142,10 @@ def fromisoformat(datestr):
 
         params['tzinfo'] = datetime.timezone(datetime.timedelta(seconds=offset))
     else:
-        params['tzinfo'] = get_localzone()
+        if HAS_GET_LOCALZONE:
+            params['tzinfo'] = get_localzone()
+        else:
+            params['tzinfo'] = DEFAULT_TZ
 
     return datetime.datetime(**params)
 
index 2f3dafd4e99a0c8e02ebe20af164292da5dc200a..446afef7e81afd5d3d1976a8c0b44ae6fd73efcb 100755 (executable)
@@ -88,6 +88,7 @@ class TestPostfixLogparser(PpAdminToolsTestcase):
 
         from pp_admintools.handler.pflogparse import PostfixLogfileParser
 
+        PostfixLogfileParser.warn_on_parse_error = False
         parser = PostfixLogfileParser(appname=APPNAME, verbose=self.verbose)
 
         LOG.debug('PostfixLogfileParser %r: {!r}'.format(parser))