PageRenderTime 36ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/ta_luhn/bin/splunklib/searchcommands/validators.py

https://gitlab.com/johnfromthefuture/TA-luhn
Python | 394 lines | 346 code | 11 blank | 37 comment | 9 complexity | 97a3bc794f7d4ee3cb17949cdb801558 MD5 | raw file
  1. # coding=utf-8
  2. #
  3. # Copyright 2011-2015 Splunk, Inc.
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License"): you may
  6. # not use this file except in compliance with the License. You may obtain
  7. # a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. # License for the specific language governing permissions and limitations
  15. # under the License.
  16. from __future__ import absolute_import, division, print_function, unicode_literals
  17. from json.encoder import encode_basestring_ascii as json_encode_string
  18. from collections import namedtuple
  19. from splunklib.six.moves import StringIO
  20. from io import open
  21. import csv
  22. import os
  23. import re
  24. from splunklib import six
  25. from splunklib.six.moves import getcwd
  26. class Validator(object):
  27. """ Base class for validators that check and format search command options.
  28. You must inherit from this class and override :code:`Validator.__call__` and
  29. :code:`Validator.format`. :code:`Validator.__call__` should convert the
  30. value it receives as argument and then return it or raise a
  31. :code:`ValueError`, if the value will not convert.
  32. :code:`Validator.format` should return a human readable version of the value
  33. it receives as argument the same way :code:`str` does.
  34. """
  35. def __call__(self, value):
  36. raise NotImplementedError()
  37. def format(self, value):
  38. raise NotImplementedError()
  39. class Boolean(Validator):
  40. """ Validates Boolean option values.
  41. """
  42. truth_values = {
  43. '1': True, '0': False,
  44. 't': True, 'f': False,
  45. 'true': True, 'false': False,
  46. 'y': True, 'n': False,
  47. 'yes': True, 'no': False
  48. }
  49. def __call__(self, value):
  50. if not (value is None or isinstance(value, bool)):
  51. value = six.text_type(value).lower()
  52. if value not in Boolean.truth_values:
  53. raise ValueError('Unrecognized truth value: {0}'.format(value))
  54. value = Boolean.truth_values[value]
  55. return value
  56. def format(self, value):
  57. return None if value is None else 't' if value else 'f'
  58. class Code(Validator):
  59. """ Validates code option values.
  60. This validator compiles an option value into a Python code object that can be executed by :func:`exec` or evaluated
  61. by :func:`eval`. The value returned is a :func:`namedtuple` with two members: object, the result of compilation, and
  62. source, the original option value.
  63. """
  64. def __init__(self, mode='eval'):
  65. """
  66. :param mode: Specifies what kind of code must be compiled; it can be :const:`'exec'`, if source consists of a
  67. sequence of statements, :const:`'eval'`, if it consists of a single expression, or :const:`'single'` if it
  68. consists of a single interactive statement. In the latter case, expression statements that evaluate to
  69. something other than :const:`None` will be printed.
  70. :type mode: unicode or bytes
  71. """
  72. self._mode = mode
  73. def __call__(self, value):
  74. if value is None:
  75. return None
  76. try:
  77. return Code.object(compile(value, 'string', self._mode), six.text_type(value))
  78. except (SyntaxError, TypeError) as error:
  79. if six.PY2:
  80. message = error.message
  81. else:
  82. message = str(error)
  83. six.raise_from(ValueError(message), error)
  84. def format(self, value):
  85. return None if value is None else value.source
  86. object = namedtuple('Code', ('object', 'source'))
  87. class Fieldname(Validator):
  88. """ Validates field name option values.
  89. """
  90. pattern = re.compile(r'''[_.a-zA-Z-][_.a-zA-Z0-9-]*$''')
  91. def __call__(self, value):
  92. if value is not None:
  93. value = six.text_type(value)
  94. if Fieldname.pattern.match(value) is None:
  95. raise ValueError('Illegal characters in fieldname: {}'.format(value))
  96. return value
  97. def format(self, value):
  98. return value
  99. class File(Validator):
  100. """ Validates file option values.
  101. """
  102. def __init__(self, mode='rt', buffering=None, directory=None):
  103. self.mode = mode
  104. self.buffering = buffering
  105. self.directory = File._var_run_splunk if directory is None else directory
  106. def __call__(self, value):
  107. if value is None:
  108. return value
  109. path = six.text_type(value)
  110. if not os.path.isabs(path):
  111. path = os.path.join(self.directory, path)
  112. try:
  113. value = open(path, self.mode) if self.buffering is None else open(path, self.mode, self.buffering)
  114. except IOError as error:
  115. raise ValueError('Cannot open {0} with mode={1} and buffering={2}: {3}'.format(
  116. value, self.mode, self.buffering, error))
  117. return value
  118. def format(self, value):
  119. return None if value is None else value.name
  120. _var_run_splunk = os.path.join(
  121. os.environ['SPLUNK_HOME'] if 'SPLUNK_HOME' in os.environ else getcwd(), 'var', 'run', 'splunk')
  122. class Integer(Validator):
  123. """ Validates integer option values.
  124. """
  125. def __init__(self, minimum=None, maximum=None):
  126. if minimum is not None and maximum is not None:
  127. def check_range(value):
  128. if not (minimum <= value <= maximum):
  129. raise ValueError('Expected integer in the range [{0},{1}], not {2}'.format(minimum, maximum, value))
  130. return
  131. elif minimum is not None:
  132. def check_range(value):
  133. if value < minimum:
  134. raise ValueError('Expected integer in the range [{0},+∞], not {1}'.format(minimum, value))
  135. return
  136. elif maximum is not None:
  137. def check_range(value):
  138. if value > maximum:
  139. raise ValueError('Expected integer in the range [-∞,{0}], not {1}'.format(maximum, value))
  140. return
  141. else:
  142. def check_range(value):
  143. return
  144. self.check_range = check_range
  145. return
  146. def __call__(self, value):
  147. if value is None:
  148. return None
  149. try:
  150. if six.PY2:
  151. value = long(value)
  152. else:
  153. value = int(value)
  154. except ValueError:
  155. raise ValueError('Expected integer value, not {}'.format(json_encode_string(value)))
  156. self.check_range(value)
  157. return value
  158. def format(self, value):
  159. return None if value is None else six.text_type(int(value))
  160. class Duration(Validator):
  161. """ Validates duration option values.
  162. """
  163. def __call__(self, value):
  164. if value is None:
  165. return None
  166. p = value.split(':', 2)
  167. result = None
  168. _60 = Duration._60
  169. _unsigned = Duration._unsigned
  170. try:
  171. if len(p) == 1:
  172. result = _unsigned(p[0])
  173. if len(p) == 2:
  174. result = 60 * _unsigned(p[0]) + _60(p[1])
  175. if len(p) == 3:
  176. result = 3600 * _unsigned(p[0]) + 60 * _60(p[1]) + _60(p[2])
  177. except ValueError:
  178. raise ValueError('Invalid duration value: {0}'.format(value))
  179. return result
  180. def format(self, value):
  181. if value is None:
  182. return None
  183. value = int(value)
  184. s = value % 60
  185. m = value // 60 % 60
  186. h = value // (60 * 60)
  187. return '{0:02d}:{1:02d}:{2:02d}'.format(h, m, s)
  188. _60 = Integer(0, 59)
  189. _unsigned = Integer(0)
  190. class List(Validator):
  191. """ Validates a list of strings
  192. """
  193. class Dialect(csv.Dialect):
  194. """ Describes the properties of list option values. """
  195. strict = True
  196. delimiter = str(',')
  197. quotechar = str('"')
  198. doublequote = True
  199. lineterminator = str('\n')
  200. skipinitialspace = True
  201. quoting = csv.QUOTE_MINIMAL
  202. def __init__(self, validator=None):
  203. if not (validator is None or isinstance(validator, Validator)):
  204. raise ValueError('Expected a Validator instance or None for validator, not {}', repr(validator))
  205. self._validator = validator
  206. def __call__(self, value):
  207. if value is None or isinstance(value, list):
  208. return value
  209. try:
  210. value = next(csv.reader([value], self.Dialect))
  211. except csv.Error as error:
  212. raise ValueError(error)
  213. if self._validator is None:
  214. return value
  215. try:
  216. for index, item in enumerate(value):
  217. value[index] = self._validator(item)
  218. except ValueError as error:
  219. raise ValueError('Could not convert item {}: {}'.format(index, error))
  220. return value
  221. def format(self, value):
  222. output = StringIO()
  223. writer = csv.writer(output, List.Dialect)
  224. writer.writerow(value)
  225. value = output.getvalue()
  226. return value[:-1]
  227. class Map(Validator):
  228. """ Validates map option values.
  229. """
  230. def __init__(self, **kwargs):
  231. self.membership = kwargs
  232. def __call__(self, value):
  233. if value is None:
  234. return None
  235. value = six.text_type(value)
  236. if value not in self.membership:
  237. raise ValueError('Unrecognized value: {0}'.format(value))
  238. return self.membership[value]
  239. def format(self, value):
  240. return None if value is None else list(self.membership.keys())[list(self.membership.values()).index(value)]
  241. class Match(Validator):
  242. """ Validates that a value matches a regular expression pattern.
  243. """
  244. def __init__(self, name, pattern, flags=0):
  245. self.name = six.text_type(name)
  246. self.pattern = re.compile(pattern, flags)
  247. def __call__(self, value):
  248. if value is None:
  249. return None
  250. value = six.text_type(value)
  251. if self.pattern.match(value) is None:
  252. raise ValueError('Expected {}, not {}'.format(self.name, json_encode_string(value)))
  253. return value
  254. def format(self, value):
  255. return None if value is None else six.text_type(value)
  256. class OptionName(Validator):
  257. """ Validates option names.
  258. """
  259. pattern = re.compile(r'''(?=\w)[^\d]\w*$''', re.UNICODE)
  260. def __call__(self, value):
  261. if value is not None:
  262. value = six.text_type(value)
  263. if OptionName.pattern.match(value) is None:
  264. raise ValueError('Illegal characters in option name: {}'.format(value))
  265. return value
  266. def format(self, value):
  267. return None if value is None else six.text_type(value)
  268. class RegularExpression(Validator):
  269. """ Validates regular expression option values.
  270. """
  271. def __call__(self, value):
  272. if value is None:
  273. return None
  274. try:
  275. value = re.compile(six.text_type(value))
  276. except re.error as error:
  277. raise ValueError('{}: {}'.format(six.text_type(error).capitalize(), value))
  278. return value
  279. def format(self, value):
  280. return None if value is None else value.pattern
  281. class Set(Validator):
  282. """ Validates set option values.
  283. """
  284. def __init__(self, *args):
  285. self.membership = set(args)
  286. def __call__(self, value):
  287. if value is None:
  288. return None
  289. value = six.text_type(value)
  290. if value not in self.membership:
  291. raise ValueError('Unrecognized value: {}'.format(value))
  292. return value
  293. def format(self, value):
  294. return self.__call__(value)
  295. __all__ = ['Boolean', 'Code', 'Duration', 'File', 'Integer', 'List', 'Map', 'RegularExpression', 'Set']