Skip to content

Instantly share code, notes, and snippets.

@samuelcolvin
Last active November 15, 2022 12:22
Show Gist options
  • Save samuelcolvin/ae5fa158e67fbf36b8dd1d0d2280359b to your computer and use it in GitHub Desktop.
Save samuelcolvin/ae5fa158e67fbf36b8dd1d0d2280359b to your computer and use it in GitHub Desktop.
<style>
main {
display: flex;
}
pre {
margin: 0;
padding: 0;
}
code, #output {
white-space: pre-wrap;
padding: 2px;
margin: 2px;
flex: 1 1;
}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
<script src="https://cdn.jsdelivr.net/pyodide/v0.21.0a3/full/pyodide.js"></script>
<main>
<pre id="code">
<!-- language=python -->
<code class="language-python">
import time
import micropip
await micropip.install([
'https://smokeshow.helpmanual.io/5y5m0h4s3k415a5s430c/pydantic_core-0.0.1-cp310-cp310-emscripten_3_1_14_wasm32.whl',
'devtools'
])
from pydantic_core import SchemaValidator
import devtools
def schema(*, strict: bool = False) -> dict:
class MyModel:
# __slots__ is not required, but it avoids __fields_set__ falling into __dict__
__slots__ = '__dict__', '__fields_set__'
def append_func(input_value, **kwargs):
return f'{input_value} Changed'
def wrap_function(input_value, *, validator, **kwargs):
return f'Input {validator(input_value)} Changed'
return {
'type': 'model-class',
'class_type': MyModel,
'config': {'strict': strict},
'schema': {
'type': 'typed-dict',
'return_fields_set': True,
'fields': {
'field_str': {'schema': 'str'},
'field_str_con': {'schema': {'type': 'str', 'min_length': 3, 'max_length': 5, 'pattern': '^[a-z]+$'}},
'field_int': {'schema': 'int'},
'field_int_con': {'schema': {'type': 'int', 'gt': 1, 'lt': 10, 'multiple_of': 2}},
'field_float': {'schema': 'float'},
'field_float_con': {'schema': {'type': 'float', 'ge': 1.0, 'le': 10.0, 'multiple_of': 0.5}},
'field_bool': {'schema': 'bool'},
'field_bytes': {'schema': 'bytes'},
'field_bytes_con': {'schema': {'type': 'bytes', 'min_length': 6, 'max_length': 1000}},
'field_date': {'schema': 'date'},
'field_date_con': {'schema': {'type': 'date', 'ge': '2020-01-01', 'lt': '2020-01-02'}},
'field_time': {'schema': 'time'},
'field_time_con': {'schema': {'type': 'time', 'ge': '06:00:00', 'lt': '12:13:14'}},
'field_datetime': {'schema': 'datetime'},
'field_datetime_con': {
'schema': {'type': 'datetime', 'ge': '2000-01-01T06:00:00', 'lt': '2020-01-02T12:13:14'}
},
'field_list_any': {'schema': 'list'},
'field_list_str': {'schema': {'type': 'list', 'items_schema': 'str'}},
'field_list_str_con': {
'schema': {'type': 'list', 'items_schema': 'str', 'min_items': 3, 'max_items': 42}
},
'field_set_any': {'schema': 'set'},
'field_set_int': {'schema': {'type': 'set', 'items_schema': 'int'}},
'field_set_int_con': {
'schema': {'type': 'set', 'items_schema': 'int', 'min_items': 3, 'max_items': 42}
},
'field_frozenset_any': {'schema': 'frozenset'},
'field_frozenset_bytes': {'schema': {'type': 'frozenset', 'items_schema': 'bytes'}},
'field_frozenset_bytes_con': {
'schema': {'type': 'frozenset', 'items_schema': 'bytes', 'min_items': 3, 'max_items': 42}
},
'field_tuple_var_len_any': {'schema': 'tuple-var-len'},
'field_tuple_var_len_float': {'schema': {'type': 'tuple-var-len', 'items_schema': 'float'}},
'field_tuple_var_len_float_con': {
'schema': {'type': 'tuple-var-len', 'items_schema': 'float', 'min_items': 3, 'max_items': 42}
},
'field_tuple_fix_len': {
'schema': {'type': 'tuple-fix-len', 'items_schema': ['str', 'int', 'float', 'bool']}
},
'field_dict_any': {'schema': 'dict'},
'field_dict_str_float': {'schema': {'type': 'dict', 'keys_schema': 'str', 'values_schema': 'float'}},
'field_literal_1_int': {'schema': {'type': 'literal', 'expected': [1]}},
'field_literal_1_str': {'schema': {'type': 'literal', 'expected': ['foobar']}},
'field_literal_mult_int': {'schema': {'type': 'literal', 'expected': [1, 2, 3]}},
'field_literal_mult_str': {'schema': {'type': 'literal', 'expected': ['foo', 'bar', 'baz']}},
'field_literal_assorted': {'schema': {'type': 'literal', 'expected': [1, 'foo', True]}},
'field_list_nullable_int': {
'schema': {'type': 'list', 'items_schema': {'type': 'nullable', 'schema': 'int'}}
},
'field_union': {
'schema': {
'type': 'union',
'choices': [
'str',
{
'type': 'typed-dict',
'fields': {
'field_str': {'schema': 'str'},
'field_int': {'schema': 'int'},
'field_float': {'schema': 'float'},
},
},
{
'type': 'typed-dict',
'fields': {
'field_float': {'schema': 'float'},
'field_bytes': {'schema': 'bytes'},
'field_date': {'schema': 'date'},
},
},
],
}
},
'field_functions_model': {
'schema': {
'type': 'typed-dict',
'fields': {
'field_before': {
'schema': {
'type': 'function',
'mode': 'before',
'function': append_func,
'schema': {'type': 'str'},
}
},
'field_after': {
'schema': {
'type': 'function',
'mode': 'after',
'function': append_func,
'schema': {'type': 'str'},
}
},
'field_wrap': {
'schema': {
'type': 'function',
'mode': 'wrap',
'function': wrap_function,
'schema': {'type': 'str'},
}
},
'field_plain': {'schema': {'type': 'function', 'mode': 'plain', 'function': append_func}},
},
}
},
'field_recursive': {
'schema': {
'ref': 'Branch',
'type': 'typed-dict',
'fields': {
'name': {'schema': 'str'},
'sub_branch': {
'schema': {
'type': 'nullable',
'schema': {'type': 'recursive-ref', 'schema_ref': 'Branch'},
},
'default': None,
},
},
}
},
},
},
}
def input_data_lax():
return {
'field_str': 'fo',
'field_str_con': 'fooba',
'field_int': 1,
'field_int_con': 8,
'field_float': 1.0,
'field_float_con': 10.0,
'field_bool': True,
'field_bytes': b'foobar',
'field_bytes_con': b'foobar',
'field_date': '2010-02-03',
'field_date_con': '2020-01-01',
'field_time': '12:00:00',
'field_time_con': '12:00:00',
'field_datetime': '2020-01-01T12:13:14',
'field_datetime_con': '2020-01-01T00:00:00',
'field_list_any': ['a', b'b', True, 1.0, None] * 10,
'field_list_str': ['a', 'b', 'c'] * 10,
'field_list_str_con': ['a', 'b', 'c'] * 10,
'field_set_any': {'a', b'b', True, 1.0, None},
'field_set_int': set(range(100)),
'field_set_int_con': set(range(42)),
'field_frozenset_any': frozenset({'a', b'b', True, 1.0, None}),
'field_frozenset_bytes': frozenset([f'{i}'.encode() for i in range(100)]),
'field_frozenset_bytes_con': frozenset([f'{i}'.encode() for i in range(42)]),
'field_tuple_var_len_any': ('a', b'b', True, 1.0, None),
'field_tuple_var_len_float': tuple((i + 0.5 for i in range(100))),
'field_tuple_var_len_float_con': tuple((i + 0.5 for i in range(42))),
'field_tuple_fix_len': ('a', 1, 1.0, True),
'field_dict_any': {'a': 'b', 1: True, 1.0: 1.0},
'field_dict_str_float': {f'{i}': i + 0.5 for i in range(100)},
'field_literal_1_int': 1,
'field_literal_1_str': 'foobar',
'field_literal_mult_int': 3,
'field_literal_mult_str': 'foo',
'field_literal_assorted': 'foo',
'field_list_nullable_int': [1, None, 2, None, 3, None, 4, None],
'field_union': {'field_str': 'foo', 'field_int': 1, 'field_float': 1.0},
'field_functions_model': {
'field_before': 'foo',
'field_after': 'foo',
'field_wrap': 'foo',
'field_plain': 'foo',
},
'field_recursive': {
'name': 'foo',
'sub_branch': {'name': 'bar', 'sub_branch': {'name': 'baz', 'sub_branch': None}},
},
}
lax_schema = schema()
lax_validator = SchemaValidator(lax_schema)
start = time.perf_counter_ns()
for i in range(1000):
m = lax_validator.validate_python(input_data_lax())
diff = time.perf_counter_ns() - start
f'\n\ntime taken: {diff / 1000 / 1000:0.0f}us\n\noutput:{devtools.pformat(m.__dict__)}'
</code>
</pre>
<pre id="output">
</pre>
</main>
<script>
hljs.highlightAll()
async function main() {
const pyodide = await loadPyodide()
await pyodide.loadPackage(['micropip'])
const code = document.getElementById('code').innerText
let output = await pyodide.runPythonAsync(code)
console.log(output)
document.getElementById('output').innerText = output
}
main()
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment