Skip to content

Commit 6f8fbf7

Browse files
committed
base3: Move Date/Time-related Functions to a new "time3.py" Library (fixed #55)
1 parent aecd246 commit 6f8fbf7

File tree

5 files changed

+116
-100
lines changed

5 files changed

+116
-100
lines changed

base3.py

+23-86
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,21 @@
1010

1111
"""Provides very common every-day functions.
1212
13-
The functions "to_text()" and "to_bytes()" are copied from
13+
The functions "to_text()" and "to_bytes()" are copied from
1414
/usr/lib/python3.10/site-packages/ansible/module_utils/_text.py (BSD license).
1515
"""
1616

1717
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
1818
__version__ = '2022021504'
1919

2020
import collections
21-
import datetime
2221
import numbers
2322
import operator
2423
import os
2524
import re
2625
import shlex
2726
import subprocess
2827
import sys
29-
import time
3028

3129
from traceback import format_exc # pylint: disable=C0413
3230

@@ -92,16 +90,6 @@ def cu():
9290
sys.exit(STATE_UNKNOWN)
9391

9492

95-
def epoch2iso(timestamp):
96-
"""Returns the ISO representaton of a UNIX timestamp (epoch).
97-
98-
>>> epoch2iso(1620459129)
99-
'2021-05-08 09:32:09'
100-
"""
101-
timestamp = float(timestamp)
102-
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp))
103-
104-
10593
def get_command_output(cmd, regex=None):
10694
"""Runs a shell command and returns its output. Optionally, applies a regex and just
10795
returns the first matching group. If the command is not found, an empty string is returned.
@@ -134,7 +122,7 @@ def get_command_output(cmd, regex=None):
134122
return stdout.strip()
135123

136124

137-
def get_perfdata(label, value, uom, warn, crit, min, max):
125+
def get_perfdata(label, value, uom, warn, crit, _min, _max):
138126
"""Returns 'label'=value[UOM];[warn];[crit];[min];[max]
139127
"""
140128
msg = "'{}'={}".format(label, value)
@@ -147,11 +135,11 @@ def get_perfdata(label, value, uom, warn, crit, min, max):
147135
if crit is not None:
148136
msg += str(crit)
149137
msg += ';'
150-
if min is not None:
151-
msg += str(min)
138+
if _min is not None:
139+
msg += str(_min)
152140
msg += ';'
153-
if max is not None:
154-
msg += str(max)
141+
if _max is not None:
142+
msg += str(_max)
155143
msg += ' '
156144
return msg
157145

@@ -350,7 +338,8 @@ def get_worst(state1, state2):
350338

351339

352340
def guess_type(v, consumer='python'):
353-
"""Guess the type of a value (None, int, float or string) for different types of consumers (Python, SQLite etc.).
341+
"""Guess the type of a value (None, int, float or string) for different types of consumers
342+
(Python, SQLite etc.).
354343
For Python, use isinstance() to check for example if a number is an integer.
355344
356345
>>> guess_type('1')
@@ -373,34 +362,32 @@ def guess_type(v, consumer='python'):
373362
if consumer == 'python':
374363
if v is None:
375364
return None
376-
else:
365+
try:
366+
return int(v)
367+
except ValueError:
377368
try:
378-
return int(v)
369+
return float(v)
379370
except ValueError:
380-
try:
381-
return float(v)
382-
except ValueError:
383-
return str(v)
371+
return str(v)
384372

385373
if consumer == 'sqlite':
386374
if v is None:
387375
return 'string'
388-
else:
376+
try:
377+
int(v)
378+
return 'integer'
379+
except ValueError:
389380
try:
390-
int(v)
391-
return 'integer'
381+
float(v)
382+
return 'real'
392383
except ValueError:
393-
try:
394-
float(v)
395-
return 'real'
396-
except ValueError:
397-
return 'text'
384+
return 'text'
398385

399386

400387
def is_empty_list(l):
401388
"""Check if a list only contains either empty elements or whitespace
402389
"""
403-
return all('' == s or s.isspace() for s in l)
390+
return all(s == '' or s.isspace() for s in l)
404391

405392

406393
def is_numeric(value):
@@ -497,7 +484,7 @@ def parse_atom(atom, default):
497484
if not success:
498485
return (success, result)
499486
start, end, invert = result
500-
if isinstance(value, str) or isinstance(value, bytes):
487+
if isinstance(value, (str, bytes)):
501488
value = float(value.replace('%', ''))
502489
if value < start:
503490
return (True, False ^ invert)
@@ -506,29 +493,6 @@ def parse_atom(atom, default):
506493
return (True, True ^ invert)
507494

508495

509-
def now(as_type=''):
510-
"""Returns the current date and time as UNIX time in seconds (default), or
511-
as a datetime object.
512-
513-
lib.base3.now()
514-
>>> 1586422786
515-
516-
lib.base3.now(as_type='epoch')
517-
>>> 1586422786
518-
519-
lib.base3.now(as_type='datetime')
520-
>>> datetime.datetime(2020, 4, 9, 11, 1, 41, 228752)
521-
522-
lib.base3.now(as_type='iso')
523-
>>> '2020-04-09 11:31:24'
524-
"""
525-
if as_type == 'datetime':
526-
return datetime.datetime.now()
527-
if as_type == 'iso':
528-
return time.strftime("%Y-%m-%d %H:%M:%S")
529-
return int(time.time())
530-
531-
532496
def oao(msg, state=STATE_OK, perfdata='', always_ok=False):
533497
"""Over and Out (OaO)
534498
@@ -746,32 +710,6 @@ def state2str(state, empty_ok=True, prefix='', suffix=''):
746710
return state
747711

748712

749-
def timestr2datetime(timestr, pattern='%Y-%m-%d %H:%M:%S'):
750-
"""Takes a string (default: ISO format) and returns a
751-
datetime object.
752-
"""
753-
return datetime.datetime.strptime(timestr, pattern)
754-
755-
756-
def timestrdiff(timestr1, timestr2, pattern1='%Y-%m-%d %H:%M:%S', pattern2='%Y-%m-%d %H:%M:%S'):
757-
"""Returns the difference between two datetime strings in seconds. This
758-
function expects two ISO timestamps, by default each in ISO format.
759-
"""
760-
timestr1 = timestr2datetime(timestr1, pattern1)
761-
timestr2 = timestr2datetime(timestr2, pattern2)
762-
timedelta = abs(timestr1 - timestr2)
763-
return timedelta.total_seconds()
764-
765-
766-
def utc_offset():
767-
"""Returns the current local UTC offset, for example '+0200'.
768-
769-
utc_offset()
770-
>>> '+0200'
771-
"""
772-
return time.strftime("%z")
773-
774-
775713
def version(v):
776714
"""Use this function to compare string-based version numbers.
777715
@@ -813,5 +751,4 @@ def version2float(v):
813751
v = v.split('.')
814752
if len(v) > 1:
815753
return float('{}.{}'.format(v[0], ''.join(v[1:])))
816-
else:
817-
return float(''.join(v))
754+
return float(''.join(v))

cache3.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
1616
>>> cache3.get('session-key')
1717
False
18-
>>> cache3.set('session-key', '123abc', expire=base.now() + 5)
18+
>>> cache3.set('session-key', '123abc', expire=time3.now() + 5)
1919
True
2020
>>> cache3.get('session-key')
2121
u'123abc'
@@ -25,9 +25,9 @@
2525
"""
2626

2727
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
28-
__version__ = '2021100801'
28+
__version__ = '2022021501'
2929

30-
from . import base3
30+
from . import time3
3131
from . import db_sqlite3
3232

3333

@@ -65,13 +65,13 @@ def get(key, as_dict=False, path='', filename='linuxfabrik-plugin-cache.db'):
6565
db_sqlite3.close(conn)
6666
return False
6767

68-
if result['timestamp'] != 0 and result['timestamp'] <= base3.now():
68+
if result['timestamp'] != 0 and result['timestamp'] <= time3.now():
6969
# key was found, but timstamp was set and has expired:
7070
# delete all expired keys and return false
7171
data = {'key' : result['key']}
7272
success, result = db_sqlite3.delete(
7373
conn,
74-
sql='DELETE FROM cache WHERE timestamp <= {};'.format(base3.now())
74+
sql='DELETE FROM cache WHERE timestamp <= {};'.format(time3.now())
7575
)
7676
success, result = db_sqlite3.commit(conn)
7777
db_sqlite3.close(conn)

feedparser3.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@
1919
print('Python module "BeautifulSoup4" is not installed.')
2020
exit(3)
2121

22-
from . import base3
22+
from . import time3
2323
from . import url3
2424

2525
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
26-
__version__ = '2021050601'
26+
__version__ = '2022021501'
2727

2828

2929
def parse_atom(soup):
3030
result = {}
3131
result['title'] = soup.title.string
3232
result['updated'] = soup.updated.string
3333
# cut the timezone part
34-
result['updated_parsed'] = base3.timestr2datetime(result['updated'][0:19], pattern='%Y-%m-%dT%H:%M:%S')
34+
result['updated_parsed'] = time3.timestr2datetime(result['updated'][0:19], pattern='%Y-%m-%dT%H:%M:%S')
3535

3636
result['entries'] = []
3737
for entry in soup.find_all('entry'):
@@ -40,7 +40,7 @@ def parse_atom(soup):
4040
tmp['id'] = entry.id.string
4141
tmp['updated'] = entry.updated.string
4242
# cut the timezone part
43-
tmp['updated_parsed'] = base3.timestr2datetime(tmp['updated'][0:19], pattern='%Y-%m-%dT%H:%M:%S')
43+
tmp['updated_parsed'] = time3.timestr2datetime(tmp['updated'][0:19], pattern='%Y-%m-%dT%H:%M:%S')
4444
try:
4545
soup = BeautifulSoup(entry.summary.string, 'lxml')
4646
tmp['summary'] = soup.get_text()
@@ -59,7 +59,7 @@ def parse_rss(soup):
5959
result['title'] = soup.rss.channel.title.string
6060
result['updated'] = soup.rss.channel.pubDate.string
6161
# cut the timezone part
62-
result['updated_parsed'] = base3.timestr2datetime(result['updated'][0:25], pattern='%a, %d %b %Y %H:%M:%S')
62+
result['updated_parsed'] = time3.timestr2datetime(result['updated'][0:25], pattern='%a, %d %b %Y %H:%M:%S')
6363

6464
result['entries'] = []
6565
for entry in soup.find_all('item'):
@@ -68,7 +68,7 @@ def parse_rss(soup):
6868
tmp['id'] = entry.guid.string
6969
tmp['updated'] = entry.pubDate.string
7070
# cut the timezone part
71-
tmp['updated_parsed'] = base3.timestr2datetime(tmp['updated'][0:25], pattern='%a, %d %b %Y %H:%M:%S')
71+
tmp['updated_parsed'] = time3.timestr2datetime(tmp['updated'][0:25], pattern='%a, %d %b %Y %H:%M:%S')
7272
try:
7373
soup = BeautifulSoup(entry.description.string, 'lxml')
7474
tmp['summary'] = soup.get_text()

huawei3.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@
99
# https://git.linuxfabrik.ch/linuxfabrik-icinga-plugins/checks-linux/-/blob/master/CONTRIBUTING.md
1010

1111
"""This library collects some LibreNMS related functions that are
12-
needed by LibreNMS check plugins."""
12+
needed by LibreNMS check plugins.
13+
"""
1314

1415
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
15-
__version__ = '2022012101'
16+
__version__ = '2022021501'
1617

1718
import time
1819

1920
from .globals3 import STATE_CRIT, STATE_OK, STATE_UNKNOWN, STATE_WARN
2021

2122
from . import base3
2223
from . import cache3
24+
from . import time3
2325
from . import url3
2426

2527

@@ -53,7 +55,7 @@ def get_creds(args):
5355
ibasetoken = result.get('response_json').get('data').get('iBaseToken')
5456
# In Python 3, getheader() should be get()
5557
cookie = result.get('response_header').get('Set-Cookie')
56-
expire = base3.now() + args.CACHE_EXPIRE*60
58+
expire = time3.now() + args.CACHE_EXPIRE*60
5759
cache3.set('huawei-{}-ibasetoken'.format(args.DEVICE_ID), ibasetoken, expire)
5860
cache3.set('huawei-{}-cookie'.format(args.DEVICE_ID), cookie, expire)
5961
return ibasetoken, cookie

time3.py

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#! /usr/bin/env python3
2+
# -*- coding: utf-8; py-indent-offset: 4 -*-
3+
#
4+
# Author: Linuxfabrik GmbH, Zurich, Switzerland
5+
# Contact: info (at) linuxfabrik (dot) ch
6+
# https://www.linuxfabrik.ch/
7+
# License: The Unlicense, see LICENSE file.
8+
9+
# https://git.linuxfabrik.ch/linuxfabrik-icinga-plugins/checks-linux/-/blob/master/CONTRIBUTING.md
10+
11+
"""Provides datetime functions.
12+
"""
13+
14+
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
15+
__version__ = '2022021501'
16+
17+
import datetime
18+
import time
19+
20+
21+
def epoch2iso(timestamp):
22+
"""Returns the ISO representaton of a UNIX timestamp (epoch).
23+
24+
>>> epoch2iso(1620459129)
25+
'2021-05-08 09:32:09'
26+
"""
27+
timestamp = float(timestamp)
28+
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp))
29+
30+
31+
def now(as_type=''):
32+
"""Returns the current date and time as UNIX time in seconds (default), or
33+
as a datetime object.
34+
35+
lib.base3.now()
36+
>>> 1586422786
37+
38+
lib.base3.now(as_type='epoch')
39+
>>> 1586422786
40+
41+
lib.base3.now(as_type='datetime')
42+
>>> datetime.datetime(2020, 4, 9, 11, 1, 41, 228752)
43+
44+
lib.base3.now(as_type='iso')
45+
>>> '2020-04-09 11:31:24'
46+
"""
47+
if as_type == 'datetime':
48+
return datetime.datetime.now()
49+
if as_type == 'iso':
50+
return time.strftime("%Y-%m-%d %H:%M:%S")
51+
return int(time.time())
52+
53+
54+
def timestr2datetime(timestr, pattern='%Y-%m-%d %H:%M:%S'):
55+
"""Takes a string (default: ISO format) and returns a
56+
datetime object.
57+
"""
58+
return datetime.datetime.strptime(timestr, pattern)
59+
60+
61+
def timestrdiff(timestr1, timestr2, pattern1='%Y-%m-%d %H:%M:%S', pattern2='%Y-%m-%d %H:%M:%S'):
62+
"""Returns the difference between two datetime strings in seconds. This
63+
function expects two ISO timestamps, by default each in ISO format.
64+
"""
65+
timestr1 = timestr2datetime(timestr1, pattern1)
66+
timestr2 = timestr2datetime(timestr2, pattern2)
67+
timedelta = abs(timestr1 - timestr2)
68+
return timedelta.total_seconds()
69+
70+
71+
def utc_offset():
72+
"""Returns the current local UTC offset, for example '+0200'.
73+
74+
utc_offset()
75+
>>> '+0200'
76+
"""
77+
return time.strftime("%z")

0 commit comments

Comments
 (0)