Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solve weekly technical debt #13

Merged
merged 14 commits into from
Apr 22, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/delete-merged-branch-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exclude:
- develop
- master
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ script:
- pypi-version check
- cat requirements.txt requirements-tests.txt requirements-dev.txt | safety check --stdin
- radon cc cli -nb --total-average
- isort -rc cli --diff && isort -rc tests --diff
- ./scripts/isort-diff.sh
- flake8 cli && flake8 tests
- coverage run -m pytest -vv tests

Expand Down
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* [Requirements](#getting-started-requirements)
* [Installation](#installation)
* [Usage](#usage)
* [Nodes](#nodes)
* [Configuration file](#configuration-file)
* [Service](#service)
* [Account](#account)
Expand All @@ -39,6 +40,13 @@ $ pip3 install remme-core-cli

## Usage

### Nodes

You can use the following list of the addresses of the nodes to execute commands to:

- `node-genesis-testnet.remme.io`,
- `node-6-testnet.remme.io`.

### Configuration file

Using the command line interface, you will have an option to declare the `node URL` to send commands to as illustrated below:
Expand Down Expand Up @@ -94,7 +102,7 @@ Get balance of the account by its address — ``remme account get-balance``:

| Arguments | Type | Required | Description |
| :-------: | :----: | :-------: | --------------------------------------------------- |
| address | String | Yes | Get balance of the account by its address. |
| address | String | Yes | Account address to get a balance by. |
| node-url | String | No | Apply the command to the specified node by its URL. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node URL to apply the command to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Art17, done.


```bash
Expand Down Expand Up @@ -187,7 +195,11 @@ $ git clone https://github.com/Remmeauth/remme-core-cli && cd remme-core-cli
$ pip3 install -r requirements.txt -r requirements-dev.txt -r requirements-tests.txt
```

When you make changes, ensure your code pass [the checkers](https://github.com/Remmeauth/remme-core-cli/blob/develop/.travis.yml#L16) and is covered by tests using [pytest](https://docs.pytest.org/en/latest).
When you make changes, ensure your code:

* pass [the checkers](https://github.com/Remmeauth/remme-core-cli/blob/develop/.travis.yml#L16),
* is covered by tests using [pytest](https://docs.pytest.org/en/latest),
* follow team [code style](https://github.com/dmytrostriletskyi/nimble-python-code-style-guide).

If you are new for the contribution, please read:

Expand All @@ -198,10 +210,6 @@ If you are new for the contribution, please read:
### Request pull request's review

If you want to your pull request to be review, ensure you:
- `have wrote the description of the pull request`,
- `have added at least 2 reviewers`,
- `continuous integration has been passed`.

![Example of the description and reviewers](https://habrastorage.org/webt/t1/py/cu/t1pycu1bxjslyojlpy50mxb5yie.png)

![Example of the CI which passed](https://habrastorage.org/webt/oz/fl/-n/ozfl-nl-jynrh7ofz8yuz9_gapy.png)
1. [Branch isn't out-of-date with the base branch](https://habrastorage.org/webt/ux/gi/wm/uxgiwmnft08fubvjfd6d-8pw2wq.png).
2. [Have wrote the description of the pull request and have added at least 2 reviewers](https://github.com/camo/55c309334a8b61a4848a6ef25f9b0fb3751ae5e9/68747470733a2f2f686162726173746f726167652e6f72672f776562742f74312f70792f63752f7431707963753162786a736c796f6a6c707935306d7862357969652e706e67).
Copy link
Contributor

@Art17 Art17 Apr 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have wrote > Have written.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Art17, done.

3. [Continuous integration has been passed](https://habrastorage.org/webt/oz/fl/-n/ozfl-nl-jynrh7ofz8yuz9_gapy.png).
34 changes: 21 additions & 13 deletions cli/account/cli.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
"""
Provide implementation of the command line interface's account commands.
"""
import asyncio
import sys
import re

import asyncio
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.service import Account
from cli.constants import (
ADDRESS_REGEXP,
FAILED_EXIT_FROM_COMMAND,
FAILED_EXIT_FROM_COMMAND_CODE,
NODE_URL_ARGUMENT_HELP_MESSAGE,
)
from cli.utils import (
default_node_url,
dict_to_pretty_json,
)

loop = asyncio.get_event_loop()

Expand All @@ -28,24 +31,29 @@ def account_commands():


@click.option('--address', type=str, required=True, help=GET_ACCOUNT_BALANCE_ADDRESS_ARGUMENT_HELP_MESSAGE)
@click.option('--node-url', type=str, help=NODE_URL_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):
"""
Get balance of the account by its address.
"""
if re.match(pattern=ADDRESS_REGEXP, string=address) is None:
click.echo('The following address `{address}` is not valid.'.format(address=address))
sys.exit(FAILED_EXIT_FROM_COMMAND)
arguments, errors = GetAccountBalanceForm().load({
'address': address,
'node_url': node_url,
})

if errors:
click.echo(dict_to_pretty_json(errors))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stylize please error output.
Example

Copy link
Contributor Author

@dmytrostriletskyi dmytrostriletskyi Apr 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Alladin9393, your approach has:

  1. Additional function.
  2. Which is based on marshmallow (so it has dependency).

We could remove additional function, and just do the following:

pprint(dict_to_pretty_json(errors))

And the result would be the same but without library's dependency using already created custom code in dict_to_pretty_json.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmytrostriletskyi, ok, I think its better pprint(dict_to_pretty_json(errors)).

sys.exit(FAILED_EXIT_FROM_COMMAND_CODE)

if node_url is None:
node_url = 'localhost'
address = arguments.get('address')
node_url = arguments.get('node_url')

remme = Remme(private_key_hex=None, network_config={
remme = Remme(network_config={
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a function that returns Remme object, because its code reuses all functions in command/cli.py.
Like here: click

Copy link
Contributor Author

@dmytrostriletskyi dmytrostriletskyi Apr 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Alladin9393, there is no:

if node_url is None:
    node_url = 'localhost'

anymore. The initialization of the remme object only. I do not think, we should create a separated function for object creation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Alladin9393, maybe we could write the code in the following way:

remme = Remme(network_config={'node_address': str(node_url) + ':8080', })

To make it smaller. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmytrostriletskyi, Ok, let it be as it is now.

'node_address': str(node_url) + ':8080',
})

account = Account(service=remme)
balance = loop.run_until_complete(account.get_balance(address=address))
account_service = Account(service=remme)
balance = loop.run_until_complete(account_service.get_balance(address=address))

click.echo(balance)
49 changes: 49 additions & 0 deletions cli/account/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
Provide forms for command line interface's account commands.
"""
import re

from marshmallow import (
Schema,
ValidationError,
fields,
validates,
)

from cli.constants import (
ADDRESS_REGEXP,
DOMAIN_NAME_REGEXP,
)


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.')
2 changes: 1 addition & 1 deletion cli/account/help.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""
Provide help messages for command line interface's account commands.
"""
GET_ACCOUNT_BALANCE_ADDRESS_ARGUMENT_HELP_MESSAGE = 'Get balance of the account by its address.'
GET_ACCOUNT_BALANCE_ADDRESS_ARGUMENT_HELP_MESSAGE = 'Account address to get a balance by.'
8 changes: 6 additions & 2 deletions cli/constants.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"""
Provide constants for command line interface.
"""
ADDRESS_REGEXP = '[0-9a-f]{70}'
ADDRESS_REGEXP = r'^[0-9a-f]{70}$'
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]'

FAILED_EXIT_FROM_COMMAND = -1
PASSED_EXIT_FROM_COMMAND_CODE = 0
FAILED_EXIT_FROM_COMMAND_CODE = -1

NODE_URL_ARGUMENT_HELP_MESSAGE = 'Apply the command to the specified node by its URL.'

CLI_CONFIG_FILE_NAME = 'remme-core-cli'

NODE_IP_ADDRESS_FOR_TESTING = '159.89.104.9'
23 changes: 23 additions & 0 deletions cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,26 @@ def dict_to_pretty_json(data):
Convert dictionary to string with indents as human readable text.
"""
return json.dumps(data, indent=4, sort_keys=True)


def default_node_url():
"""
Get default node URL.
"""
return 'localhost'


async def return_async_value(value):
"""
Asynchronous function return value impostor.

Using for mock particular asynchronous function with specified return value.

Example of usage in code:
mock_account_get_balance = mock.patch('cli.account.service.Account.get_balance')
mock_account_get_balance.return_value = return_async_value(13500)

References:
- https://github.com/pytest-dev/pytest-mock/issues/60
"""
return value
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ accessify==0.3.1
asyncio==3.4.3
click==7.0
remme==1.0.0
marshmallow==2.19.2
13 changes: 13 additions & 0 deletions scripts/isort-diff.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
# Check if isort show difference.

ISORT_OUTPUT=$(isort -rc . --diff)
IS_ISORT_DIFF=$(echo ${ISORT_OUTPUT} | grep '+')

if [ -z "$IS_ISORT_DIFF" ]
then
exit 0
else
echo "${ISORT_OUTPUT}"
exit 1
fi
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""
Setup the package.
"""
from setuptools import find_packages, setup
from setuptools import (
find_packages,
setup,
)

with open('README.md', 'r') as read_me:
long_description = read_me.read()
Expand Down
Loading