def __init__(self): super(GetNewAddressesRequestFilter, self).__init__( { # Everything except ``seed`` is optional. 'checksum': f.Type(bool) | f.Optional(default=False), 'count': f.Type(int) | f.Min(1), 'index': f.Type(int) | f.Min(0) | f.Optional(default=0), 'securityLevel': f.Type(int) | f.Min(1) | f.Max(self.MAX_SECURITY_LEVEL) | f.Optional(default=AddressGenerator.DEFAULT_SECURITY_LEVEL), 'seed': f.Required | Trytes(result_type=Seed), }, allow_missing_keys={ 'checksum', 'count', 'index', 'securityLevel', }, )
def __init__(self): super(GetPrivateKeysRequestFilter, self).__init__( { # Optional Parameters 'count': f.Type(int) | f.Min(1) | f.Optional(default=1), 'index': f.Type(int) | f.Min(0) | f.Optional(default=0), 'securityLevel': f.Type(int) | f.Min(1) | f.Optional(default=AddressGenerator.DEFAULT_SECURITY_LEVEL), # Required Parameters 'seed': f.Required | Trytes(result_type=Seed), }, allow_missing_keys={ 'count', 'index', 'securityLevel', }, )
def __init__(self): super(SendTransferRequestFilter, self).__init__( { # Required parameters. 'depth': f.Required | f.Type(int) | f.Min(1), 'seed': f.Required | Trytes(result_type=Seed), # Loosely-validated; testnet nodes require a different value # than mainnet. 'minWeightMagnitude': f.Required | f.Type(int) | f.Min(1), 'transfers': (f.Required | f.Array | f.FilterRepeater(f.Required | f.Type(ProposedTransaction))), # Optional parameters. 'changeAddress': Trytes(result_type=Address), # Note that ``inputs`` is allowed to be an empty array. 'inputs': f.Array | f.FilterRepeater(f.Required | Trytes(result_type=Address)), }, allow_missing_keys={ 'changeAddress', 'inputs', }, )
def __init__(self): super(ReplayBundleRequestFilter, self).__init__({ 'depth': f.Required | f.Type(int) | f.Min(1), 'transaction': f.Required | Trytes(result_type=TransactionHash), # Loosely-validated; testnet nodes require a different value than # mainnet. 'minWeightMagnitude': f.Required | f.Type(int) | f.Min(1), })
def __init__(self): super(PromoteTransactionRequestFilter, self).__init__({ 'depth': f.Required | f.Type(int) | f.Min(1), 'transaction': f.Required | Trytes(TransactionHash), # Loosely-validated; testnet nodes require a different value # than mainnet. 'minWeightMagnitude': f.Required | f.Type(int) | f.Min(1), })
def __init__(self): super(GetNewAddressesRequestFilter, self).__init__( { # ``count`` and ``index`` are optional. 'count': f.Type(int) | f.Min(1), 'index': f.Type(int) | f.Min(0) | f.Optional(default=0), 'seed': f.Required | Trytes(result_type=Seed), }, allow_missing_keys={ 'count', 'index', }, )
def __init__(self): super(SendTrytesRequestFilter, self).__init__({ 'depth': f.Required | f.Type(int) | f.Min(1), 'trytes': f.Required | f.Array | f.FilterRepeater(f.Required | Trytes(result_type=TransactionTrytes)), # Loosely-validated; testnet nodes require a different value than # mainnet. 'minWeightMagnitude': f.Required | f.Type(int) | f.Min(1), })
def test_extra_keys_disallowed(self): """ FilterMappers can be configured to treat any extra key as an invalid value. """ self.filter_type = lambda: f.FilterMapper( { 'id': f.Required | f.Int | f.Min(1), 'subject': f.NotEmpty | f.MaxLength(16), }, # Treat all extra keys as invalid values.s allow_extra_keys = False, ) self.assertFilterErrors( { 'id': '42', 'subject': 'Hello, world!', 'extra': 'ignored', }, { 'extra': [f.FilterMapper.CODE_EXTRA_KEY], }, # The valid fields were still included in the return value, # but the invalid field was removed. expected_value = { 'id': 42, 'subject': 'Hello, world!', } )
def test_pass_ordered_mapping(self): """ Configuring the FilterRepeater to return an OrderedDict. """ # Note that we pass an OrderedDict to the filter initializer. self.filter_type = lambda: f.FilterMapper(OrderedDict(( ('subject', f.NotEmpty | f.MaxLength(16)), ('id', f.Required | f.Int | f.Min(1)), ))) filter_ = self._filter({ 'id': '42', 'subject': 'Hello, world!', }) self.assertFilterPasses( filter_, OrderedDict(( ('subject', 'Hello, world!'), ('id', 42), )), ) # The result is an OrderedDict, to match the type of the filter # map. self.assertIs(type(filter_.cleaned_data), OrderedDict)
def test_missing_keys_specified(self): """ FilterMappers can be configured to allow some missing keys but not others. """ self.filter_type = lambda: f.FilterMapper( { 'id': f.Required | f.Int | f.Min(1), 'subject': f.NotEmpty | f.MaxLength(16), }, allow_missing_keys={'subject'}, ) # The FilterMapper is configured to treat missing 'subject' as # if it were set to `None`. self.assertFilterPasses( {'id': '42'}, { 'id': 42, 'subject': None, }, ) # However, 'id' is still required. self.assertFilterErrors({ 'subject': 'Hello, world!', }, { 'id': [f.FilterMapper.CODE_MISSING_KEY], }, expected_value={ 'id': None, 'subject': 'Hello, world!', })
def test_missing_keys_allowed(self): """ By default, FilterMappers treat missing keys as `None`. """ self.filter_type = lambda: f.FilterMapper( { 'id': f.Required | f.Int | f.Min(1), 'subject': f.NotEmpty | f.MaxLength(16), }) # 'subject' allows null values, so no errors are generated. self.assertFilterPasses( { 'id': '42', }, { 'id': 42, 'subject': None, }, ) # However, 'id' has Required in its FilterChain, so a missing # 'id' is still an error. self.assertFilterErrors( { 'subject': 'Hello, world!', }, { 'id': [f.Required.CODE_EMPTY], }, expected_value={ 'id': None, 'subject': 'Hello, world!', }, )
def test_fail_match_case(self): """ The incoming value matches one of the switch cases, but it is not valid, according to the corresponding filter. """ self.assertFilterErrors( self._filter( { 'name': 'positive', 'value': -1 }, getter=lambda value: value['name'], cases={ 'positive': f.FilterMapper({'value': f.Int | f.Min(0)}), }, ), {'value': [f.Min.CODE_TOO_SMALL]}, # The result is the exact same as if the value were passed # directly to the corresponding filter. expected_value={ 'name': 'positive', 'value': None }, )
def test_missing_keys_disallowed(self): """ FilterMappers can be configured to treat missing keys as invalid values. """ self.filter_type = lambda: f.FilterMapper( { 'id': f.Required | f.Int | f.Min(1), 'subject': f.NotEmpty | f.MaxLength(16), }, # Treat missing keys as invalid values. allow_missing_keys = False, ) self.assertFilterErrors( {}, { 'id': [f.FilterMapper.CODE_MISSING_KEY], 'subject': [f.FilterMapper.CODE_MISSING_KEY], }, expected_value = { 'id': None, 'subject': None, }, )
def test_pass_mapping(self): """ A FilterRepeater is applied to a dict containing valid values. """ self.filter_type = lambda: f.FilterMapper({ 'id': f.Required | f.Int | f.Min(1), 'subject': f.NotEmpty | f.MaxLength(16), }) filter_ = self._filter({ 'id': '42', 'subject': 'Hello, world!', }) self.assertFilterPasses( filter_, { 'id': 42, 'subject': 'Hello, world!', }, ) # The result is a dict, to match the type of the filter map. self.assertIs(type(filter_.cleaned_data), dict)
def __init__(self): super(GetInputsRequestFilter, self).__init__( { # These arguments are optional. 'stop': f.Type(int) | f.Min(0), 'start': f.Type(int) | f.Min(0) | f.Optional(0), 'threshold': f.Type(int) | f.Min(0), # These arguments are required. 'seed': f.Required | Trytes(result_type=Seed), }, allow_missing_keys={ 'stop', 'start', 'threshold', })
def test_fail_mapping(self): """ A FilterRepeater is applied to a dict containing invalid values. """ self.filter_type = lambda: f.FilterMapper({ 'id': f.Required | f.Int | f.Min(1), 'subject': f.NotEmpty | f.MaxLength(16), }) self.assertFilterErrors( { 'id': None, 'subject': 'Antidisestablishmentarianism', }, { 'id': [f.Required.CODE_EMPTY], 'subject': [f.MaxLength.CODE_TOO_LONG], }, expected_value = { 'id': None, 'subject': None, } )
def __init__(self) -> None: super(GetAccountDataRequestFilter, self).__init__( { # Required parameters. 'seed': f.Required | Trytes(Seed), # Optional parameters. 'stop': f.Type(int) | f.Min(0), 'start': f.Type(int) | f.Min(0) | f.Optional(0), 'inclusionStates': f.Type(bool) | f.Optional(False), 'security_level': SecurityLevel }, allow_missing_keys={ 'stop', 'start', 'inclusionStates', 'security_level' }, )
def test_extra_keys_ordered(self): """ When the filter map is an OrderedDict, extra keys are alphabetized. """ # Note that we pass an OrderedDict to the filter initializer. self.filter_type = lambda: f.FilterMapper(OrderedDict(( ('subject', f.NotEmpty | f.MaxLength(16)), ('id', f.Required | f.Int | f.Min(1)), ))) filter_ = self._filter({ 'id': '42', 'subject': 'Hello, world!', 'cat': 'felix', 'bird': 'phoenix', 'fox': 'fennecs', }) self.assertFilterPasses( filter_, OrderedDict(( # The filtered keys are always listed first. ('subject', 'Hello, world!'), ('id', 42), # Extra keys are listed afterward, in alphabetical # order. ('bird', 'phoenix'), ('cat', 'felix'), ('fox', 'fennecs'), )), )
def test_mapper_chained_with_mapper(self): """ Chaining two FilterMappers together has basically the same effect as combining their Filters. Generally, combining two FilterMappers into a single instance is much easier to read/maintain than chaining them, but in a few cases it may be unavoidable (for example, if you need each FilterMapper to handle extra and/or missing keys differently). """ fm1 = f.FilterMapper( { 'id': f.Int | f.Min(1), }, allow_missing_keys=True, allow_extra_keys=True, ) fm2 = f.FilterMapper( { 'id': f.Required | f.Max(256), 'subject': f.NotEmpty | f.MaxLength(16), }, allow_missing_keys=False, allow_extra_keys=False, ) self.filter_type = lambda: fm1 | fm2 self.assertFilterPasses( { 'id': '42', 'subject': 'Hello, world!', }, { 'id': 42, 'subject': 'Hello, world!', }, ) self.assertFilterErrors( {}, { # ``fm1`` allows missing keys, so it sets 'id' to # ``None``. # However, ``fm2`` does not allow ``None`` for 'id' # (because of the ``Required`` filter). 'id': [f.Required.CODE_EMPTY], # `fm1` does not care about `subject`, but `fm2` # expects it to be there. 'subject': [f.FilterMapper.CODE_MISSING_KEY], }, expected_value={ 'id': None, 'subject': None, }, )
def __init__(self): super(GetNewAddressesRequestFilter, self).__init__( { # Everything except ``seed`` is optional. 'checksum': f.Type(bool) | f.Optional(default=False), 'count': f.Type(int) | f.Min(1), 'index': f.Type(int) | f.Min(0) | f.Optional(default=0), 'securityLevel': SecurityLevel, 'seed': f.Required | Trytes(Seed), }, allow_missing_keys={ 'checksum', 'count', 'index', 'securityLevel', }, )
def test_success_filter_map(self): """ Applying a :py:class:`f.FilterMap` to the values in a namedtuple after converting (success case). """ self.filter_type = lambda: f.NamedTuple( Color, { # For whatever reason, we decide not to filter ``r``. 'g': f.Required | f.Int | f.Min(0) | f.Max(255), 'b': f.Required | f.Int | f.Min(0) | f.Max(255), }) self.assertFilterPasses( ('64.0', '128', 192.0), Color('64.0', 128, 192), )
def __init__(self): super(GetAccountDataRequestFilter, self).__init__( { # Required parameters. 'seed': f.Required | Trytes(result_type=Seed), # Optional parameters. 'stop': f.Type(int) | f.Min(0), 'start': f.Type(int) | f.Min(0) | f.Optional(0), 'inclusionStates': f.Type(bool) | f.Optional(False), }, allow_missing_keys={ 'stop', 'inclusionStates', 'start', }, )
def __init__(self) -> None: super(GetDigestsRequestFilter, self).__init__( { # Optional Parameters 'count': f.Type(int) | f.Min(1) | f.Optional(default=1), 'index': f.Type(int) | f.Min(0) | f.Optional(default=0), 'securityLevel': SecurityLevel, # Required Parameters 'seed': f.Required | Trytes(Seed), }, allow_missing_keys={ 'count', 'index', 'securityLevel', }, )
def __init__(self) -> None: super(GetTransfersRequestFilter, self).__init__( { # Required parameters. 'seed': f.Required | Trytes(Seed), # Optional parameters. 'stop': f.Type(int) | f.Min(0), 'start': f.Type(int) | f.Min(0) | f.Optional(0), 'inclusionStates': f.Type(bool) | f.Optional(False), }, allow_missing_keys={ 'stop', 'inclusionStates', 'start', }, )
def __init__(self): super(GetTransactionsToApproveRequestFilter, self).__init__( { 'depth': f.Required | f.Type(int) | f.Min(1), 'reference': Trytes(result_type=TransactionHash), }, allow_missing_keys={ 'reference', })
def SecurityLevel(): """ Generates a filter chain for validating a security level. :return: :py:class:`filters.FilterChain` object. """ return (f.Type(int) | f.Min(1) | f.Max(3) | f.Optional(default=AddressGenerator.DEFAULT_SECURITY_LEVEL))
def __init__(self) -> None: super(SendTrytesRequestFilter, self).__init__( { 'depth': f.Required | f.Type(int) | f.Min(1), 'trytes': f.Required | f.Array | f.FilterRepeater(f.Required | Trytes(TransactionTrytes), ), # Loosely-validated; devnet nodes require a different value # than mainnet. 'minWeightMagnitude': f.Required | f.Type(int) | f.Min(1), 'reference': Trytes(TransactionHash), }, allow_missing_keys={ 'reference', })
def test_passthru_key(self): """ If you want to make a key required but do not want to run any Filters on it, set its FilterChain to `None`. """ self.filter_type = lambda: f.FilterMapper( { 'id': f.Required | f.Int | f.Min(1), 'subject': None, }, # If you configure a FilterMapper with passthru keys(s), # you generally also want to disallow missing keys. allow_missing_keys = False, ) self.assertFilterPasses( { 'id': '42', 'subject': 'Hello, world!', }, { 'id': 42, 'subject': 'Hello, world!', }, ) self.assertFilterPasses( { 'id': '42', 'subject': None, }, { 'id': 42, 'subject': None, }, ) self.assertFilterErrors( { 'id': '42', }, { 'subject': [f.FilterMapper.CODE_MISSING_KEY], }, expected_value = { 'id': 42, 'subject': None, }, )
def test_fail_filter_map(self): """ Applying a :py:class:`f.FilterMap` to the values in a namedtuple after converting (failure case). """ self.filter_type = lambda: f.NamedTuple( Color, { # For whatever reason, we decide not to filter ``r``. 'g': f.Required | f.Int | f.Min(0) | f.Max(255), 'b': f.Required | f.Int | f.Min(0) | f.Max(255), }) self.assertFilterErrors( ['NaN', None, (42, )], { 'g': [f.Required.CODE_EMPTY], 'b': [f.Decimal.CODE_INVALID], }, )
def test_fail_non_mapping(self): """The incoming value is not a mapping.""" self.filter_type = lambda: f.FilterMapper({ 'id': f.Required | f.Int | f.Min(1), 'subject': f.NotEmpty | f.MaxLength(16), }) self.assertFilterErrors( # Nope; it's gotta be an explicit mapping. (('id', '42'), ('subject', 'Hello, world!')), [f.Type.CODE_WRONG_TYPE], )