Skip to content

Commit

Permalink
[feature] Add Python checks in CI #3961
Browse files Browse the repository at this point in the history
Signed-off-by: alexstroke <[email protected]>
  • Loading branch information
alexstroke authored and AlexStroke committed Feb 14, 2024
1 parent c3180ab commit ed70124
Show file tree
Hide file tree
Showing 39 changed files with 1,473 additions and 1,001 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/iroha2-dev-pr-static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- '**.json'
- '**.toml'
- '.github/workflows/**.yml'
- 'client_cli/pytests/**/*.py'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -54,3 +55,39 @@ jobs:
- name: Documentation
if: always()
run: cargo doc --no-deps --quiet
python_static_analysis:
runs-on: ubuntu-latest
container:
image: hyperledger/iroha2-ci:nightly-2024-01-12
steps:
- uses: actions/checkout@v4

- name: Install dependencies using Poetry
working-directory: client_cli/pytests
run: |
poetry install
- name: Check code formatting with Black
working-directory: client_cli/pytests
run: |
poetry run black --check .
- name: Run pylint (Code Linter)
working-directory: client_cli/pytests
run: |
poetry run pylint .
- name: Run flake8 (Linter)
working-directory: client_cli/pytests
run: |
poetry run flake8 .
- name: Run isort (Import Sorter)
working-directory: client_cli/pytests
run: |
poetry run isort --check-only .
- name: Run mypy (Type Checker)
working-directory: client_cli/pytests
run: |
poetry run mypy .
31 changes: 18 additions & 13 deletions client_cli/pytests/common/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,26 @@ class Stderr(Enum):
"""
Enum for standard error messages.
"""
CANNOT_BE_EMPTY = 'cannot be empty\n\nFor more information, try \'--help\'.\n'
REPETITION = 'Repetition'
TOO_LONG = 'Name length violation'
FAILED_TO_FIND_DOMAIN = 'Failed to find domain'
INVALID_CHARACTER = 'Invalid character'
INVALID_VALUE_TYPE = 'Matching variant not found'
RESERVED_CHARACTER = 'The `@` character is reserved for `account@domain` constructs,' \
' `#` — for `asset#domain` and `$` — for `trigger$domain`.'
WHITESPACES = 'White space not allowed'
INSUFFICIENT_FUNDS = 'Not enough quantity to transfer/burn'

CANNOT_BE_EMPTY = "cannot be empty\n\nFor more information, try '--help'.\n"
REPETITION = "Repetition"
TOO_LONG = "Name length violation"
FAILED_TO_FIND_DOMAIN = "Failed to find domain"
INVALID_CHARACTER = "Invalid character"
INVALID_VALUE_TYPE = "Matching variant not found"
RESERVED_CHARACTER = (
"The `@` character is reserved for `account@domain` constructs,"
" `#` — for `asset#domain` and `$` — for `trigger$domain`."
)
WHITESPACES = "White space not allowed"
INSUFFICIENT_FUNDS = "Not enough quantity to transfer/burn"


class ReservedChars(Enum):
"""
Enum for reserved characters in names.
"""

SPECIAL = "@#$"
WHITESPACES = string.whitespace
ALL = SPECIAL + WHITESPACES
Expand All @@ -39,8 +43,9 @@ class ValueTypes(Enum):
"""
Enum for value types used in the application.
"""
QUANTITY = 'Quantity' # unsigned 32-bit integer
STORE = 'Store' #storing key-values in object's metadata
BIG_QUANTITY = 'BigQuantity' #unsigned 128-bit integer

QUANTITY = "Quantity" # unsigned 32-bit integer
STORE = "Store" # storing key-values in object's metadata
BIG_QUANTITY = "BigQuantity" # unsigned 128-bit integer
# FIXED = 'Fixed' 64-bit fixed-precision number with
# nine significant digits after the decimal point
35 changes: 24 additions & 11 deletions client_cli/pytests/common/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,26 @@ def extract_hash(stdout):
match = re.search(pattern, stdout)
return match.group(1) if match else None


def get_peers_config_files(path_to_configs):
"""
Returns a list of config file paths from the given directory.
"""
config_files = []
for entry in os.listdir(path_to_configs):
if entry.endswith('.json') and 'config_to_peer' in entry:
if entry.endswith(".json") and "config_to_peer" in entry:
config_files.append(os.path.join(path_to_configs, entry))
return config_files


def read_isi_from_json(file_path):
"""
Reads ISI instruction from a JSON file.
:param file_path: Path to the JSON file containing ISI instruction.
:return: Dictionary with ISI instruction.
"""
with open(file_path, 'r', encoding='utf-8') as file:
with open(file_path, "r", encoding="utf-8") as file:
isi_data = json.load(file)
return isi_data

Expand All @@ -59,9 +61,10 @@ def write_isi_to_json(isi_data, file_path):
"""
if not isinstance(isi_data, list):
isi_data = [isi_data]
with open(file_path, 'w', encoding='utf-8') as file:
with open(file_path, "w", encoding="utf-8") as file:
json.dump(isi_data, file, indent=4)


def generate_random_string_with_reserved_char():
"""
Generate a random string with a reserved character.
Expand Down Expand Up @@ -89,25 +92,31 @@ def generate_public_key():
Generate a public key using Ed25519PrivateKey.
"""
public_key = binascii.hexlify(
Ed25519PrivateKey.generate().public_key().public_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw)).decode()
Ed25519PrivateKey.generate()
.public_key()
.public_bytes(
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
)
).decode()
return public_key


def generate_random_string(length, allowed_chars):
"""
Generate a random string with the specified length and characters.
"""
return ''.join(random.choice(allowed_chars) for _ in range(length))
return "".join(random.choice(allowed_chars) for _ in range(length))


def generate_random_string_without_reserved_chars(length):
"""
Generate a random string with the specified length, excluding reserved characters.
"""
allowed_chars = \
[c for c in [*string.ascii_letters, *string.digits] if c not in ReservedChars.ALL.value]
allowed_chars = [
c
for c in [*string.ascii_letters, *string.digits]
if c not in ReservedChars.ALL.value
]
return generate_random_string(length, allowed_chars)


Expand All @@ -130,7 +139,7 @@ def not_existing_name():
"""
Generate a non-existing name.
"""
return 'not_existing_name'
return "not_existing_name"


def key_with_invalid_character_in_key(public_key, random_character):
Expand All @@ -145,5 +154,9 @@ def name_with_uppercase_letter(name):
Change one random letter in a name to uppercase.
"""
random_position = random.randint(0, len(name) - 1)
name = name[:random_position] + name[random_position].upper() + name[random_position + 1:]
name = (
name[:random_position]
+ name[random_position].upper()
+ name[random_position + 1 :]
)
return name
9 changes: 3 additions & 6 deletions client_cli/pytests/common/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@

load_dotenv()

BASE_DIR = os.path.dirname \
(os.path.dirname
(os.path.dirname
(os.path.abspath(__file__))))
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

ROOT_DIR = os.environ.get("CLIENT_CLI_DIR", BASE_DIR)

PATH_CONFIG_CLIENT_CLI = os.path.join(ROOT_DIR, "config.json")
CLIENT_CLI_PATH = os.path.join(ROOT_DIR, "iroha_client_cli")
PEERS_CONFIGS_PATH = os.path.join(ROOT_DIR, "peers_configs")

PORT_MIN = int(os.getenv('TORII_API_PORT_MIN', '8080'))
PORT_MAX = int(os.getenv('TORII_API_PORT_MAX', '8083'))
PORT_MIN = int(os.getenv("TORII_API_PORT_MIN", "8080"))
PORT_MAX = int(os.getenv("TORII_API_PORT_MAX", "8083"))
2 changes: 2 additions & 0 deletions client_cli/pytests/models/account.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
This module provides an Account class for working with Iroha network accounts.
"""

from dataclasses import dataclass


Expand All @@ -16,6 +17,7 @@ class Account:
:param public_key: The public key of the account.
:type public_key: str
"""

name: str
domain: str
public_key: str = None
Expand Down
3 changes: 3 additions & 0 deletions client_cli/pytests/models/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class AssetDefinition:
:param value_type: The value type of the asset definition.
:type value_type: str
"""

name: str
domain: str
value_type: str
Expand All @@ -33,6 +34,7 @@ def get_id(self):
"""
return f"{self.name}#{self.domain}"


@dataclass
class Asset:
"""
Expand All @@ -45,6 +47,7 @@ class Asset:
:param value: The value of the asset.
:type value: str
"""

definition: AssetDefinition
account: str
value: str
Expand Down
3 changes: 2 additions & 1 deletion client_cli/pytests/models/domain.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
This module contains the Domain class.
"""

from dataclasses import dataclass


Expand All @@ -12,8 +13,8 @@ class Domain:
:param name: The name of the domain.
:type name: str
"""
name: str

name: str

def get_name(self):
"""
Expand Down
Loading

0 comments on commit ed70124

Please sign in to comment.