def inner(mapping, context=None): register = context if not isinstance(mapping, dict): raise t.DataError("value is not a dict", value=mapping) checked_mapping = {} errors = {} for key, value in mapping.items(): pair_errors = {} try: checked_key = key_trafaret.check(key, context=register) except t.DataError as err: pair_errors['key'] = err checked_key = None try: if checked_key: register.push(path) register.push(checked_key) schema = json_schema.check(value, context=register) except t.DataError as err: pair_errors['value'] = err else: register.save_schema(schema) finally: if checked_key: register.pop() register.pop() if pair_errors: errors[key] = t.DataError(error=pair_errors) else: checked_mapping[checked_key] = schema if errors: raise t.DataError(error=errors) return checked_mapping
def test_nested_dataerror_value(): error = t.DataError( error={ 0: t.DataError(error='Wait for good value', value='BAD ONE', code='bad_value') }, code='some_elements_going_mad', ) assert error.as_dict() == {0: 'Wait for good value'} assert error.as_dict(value=True) == { 0: "Wait for good value, got 'BAD ONE'" } assert error.to_struct() == { 'code': 'some_elements_going_mad', 'nested': { 0: { 'code': 'bad_value', 'message': 'Wait for good value', } }, } assert error.to_struct(value=True) == { 'code': 'some_elements_going_mad', 'nested': { 0: { 'code': 'bad_value', 'message': "Wait for good value, got 'BAD ONE'", } }, }
def process_payment(self): status = http.OK data = self.order.details data['status'] = 'OK' try: option_id = session.pop('valid_option', None) carts = self.order.goods.filter_by(price_option_id=option_id) if carts.count() != self.order.goods.count(): raise t.DataError({'voucher': _('Invalid price option')}) redemption = self.__redeem(voucher=data['voucher'], security=data['code'], deal=data['deal']) if redemption.status_code != http.OK: raise t.DataError({'voucher': _('Invalid voucher')}) else: self.order.mark_paid() data.update(self.order.as_dict()) except t.DataError as e: status = http.BAD_REQUEST data.update({ 'message': 'ERROR', 'errors': e.as_dict(), 'status': 'ERR' }) return jsonify_status_code(data, status)
class TestCall(unittest.TestCase): TRAFARET = T.Dict({ T.Key("call_dict", optional=True): # The following is the ordered dict because we want to obey order # in the error messages. Otherwise, it could be normal dict as well T.Call(lambda _: T.DataError({ "anything": "bad idea", "bad": "another bad idea", })), T.Key("call_str", optional=True): T.Call(lambda _: T.DataError("some error")), }) def test_call_dict(self): self.assertEqual( get_err(self.TRAFARET, u""" call_dict: "hello" """), dedent(u"""\ config.yaml:2: call_dict.anything: bad idea config.yaml:2: call_dict.bad: another bad idea """)) def test_call_str(self): self.assertEqual( get_err(self.TRAFARET, u""" call_str: "hello" """), dedent(u"""\ config.yaml:2: call_str: some error -> 'hello' """))
def ensure_callback_args(value): callback = value.get("callback") if not callback: return value kwargs = value.get("callback_args", {}) callback_params = set(kwargs) | {"context"} sig = signature(callback) required_params = { name for name, param in sig.parameters.items() if param.default is param.empty and param.kind != 2 } missed_params = required_params - callback_params if missed_params: raise t.DataError("Missed parameters for %s: %s" % (callback, ", ".join(missed_params))) all_params = { name for name, param in sig.parameters.items() if param.kind != 2 # ignore vararg } unknown_params = callback_params - all_params if unknown_params: raise t.DataError("Unexpected parameters for %s: %s" % (callback, ", ".join(unknown_params))) return value
def check(value): errors = {} for name in names: if name not in value: errors[name] = t.DataError('%s is required' % name) if errors: return t.DataError(errors) return value
def test_nested_dataerror_value(self): error = t.DataError( error={ 0: t.DataError(error='Wait for good value', value='BAD ONE') }) self.assertEqual(error.as_dict(), {0: 'Wait for good value'}) self.assertEqual(error.as_dict(value=True), {0: "Wait for good value, got 'BAD ONE'"})
def check_headers(headers): if not isinstance(headers, dict): return t.DataError('value is not a dict') headers = dict((k.lower(), v) for k, v in headers.items()) for item in ('fs-signature', 'fs-timestamp'): if item.lower() not in headers: return t.DataError('{} header is missing'.format(item)) return headers
def test_as_dict(): exc = t.DataError() resp = as_dict(exc) assert isinstance(resp, dict) exc = t.DataError() assert isinstance(exc.as_dict("boom"), str) resp = as_dict(exc, 'boom') assert isinstance(resp, dict)
def check_(value): if (first in value) ^ (second in value): key = first if first in value else second yield first, t.catch_error(trafaret, value[key]), (key,) elif first in value and second in value: yield first, t.DataError(error=f'correct only if {second} is not defined'), (first,) yield second, t.DataError(error=f'correct only if {first} is not defined'), (second,) else: yield first, t.DataError(error=f'is required if {second} is not defined'), (first,) yield second, t.DataError(error=f'is required if {first} is not defined'), (second,)
def _cmp_pwd(self, value): password, confirmation = (value.pop('password', None), value.pop('confirmation', None)) if password: if len(password) < 6: return t.DataError({ 'password': _("Passwords should be more than 6 symbols length") }) if password != confirmation: return t.DataError( {'confirmation': _("Passwords doesn't match")}) value['password'] = encrypt_password(password) return value
def check_(value): first, second = None, None if name in value: first = value[name] else: yield name, t.DataError('is required'), (name,) if confirm_name in value: second = value[confirm_name] else: yield confirm_name, t.DataError('is required'), (confirm_name,) if not (first and second): return yield name, t.catch_error(trafaret, first), (name,) yield confirm_name, t.catch_error(trafaret, second), (confirm_name,) if first != second: yield confirm_name, t.DataError(f'must be equal to {name}'), (confirm_name,)
def test_call(self): a_three = lambda val: val if val == 3 else t.DataError('not a 3') tt = construct([a_three]) self.assertEqual(tt([3, 3, 3]), [3, 3, 3]) with self.assertRaises(t.DataError): tt([5])
def test_keys_subset(self): cmp_pwds = lambda x: { 'pwd': x['pwd'] if x.get('pwd') == x.get('pwd1') else t.DataError('Not equal') } d = t.Dict({KeysSubset('pwd', 'pwd1'): cmp_pwds, 'key1': t.String}) res = d.check({'pwd': 'a', 'pwd1': 'a', 'key1': 'b'}).keys() self.assertEqual(list(sorted(res)), ['key1', 'pwd']) res = extract_error(d.check, {'pwd': 'a', 'pwd1': 'c', 'key1': 'b'}) self.assertEqual(res, {'pwd': 'Not equal'}) res = extract_error(d.check, {'pwd': 'a', 'pwd1': None, 'key1': 'b'}) self.assertEqual(res, {'pwd': 'Not equal'}) get_values = (lambda d, keys: [d[k] for k in keys if k in d]) join = (lambda d: {'name': ' '.join(get_values(d, ['name', 'last']))}) res = t.Dict({ KeysSubset('name', 'last'): join }).check({ 'name': 'Adam', 'last': 'Smith' }) self.assertEqual(res, {'name': 'Adam Smith'}) res = t.Dict({KeysSubset(): t.Dict({'a': t.Any})}).check({'a': 3}) self.assertEqual(res, {'a': 3})
def cast_interval(value): r"""Casts interval value into `datetime.timedelta` instance. If value is `int`, returned `timedelta` get constructed from a given by the value`s seconds. If value is `str`, then it get converted into seconds according the rules: - ``\d+s`` - time delta in seconds. Example: ``10s`` for 10 seconds; - ``\d+m`` - time delta in minutes. Example: ``42m`` for 42 minutes; - ``\d+h`` - time delta in hours. Example: ``1h`` for 1 hour; - ``\d+d`` - time delta in days. Example: ``10d`` for 10 days. :param str | int | datetime.timedelta value: An interval value. :rtype: datetime.timedelta """ if isinstance(value, str): match = re.match(r"^(-)?(\d+)([dhms])$", value) if match is not None: has_neg_sign, value, unit = match.groups() value = int(value) value *= { # fmt: off "s": 1, "m": 60, "h": 60 * 60, "d": 60 * 60 * 24, # fmt: on }[unit] value *= -1 if has_neg_sign else 1 if isinstance(value, int): value = datetime.timedelta(seconds=value) elif not isinstance(value, datetime.timedelta): raise t.DataError("invalid interval value %s" % value) return value
def validate_schema(schema, context=None): # we use `context` to provide register to deep schemas if context is None or isinstance(context, Register): register = context or Register() schema_name = schema.get('$id') or uuid4().urn schema_register = register.reg_schema(schema_name) elif isinstance(context, SchemaRegister): schema_register = context else: ValueError('You need to provide Register instance to json_schema and nothing else') touched_names = set() errors = {} keywords_checks = [] format_transform = t.Any for key in all_keywords: for k, v, names in key(schema, context=schema_register): if isinstance(v, t.DataError): errors[k] = v else: if k == 'format': format_transform = v keywords_checks.append(v) touched_names = touched_names.union(names) schema_keys = set(schema.keys()) for key in schema_keys - touched_names: errors[key] = '%s is not allowed key' % key if errors: raise t.DataError(errors) schema_trafaret = All(keywords_checks) & format_transform return schema_trafaret
def post(self): data = self.clean(g.request_json) if not User.is_unique(data['email']): raise t.DataError({'email': _("This email is already taken")}) register_user(email=data['email'], password=data.get('password', '*')) return self._get_response()
def transform(value): assert isinstance(value, dict) data = value.copy() if data.get(main) != data.get(extra): return t.DataError(error={main: msg}) data.pop(extra, None) return data
def check_for_class_callback_collisions(value): if "class" in value: if "callback" in value or "callback_args" in value: raise t.DataError( "when `class` specified, there should be no" " `callback` and `callback_args`" ) return value
def get_schema(self, ref): if ref.startswith('#'): # local reference if ref not in self.schemas: # TODO detect on build raise t.DataError('Bad reference `%s` in JSON schema' % ref) return self.schemas.get(ref) else: return self.register().get_schema(ref)
def test_call(self): a_three = lambda val: val if val == 3 else t.DataError('not a 3', code='not_a_3') tt = construct([a_three]) assert tt([3, 3, 3]) == [3, 3, 3] with pytest.raises(t.DataError): tt([5])
def strong_password(string): """Check that ``string`` is strong enough password""" if (any(char.isdigit() for char in string) and any(char.islower() for char in string) and any(char.isupper() for char in string) and any(char in punctuation for char in string)): return string else: raise t.DataError('Password is not strong enough')
def transform(self, value, context=None): errors = [] for trafaret in self.trafarets: res = t.catch_error(trafaret, value, context=context) if isinstance(res, t.DataError): errors.append(res) else: return value raise t.DataError(errors)
def check(data): for v in data: try: trafaret(v) except t.DataError: pass else: return data raise t.DataError('Array does not contains any value that completes test')
def check_(value): if (first in value) ^ (second in value): key = first if first in value else second yield first, t.catch_error(trafaret, value[key]), (key, ) elif first in value and second in value: yield first, t.DataError( error='correct only if {} is not defined'.format(second)), ( first, ) yield second, t.DataError( error='correct only if {} is not defined'.format(first)), ( second, ) else: yield first, t.DataError( error='is required if {} is not defined'.format('second')), ( first, ) yield second, t.DataError( error='is required if {} is not defined'.format('first')), ( second, )
def _authenticate(self, data_dict): user = security.datastore.find_user(email=data_dict['email']) if verify_password(data_dict.get('password'), user.password): login_user(user) else: raise t.DataError( {'email': "Can't find anyone with this credentials"}) return data_dict
def test_dataerror_value(): error = t.DataError(error='Wait for good value', value='BAD ONE', code='bad_value') assert error.as_dict() == 'Wait for good value' assert error.as_dict(value=True) == "Wait for good value, got 'BAD ONE'" assert error.to_struct() == { 'code': 'bad_value', 'message': 'Wait for good value', }
def test_dataerror_value(self): error = t.DataError(error='Wait for good value', value='BAD ONE') self.assertEqual( error.as_dict(), 'Wait for good value' ) self.assertEqual( error.as_dict(value=True), "Wait for good value, got 'BAD ONE'" )
def check_and_return(self, value, context=None): try: return self.to_enum_func(value, self.converter) except ValueError: raise trf.DataError( "Incorrect value `{val}`. Possible variants: {possible_vals}".format( val=value, possible_vals=", ".join(e.name for e in self.converter), ), value=value, trafaret=self, )
def check_(value): first, second = None, None if name in value: first = value[name] yield name, t.catch_error(trafaret, first), (name, ) else: yield name, t.DataError('is required', code=codes.REQUIRED), (name, ) if confirm_name in value: second = value[confirm_name] yield confirm_name, t.catch_error(trafaret, second), (confirm_name, ) else: yield confirm_name, t.DataError( 'is required', code=codes.REQUIRED), (confirm_name, ) if not (first and second): return if first != second: yield (confirm_name, t.DataError('must be equal to {}'.format(name), code=codes.MUST_BE_EQUAL), (confirm_name, ))