/usr/lib/python3/dist-packages/nagiosplugin/range.py is in python3-nagiosplugin 1.2.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | # Copyright (c) gocept gmbh & co. kg
# See also LICENSE.txt
import collections
class Range(collections.namedtuple('Range', 'invert start end')):
"""Represents a threshold range.
The general format is "[@][start:][end]". "start:" may be omitted if
start==0. "~:" means that start is negative infinity. If `end` is
omitted, infinity is assumed. To invert the match condition, prefix
the range expression with "@".
See
http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT
for details.
"""
def __new__(cls, spec=''):
"""Creates a Range object according to `spec`.
:param spec: may be either a string, an int, or another
Range object.
"""
spec = spec or ''
if isinstance(spec, Range):
return super(cls, Range).__new__(
cls, spec.invert, spec.start, spec.end)
elif (isinstance(spec, int) or isinstance(spec, float)):
start, end, invert = 0, spec, False
start, end, invert = cls._parse(str(spec))
cls._verify(start, end)
return super(cls, Range).__new__(cls, invert, start, end)
@classmethod
def _parse(cls, spec):
invert = False
if spec.startswith('@'):
invert = True
spec = spec[1:]
if ':' in spec:
start, end = spec.split(':')
else:
start, end = '', spec
if start == '~':
start = float('-inf')
else:
start = cls._parse_atom(start, 0)
end = cls._parse_atom(end, float('inf'))
return start, end, invert
@staticmethod
def _parse_atom(atom, default):
if atom is '':
return default
if '.' in atom:
return float(atom)
return int(atom)
@staticmethod
def _verify(start, end):
"""Throws ValueError if the range is not consistent."""
if start > end:
raise ValueError('start %s must not be greater than end %s' % (
start, end))
def match(self, value):
"""Decides if `value` is inside/outside the threshold.
:returns: `True` if value is inside the bounds for non-inverted
Ranges.
Also available as `in` operator.
"""
if value < self.start:
return False ^ self.invert
if value > self.end:
return False ^ self.invert
return True ^ self.invert
def __contains__(self, value):
return self.match(value)
def _format(self, omit_zero_start=True):
result = []
if self.invert:
result.append('@')
if self.start == float('-inf'):
result.append('~:')
elif not omit_zero_start or self.start != 0:
result.append(('%s:' % self.start))
if self.end != float('inf'):
result.append(('%s' % self.end))
return ''.join(result)
def __str__(self):
"""Human-readable range specification."""
return self._format()
def __repr__(self):
"""Parseable range specification."""
return 'Range(%r)' % str(self)
@property
def violation(self):
"""Human-readable description why a value does not match."""
return 'outside range {0}'.format(self._format(False))
|