validator.py 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. import re
  2. import struct
  3. import sys
  4. import time
  5. import uuid
  6. from functools import lru_cache
  7. from ipaddress import IPv4Address, IPv6Address, ip_address
  8. from urllib import parse as urlparse
  9. from google.protobuf.message import Message
  10. from jinja2 import Template
  11. from validate_email import validate_email
  12. printer = ""
  13. # Well known regex mapping.
  14. regex_map = {
  15. "UNKNOWN": "",
  16. "HTTP_HEADER_NAME": r'^:?[0-9a-zA-Z!#$%&\'*+-.^_|~\x60]+$',
  17. "HTTP_HEADER_VALUE": r'^[^\u0000-\u0008\u000A-\u001F\u007F]*$',
  18. "HEADER_STRING": r'^[^\u0000\u000A\u000D]*$'
  19. }
  20. class ValidationFailed(Exception):
  21. pass
  22. class ValidatingMessage(object):
  23. """Wrap a proto message to cache validate functions with the message class name.
  24. A validate function is defined per message class in protoc-gen-validate,
  25. so we can reuse an already generated function for the same message class.
  26. """
  27. def __init__(self, proto_message):
  28. self.DESCRIPTOR = proto_message.DESCRIPTOR
  29. def __hash__(self):
  30. return hash(self.DESCRIPTOR.full_name)
  31. def __eq__(self, other):
  32. if isinstance(other, ValidatingMessage):
  33. return self.DESCRIPTOR.full_name == other.DESCRIPTOR.full_name
  34. else:
  35. return False
  36. def validate(proto_message: Message):
  37. return _validate_inner(ValidatingMessage(proto_message))(proto_message)
  38. # Cache generated functions with the message descriptor's full_name as the cache key
  39. @lru_cache()
  40. def _validate_inner(proto_message: Message):
  41. func = file_template(proto_message)
  42. global printer
  43. printer += func + "\n"
  44. exec(func)
  45. try:
  46. return generate_validate
  47. except NameError:
  48. return locals()['generate_validate']
  49. def print_validate():
  50. return "".join([s for s in printer.splitlines(True) if s.strip()])
  51. def has_validate(field):
  52. if field.GetOptions() is None:
  53. return False
  54. for option_descriptor, option_value in field.GetOptions().ListFields():
  55. if option_descriptor.full_name == "validate.rules":
  56. return True
  57. return False
  58. def byte_len(s):
  59. try:
  60. return len(s.encode('utf-8'))
  61. except: # noqa
  62. return len(s)
  63. def _validateHostName(host):
  64. if not host:
  65. return False
  66. if len(host) > 253:
  67. return False
  68. if host[-1] == '.':
  69. host = host[:-1]
  70. for part in host.split("."):
  71. if len(part) == 0 or len(part) > 63:
  72. return False
  73. # Host names cannot begin or end with hyphens
  74. if part[0] == "-" or part[-1] == '-':
  75. return False
  76. for r in part:
  77. if (r < 'A' or r > 'Z') and (r < 'a' or r > 'z') and (r < '0' or r > '9') and r != '-':
  78. return False
  79. return True
  80. def _validateEmail(addr):
  81. if '<' in addr and '>' in addr:
  82. addr = addr.split("<")[1].split(">")[0]
  83. if not validate_email(addr):
  84. return False
  85. if len(addr) > 254:
  86. return False
  87. parts = addr.split("@")
  88. if len(parts[0]) > 64:
  89. return False
  90. return _validateHostName(parts[1])
  91. def _has_field(message_pb, property_name):
  92. # NOTE: As of proto3, HasField() only works for message fields, not for
  93. # singular (non-message) fields. First try to use HasField and
  94. # if it fails (with a ValueError) we manually consult the fields.
  95. try:
  96. return message_pb.HasField(property_name)
  97. except: # noqa
  98. all_fields = set([field.name for field in message_pb.DESCRIPTOR.fields])
  99. return property_name in all_fields
  100. def const_template(option_value, name):
  101. const_tmpl = """{%- if str(o.string) and o.string.HasField('const') -%}
  102. if {{ name }} != \"{{ o.string['const'] }}\":
  103. raise ValidationFailed(\"{{ name }} not equal to {{ o.string['const'] }}\")
  104. {%- elif str(o.bool) and o.bool['const'] != "" -%}
  105. if {{ name }} != {{ o.bool['const'] }}:
  106. raise ValidationFailed(\"{{ name }} not equal to {{ o.bool['const'] }}\")
  107. {%- elif str(o.enum) and o.enum['const'] -%}
  108. if {{ name }} != {{ o.enum['const'] }}:
  109. raise ValidationFailed(\"{{ name }} not equal to {{ o.enum['const'] }}\")
  110. {%- elif str(o.bytes) and o.bytes.HasField('const') -%}
  111. {% if sys.version_info[0] >= 3 %}
  112. if {{ name }} != {{ o.bytes['const'] }}:
  113. raise ValidationFailed(\"{{ name }} not equal to {{ o.bytes['const'] }}\")
  114. {% else %}
  115. if {{ name }} != b\"{{ o.bytes['const'].encode('string_escape') }}\":
  116. raise ValidationFailed(\"{{ name }} not equal to {{ o.bytes['const'].encode('string_escape') }}\")
  117. {% endif %}
  118. {%- endif -%}
  119. """
  120. return Template(const_tmpl).render(sys=sys, o=option_value, name=name, str=str)
  121. def in_template(value, name):
  122. in_tmpl = """
  123. {%- if value['in'] %}
  124. if {{ name }} not in {{ value['in'] }}:
  125. raise ValidationFailed(\"{{ name }} not in {{ value['in'] }}\")
  126. {%- endif -%}
  127. {%- if value['not_in'] %}
  128. if {{ name }} in {{ value['not_in'] }}:
  129. raise ValidationFailed(\"{{ name }} in {{ value['not_in'] }}\")
  130. {%- endif -%}
  131. """
  132. return Template(in_tmpl).render(value=value, name=name)
  133. def string_template(option_value, name):
  134. if option_value.string.well_known_regex:
  135. known_regex_type = option_value.string.DESCRIPTOR.fields_by_name['well_known_regex'].enum_type
  136. regex_value = option_value.string.well_known_regex
  137. regex_name = known_regex_type.values_by_number[regex_value].name
  138. if regex_name in ["HTTP_HEADER_NAME", "HTTP_HEADER_VALUE"] and not option_value.string.strict:
  139. option_value.string.pattern = regex_map["HEADER_STRING"]
  140. else:
  141. option_value.string.pattern = regex_map[regex_name]
  142. str_templ = """
  143. {%- set s = o.string -%}
  144. {% set i = 0 %}
  145. {%- if s['ignore_empty'] -%}
  146. if {{ name }}:
  147. {% set i = 4 %}
  148. {%- endif -%}
  149. {% filter indent(i,True) %}
  150. {{ const_template(o, name) -}}
  151. {{ in_template(o.string, name) -}}
  152. {%- if s['len'] %}
  153. if len({{ name }}) != {{ s['len'] }}:
  154. raise ValidationFailed(\"{{ name }} length does not equal {{ s['len'] }}\")
  155. {%- endif -%}
  156. {%- if s['min_len'] %}
  157. if len({{ name }}) < {{ s['min_len'] }}:
  158. raise ValidationFailed(\"{{ name }} length is less than {{ s['min_len'] }}\")
  159. {%- endif -%}
  160. {%- if s['max_len'] %}
  161. if len({{ name }}) > {{ s['max_len'] }}:
  162. raise ValidationFailed(\"{{ name }} length is more than {{ s['max_len'] }}\")
  163. {%- endif -%}
  164. {%- if s['len_bytes'] %}
  165. if byte_len({{ name }}) != {{ s['len_bytes'] }}:
  166. raise ValidationFailed(\"{{ name }} length does not equal {{ s['len_bytes'] }}\")
  167. {%- endif -%}
  168. {%- if s['min_bytes'] %}
  169. if byte_len({{ name }}) < {{ s['min_bytes'] }}:
  170. raise ValidationFailed(\"{{ name }} length is less than {{ s['min_bytes'] }}\")
  171. {%- endif -%}
  172. {%- if s['max_bytes'] %}
  173. if byte_len({{ name }}) > {{ s['max_bytes'] }}:
  174. raise ValidationFailed(\"{{ name }} length is greater than {{ s['max_bytes'] }}\")
  175. {%- endif -%}
  176. {%- if s['pattern'] %}
  177. if re.search(r\'{{ s['pattern'] }}\', {{ name }}) is None:
  178. raise ValidationFailed(\"{{ name }} pattern does not match {{ s['pattern'] }}\")
  179. {%- endif -%}
  180. {%- if s['prefix'] %}
  181. if not {{ name }}.startswith(\"{{ s['prefix'] }}\"):
  182. raise ValidationFailed(\"{{ name }} does not start with prefix {{ s['prefix'] }}\")
  183. {%- endif -%}
  184. {%- if s['suffix'] %}
  185. if not {{ name }}.endswith(\"{{ s['suffix'] }}\"):
  186. raise ValidationFailed(\"{{ name }} does not end with suffix {{ s['suffix'] }}\")
  187. {%- endif -%}
  188. {%- if s['contains'] %}
  189. if not \"{{ s['contains'] }}\" in {{ name }}:
  190. raise ValidationFailed(\"{{ name }} does not contain {{ s['contains'] }}\")
  191. {%- endif -%}
  192. {%- if s['not_contains'] %}
  193. if \"{{ s['not_contains'] }}\" in {{ name }}:
  194. raise ValidationFailed(\"{{ name }} contains {{ s['not_contains'] }}\")
  195. {%- endif -%}
  196. {%- if s['email'] %}
  197. if not _validateEmail({{ name }}):
  198. raise ValidationFailed(\"{{ name }} is not a valid email\")
  199. {%- endif -%}
  200. {%- if s['hostname'] %}
  201. if not _validateHostName({{ name }}):
  202. raise ValidationFailed(\"{{ name }} is not a valid email\")
  203. {%- endif -%}
  204. {%- if s['address'] %}
  205. try:
  206. ip_address({{ name }})
  207. except ValueError:
  208. if not _validateHostName({{ name }}):
  209. raise ValidationFailed(\"{{ name }} is not a valid address\")
  210. {%- endif -%}
  211. {%- if s['ip'] %}
  212. try:
  213. ip_address({{ name }})
  214. except ValueError:
  215. raise ValidationFailed(\"{{ name }} is not a valid ip\")
  216. {%- endif -%}
  217. {%- if s['ipv4'] %}
  218. try:
  219. IPv4Address({{ name }})
  220. except ValueError:
  221. raise ValidationFailed(\"{{ name }} is not a valid ipv4\")
  222. {%- endif -%}
  223. {%- if s['ipv6'] %}
  224. try:
  225. IPv6Address({{ name }})
  226. except ValueError:
  227. raise ValidationFailed(\"{{ name }} is not a valid ipv6\")
  228. {%- endif %}
  229. {%- if s['uri'] %}
  230. url = urlparse.urlparse({{ name }})
  231. if not all([url.scheme, url.netloc, url.path]):
  232. raise ValidationFailed(\"{{ name }} is not a valid uri\")
  233. {%- endif %}
  234. {%- if s['uri_ref'] %}
  235. url = urlparse.urlparse({{ name }})
  236. if not all([url.scheme, url.path]) and url.fragment:
  237. raise ValidationFailed(\"{{ name }} is not a valid uri ref\")
  238. {%- endif -%}
  239. {%- if s['uuid'] %}
  240. try:
  241. uuid.UUID({{ name }})
  242. except ValueError:
  243. raise ValidationFailed(\"{{ name }} is not a valid UUID\")
  244. {%- endif -%}
  245. {% endfilter %}
  246. """
  247. return Template(str_templ).render(o=option_value, name=name, const_template=const_template, in_template=in_template)
  248. def required_template(value, name):
  249. req_tmpl = """{%- if value['required'] %}
  250. if not _has_field(p, \"{{ name.split('.')[-1] }}\"):
  251. raise ValidationFailed(\"{{ name }} is required.\")
  252. {%- endif -%}
  253. """
  254. return Template(req_tmpl).render(value=value, name=name)
  255. def message_template(option_value, name, repeated=False):
  256. message_tmpl = """{%- if m.message %}
  257. {{- required_template(m.message, name) }}
  258. {%- endif -%}
  259. {%- if m.message and m.message['skip'] %}
  260. # Skipping validation for {{ name }}
  261. {%- else %}
  262. {% if repeated %}
  263. if {{ name }}:
  264. {% else %}
  265. if _has_field(p, \"{{ name.split('.')[-1] }}\"):
  266. {% endif %}
  267. embedded = validate(p.{{ name }})
  268. if embedded is not None:
  269. return embedded
  270. {%- endif -%}
  271. """
  272. return Template(message_tmpl).render(
  273. m=option_value, name=name, required_template=required_template, repeated=repeated)
  274. def bool_template(option_value, name):
  275. bool_tmpl = """
  276. {{ const_template(o, name) -}}
  277. """
  278. return Template(bool_tmpl).render(o=option_value, name=name, const_template=const_template)
  279. def num_template(option_value, name, num):
  280. num_tmpl = """
  281. {% set i = 0 %}
  282. {%- if num.HasField('ignore_empty') -%}
  283. if {{ name }}:
  284. {% set i = 4 %}
  285. {%- endif -%}
  286. {% filter indent(i,True) %}
  287. {%- if num.HasField('const') and str(o.float) == "" -%}
  288. if {{ name }} != {{ num['const'] }}:
  289. raise ValidationFailed(\"{{ name }} not equal to {{ num['const'] }}\")
  290. {%- endif -%}
  291. {%- if num.HasField('const') and str(o.float) != "" %}
  292. if {{ name }} != struct.unpack(\"f\", struct.pack(\"f\", ({{ num['const'] }})))[0]:
  293. raise ValidationFailed(\"{{ name }} not equal to {{ num['const'] }}\")
  294. {%- endif -%}
  295. {{ in_template(num, name) }}
  296. {%- if num.HasField('lt') %}
  297. {%- if num.HasField('gt') %}
  298. {%- if num['lt'] > num['gt'] %}
  299. if {{ name }} <= {{ num['gt'] }} or {{ name }} >= {{ num ['lt'] }}:
  300. raise ValidationFailed(\"{{ name }} is not in range {{ num['lt'], num['gt'] }}\")
  301. {%- else %}
  302. if {{ name }} >= {{ num['lt'] }} and {{ name }} <= {{ num['gt'] }}:
  303. raise ValidationFailed(\"{{ name }} is not in range {{ num['gt'], num['lt'] }}\")
  304. {%- endif -%}
  305. {%- elif num.HasField('gte') %}
  306. {%- if num['lt'] > num['gte'] %}
  307. if {{ name }} < {{ num['gte'] }} or {{ name }} >= {{ num ['lt'] }}:
  308. raise ValidationFailed(\"{{ name }} is not in range {{ num['lt'], num['gte'] }}\")
  309. {%- else %}
  310. if {{ name }} >= {{ num['lt'] }} and {{ name }} < {{ num['gte'] }}:
  311. raise ValidationFailed(\"{{ name }} is not in range {{ num['gte'], num['lt'] }}\")
  312. {%- endif -%}
  313. {%- else %}
  314. if {{ name }} >= {{ num['lt'] }}:
  315. raise ValidationFailed(\"{{ name }} is not lesser than {{ num['lt'] }}\")
  316. {%- endif -%}
  317. {%- elif num.HasField('lte') %}
  318. {%- if num.HasField('gt') %}
  319. {%- if num['lte'] > num['gt'] %}
  320. if {{ name }} <= {{ num['gt'] }} or {{ name }} > {{ num ['lte'] }}:
  321. raise ValidationFailed(\"{{ name }} is not in range {{ num['lte'], num['gt'] }}\")
  322. {%- else %}
  323. if {{ name }} > {{ num['lte'] }} and {{ name }} <= {{ num['gt'] }}:
  324. raise ValidationFailed(\"{{ name }} is not in range {{ num['gt'], num['lte'] }}\")
  325. {%- endif -%}
  326. {%- elif num.HasField('gte') %}
  327. {%- if num['lte'] > num['gte'] %}
  328. if {{ name }} < {{ num['gte'] }} or {{ name }} > {{ num ['lte'] }}:
  329. raise ValidationFailed(\"{{ name }} is not in range {{ num['lte'], num['gte'] }}\")
  330. {%- else %}
  331. if {{ name }} > {{ num['lte'] }} and {{ name }} < {{ num['gte'] }}:
  332. raise ValidationFailed(\"{{ name }} is not in range {{ num['gte'], num['lte'] }}\")
  333. {%- endif -%}
  334. {%- else %}
  335. if {{ name }} > {{ num['lte'] }}:
  336. raise ValidationFailed(\"{{ name }} is not lesser than or equal to {{ num['lte'] }}\")
  337. {%- endif -%}
  338. {%- elif num.HasField('gt') %}
  339. if {{ name }} <= {{ num['gt'] }}:
  340. raise ValidationFailed(\"{{ name }} is not greater than {{ num['gt'] }}\")
  341. {%- elif num.HasField('gte') %}
  342. if {{ name }} < {{ num['gte'] }}:
  343. raise ValidationFailed(\"{{ name }} is not greater than or equal to {{ num['gte'] }}\")
  344. {%- endif -%}
  345. {% endfilter %}
  346. """
  347. return Template(num_tmpl).render(o=option_value, name=name, num=num, in_template=in_template, str=str)
  348. def dur_arr(dur):
  349. value = 0
  350. arr = []
  351. for val in dur:
  352. value += val.seconds
  353. value += (10**-9 * val.nanos)
  354. arr.append(value)
  355. value = 0
  356. return arr
  357. def dur_lit(dur):
  358. value = dur.seconds + (10**-9 * dur.nanos)
  359. return value
  360. def duration_template(option_value, name, repeated=False):
  361. dur_tmpl = """
  362. {{- required_template(o.duration, name) }}
  363. {% if repeated %}
  364. if {{ name }}:
  365. {% else %}
  366. if _has_field(p, \"{{ name.split('.')[-1] }}\"):
  367. {% endif %}
  368. dur = {{ name }}.seconds + round((10**-9 * {{ name }}.nanos), 9)
  369. {%- set dur = o.duration -%}
  370. {%- if dur.HasField('lt') %}
  371. lt = {{ dur_lit(dur['lt']) }}
  372. {% endif %}
  373. {%- if dur.HasField('lte') %}
  374. lte = {{ dur_lit(dur['lte']) }}
  375. {% endif %}
  376. {%- if dur.HasField('gt') %}
  377. gt = {{ dur_lit(dur['gt']) }}
  378. {% endif %}
  379. {%- if dur.HasField('gte') %}
  380. gte = {{ dur_lit(dur['gte']) }}
  381. {% endif %}
  382. {%- if dur.HasField('const') %}
  383. if dur != {{ dur_lit(dur['const']) }}:
  384. raise ValidationFailed(\"{{ name }} is not equal to {{ dur_lit(dur['const']) }}\")
  385. {%- endif -%}
  386. {%- if dur['in'] %}
  387. if dur not in {{ dur_arr(dur['in']) }}:
  388. raise ValidationFailed(\"{{ name }} is not in {{ dur_arr(dur['in']) }}\")
  389. {%- endif -%}
  390. {%- if dur['not_in'] %}
  391. if dur in {{ dur_arr(dur['not_in']) }}:
  392. raise ValidationFailed(\"{{ name }} is not in {{ dur_arr(dur['not_in']) }}\")
  393. {%- endif -%}
  394. {%- if dur.HasField('lt') %}
  395. {%- if dur.HasField('gt') %}
  396. {%- if dur_lit(dur['lt']) > dur_lit(dur['gt']) %}
  397. if dur <= gt or dur >= lt:
  398. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['lt']), dur_lit(dur['gt']) }}\")
  399. {%- else -%}
  400. if dur >= lt and dur <= gt:
  401. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['gt']), dur_lit(dur['lt']) }}\")
  402. {%- endif -%}
  403. {%- elif dur.HasField('gte') %}
  404. {%- if dur_lit(dur['lt']) > dur_lit(dur['gte']) %}
  405. if dur < gte or dur >= lt:
  406. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['lt']), dur_lit(dur['gte']) }}\")
  407. {%- else -%}
  408. if dur >= lt and dur < gte:
  409. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['gte']), dur_lit(dur['lt']) }}\")
  410. {%- endif -%}
  411. {%- else -%}
  412. if dur >= lt:
  413. raise ValidationFailed(\"{{ name }} is not lesser than {{ dur_lit(dur['lt']) }}\")
  414. {%- endif -%}
  415. {%- elif dur.HasField('lte') %}
  416. {%- if dur.HasField('gt') %}
  417. {%- if dur_lit(dur['lte']) > dur_lit(dur['gt']) %}
  418. if dur <= gt or dur > lte:
  419. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['lte']), dur_lit(dur['gt']) }}\")
  420. {%- else -%}
  421. if dur > lte and dur <= gt:
  422. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['gt']), dur_lit(dur['lte']) }}\")
  423. {%- endif -%}
  424. {%- elif dur.HasField('gte') %}
  425. {%- if dur_lit(dur['lte']) > dur_lit(dur['gte']) %}
  426. if dur < gte or dur > lte:
  427. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['lte']), dur_lit(dur['gte']) }}\")
  428. {%- else -%}
  429. if dur > lte and dur < gte:
  430. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(dur['gte']), dur_lit(dur['lte']) }}\")
  431. {%- endif -%}
  432. {%- else -%}
  433. if dur > lte:
  434. raise ValidationFailed(\"{{ name }} is not lesser than or equal to {{ dur_lit(dur['lte']) }}\")
  435. {%- endif -%}
  436. {%- elif dur.HasField('gt') %}
  437. if dur <= gt:
  438. raise ValidationFailed(\"{{ name }} is not greater than {{ dur_lit(dur['gt']) }}\")
  439. {%- elif dur.HasField('gte') %}
  440. if dur < gte:
  441. raise ValidationFailed(\"{{ name }} is not greater than or equal to {{ dur_lit(dur['gte']) }}\")
  442. {%- endif -%}
  443. """
  444. return Template(dur_tmpl).render(o=option_value, name=name, required_template=required_template,
  445. dur_lit=dur_lit, dur_arr=dur_arr, repeated=repeated)
  446. def timestamp_template(option_value, name, repeated=False):
  447. timestamp_tmpl = """
  448. {{- required_template(o.timestamp, name) }}
  449. {% if repeated %}
  450. if {{ name }}:
  451. {% else %}
  452. if _has_field(p, \"{{ name.split('.')[-1] }}\"):
  453. {% endif %}
  454. ts = {{ name }}.seconds + round((10**-9 * {{ name }}.nanos), 9)
  455. {%- set ts = o.timestamp -%}
  456. {%- if ts.HasField('lt') %}
  457. lt = {{ dur_lit(ts['lt']) }}
  458. {% endif -%}
  459. {%- if ts.HasField('lte') %}
  460. lte = {{ dur_lit(ts['lte']) }}
  461. {% endif -%}
  462. {%- if ts.HasField('gt') %}
  463. gt = {{ dur_lit(ts['gt']) }}
  464. {% endif -%}
  465. {%- if ts.HasField('gte') %}
  466. gte = {{ dur_lit(ts['gte']) }}
  467. {% endif -%}
  468. {%- if ts.HasField('const') %}
  469. if ts != {{ dur_lit(ts['const']) }}:
  470. raise ValidationFailed(\"{{ name }} is not equal to {{ dur_lit(ts['const']) }}\")
  471. {% endif %}
  472. {%- if ts['in'] %}
  473. if ts not in {{ dur_arr(ts['in']) }}:
  474. raise ValidationFailed(\"{{ name }} is not in {{ dur_arr(ts['in']) }}\")
  475. {%- endif %}
  476. {%- if ts['not_in'] %}
  477. if ts in {{ dur_arr(ts['not_in']) }}:
  478. raise ValidationFailed(\"{{ name }} is not in {{ dur_arr(ts['not_in']) }}\")
  479. {%- endif %}
  480. {%- if ts.HasField('lt') %}
  481. {%- if ts.HasField('gt') %}
  482. {%- if dur_lit(ts['lt']) > dur_lit(ts['gt']) %}
  483. if ts <= gt or ts >= lt:
  484. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['lt']), dur_lit(ts['gt']) }}\")
  485. {%- else -%}
  486. if ts >= lt and ts <= gt:
  487. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['gt']), dur_lit(ts['lt']) }}\")
  488. {%- endif -%}
  489. {%- elif ts.HasField('gte') %}
  490. {%- if dur_lit(ts['lt']) > dur_lit(ts['gte']) %}
  491. if ts < gte or ts >= lt:
  492. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['lt']), dur_lit(ts['gte']) }}\")
  493. {%- else -%}
  494. if ts >= lt and ts < gte:
  495. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['gte']), dur_lit(ts['lt']) }}\")
  496. {%- endif -%}
  497. {%- else -%}
  498. if ts >= lt:
  499. raise ValidationFailed(\"{{ name }} is not lesser than {{ dur_lit(ts['lt']) }}\")
  500. {%- endif -%}
  501. {%- elif ts.HasField('lte') %}
  502. {%- if ts.HasField('gt') %}
  503. {%- if dur_lit(ts['lte']) > dur_lit(ts['gt']) %}
  504. if ts <= gt or ts > lte:
  505. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['lte']), dur_lit(ts['gt']) }}\")
  506. {%- else -%}
  507. if ts > lte and ts <= gt:
  508. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['gt']), dur_lit(ts['lte']) }}\")
  509. {%- endif -%}
  510. {%- elif ts.HasField('gte') %}
  511. {%- if dur_lit(ts['lte']) > dur_lit(ts['gte']) %}
  512. if ts < gte or ts > lte:
  513. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['lte']), dur_lit(ts['gte']) }}\")
  514. {%- else -%}
  515. if ts > lte and ts < gte:
  516. raise ValidationFailed(\"{{ name }} is not in range {{ dur_lit(ts['gte']), dur_lit(ts['lte']) }}\")
  517. {%- endif -%}
  518. {%- else -%}
  519. if ts > lte:
  520. raise ValidationFailed(\"{{ name }} is not lesser than or equal to {{ dur_lit(ts['lte']) }}\")
  521. {%- endif -%}
  522. {%- elif ts.HasField('gt') %}
  523. if ts <= gt:
  524. raise ValidationFailed(\"{{ name }} is not greater than {{ dur_lit(ts['gt']) }}\")
  525. {%- elif ts.HasField('gte') %}
  526. if ts < gte:
  527. raise ValidationFailed(\"{{ name }} is not greater than or equal to {{ dur_lit(ts['gte']) }}\")
  528. {%- elif ts.HasField('lt_now') %}
  529. now = time.time()
  530. {%- if ts.HasField('within') %}
  531. within = {{ dur_lit(ts['within']) }}
  532. if ts >= now or ts <= now - within:
  533. raise ValidationFailed(\"{{ name }} is not within range {{ dur_lit(ts['within']) }}\")
  534. {%- else %}
  535. if ts >= now:
  536. raise ValidationFailed(\"{{ name }} is not lesser than now\")
  537. {%- endif -%}
  538. {%- elif ts.HasField('gt_now') %}
  539. now = time.time()
  540. {%- if ts.HasField('within') %}
  541. within = {{ dur_lit(ts['within']) }}
  542. if ts <= now or ts >= now + within:
  543. raise ValidationFailed(\"{{ name }} is not within range {{ dur_lit(ts['within']) }}\")
  544. {%- else %}
  545. if ts <= now:
  546. raise ValidationFailed(\"{{ name }} is not greater than now\")
  547. {%- endif -%}
  548. {%- elif ts.HasField('within') %}
  549. now = time.time()
  550. within = {{ dur_lit(ts['within']) }}
  551. if ts >= now + within or ts <= now - within:
  552. raise ValidationFailed(\"{{ name }} is not within range {{ dur_lit(ts['within']) }}\")
  553. {%- endif -%}
  554. """
  555. return Template(timestamp_tmpl).render(o=option_value, name=name, required_template=required_template,
  556. dur_lit=dur_lit, dur_arr=dur_arr, repeated=repeated)
  557. def wrapper_template(option_value, name, repeated=False):
  558. wrapper_tmpl = """
  559. {% if repeated %}
  560. if {{ name }}:
  561. {% else %}
  562. if p.HasField(\"{{ name[2:] }}\"):
  563. {% endif %}
  564. {%- if str(option_value.float) %}
  565. {{- num_template(option_value, name + ".value", option_value.float)|indent(4,True) -}}
  566. {% endif -%}
  567. {%- if str(option_value.double) %}
  568. {{- num_template(option_value, name + ".value", option_value.double)|indent(4,True) -}}
  569. {% endif -%}
  570. {%- if str(option_value.int32) %}
  571. {{- num_template(option_value, name + ".value", option_value.int32)|indent(4,True) -}}
  572. {% endif -%}
  573. {%- if str(option_value.int64) %}
  574. {{- num_template(option_value, name + ".value", option_value.int64)|indent(4,True) -}}
  575. {% endif -%}
  576. {%- if str(option_value.uint32) %}
  577. {{- num_template(option_value, name + ".value", option_value.uint32)|indent(4,True) -}}
  578. {% endif -%}
  579. {%- if str(option_value.uint64) %}
  580. {{- num_template(option_value, name + ".value", option_value.uint64)|indent(4,True) -}}
  581. {% endif -%}
  582. {%- if str(option_value.bool) %}
  583. {{- bool_template(option_value, name + ".value")|indent(4,True) -}}
  584. {% endif -%}
  585. {%- if str(option_value.string) %}
  586. {{- string_template(option_value, name + ".value")|indent(4,True) -}}
  587. {% endif -%}
  588. {%- if str(option_value.bytes) %}
  589. {{- bytes_template(option_value, name + ".value")|indent(4,True) -}}
  590. {% endif -%}
  591. {%- if str(option_value.message) and option_value.message['required'] %}
  592. else:
  593. raise ValidationFailed(\"{{ name }} is required.\")
  594. {%- endif %}
  595. """
  596. return Template(wrapper_tmpl).render(option_value=option_value, name=name, str=str, num_template=num_template,
  597. bool_template=bool_template, string_template=string_template,
  598. bytes_template=bytes_template, repeated=repeated)
  599. def enum_values(field):
  600. return [x.number for x in field.enum_type.values]
  601. def enum_template(option_value, name, field):
  602. enum_tmpl = """
  603. {{ const_template(option_value, name) -}}
  604. {{ in_template(option_value.enum, name) -}}
  605. {% if option_value.enum['defined_only'] %}
  606. if {{ name }} not in {{ enum_values(field) }}:
  607. raise ValidationFailed(\"{{ name }} is not defined\")
  608. {% endif %}
  609. """
  610. return Template(enum_tmpl).render(option_value=option_value, name=name, const_template=const_template,
  611. in_template=in_template, field=field, enum_values=enum_values)
  612. def any_template(option_value, name, repeated=False):
  613. any_tmpl = """
  614. {{- required_template(o, name) }}
  615. {%- if o['in'] %}
  616. {% if repeated %}
  617. if {{ name }}:
  618. {% else %}
  619. if _has_field(p, \"{{ name.split('.')[-1] }}\"):
  620. {% endif %}
  621. if {{ name }}.type_url not in {{ o['in'] }}:
  622. raise ValidationFailed(\"{{ name }} not in {{ o['in'] }}\")
  623. {%- endif %}
  624. {%- if o['not_in'] %}
  625. {% if repeated %}
  626. if {{ name }}:
  627. {% else %}
  628. if _has_field(p, \"{{ name.split('.')[-1] }}\"):
  629. {% endif %}
  630. if {{ name }}.type_url in {{ o['not_in'] }}:
  631. raise ValidationFailed(\"{{ name }} in {{ o['not_in'] }}\")
  632. {%- endif %}
  633. """
  634. return Template(any_tmpl).render(
  635. o=option_value.any, name=name, required_template=required_template, repeated=repeated)
  636. def bytes_template(option_value, name):
  637. bytes_tmpl = """
  638. {% set i = 0 %}
  639. {%- if b['ignore_empty'] -%}
  640. if {{ name }}:
  641. {% set i = 4 %}
  642. {%- endif -%}
  643. {% filter indent(i,True) %}
  644. {{ const_template(o, name) -}}
  645. {{ in_template(o.bytes, name) -}}
  646. {%- if b['len'] %}
  647. if len({{ name }}) != {{ b['len'] }}:
  648. raise ValidationFailed(\"{{ name }} length does not equal {{ b['len'] }}\")
  649. {%- endif -%}
  650. {%- if b['min_len'] %}
  651. if len({{ name }}) < {{ b['min_len'] }}:
  652. raise ValidationFailed(\"{{ name }} length is less than {{ b['min_len'] }}\")
  653. {%- endif -%}
  654. {%- if b['max_len'] %}
  655. if len({{ name }}) > {{ b['max_len'] }}:
  656. raise ValidationFailed(\"{{ name }} length is more than {{ b['max_len'] }}\")
  657. {%- endif -%}
  658. {%- if b['ip'] %}
  659. try:
  660. ip_address({{ name }})
  661. except ValueError:
  662. raise ValidationFailed(\"{{ name }} is not a valid ip\")
  663. {%- endif -%}
  664. {%- if b['ipv4'] %}
  665. try:
  666. IPv4Address({{ name }})
  667. except ValueError:
  668. raise ValidationFailed(\"{{ name }} is not a valid ipv4\")
  669. {%- endif -%}
  670. {%- if b['ipv6'] %}
  671. try:
  672. IPv6Address({{ name }})
  673. except ValueError:
  674. raise ValidationFailed(\"{{ name }} is not a valid ipv6\")
  675. {%- endif -%}
  676. {% if b['pattern'] %}
  677. {% if sys.version_info[0] >= 3%}
  678. if re.search({{ b['pattern'].encode('unicode-escape') }}, {{ name }}) is None:
  679. raise ValidationFailed(\"{{ name }} pattern does not match b['pattern'].encode('unicode-escape')\")
  680. {% else %}
  681. if re.search(b\"{{ b['pattern'].encode('unicode-escape') }}\", {{ name }}) is None:
  682. raise ValidationFailed(\"{{ name }} pattern does not match \")
  683. {% endif %}
  684. {% endif %}
  685. {% if b['contains'] %}
  686. {% if sys.version_info[0] >= 3 %}
  687. if not {{ b['contains'] }} in {{ name }}:
  688. raise ValidationFailed(\"{{ name }} does not contain {{ b['contains'] }}\")
  689. {% else %}
  690. if not b\"{{ b['contains'].encode('string_escape') }}\" in {{ name }}:
  691. raise ValidationFailed(\"{{ name }} does not contain \")
  692. {% endif %}
  693. {% endif %}
  694. {% if b['prefix'] %}
  695. {% if sys.version_info[0] >= 3 %}
  696. if not {{ name }}.startswith({{ b['prefix'] }}):
  697. raise ValidationFailed(\"{{ name }} does not start with prefix {{ b['prefix'] }}\")
  698. {% else %}
  699. if not {{name}}.startswith(b\"{{ b['prefix'].encode('string_escape') }}\"):
  700. raise ValidationFailed(\"{{ name }} does not start with prefix {{ b['prefix'].encode('string_escape') }}\")
  701. {% endif %}
  702. {% endif %}
  703. {% if b['suffix'] %}
  704. {% if sys.version_info[0] >= 3 %}
  705. if not {{ name }}.endswith({{ b['suffix'] }}):
  706. raise ValidationFailed(\"{{ name }} does not end with suffix {{ b['suffix'] }}\")
  707. {% else %}
  708. if not {{name}}.endswith(b\"{{ b['suffix'].encode('string_escape') }}\"):
  709. raise ValidationFailed(\"{{ name }} does not end with suffix {{ b['suffix'] }}\")
  710. {% endif %}
  711. {% endif %}
  712. {% endfilter %}
  713. """
  714. return Template(bytes_tmpl).render(sys=sys, o=option_value, name=name,
  715. const_template=const_template, in_template=in_template, b=option_value.bytes)
  716. def switcher_template(accessor, name, field, map=False):
  717. switcher_tmpl = """
  718. {%- if str(accessor.float) %}
  719. {{- num_template(accessor, name, accessor.float)|indent(4,True) -}}
  720. {%- elif str(accessor.double) %}
  721. {{- num_template(accessor, name, accessor.double)|indent(4,True) -}}
  722. {%- elif str(accessor.int32) %}
  723. {{- num_template(accessor, name, accessor.int32)|indent(4,True) -}}
  724. {%- elif str(accessor.int64) %}
  725. {{- num_template(accessor, name, accessor.int64)|indent(4,True) -}}
  726. {%- elif str(accessor.uint32) %}
  727. {{- num_template(accessor, name, accessor.uint32)|indent(4,True) -}}
  728. {%- elif str(accessor.uint64) %}
  729. {{- num_template(accessor, name, accessor.uint64)|indent(4,True) -}}
  730. {%- elif str(accessor.sint32) %}
  731. {{- num_template(accessor, name, accessor.sint32)|indent(4,True) -}}
  732. {%- elif str(accessor.sint64) %}
  733. {{- num_template(accessor, name, accessor.sint64)|indent(4,True) -}}
  734. {%- elif str(accessor.fixed32) %}
  735. {{- num_template(accessor, name, accessor.fixed32)|indent(4,True) -}}
  736. {%- elif str(accessor.fixed64) %}
  737. {{- num_template(accessor, name, accessor.fixed64)|indent(4,True) -}}
  738. {%- elif str(accessor.sfixed32) %}
  739. {{- num_template(accessor, name, accessor.sfixed32)|indent(4,True) -}}
  740. {%- elif str(accessor.sfixed64) %}
  741. {{- num_template(accessor, name, accessor.sfixed64)|indent(4,True) -}}
  742. {%- elif str(accessor.bool) %}
  743. {{- bool_template(accessor, name)|indent(4,True) -}}
  744. {%- elif str(accessor.string) %}
  745. {{- string_template(accessor, name)|indent(4,True) -}}
  746. {%- elif str(accessor.enum) and map %}
  747. {{- enum_template(accessor, name, field.message_type.fields[1])|indent(4,True) -}}
  748. {%- elif str(accessor.enum) and not map %}
  749. {{- enum_template(accessor, name, field)|indent(4,True) -}}
  750. {%- elif str(accessor.duration) %}
  751. {{- duration_template(accessor, name, True)|indent(4,True) -}}
  752. {%- elif str(accessor.timestamp) %}
  753. {{- timestamp_template(accessor, name, True)|indent(4,True) -}}
  754. {%- elif str(accessor.message) %}
  755. {{- message_template(accessor, name, True)|indent(4,True) -}}
  756. {%- elif str(accessor.any) %}
  757. {{- any_template(accessor, name, True)|indent(4,True) -}}
  758. {%- elif str(accessor.message) %}
  759. {{- message_template(accessor, name, True)|indent(4,True) -}}
  760. {%- endif %}
  761. """
  762. return Template(switcher_tmpl).render(accessor=accessor, name=name, str=str, num_template=num_template,
  763. bool_template=bool_template, string_template=string_template,
  764. enum_template=enum_template, duration_template=duration_template,
  765. timestamp_template=timestamp_template, any_template=any_template,
  766. message_template=message_template, field=field, map=map)
  767. def repeated_template(option_value, name, field):
  768. rep_tmpl = """
  769. {% set i = 0 %}
  770. {%- if o and o.repeated['ignore_empty'] %}
  771. if {{ name }}:
  772. {% set i = 4 %}
  773. {%- endif -%}
  774. {% filter indent(i,True) %}
  775. {%- if o and o.repeated['min_items'] %}
  776. if len({{ name }}) < {{ o.repeated['min_items'] }}:
  777. raise ValidationFailed(\"{{ name }} needs to contain at least {{ o.repeated['min_items'] }} items\")
  778. {%- endif %}
  779. {%- if o and o.repeated['max_items'] %}
  780. if len({{ name }}) > {{ o.repeated['max_items'] }}:
  781. raise ValidationFailed(\"{{ name }} needs to contain at most {{ o.repeated['max_items'] }} items\")
  782. {%- endif %}
  783. {%- if o and o.repeated['unique'] %}
  784. seen = set()
  785. for item in {{ name }}:
  786. if item in seen:
  787. raise ValidationFailed(\"{{ name }} must contain unique items. %s has been repeated.\" %item)
  788. else:
  789. seen.add(item)
  790. {%- endif %}
  791. {%- if message_type %}
  792. for item in {{ name }}:
  793. {%- if o and o.repeated and o.repeated.items.message.skip %}
  794. pass
  795. {% else %}
  796. validate(item)
  797. {% endif %}
  798. {%- endif %}
  799. {%- if o and str(o.repeated['items']) %}
  800. for item in {{ name }}:
  801. {%- set accessor = o.repeated['items'] -%}
  802. {{ switcher_template(accessor, 'item', field) }}
  803. pass
  804. {%- endif %}
  805. {% endfilter %}
  806. """
  807. return Template(rep_tmpl).render(o=option_value, name=name, message_type=field.message_type,
  808. str=str, field=field, switcher_template=switcher_template)
  809. def is_map(field):
  810. return field.label == 3 and field.message_type and len(field.message_type.fields) == 2 and \
  811. field.message_type.fields[0].name == "key" and field.message_type.fields[1].name == "value"
  812. def map_template(option_value, name, field):
  813. map_tmpl = """
  814. {% set i = 0 %}
  815. {%- if o and o.map['ignore_empty'] %}
  816. if {{ name }}:
  817. {% set i = 4 %}
  818. {%- endif -%}
  819. {% filter indent(i,True) %}
  820. {%- if o and o.map['min_pairs'] %}
  821. if len({{ name }}) < {{ o.map['min_pairs'] }}:
  822. raise ValidationFailed(\"{{ name }} needs to contain at least {{ o.map['min_pairs'] }} items\")
  823. {%- endif %}
  824. {%- if o and o.map['max_pairs'] %}
  825. if len({{ name }}) > {{ o.map['max_pairs'] }}:
  826. raise ValidationFailed(\"{{ name }} can contain at most {{ o.map['max_pairs'] }} items\")
  827. {%- endif %}
  828. {%- if o and (str(o.map['keys']) or str(o.map['values']))%}
  829. for key in {{ name }}:
  830. {%- set keys = o.map['keys'] -%}
  831. {%- set values = o.map['values'] -%}
  832. {%- if str(keys.double) %}
  833. {{- num_template(keys, 'key', keys.double)|indent(4,True) -}}
  834. {%- elif str(keys.int32) %}
  835. {{- num_template(keys, 'key', keys.int32)|indent(4,True) -}}
  836. {%- elif str(keys.int64) %}
  837. {{- num_template(keys, 'key', keys.int64)|indent(4,True) -}}
  838. {%- elif str(keys.uint32) %}
  839. {{- num_template(keys, 'key', keys.uint32)|indent(4,True) -}}
  840. {%- elif str(keys.uint64) %}
  841. {{- num_template(keys, 'key', keys.uint64)|indent(4,True) -}}
  842. {%- elif str(keys.sint32) %}
  843. {{- num_template(keys, 'key', keys.sint32)|indent(4,True) -}}
  844. {%- elif str(keys.sint64) %}
  845. {{- num_template(keys, 'key', keys.sint64)|indent(4,True) -}}
  846. {%- elif str(keys.fixed32) %}
  847. {{- num_template(keys, 'key', keys.fixed32)|indent(4,True) -}}
  848. {%- elif str(keys.fixed64) %}
  849. {{- num_template(keys, 'key', keys.fixed64)|indent(4,True) -}}
  850. {%- elif str(keys.sfixed32) %}
  851. {{- num_template(keys, 'key', keys.sfixed32)|indent(4,True) -}}
  852. {%- elif str(keys.sfixed64) %}
  853. {{- num_template(keys, 'key', keys.sfixed64)|indent(4,True) -}}
  854. {%- elif str(keys.bool) %}
  855. {{- bool_template(keys, 'key')|indent(4,True) -}}
  856. {%- elif str(keys.string) %}
  857. {{- string_template(keys, 'key')|indent(4,True) -}}
  858. {%- endif %}
  859. {%- set values = o.map['values'] -%}
  860. {{ switcher_template(values, name +'[key]', field, True) }}
  861. pass
  862. {%- elif field.message_type.fields[1].message_type %}
  863. for key in {{ name }}:
  864. validate({{ name }}[key])
  865. {%- endif %}
  866. {% endfilter %}
  867. """
  868. return Template(map_tmpl).render(o=option_value, name=name, message_type=field.message_type, str=str,
  869. field=field, switcher_template=switcher_template, num_template=num_template,
  870. string_template=string_template, bool_template=bool_template)
  871. def rule_type(field):
  872. name = "p." + field.name
  873. if has_validate(field) and field.message_type is None:
  874. for option_descriptor, option_value in field.GetOptions().ListFields():
  875. if option_descriptor.full_name == "validate.rules":
  876. if str(option_value.string):
  877. return string_template(option_value, name)
  878. elif str(option_value.message):
  879. return message_template(option_value, field.name)
  880. elif str(option_value.bool):
  881. return bool_template(option_value, name)
  882. elif str(option_value.float):
  883. return num_template(option_value, name, option_value.float)
  884. elif str(option_value.double):
  885. return num_template(option_value, name, option_value.double)
  886. elif str(option_value.int32):
  887. return num_template(option_value, name, option_value.int32)
  888. elif str(option_value.int64):
  889. return num_template(option_value, name, option_value.int64)
  890. elif str(option_value.uint32):
  891. return num_template(option_value, name, option_value.uint32)
  892. elif str(option_value.uint64):
  893. return num_template(option_value, name, option_value.uint64)
  894. elif str(option_value.sint32):
  895. return num_template(option_value, name, option_value.sint32)
  896. elif str(option_value.sint64):
  897. return num_template(option_value, name, option_value.sint64)
  898. elif str(option_value.fixed32):
  899. return num_template(option_value, name, option_value.fixed32)
  900. elif str(option_value.fixed64):
  901. return num_template(option_value, name, option_value.fixed64)
  902. elif str(option_value.sfixed32):
  903. return num_template(option_value, name, option_value.sfixed32)
  904. elif str(option_value.sfixed64):
  905. return num_template(option_value, name, option_value.sfixed64)
  906. elif str(option_value.enum):
  907. return enum_template(option_value, name, field)
  908. elif str(option_value.bytes):
  909. return bytes_template(option_value, name)
  910. elif str(option_value.repeated):
  911. return repeated_template(option_value, name, field)
  912. elif str(option_value.map):
  913. return map_template(option_value, name, field)
  914. elif str(option_value.required):
  915. return required_template(option_value, name)
  916. if field.message_type:
  917. for option_descriptor, option_value in field.GetOptions().ListFields():
  918. if option_descriptor.full_name == "validate.rules":
  919. if str(option_value.duration):
  920. return duration_template(option_value, name)
  921. elif str(option_value.timestamp):
  922. return timestamp_template(option_value, name)
  923. elif str(option_value.float) or str(option_value.int32) or str(option_value.int64) or \
  924. str(option_value.double) or str(option_value.uint32) or str(option_value.uint64) or \
  925. str(option_value.bool) or str(option_value.string) or str(option_value.bytes):
  926. return wrapper_template(option_value, name)
  927. elif str(option_value.message) != "":
  928. return message_template(option_value, field.name)
  929. elif str(option_value.any):
  930. return any_template(option_value, name)
  931. elif str(option_value.repeated):
  932. return repeated_template(option_value, name, field)
  933. elif str(option_value.map):
  934. return map_template(option_value, name, field)
  935. elif str(option_value.required):
  936. return required_template(option_value, name)
  937. if field.message_type.full_name.startswith("google.protobuf"):
  938. return ""
  939. elif is_map(field):
  940. return map_template(None, name, field)
  941. elif field.label == 3:
  942. return repeated_template(None, name, field)
  943. else:
  944. return message_template(None, field.name)
  945. return ""
  946. def file_template(proto_message):
  947. file_tmp = """
  948. # Validates {{ p.DESCRIPTOR.name }}
  949. def generate_validate(p):
  950. {%- for option_descriptor, option_value in p.DESCRIPTOR.GetOptions().ListFields() %}
  951. {%- if option_descriptor.full_name == "validate.disabled" and option_value %}
  952. return None
  953. {%- elif option_descriptor.full_name == "validate.ignored" and option_value %}
  954. return None
  955. {%- endif -%}
  956. {%- endfor -%}
  957. {%- for oneof in p.DESCRIPTOR.oneofs %}
  958. present = False
  959. {%- for field in oneof.fields %}
  960. if _has_field(p, \"{{ field.name }}\"):
  961. present = True
  962. {{ rule_type(field)|indent(4,True) }}
  963. {%- endfor %}
  964. {% for option in oneof.GetOptions().ListFields() %}
  965. {% if option[0].name == 'required' and option[1] %}
  966. if not present:
  967. raise ValidationFailed(\"Oneof {{ oneof.name }} is required\")
  968. {% endif %}
  969. {% endfor %}
  970. {%- endfor %}
  971. {%- for field in p.DESCRIPTOR.fields -%}
  972. {%- if not field.containing_oneof %}
  973. {{ rule_type(field) -}}
  974. {%- endif %}
  975. {%- endfor %}
  976. return None"""
  977. return Template(file_tmp).render(rule_type=rule_type, p=proto_message)