1from .draft04 import DATE_REGEX
2from .draft06 import CodeGeneratorDraft06
3from .generator import VALIDATION_EXCEPTIONS
4
5
6class CodeGeneratorDraft07(CodeGeneratorDraft06):
7 FORMAT_REGEXS = dict(CodeGeneratorDraft06.FORMAT_REGEXS, **{
8 'date': r'^(?:' + DATE_REGEX + r')\Z',
9 'iri': r'^\w+:(\/?\/?)[^\s]+\Z',
10 'iri-reference': r'^(\w+:(\/?\/?))?[^#\\\s]*(#[^\\\s]*)?\Z',
11 'idn-email': r'^[^@]+@[^@]+\.[^@]+\Z',
12 # pylint: disable=line-too-long
13 'idn-hostname': r'^(?!-)(xn--)?[a-zA-Z0-9][a-zA-Z0-9-_]{0,61}[a-zA-Z0-9]{0,1}\.(?!-)(xn--)?([a-zA-Z0-9\-]{1,50}|[a-zA-Z0-9-]{1,30}\.[a-zA-Z]{2,})$',
14 'relative-json-pointer': r'^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)\Z',
15 #'regex': r'',
16 'time': (
17 r'^(?P<hour>[01]?\d|2[0-3]):(?P<minute>[0-5]?\d)'
18 r'(?::(?P<second>[0-5]?\d|60)(?:\.(?P<microsecond>\d{1,6}))?'
19 r'([zZ]|[+-](?:[01]\d|2[0-3]):[0-5]\d)?)?\Z'
20 ),
21 })
22
23 def __init__(
24 self,
25 definition,
26 resolver=None,
27 formats={},
28 use_default=True,
29 use_formats=True,
30 detailed_exceptions=True,
31 fast_fail=True
32 ):
33 super().__init__(definition, resolver, formats, use_default, use_formats, detailed_exceptions, fast_fail)
34 # pylint: disable=duplicate-code
35 self._json_keywords_to_function.update((
36 ('if', self.generate_if_then_else),
37 ('contentEncoding', self.generate_content_encoding),
38 ('contentMediaType', self.generate_content_media_type),
39 ))
40
41 def generate_if_then_else(self):
42 """
43 Implementation of if-then-else.
44
45 .. code-block:: python
46
47 {
48 'if': {
49 'exclusiveMaximum': 0,
50 },
51 'then': {
52 'minimum': -10,
53 },
54 'else': {
55 'multipleOf': 2,
56 },
57 }
58
59 Valid values are any between -10 and 0 or any multiplication of two.
60 """
61 with self.l('try:', optimize=False):
62 code_len = len(self._code)
63 with self.trial_validation():
64 self.generate_func_code_block(
65 self._definition['if'],
66 self._variable,
67 self._variable_name,
68 clear_variables=True
69 )
70 if len(self._code) == code_len:
71 self.l('pass')
72 with self.l('except {}:', VALIDATION_EXCEPTIONS):
73 if 'else' in self._definition:
74 code_len = len(self._code)
75 self.generate_func_code_block(
76 self._definition['else'],
77 self._variable,
78 self._variable_name,
79 clear_variables=True
80 )
81 if len(self._code) == code_len:
82 self.l('pass')
83 else:
84 self.l('pass')
85 if 'then' in self._definition:
86 with self.l('else:'):
87 code_len = len(self._code)
88 self.generate_func_code_block(
89 self._definition['then'],
90 self._variable,
91 self._variable_name,
92 clear_variables=True
93 )
94 if len(self._code) == code_len:
95 self.l('pass')
96
97 def generate_content_encoding(self):
98 """
99 Means decoding value when it's encoded by base64.
100
101 .. code-block:: python
102
103 {
104 'contentEncoding': 'base64',
105 }
106 """
107 if self._definition['contentEncoding'] == 'base64':
108 with self.l('if isinstance({variable}, str):'):
109 with self.l('try:'):
110 self.l('import base64')
111 self.l('{variable} = base64.b64decode({variable})')
112 with self.l('except Exception:'):
113 self.exc('{name} must be encoded by base64')
114 with self.l('if {variable} == "":'):
115 self.exc('contentEncoding must be base64')
116
117 def generate_content_media_type(self):
118 """
119 Means loading value when it's specified as JSON.
120
121 .. code-block:: python
122
123 {
124 'contentMediaType': 'application/json',
125 }
126 """
127 if self._definition['contentMediaType'] == 'application/json':
128 with self.l('if isinstance({variable}, bytes):'):
129 with self.l('try:'):
130 self.l('{variable} = {variable}.decode("utf-8")')
131 with self.l('except Exception:'):
132 self.exc('{name} must encoded by utf8')
133 with self.l('if isinstance({variable}, str):'):
134 with self.l('try:'):
135 self.l('import json')
136 self.l('{variable} = json.loads({variable})')
137 with self.l('except Exception:'):
138 self.exc('{name} must be valid JSON')