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