From 511098cf98244ecc8ddcb0cc763c6a2f2c525c39 Mon Sep 17 00:00:00 2001 From: Ryan Barrett Date: Thu, 26 Sep 2024 10:25:20 -0700 Subject: [PATCH] noop: rename Base.maybe_validate => validate --- lexrpc/base.py | 2 +- lexrpc/client.py | 6 +-- lexrpc/server.py | 6 +-- lexrpc/tests/lexicons.py | 71 +++++++++++++++++++++++++++++++++++ lexrpc/tests/test_base.py | 49 +++++++++++++++++------- lexrpc/tests/test_testdata.py | 4 +- 6 files changed, 115 insertions(+), 23 deletions(-) diff --git a/lexrpc/base.py b/lexrpc/base.py index 41cb2e1..5acc155 100644 --- a/lexrpc/base.py +++ b/lexrpc/base.py @@ -219,7 +219,7 @@ def _get_def(self, id): return lexicon - def maybe_validate(self, nsid, type, obj): + def validate(self, nsid, type, obj): """If configured to do so, validates a ATProto value against its lexicon. Returns ``None`` if the object validates, otherwise raises an exception. diff --git a/lexrpc/client.py b/lexrpc/client.py index 6365cad..d1f1434 100644 --- a/lexrpc/client.py +++ b/lexrpc/client.py @@ -147,12 +147,12 @@ def loggable(val): # strip null params, validate params and input, then encode params params = {k: v for k, v in params.items() if v is not None} - params = self.maybe_validate(nsid, 'parameters', params) + params = self.validate(nsid, 'parameters', params) params_str = self.encode_params(params) type = self._get_def(nsid)['type'] if type == 'subscription': - input = self.maybe_validate(nsid, 'input', input) + input = self.validate(nsid, 'input', input) req_headers = { **DEFAULT_HEADERS, @@ -222,7 +222,7 @@ def loggable(val): resp.raise_for_status() - output = self.maybe_validate(nsid, 'output', output) + output = self.validate(nsid, 'output', output) return output def _subscribe(self, url, decode=True): diff --git a/lexrpc/server.py b/lexrpc/server.py index 70ce0f7..2f9a6b0 100644 --- a/lexrpc/server.py +++ b/lexrpc/server.py @@ -102,9 +102,9 @@ def loggable(val): subscription = self.defs[nsid]['type'] == 'subscription' # validate params and input, then encode params - params = self.maybe_validate(nsid, 'parameters', params) + params = self.validate(nsid, 'parameters', params) if not subscription: - input = self.maybe_validate(nsid, 'input', input) + input = self.validate(nsid, 'input', input) logger.debug('Running method') args = [] if subscription else [input] @@ -112,6 +112,6 @@ def loggable(val): if not subscription: logger.debug(f'Got: {loggable(output)}') - output = self.maybe_validate(nsid, 'output', output) + output = self.validate(nsid, 'output', output) return output diff --git a/lexrpc/tests/lexicons.py b/lexrpc/tests/lexicons.py index 0aef817..2dd4d35 100644 --- a/lexrpc/tests/lexicons.py +++ b/lexrpc/tests/lexicons.py @@ -162,6 +162,77 @@ }, }, + { + 'lexicon': 1, + 'id': 'io.example.objectArray', + 'defs': { + 'main': { + 'type': 'record', + 'record': { + 'required': ['bar'], + 'properties': { + 'foo': { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'bar': {'type': 'integer'}, + 'baj': {'type': 'string'}, + }, + }, + }, + }, + }, + }, + }, + }, + + { + 'lexicon': 1, + 'id': 'io.example.refArray', + 'defs': { + 'main': { + 'type': 'record', + 'record': { + 'properties': { + 'foo': { + 'type': 'array', + 'items': { + 'type': 'ref', + 'ref': '#object' + }, + }, + }, + }, + }, + }, + }, + + { + 'lexicon': 1, + 'id': 'io.example.unionArray', + 'defs': { + 'main': { + 'type': 'record', + 'record': { + 'required': ['bar'], + 'properties': { + 'foo': { + 'type': 'array', + 'items': { + 'type': 'union', + 'refs': [ + 'com.example.kitchenSink#object', + 'com.example.kitchenSink#subobject', + ], + }, + }, + }, + }, + }, + }, + }, + { 'lexicon': 1, 'id': 'io.example.token', diff --git a/lexrpc/tests/test_base.py b/lexrpc/tests/test_base.py index bd20ed9..812bae4 100644 --- a/lexrpc/tests/test_base.py +++ b/lexrpc/tests/test_base.py @@ -14,7 +14,7 @@ class BaseTest(TestCase): def setUp(self): super().setUp() - self.base = Base(LEXICONS) + self.base = Base(LEXICONS, validate=True) def test_get_def(self): for nsid in 'io.exa-mple.dashedName', 'io.example.noParamsInputOutput': @@ -29,14 +29,14 @@ def test_get_def(self): }, self.base._get_def('io.example.kitchenSink#subobject')) def test_validate_record_pass(self): - self.base.maybe_validate('io.example.record', 'record', { + self.base.validate('io.example.record', 'record', { 'baz': 3, 'biff': { 'baj': 'foo', }, }) - def test_maybe_validate_truncate(self): + def test_validate_truncate(self): base = Base(LEXICONS, truncate=True) for input, expected in ( @@ -48,26 +48,25 @@ def test_maybe_validate_truncate(self): with self.subTest(input=input, expected=expected): self.assertEqual( {'string': expected}, - base.maybe_validate('com.example.stringLength', 'record', + base.validate('com.example.stringLength', 'record', {'string': input})) def test_validate_record_pass_nested_optional_field_missing(self): - self.base.maybe_validate('io.example.record', 'record', { + self.base.validate('io.example.record', 'record', { 'baz': 3, 'biff': { }, }) def test_validate_record_pass_optional_field_missing(self): - self.base.maybe_validate('io.example.record', 'record', { + self.base.validate('io.example.record', 'record', { 'baz': 3, }) def test_validate_record_fail_integer_field_bad_type(self): - self.base._validate = True with self.assertRaises(ValidationError): - self.base.maybe_validate('io.example.record', 'record', { + self.base.validate('io.example.record', 'record', { 'baz': 'x', 'biff': { 'baj': 'foo', @@ -75,24 +74,22 @@ def test_validate_record_fail_integer_field_bad_type(self): }) def test_validate_record_fail_object_field_bad_type(self): - self.base._validate = True with self.assertRaises(ValidationError): - self.base.maybe_validate('io.example.record', 'record', { + self.base.validate('io.example.record', 'record', { 'baz': 3, 'biff': 4, }) def test_validate_record_fail_missing_required_field(self): - self.base._validate = True with self.assertRaises(ValidationError): - self.base.maybe_validate('io.example.record', 'record', { + self.base.validate('io.example.record', 'record', { 'biff': { 'baj': 'foo', }, }) def test_validate_record_kitchen_sink_pass(self): - self.base.maybe_validate('io.example.kitchenSink', 'record', { + self.base.validate('io.example.kitchenSink', 'record', { 'array': ['x', 'y'], 'boolean': True, 'integer': 3, @@ -107,4 +104,28 @@ def test_validate_record_kitchen_sink_pass(self): }, }) - # TODO: test arrays of objects, refs, etc + def test_validate_record_object_array_pass(self): + self.base.validate('io.example.objectArray', 'record', {'foo': []}) + + self.base.validate('io.example.objectArray', 'record', { + 'foo': [ + {'bar': 3, 'baj': 'foo'}, + {'bar': 4}, + ], + }) + + def test_validate_record_object_array_fail_bad_type(self): + with self.assertRaises(ValidationError): + self.base.validate('io.example.objectArray', 'record', { + 'foo': [ + {'bar': 'x'} + ], + }) + + def test_validate_record_object_array_fail_missing_required(self): + with self.assertRaises(ValidationError): + self.base.validate('io.example.objectArray', 'record', { + 'foo': [ + {'baz': 'x'} + ], + }) diff --git a/lexrpc/tests/test_testdata.py b/lexrpc/tests/test_testdata.py index 000d4d2..2c08f3d 100644 --- a/lexrpc/tests/test_testdata.py +++ b/lexrpc/tests/test_testdata.py @@ -54,7 +54,7 @@ def test_fn(): data = input['data'] def test(self): # shouldn't raise - base.maybe_validate(data['$type'], 'record', data) + base.validate(data['$type'], 'record', data) return test tests[test_name('record_valid_' + input['name'])] = test_fn() @@ -66,7 +66,7 @@ def test_fn(): data = input['data'] def test(self): with self.assertRaises(ValidationError): - base.maybe_validate(data['$type'], 'record', data) + base.validate(data['$type'], 'record', data) return test tests[test_name('record_invalid_' + input['name'])] = test_fn()