From 7e80de0a1e1e5abb1efc57b243db52b393a19df6 Mon Sep 17 00:00:00 2001 From: Ember Date: Tue, 23 Apr 2019 15:55:02 +0300 Subject: [PATCH] Add custom validation fields --- README.md | 4 ++- cli/account/cli.py | 6 ++-- cli/account/forms.py | 43 ++++-------------------- cli/account/help.py | 2 +- cli/constants.py | 1 + cli/generic/__init__.py | 0 cli/generic/forms/__init__.py | 0 cli/generic/forms/fields.py | 62 +++++++++++++++++++++++++++++++++++ setup.cfg | 2 +- 9 files changed, 77 insertions(+), 43 deletions(-) create mode 100644 cli/generic/__init__.py create mode 100644 cli/generic/forms/__init__.py create mode 100644 cli/generic/forms/fields.py diff --git a/README.md b/README.md index 2cc4d6b..aa3c553 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,9 @@ Get balance of the account by its address — ``remme account get-balance``: $ remme account get-balance \ --address=1120076ecf036e857f42129b58303bcf1e03723764a1702cbe98529802aad8514ee3cf \ --node-url=node-genesis-testnet.remme.io -368440.0 +{ + "result": 368440.0 +} ``` ## Development diff --git a/cli/account/cli.py b/cli/account/cli.py index 20ab4f3..e24cf48 100644 --- a/cli/account/cli.py +++ b/cli/account/cli.py @@ -6,13 +6,13 @@ import click from remme import Remme -from cli.account.forms import GetAccountBalanceForm -from cli.account.help import GET_ACCOUNT_BALANCE_ADDRESS_ARGUMENT_HELP_MESSAGE +from cli.account.help import ADDRESS_ARGUMENT_HELP_MESSAGE from cli.account.service import Account from cli.constants import ( FAILED_EXIT_FROM_COMMAND_CODE, NODE_URL_ARGUMENT_HELP_MESSAGE, ) +from cli.account.forms import GetAccountBalanceForm from cli.utils import ( default_node_url, print_errors, @@ -28,7 +28,7 @@ def account_commands(): pass -@click.option('--address', type=str, required=True, help=GET_ACCOUNT_BALANCE_ADDRESS_ARGUMENT_HELP_MESSAGE) +@click.option('--address', type=str, required=True, help=ADDRESS_ARGUMENT_HELP_MESSAGE) @click.option('--node-url', type=str, required=False, help=NODE_URL_ARGUMENT_HELP_MESSAGE, default=default_node_url()) @account_commands.command('get-balance') def get_balance(address, node_url): diff --git a/cli/account/forms.py b/cli/account/forms.py index 1184e16..85be7a7 100644 --- a/cli/account/forms.py +++ b/cli/account/forms.py @@ -1,18 +1,11 @@ """ Provide forms for command line interface's account commands. """ -import re +from marshmallow import Schema -from marshmallow import ( - Schema, - ValidationError, - fields, - validates, -) - -from cli.constants import ( - ADDRESS_REGEXP, - DOMAIN_NAME_REGEXP, +from cli.generic.forms.fields import ( + AccountAddressField, + NodeURLField, ) @@ -21,29 +14,5 @@ class GetAccountBalanceForm(Schema): Get balance of the account form. """ - address = fields.String(required=True) - node_url = fields.String(allow_none=True, required=False) - - @validates('address') - def validate_address(self, address): - """ - Validate account address. - """ - if re.match(pattern=ADDRESS_REGEXP, string=address) is None: - raise ValidationError(f'The following address `{address}` is invalid.') - - @validates('node_url') - def validate_node_url(self, node_url): - """ - Validate node URL. - - If node URL is localhost, it means client didn't passed any URL, so nothing to validate. - """ - if node_url == 'localhost': - return - - if 'http' in node_url or 'https' in node_url: - raise ValidationError(f'Pass the following node URL `{node_url}` without protocol (http, https, etc.).') - - if re.match(pattern=DOMAIN_NAME_REGEXP, string=node_url) is None: - raise ValidationError(f'The following node URL `{node_url}` is invalid.') + address = AccountAddressField(required=True) + node_url = NodeURLField(allow_none=True, required=False) diff --git a/cli/account/help.py b/cli/account/help.py index f77a131..36fce4f 100644 --- a/cli/account/help.py +++ b/cli/account/help.py @@ -1,4 +1,4 @@ """ Provide help messages for command line interface's account commands. """ -GET_ACCOUNT_BALANCE_ADDRESS_ARGUMENT_HELP_MESSAGE = 'Account address to get a balance by.' +ADDRESS_ARGUMENT_HELP_MESSAGE = 'Account address to get a balance by.' diff --git a/cli/constants.py b/cli/constants.py index 69b1240..f49d571 100644 --- a/cli/constants.py +++ b/cli/constants.py @@ -2,6 +2,7 @@ Provide constants for command line interface. """ ADDRESS_REGEXP = r'^[0-9a-f]{70}$' +HEADER_SIGNATURE_REGEXP = r'^[0-9a-f]{128}$' DOMAIN_NAME_REGEXP = r'(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]' PASSED_EXIT_FROM_COMMAND_CODE = 0 diff --git a/cli/generic/__init__.py b/cli/generic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cli/generic/forms/__init__.py b/cli/generic/forms/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cli/generic/forms/fields.py b/cli/generic/forms/fields.py new file mode 100644 index 0000000..8606699 --- /dev/null +++ b/cli/generic/forms/fields.py @@ -0,0 +1,62 @@ +""" +Provide implementation of the custom fields. +""" +import re + +from marshmallow import ( + ValidationError, + fields, +) + +from cli.constants import ( + ADDRESS_REGEXP, + DOMAIN_NAME_REGEXP, +) + + +class AccountAddressField(fields.Field): + """ + Implements validation of the account address. + + References: + - https://marshmallow.readthedocs.io/en/3.0/custom_fields.html + """ + + def _deserialize(self, value, attr, obj, **kwargs): + """ + Validate data (account address) that was passed to field. + """ + address = value + + if re.match(pattern=ADDRESS_REGEXP, string=address) is None: + raise ValidationError(f'The following address `{address}` is invalid.') + + return address + + +class NodeURLField(fields.Field): + """ + Implements validation of the node URL. + + If node URL is localhost, it means client didn't passed any URL, so nothing to validate. + + References: + - https://marshmallow.readthedocs.io/en/3.0/custom_fields.html + """ + + def _deserialize(self, value, attr, obj, **kwargs): + """ + Validate data (node URL) that was passed to field. + """ + node_url = value + + if node_url == 'localhost': + return node_url + + if 'http' in node_url or 'https' in node_url: + raise ValidationError(f'Pass the following node URL `{node_url}` without protocol (http, https, etc.).') + + if re.match(pattern=DOMAIN_NAME_REGEXP, string=node_url) is None: + raise ValidationError(f'The following node URL `{node_url}` is invalid.') + + return node_url diff --git a/setup.cfg b/setup.cfg index 792d491..1318256 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,7 +9,7 @@ combine_as_imports=True max-line-length=120 ignore=D200, D413, D107, D100 per-file-ignores= - */__init__.py: D104, F401, D100, + */__init__.py: D104, F401, D100 */test_*: D205 [coverage:run]