diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0c31e762525ad28d499d65214aee6127a0b75431..f64bef2bb0448d5920087eecc0c2d7c993db8aa5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,12 @@ workflow: when: never - if: '$CI_COMMIT_BRANCH || $CI_COMMIT_TAG' +include: + - project: 'hive/hive' + ref: 94cb02a00f172b69a4268a856d1e12c27cb24703 + file: '/scripts/ci-helpers/prepare_data_image_job.yml' + # Do not include common-ci-configuration here, it is already referenced by scripts/ci-helpers/prepare_data_image_job.yml included from Hive + variables: # git: GIT_STRATEGY: clone @@ -40,9 +46,10 @@ variables: HIVE_BUILD_ROOT_PATH: "hived-binaries" BEEKEEPER_BINARY: "${HIVE_BUILD_ROOT_PATH}/mainnet/beekeeper" # ci registry: - # uses registry.gitlab.syncad.com/hive/hive/ci-base-image:ubuntu24.04-2 - CI_BASE_IMAGE_TAG: "@sha256:81f56a1820497ff3cb1342327b7242dc50270db04cbfdd8d6198af1bb0e910b3" + # uses registry.gitlab.syncad.com/hive/hive/ci-base-image:ubuntu24.04-XXX (defined in hive/scripts/ci-helpers/ci_image_tag_vars.yml) + CI_BASE_IMAGE_TAG: "${TEST_IMAGE_TAG}" CI_BASE_IMAGE: "registry.gitlab.syncad.com/hive/hive/ci-base-image${CI_BASE_IMAGE_TAG}" + # uses registry.gitlab.syncad.com/hive/common-ci-configuration/python_development:3.12-u24.04 CLIVE_TESTNET_BASE_IMAGE_TAG: "@sha256:e4797f961fd6c6a843d100b1838422f3b674430af408664286c1b6a6b23baafa" CLIVE_TESTNET_BASE_IMAGE: "registry.gitlab.syncad.com/hive/common-ci-configuration/python_development${CLIVE_TESTNET_BASE_IMAGE_TAG}" @@ -52,12 +59,6 @@ variables: # other: AFTER_SCRIPT_IGNORE_ERRORS: 'false' # without this errors in after_script will be ignored and just "WARNING: after_script failed, but job will continue unaffected: exit code 1" will be shown -include: - - project: 'hive/hive' - ref: 8b287d3990df722eccd4a81fc75b1a4b2fc50fc3 - file: '/scripts/ci-helpers/prepare_data_image_job.yml' - # Do not include common-ci-configuration here, it is already referenced by scripts/ci-helpers/prepare_data_image_job.yml included from Hive - image: ${CI_BASE_IMAGE} default: diff --git a/clive/__private/before_launch.py b/clive/__private/before_launch.py index bcb7b819604fc6d7a87d4c399d45183f8e578eb1..df07b764ac95227a907fff2344f4632f9e40c1b0 100644 --- a/clive/__private/before_launch.py +++ b/clive/__private/before_launch.py @@ -5,13 +5,13 @@ from pathlib import Path from clive.__private.core.constants.env import ROOT_DIRECTORY from clive.__private.logger import logger -from clive.__private.models.schemas import ExtraFieldsPolicy, MissingFieldsInGetConfigPolicy, set_policies from clive.__private.settings import get_settings, safe_settings from clive.__private.storage.storage_history import StorageHistory from clive.dev import is_in_dev_mode def _disable_schemas_extra_fields_check() -> None: + from clive.__private.models.policies import ExtraFieldsPolicy, MissingFieldsInGetConfigPolicy, set_policies set_policies(ExtraFieldsPolicy(allow=True), MissingFieldsInGetConfigPolicy(allow=True)) diff --git a/clive/__private/cli/commands/beekeeper/beekeeper_close.py b/clive/__private/cli/commands/beekeeper/beekeeper_close.py index 0552b41dcbea815a4afcf87d6ec14921ea2d7572..b08d6fceeeb2bfdb1978e758f621ee285fe413d5 100644 --- a/clive/__private/cli/commands/beekeeper/beekeeper_close.py +++ b/clive/__private/cli/commands/beekeeper/beekeeper_close.py @@ -2,7 +2,7 @@ from __future__ import annotations from dataclasses import dataclass -from beekeepy import close_already_running_beekeeper +from beekeepy.asynchronous import close_already_running_beekeeper from beekeepy.exceptions import FailedToDetectRunningBeekeeperError from clive.__private.cli.commands.abc.external_cli_command import ExternalCLICommand diff --git a/clive/__private/cli/commands/beekeeper/beekeeper_spawn.py b/clive/__private/cli/commands/beekeeper/beekeeper_spawn.py index 6d1cf83379b3828369e435967398878124d2eb8d..aeed59a45829801d5ddfa89f515c48d6c7f7054f 100644 --- a/clive/__private/cli/commands/beekeeper/beekeeper_spawn.py +++ b/clive/__private/cli/commands/beekeeper/beekeeper_spawn.py @@ -3,14 +3,13 @@ from __future__ import annotations import time from dataclasses import dataclass -from beekeepy import AsyncBeekeeper - from clive.__private.cli.commands.abc.external_cli_command import ExternalCLICommand from clive.__private.cli.exceptions import ( CLIBeekeeperCannotSpawnNewInstanceWithEnvSetError, CLIBeekeeperLocallyAlreadyRunningError, ) from clive.__private.cli.print_cli import print_cli +from clive.__private.core.beekeeper_manager import AsyncBeekeeper from clive.__private.core.commands.beekeeper import IsBeekeeperRunning from clive.__private.core.constants.setting_identifiers import BEEKEEPER_REMOTE_ADDRESS, BEEKEEPER_SESSION_TOKEN from clive.__private.settings import clive_prefixed_envvar, safe_settings diff --git a/clive/__private/core/beekeeper_manager.py b/clive/__private/core/beekeeper_manager.py index 6c1f3a05e6183c14e19f6fa4b2757f45064f0927..aabbf248dfa06d810696d61c9a7cd944c2813e81 100644 --- a/clive/__private/core/beekeeper_manager.py +++ b/clive/__private/core/beekeeper_manager.py @@ -2,15 +2,13 @@ from __future__ import annotations from typing import TYPE_CHECKING, Final -from beekeepy import AsyncBeekeeper, AsyncSession -from beekeepy import Settings as BeekeepySettings +from beekeepy.asynchronous import AsyncBeekeeper, AsyncSession, AsyncUnlockedWallet, AsyncWallet from clive.__private.settings import safe_settings +from clive.__private.settings._safe_settings import BeekeepySettings from clive.exceptions import CliveError if TYPE_CHECKING: - from beekeepy import AsyncSession, AsyncUnlockedWallet - from clive.__private.core.wallet_container import WalletContainer @@ -111,3 +109,12 @@ class BeekeeperManager: return await AsyncBeekeeper.remote_factory(url_or_settings=self.settings) return await AsyncBeekeeper.factory(settings=self.settings) + + +__all__ = [ + "AsyncBeekeeper", + "AsyncSession", + "AsyncUnlockedWallet", + "AsyncWallet", + "BeekeepySettings", +] diff --git a/clive/__private/core/commands/abc/command_encryption.py b/clive/__private/core/commands/abc/command_encryption.py index 6c7a7fb5cec19c25bbcdb5a22b4571648a4e28aa..1698359c2ede68ba7a4f2f22c2c985e2c5535331 100644 --- a/clive/__private/core/commands/abc/command_encryption.py +++ b/clive/__private/core/commands/abc/command_encryption.py @@ -10,8 +10,7 @@ from clive.__private.core.commands.abc.command_restricted import CommandExecutio from clive.__private.core.commands.is_wallet_unlocked import IsWalletUnlocked if TYPE_CHECKING: - from beekeepy import AsyncUnlockedWallet - + from clive.__private.core.beekeeper_manager import AsyncUnlockedWallet from clive.__private.models.schemas import PublicKey diff --git a/clive/__private/core/commands/abc/command_in_unlocked.py b/clive/__private/core/commands/abc/command_in_unlocked.py index 78b123a3ce3bc9dbb7416e0a89748b9ced686046..34623997818a17e6718cc609565b82578fd69fe8 100644 --- a/clive/__private/core/commands/abc/command_in_unlocked.py +++ b/clive/__private/core/commands/abc/command_in_unlocked.py @@ -8,7 +8,7 @@ from clive.__private.core.commands.abc.command_restricted import CommandExecutio from clive.__private.core.commands.is_wallet_unlocked import IsWalletUnlocked if TYPE_CHECKING: - from beekeepy import AsyncUnlockedWallet + from clive.__private.core.beekeeper_manager import AsyncUnlockedWallet class CommandRequiresUnlockedModeError(CommandExecutionNotPossibleError): diff --git a/clive/__private/core/commands/beekeeper.py b/clive/__private/core/commands/beekeeper.py index 4c0670528840e98390ebc7f004882640bf4d8193..f3e096ddde8f8ea5f4494fffc4d8a850e1e93ee5 100644 --- a/clive/__private/core/commands/beekeeper.py +++ b/clive/__private/core/commands/beekeeper.py @@ -2,7 +2,7 @@ from __future__ import annotations from dataclasses import dataclass -from beekeepy import find_running_beekeepers +from beekeepy.asynchronous import find_running_beekeepers from clive.__private.core.commands.abc.command_with_result import CommandWithResult from clive.__private.settings import safe_settings diff --git a/clive/__private/core/commands/commands.py b/clive/__private/core/commands/commands.py index 9d5ea5a3b61a615c53ec860ca8e3d63234120253..7a20c39f2193e4f73d8e8d3bbdaa0a4ecca421c0 100644 --- a/clive/__private/core/commands/commands.py +++ b/clive/__private/core/commands/commands.py @@ -3,61 +3,14 @@ from __future__ import annotations from typing import TYPE_CHECKING, Any, Literal, overload from clive.__private.core.commands.abc.command_with_result import CommandResultT, CommandWithResult -from clive.__private.core.commands.broadcast import Broadcast + from clive.__private.core.commands.build_transaction import BuildTransaction -from clive.__private.core.commands.collect_account_authorities import CollectAccountAuthorities +from clive.__private.core.commands.update_transaction_metadata import UpdateTransactionMetadata +from clive.__private.core.commands.data_retrieval.witnesses_data import WitnessesDataRetrieval +from clive.__private.core.commands.data_retrieval.proposals_data import ProposalsDataRetrieval + from clive.__private.core.commands.command_wrappers import CommandWithResultWrapper, CommandWrapper, NoOpWrapper -from clive.__private.core.commands.create_profile_wallets import CreateProfileWallets, CreateProfileWalletsResult -from clive.__private.core.commands.data_retrieval.chain_data import ChainData, ChainDataRetrieval -from clive.__private.core.commands.data_retrieval.find_scheduled_transfers import ( - AccountScheduledTransferData, - FindScheduledTransfers, -) -from clive.__private.core.commands.data_retrieval.find_vesting_delegation_expirations import ( - FindVestingDelegationExpirations, - VestingDelegationExpirationData, -) -from clive.__private.core.commands.data_retrieval.get_dynamic_global_properties import GetDynamicGlobalProperties -from clive.__private.core.commands.data_retrieval.hive_power_data import HivePowerData, HivePowerDataRetrieval -from clive.__private.core.commands.data_retrieval.proposals_data import ProposalsData, ProposalsDataRetrieval -from clive.__private.core.commands.data_retrieval.savings_data import SavingsData, SavingsDataRetrieval -from clive.__private.core.commands.data_retrieval.update_alarms_data import UpdateAlarmsData -from clive.__private.core.commands.data_retrieval.update_node_data import UpdateNodeData -from clive.__private.core.commands.data_retrieval.witnesses_data import ( - WitnessesData, - WitnessesDataRetrieval, -) -from clive.__private.core.commands.decrypt import Decrypt -from clive.__private.core.commands.delete_profile import DeleteProfile -from clive.__private.core.commands.does_account_exist_in_node import DoesAccountExistsInNode -from clive.__private.core.commands.encrypt import Encrypt -from clive.__private.core.commands.find_accounts import FindAccounts -from clive.__private.core.commands.find_proposal import FindProposal -from clive.__private.core.commands.find_transaction import FindTransaction -from clive.__private.core.commands.find_witness import FindWitness -from clive.__private.core.commands.get_unlocked_encryption_wallet import GetUnlockedEncryptionWallet -from clive.__private.core.commands.get_unlocked_user_wallet import GetUnlockedUserWallet -from clive.__private.core.commands.get_wallet_names import GetWalletNames, WalletStatus -from clive.__private.core.commands.import_key import ImportKey -from clive.__private.core.commands.is_password_valid import IsPasswordValid -from clive.__private.core.commands.is_wallet_unlocked import IsWalletUnlocked -from clive.__private.core.commands.load_profile import LoadProfile -from clive.__private.core.commands.load_transaction import LoadTransaction -from clive.__private.core.commands.lock import Lock -from clive.__private.core.commands.migrate_profile import MigrateProfile -from clive.__private.core.commands.perform_actions_on_transaction import PerformActionsOnTransaction -from clive.__private.core.commands.remove_key import RemoveKey -from clive.__private.core.commands.save_profile import SaveProfile -from clive.__private.core.commands.save_transaction import SaveTransaction -from clive.__private.core.commands.set_timeout import SetTimeout -from clive.__private.core.commands.sign import Sign -from clive.__private.core.commands.sync_data_with_beekeeper import SyncDataWithBeekeeper -from clive.__private.core.commands.sync_state_with_beekeeper import SyncStateWithBeekeeper -from clive.__private.core.commands.unlock import Unlock, UnlockWalletStatus -from clive.__private.core.commands.unsign import UnSign -from clive.__private.core.commands.update_transaction_metadata import ( - UpdateTransactionMetadata, -) + from clive.__private.core.constants.data_retrieval import ALREADY_SIGNED_MODE_DEFAULT from clive.__private.core.constants.wallet_recovery import ( USER_WALLET_RECOVERED_MESSAGE, @@ -66,17 +19,16 @@ from clive.__private.core.constants.wallet_recovery import ( from clive.__private.core.error_handlers.abc.error_handler_context_manager import ( ResultNotAvailable, ) -from clive.__private.logger import logger + if TYPE_CHECKING: from collections.abc import Iterable from datetime import timedelta from pathlib import Path - from beekeepy import AsyncUnlockedWallet, AsyncWallet - from clive.__private.core.accounts.accounts import TrackedAccount from clive.__private.core.app_state import LockSource + from clive.__private.core.beekeeper_manager import AsyncUnlockedWallet, AsyncWallet from clive.__private.core.commands.abc.command import Command from clive.__private.core.ensure_transaction import TransactionConvertibleType from clive.__private.core.error_handlers.abc.error_handler_context_manager import ( @@ -96,6 +48,16 @@ if TYPE_CHECKING: ) from wax.models.authority import WaxAccountAuthorityInfo + from clive.__private.core.commands.data_retrieval.savings_data import SavingsData + from clive.__private.core.commands.create_profile_wallets import CreateProfileWalletsResult + from clive.__private.core.commands.data_retrieval.find_vesting_delegation_expirations import VestingDelegationExpirationData + from clive.__private.core.commands.data_retrieval.chain_data import ChainData + from clive.__private.core.commands.data_retrieval.find_scheduled_transfers import AccountScheduledTransferData + from clive.__private.core.commands.data_retrieval.hive_power_data import HivePowerData + from clive.__private.core.commands.data_retrieval.proposals_data import ProposalsData + from clive.__private.core.commands.data_retrieval.witnesses_data import WitnessesData + from clive.__private.core.commands.get_wallet_names import WalletStatus + from clive.__private.core.commands.unlock import UnlockWalletStatus class Commands[WorldT: World]: def __init__( @@ -142,6 +104,8 @@ class Commands[WorldT: World]: Returns: A wrapper containing the result of the command. """ + from clive.__private.core.commands.create_profile_wallets import CreateProfileWallets + return await self.__surround_with_exception_handlers( CreateProfileWallets( app_state=self._world.app_state, @@ -154,6 +118,7 @@ class Commands[WorldT: World]: ) async def decrypt(self, *, encrypted_content: str) -> CommandWithResultWrapper[str]: + from clive.__private.core.commands.decrypt import Decrypt return await self.__surround_with_exception_handlers( Decrypt( unlocked_wallet=self._world.beekeeper_manager.user_wallet, @@ -163,6 +128,7 @@ class Commands[WorldT: World]: ) async def delete_profile(self, *, profile_name_to_delete: str, force: bool = False) -> CommandWrapper: + from clive.__private.core.commands.delete_profile import DeleteProfile return await self.__surround_with_exception_handlers( DeleteProfile( profile_name_to_delete=profile_name_to_delete, @@ -173,11 +139,14 @@ class Commands[WorldT: World]: ) async def does_account_exists_in_node(self, *, account_name: str) -> CommandWithResultWrapper[bool]: + from clive.__private.core.commands.does_account_exist_in_node import DoesAccountExistsInNode + return await self.__surround_with_exception_handlers( DoesAccountExistsInNode(node=self._world.node, account_name=account_name) ) async def encrypt(self, *, content: str) -> CommandWithResultWrapper[str]: + from clive.__private.core.commands.encrypt import Encrypt return await self.__surround_with_exception_handlers( Encrypt( unlocked_wallet=self._world.beekeeper_manager.user_wallet, @@ -202,6 +171,8 @@ class Commands[WorldT: World]: Returns: A wrapper containing the result of the command. """ + from clive.__private.core.commands.unlock import Unlock + profile_to_unlock = profile_name or self._world.profile.name wrapper = await self.__surround_with_exception_handlers( Unlock( @@ -229,6 +200,8 @@ class Commands[WorldT: World]: Returns: A wrapper containing the result of the command. """ + from clive.__private.core.commands.lock import Lock + return await self.__surround_with_exception_handlers( Lock( app_state=self._world.app_state, @@ -237,21 +210,29 @@ class Commands[WorldT: World]: ) async def get_unlocked_encryption_wallet(self) -> CommandWithResultWrapper[AsyncUnlockedWallet]: + from clive.__private.core.commands.get_unlocked_encryption_wallet import GetUnlockedEncryptionWallet + return await self.__surround_with_exception_handlers( GetUnlockedEncryptionWallet(session=self._world.beekeeper_manager.session) ) async def get_unlocked_user_wallet(self) -> CommandWithResultWrapper[AsyncUnlockedWallet]: + from clive.__private.core.commands.get_unlocked_user_wallet import GetUnlockedUserWallet + return await self.__surround_with_exception_handlers( GetUnlockedUserWallet(session=self._world.beekeeper_manager.session) ) async def get_wallet_names(self, filter_by_status: WalletStatus = "all") -> CommandWithResultWrapper[list[str]]: + from clive.__private.core.commands.get_wallet_names import GetWalletNames + return await self.__surround_with_exception_handlers( GetWalletNames(session=self._world.beekeeper_manager.session, filter_by_status=filter_by_status) ) async def is_password_valid(self, *, password: str) -> CommandWithResultWrapper[bool]: + from clive.__private.core.commands.is_password_valid import IsPasswordValid + return await self.__surround_with_exception_handlers( IsPasswordValid( beekeeper=self._world.beekeeper_manager.beekeeper, @@ -270,6 +251,8 @@ class Commands[WorldT: World]: Returns: A wrapper containing the result of the command. """ + from clive.__private.core.commands.is_wallet_unlocked import IsWalletUnlocked + return await self.__surround_with_exception_handlers( IsWalletUnlocked( wallet=wallet if wallet is not None else self._world.beekeeper_manager.user_wallet, @@ -288,6 +271,8 @@ class Commands[WorldT: World]: Returns: A wrapper containing the result of the command. """ + from clive.__private.core.commands.set_timeout import SetTimeout + return await self.__surround_with_exception_handlers( SetTimeout(session=self._world.beekeeper_manager.session, time=time, permanent=permanent) ) @@ -304,6 +289,8 @@ class Commands[WorldT: World]: force_save_format: Literal["json", "bin"] | None = None, broadcast: bool = False, ) -> CommandWithResultWrapper[Transaction]: + from clive.__private.core.commands.perform_actions_on_transaction import PerformActionsOnTransaction + return await self.__surround_with_exception_handlers( PerformActionsOnTransaction( content=content, @@ -326,6 +313,7 @@ class Commands[WorldT: World]: content: TransactionConvertibleType, force_update_metadata: bool = BuildTransaction.DEFAULT_FORCE_UPDATE_METADATA, ) -> CommandWithResultWrapper[Transaction]: + return await self.__surround_with_exception_handlers( BuildTransaction( content=content, @@ -340,6 +328,7 @@ class Commands[WorldT: World]: transaction: Transaction, expiration: timedelta = UpdateTransactionMetadata.DEFAULT_GDPO_TIME_RELATIVE_EXPIRATION, ) -> CommandWrapper: + return await self.__surround_with_exception_handlers( UpdateTransactionMetadata( transaction=transaction, @@ -356,6 +345,8 @@ class Commands[WorldT: World]: already_signed_mode: AlreadySignedMode = ALREADY_SIGNED_MODE_DEFAULT, chain_id: str | None = None, ) -> CommandWithResultWrapper[Transaction]: + from clive.__private.core.commands.sign import Sign + return await self.__surround_with_exception_handlers( Sign( unlocked_wallet=self._world.beekeeper_manager.user_wallet, @@ -367,6 +358,8 @@ class Commands[WorldT: World]: ) async def unsign(self, *, transaction: Transaction) -> CommandWithResultWrapper[Transaction]: + from clive.__private.core.commands.unsign import UnSign + return await self.__surround_with_exception_handlers( UnSign( transaction=transaction, @@ -376,17 +369,24 @@ class Commands[WorldT: World]: async def save_to_file( self, *, transaction: Transaction, path: Path, force_format: Literal["json", "bin"] | None = None ) -> CommandWrapper: + from clive.__private.core.commands.save_transaction import SaveTransaction + return await self.__surround_with_exception_handlers( SaveTransaction(transaction=transaction, file_path=path, force_format=force_format) ) async def load_transaction_from_file(self, *, path: Path) -> CommandWithResultWrapper[Transaction]: + from clive.__private.core.commands.load_transaction import LoadTransaction + return await self.__surround_with_exception_handlers(LoadTransaction(file_path=path)) async def broadcast(self, *, transaction: Transaction) -> CommandWrapper: + from clive.__private.core.commands.broadcast import Broadcast return await self.__surround_with_exception_handlers(Broadcast(node=self._world.node, transaction=transaction)) async def import_key(self, *, key_to_import: PrivateKeyAliased) -> CommandWithResultWrapper[PublicKeyAliased]: + from clive.__private.core.commands.import_key import ImportKey + return await self.__surround_with_exception_handlers( ImportKey( unlocked_wallet=self._world.beekeeper_manager.user_wallet, @@ -395,6 +395,8 @@ class Commands[WorldT: World]: ) async def remove_key(self, *, key_to_remove: PublicKey) -> CommandWrapper: + from clive.__private.core.commands.remove_key import RemoveKey + return await self.__surround_with_exception_handlers( RemoveKey( unlocked_wallet=self._world.beekeeper_manager.user_wallet, @@ -412,6 +414,9 @@ class Commands[WorldT: World]: Returns: A wrapper containing the result of the command. """ + + from clive.__private.core.commands.sync_data_with_beekeeper import SyncDataWithBeekeeper + return await self.__surround_with_exception_handlers( SyncDataWithBeekeeper( unlocked_wallet=self._world.beekeeper_manager.user_wallet, @@ -420,6 +425,8 @@ class Commands[WorldT: World]: ) async def sync_state_with_beekeeper(self, source: LockSource = "unknown") -> CommandWrapper: + from clive.__private.core.commands.sync_state_with_beekeeper import SyncStateWithBeekeeper + return await self.__surround_with_exception_handlers( SyncStateWithBeekeeper( session=self._world.beekeeper_manager.session, @@ -429,6 +436,8 @@ class Commands[WorldT: World]: ) async def get_dynamic_global_properties(self) -> CommandWithResultWrapper[DynamicGlobalProperties]: + from clive.__private.core.commands.data_retrieval.get_dynamic_global_properties import GetDynamicGlobalProperties + result = await self.__surround_with_exception_handlers(GetDynamicGlobalProperties(node=self._world.node)) if result.success: await self._world.node.cached.update_dynamic_global_properties(result.result_or_raise) @@ -437,6 +446,8 @@ class Commands[WorldT: World]: async def update_node_data( self, *, accounts: Iterable[TrackedAccount] | None = None ) -> CommandWithResultWrapper[DynamicGlobalProperties]: + from clive.__private.core.commands.data_retrieval.update_node_data import UpdateNodeData + result = await self.__surround_with_exception_handlers( UpdateNodeData(accounts=list(accounts or []), node=self._world.node) ) @@ -445,11 +456,13 @@ class Commands[WorldT: World]: return result async def update_alarms_data(self, *, accounts: Iterable[TrackedAccount] | None = None) -> CommandWrapper: + from clive.__private.core.commands.data_retrieval.update_alarms_data import UpdateAlarmsData return await self.__surround_with_exception_handlers( UpdateAlarmsData(accounts=list(accounts) if accounts is not None else [], node=self._world.node) ) async def retrieve_savings_data(self, *, account_name: str) -> CommandWithResultWrapper[SavingsData]: + from clive.__private.core.commands.data_retrieval.savings_data import SavingsDataRetrieval return await self.__surround_with_exception_handlers( SavingsDataRetrieval(node=self._world.node, account_name=account_name) ) @@ -462,6 +475,7 @@ class Commands[WorldT: World]: witness_name_pattern: str | None = None, search_by_name_limit: int = WitnessesDataRetrieval.DEFAULT_SEARCH_BY_NAME_LIMIT, ) -> CommandWithResultWrapper[WitnessesData]: + return await self.__surround_with_exception_handlers( WitnessesDataRetrieval( node=self._world.node, @@ -480,6 +494,7 @@ class Commands[WorldT: World]: order_direction: ProposalsDataRetrieval.OrderDirections = ProposalsDataRetrieval.DEFAULT_ORDER_DIRECTION, status: ProposalsDataRetrieval.Statuses = ProposalsDataRetrieval.DEFAULT_STATUS, ) -> CommandWithResultWrapper[ProposalsData]: + return await self.__surround_with_exception_handlers( ProposalsDataRetrieval( node=self._world.node, @@ -495,34 +510,48 @@ class Commands[WorldT: World]: *, account_name: str, ) -> CommandWithResultWrapper[HivePowerData]: + from clive.__private.core.commands.data_retrieval.hive_power_data import HivePowerDataRetrieval + return await self.__surround_with_exception_handlers( HivePowerDataRetrieval(node=self._world.node, account_name=account_name) ) async def retrieve_chain_data(self) -> CommandWithResultWrapper[ChainData]: + from clive.__private.core.commands.data_retrieval.chain_data import ChainDataRetrieval + return await self.__surround_with_exception_handlers(ChainDataRetrieval(node=self._world.node)) async def find_transaction(self, *, transaction_id: str) -> CommandWithResultWrapper[TransactionStatus]: + from clive.__private.core.commands.find_transaction import FindTransaction + return await self.__surround_with_exception_handlers( FindTransaction(node=self._world.node, transaction_id=transaction_id) ) async def find_witness(self, *, witness_name: str) -> CommandWithResultWrapper[Witness]: + from clive.__private.core.commands.find_witness import FindWitness + return await self.__surround_with_exception_handlers( FindWitness(node=self._world.node, witness_name=witness_name) ) async def find_proposal(self, *, proposal_id: int) -> CommandWithResultWrapper[Proposal]: + from clive.__private.core.commands.find_proposal import FindProposal + return await self.__surround_with_exception_handlers( FindProposal(node=self._world.node, proposal_id=proposal_id) ) async def find_accounts(self, *, accounts: list[str]) -> CommandWithResultWrapper[list[Account]]: + from clive.__private.core.commands.find_accounts import FindAccounts + return await self.__surround_with_exception_handlers(FindAccounts(node=self._world.node, accounts=accounts)) async def find_vesting_delegation_expirations( self, *, account: str ) -> CommandWithResultWrapper[list[VestingDelegationExpirationData]]: + from clive.__private.core.commands.data_retrieval.find_vesting_delegation_expirations import FindVestingDelegationExpirations + return await self.__surround_with_exception_handlers( FindVestingDelegationExpirations(node=self._world.node, account=account) ) @@ -530,6 +559,8 @@ class Commands[WorldT: World]: async def find_scheduled_transfers( self, *, account_name: str ) -> CommandWithResultWrapper[AccountScheduledTransferData]: + from clive.__private.core.commands.data_retrieval.find_scheduled_transfers import FindScheduledTransfers + return await self.__surround_with_exception_handlers( FindScheduledTransfers(node=self._world.node, account_name=account_name) ) @@ -537,9 +568,13 @@ class Commands[WorldT: World]: async def save_profile(self) -> NoOpWrapper | CommandWrapper: profile = self._world.profile if not profile.should_be_saved: + from clive.__private.logger import logger + logger.debug("Saving profile skipped... Looks like was explicitly skipped or hash didn't changed.") return NoOpWrapper() + from clive.__private.core.commands.save_profile import SaveProfile + return await self.__surround_with_exception_handlers( SaveProfile( profile=profile, @@ -549,6 +584,8 @@ class Commands[WorldT: World]: ) async def load_profile(self, *, profile_name: str) -> CommandWithResultWrapper[Profile]: + from clive.__private.core.commands.load_profile import LoadProfile + return await self.__surround_with_exception_handlers( LoadProfile( profile_name=profile_name, @@ -558,6 +595,8 @@ class Commands[WorldT: World]: ) async def migrate_profile(self, *, profile_name: str | None = None) -> CommandWithResultWrapper[MigrationStatus]: + from clive.__private.core.commands.migrate_profile import MigrateProfile + return await self.__surround_with_exception_handlers( MigrateProfile( profile_name=profile_name or self._world.profile.name, @@ -569,6 +608,7 @@ class Commands[WorldT: World]: async def collect_account_authorities( self, *, account_name: str ) -> CommandWithResultWrapper[WaxAccountAuthorityInfo]: + from clive.__private.core.commands.collect_account_authorities import CollectAccountAuthorities return await self.__surround_with_exception_handlers( CollectAccountAuthorities( wax_interface=self._world.wax_interface, diff --git a/clive/__private/core/commands/create_encryption_wallet.py b/clive/__private/core/commands/create_encryption_wallet.py index 626300de6dd76d42dd292ea85307f2a0e4e14679..03bbe9400350a4818cd35f9bb9189d6c7cc9301b 100644 --- a/clive/__private/core/commands/create_encryption_wallet.py +++ b/clive/__private/core/commands/create_encryption_wallet.py @@ -3,14 +3,13 @@ from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING -from beekeepy import AsyncUnlockedWallet - +from clive.__private.core.beekeeper_manager import AsyncUnlockedWallet from clive.__private.core.commands.abc.command_with_result import CommandWithResult from clive.__private.core.encryption import EncryptionService from clive.__private.core.keys import PrivateKey if TYPE_CHECKING: - from beekeepy import AsyncSession + from beekeepy.asynchronous import AsyncSession @dataclass(kw_only=True) diff --git a/clive/__private/core/commands/create_profile_wallets.py b/clive/__private/core/commands/create_profile_wallets.py index 659693395fa9a502d246e6f2e96f39ed75b4c5f8..839e11f799a753b4bf6cb42c412125f2febb29df 100644 --- a/clive/__private/core/commands/create_profile_wallets.py +++ b/clive/__private/core/commands/create_profile_wallets.py @@ -12,9 +12,8 @@ from clive.__private.core.wallet_container import WalletContainer if TYPE_CHECKING: from datetime import timedelta - from beekeepy import AsyncSession, AsyncUnlockedWallet - from clive.__private.core.app_state import AppState + from clive.__private.core.beekeeper_manager import AsyncSession, AsyncUnlockedWallet @dataclass diff --git a/clive/__private/core/commands/create_user_wallet.py b/clive/__private/core/commands/create_user_wallet.py index 0568b1626ee4ce66cdf9bdd6c8e21483227f71fe..bec2e22cb9e7144d15f52988ee75ab242632c277 100644 --- a/clive/__private/core/commands/create_user_wallet.py +++ b/clive/__private/core/commands/create_user_wallet.py @@ -3,12 +3,11 @@ from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING -from beekeepy import AsyncUnlockedWallet - +from clive.__private.core.beekeeper_manager import AsyncUnlockedWallet from clive.__private.core.commands.abc.command_with_result import CommandWithResult if TYPE_CHECKING: - from beekeepy import AsyncSession + from beekeepy.asynchronous import AsyncSession @dataclass(kw_only=True) diff --git a/clive/__private/core/commands/delete_profile.py b/clive/__private/core/commands/delete_profile.py index 8a24df2502f57a5bba768ad3aabab65423459b80..80eb1fa53f142cbd96917f21741007208bf57f85 100644 --- a/clive/__private/core/commands/delete_profile.py +++ b/clive/__private/core/commands/delete_profile.py @@ -8,7 +8,7 @@ from clive.__private.core.commands.lock import Lock from clive.__private.core.profile import Profile if TYPE_CHECKING: - from beekeepy import AsyncSession + from beekeepy.asynchronous import AsyncSession @dataclass(kw_only=True) diff --git a/clive/__private/core/commands/get_unlocked_encryption_wallet.py b/clive/__private/core/commands/get_unlocked_encryption_wallet.py index 0f2334003c1fb9f2dcbbaf185fc2b6a3b53f8d0f..cd50e132c45435efb58a05e5402ab0adf7b0d5db 100644 --- a/clive/__private/core/commands/get_unlocked_encryption_wallet.py +++ b/clive/__private/core/commands/get_unlocked_encryption_wallet.py @@ -2,8 +2,7 @@ from __future__ import annotations from dataclasses import dataclass -from beekeepy import AsyncSession, AsyncUnlockedWallet - +from clive.__private.core.beekeeper_manager import AsyncSession, AsyncUnlockedWallet from clive.__private.core.commands.abc.command import Command, CommandError from clive.__private.core.commands.abc.command_with_result import CommandWithResult from clive.__private.core.encryption import EncryptionService diff --git a/clive/__private/core/commands/get_unlocked_user_wallet.py b/clive/__private/core/commands/get_unlocked_user_wallet.py index 9c1fcb1c06ee6e7c0d4718e7619b94c1d0131648..bb649836b132e533ded523555676bd712c3b230f 100644 --- a/clive/__private/core/commands/get_unlocked_user_wallet.py +++ b/clive/__private/core/commands/get_unlocked_user_wallet.py @@ -2,8 +2,7 @@ from __future__ import annotations from dataclasses import dataclass -from beekeepy import AsyncSession, AsyncUnlockedWallet - +from clive.__private.core.beekeeper_manager import AsyncSession, AsyncUnlockedWallet from clive.__private.core.commands.abc.command import Command, CommandError from clive.__private.core.commands.abc.command_with_result import CommandWithResult from clive.__private.core.encryption import EncryptionService diff --git a/clive/__private/core/commands/get_wallet_names.py b/clive/__private/core/commands/get_wallet_names.py index 2b3f89f4a6658cd5b4eccd44b25fe58b1f54ebd4..6277dcc3133020e8e9a145b3b671668ace9a5b13 100644 --- a/clive/__private/core/commands/get_wallet_names.py +++ b/clive/__private/core/commands/get_wallet_names.py @@ -7,7 +7,7 @@ from clive.__private.core.commands.abc.command_with_result import CommandWithRes from clive.__private.core.commands.is_wallet_unlocked import IsWalletUnlocked if TYPE_CHECKING: - from beekeepy import AsyncSession + from beekeepy.asynchronous import AsyncSession type WalletStatus = Literal["all", "locked", "unlocked"] diff --git a/clive/__private/core/commands/is_password_valid.py b/clive/__private/core/commands/is_password_valid.py index 7dad033f62d5801f44bcaee0ca43e88db33f0911..3bf99834fae812a76958d1b3ead2b472b2162d65 100644 --- a/clive/__private/core/commands/is_password_valid.py +++ b/clive/__private/core/commands/is_password_valid.py @@ -8,7 +8,7 @@ from beekeepy.exceptions import InvalidPasswordError from clive.__private.core.commands.abc.command_with_result import CommandWithResult if TYPE_CHECKING: - from beekeepy import AsyncBeekeeper, AsyncWallet + from clive.__private.core.beekeeper_manager import AsyncBeekeeper, AsyncWallet @dataclass(kw_only=True) diff --git a/clive/__private/core/commands/is_wallet_unlocked.py b/clive/__private/core/commands/is_wallet_unlocked.py index 60dc0e7bfe7108ed7646cafe16ef7d093229b04e..b12773b2576ef7a4ec7c7577dcff15e75beab088 100644 --- a/clive/__private/core/commands/is_wallet_unlocked.py +++ b/clive/__private/core/commands/is_wallet_unlocked.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING from clive.__private.core.commands.abc.command_with_result import CommandWithResult if TYPE_CHECKING: - from beekeepy import AsyncWallet + from clive.__private.core.beekeeper_manager import AsyncWallet @dataclass(kw_only=True) diff --git a/clive/__private/core/commands/lock.py b/clive/__private/core/commands/lock.py index 522267d75b0d84aa926ecff4225c26636c73b92a..ce9071ef57c78811103c24e8d646fd347f9db01c 100644 --- a/clive/__private/core/commands/lock.py +++ b/clive/__private/core/commands/lock.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING from clive.__private.core.commands.abc.command import Command if TYPE_CHECKING: - from beekeepy import AsyncSession + from beekeepy.asynchronous import AsyncSession from clive.__private.core.app_state import AppState diff --git a/clive/__private/core/commands/perform_actions_on_transaction.py b/clive/__private/core/commands/perform_actions_on_transaction.py index 87a942a59a75e640e5f188f0cf9e7d3c918c0501..125c9d14ecfaeefea146a2085645986fdf46448d 100644 --- a/clive/__private/core/commands/perform_actions_on_transaction.py +++ b/clive/__private/core/commands/perform_actions_on_transaction.py @@ -12,15 +12,11 @@ from clive.__private.core.commands.unsign import UnSign from clive.__private.core.constants.data_retrieval import ALREADY_SIGNED_MODE_DEFAULT from clive.__private.models import Transaction -if TYPE_CHECKING: - from beekeepy import AsyncUnlockedWallet - - from clive.__private.core.app_state import AppState - - if TYPE_CHECKING: from pathlib import Path + from clive.__private.core.app_state import AppState + from clive.__private.core.beekeeper_manager import AsyncUnlockedWallet from clive.__private.core.ensure_transaction import TransactionConvertibleType from clive.__private.core.keys import PublicKey from clive.__private.core.node import Node diff --git a/clive/__private/core/commands/recover_wallets.py b/clive/__private/core/commands/recover_wallets.py index 80f2dbf73d29dd35e895db64f9e254ba71e24bb7..61c7e2b5cda9a19914f6402482fb1d922fb02112 100644 --- a/clive/__private/core/commands/recover_wallets.py +++ b/clive/__private/core/commands/recover_wallets.py @@ -10,7 +10,7 @@ from clive.__private.core.commands.create_encryption_wallet import CreateEncrypt from clive.__private.core.commands.create_user_wallet import CreateUserWallet if TYPE_CHECKING: - from beekeepy import AsyncSession, AsyncUnlockedWallet + from clive.__private.core.beekeeper_manager import AsyncSession, AsyncUnlockedWallet RecoverWalletsStatus = Literal["nothing_recovered", "encryption_wallet_recovered", "user_wallet_recovered"] diff --git a/clive/__private/core/commands/set_timeout.py b/clive/__private/core/commands/set_timeout.py index f9e8c3f39b870ed04e006d74c81aadd44d1c6907..386093e135858923873b90b630626117ccc782ad 100644 --- a/clive/__private/core/commands/set_timeout.py +++ b/clive/__private/core/commands/set_timeout.py @@ -8,7 +8,7 @@ from clive.__private.core.commands.abc.command import Command from clive.__private.logger import logger if TYPE_CHECKING: - from beekeepy import AsyncSession + from beekeepy.asynchronous import AsyncSession @dataclass(kw_only=True) diff --git a/clive/__private/core/commands/sync_state_with_beekeeper.py b/clive/__private/core/commands/sync_state_with_beekeeper.py index 57113323dfadc9b1bc11bda793f2afae3b728d5f..774afece8e6fbb1d5b106cc66702264a6a801945 100644 --- a/clive/__private/core/commands/sync_state_with_beekeeper.py +++ b/clive/__private/core/commands/sync_state_with_beekeeper.py @@ -9,7 +9,7 @@ from clive.__private.core.encryption import EncryptionService from clive.__private.core.wallet_container import WalletContainer if TYPE_CHECKING: - from beekeepy import AsyncSession + from beekeepy.asynchronous import AsyncSession from clive.__private.core.app_state import AppState, LockSource diff --git a/clive/__private/core/commands/unlock.py b/clive/__private/core/commands/unlock.py index ed25ff0d5c32f20d2e8b62753c577294386d3658..a99e81b50584a22aad89ef23a2736e3647b746eb 100644 --- a/clive/__private/core/commands/unlock.py +++ b/clive/__private/core/commands/unlock.py @@ -16,9 +16,8 @@ from clive.__private.core.wallet_container import WalletContainer if TYPE_CHECKING: from datetime import timedelta - from beekeepy import AsyncSession, AsyncUnlockedWallet - from clive.__private.core.app_state import AppState + from clive.__private.core.beekeeper_manager import AsyncSession, AsyncUnlockedWallet from clive.__private.core.types import MigrationStatus diff --git a/clive/__private/core/ensure_transaction.py b/clive/__private/core/ensure_transaction.py index fa675b36d3ef0cd07c7ec43c47a32f926a6a51ac..164ad8e04227da010c5f63f00535015b1821b1ca 100644 --- a/clive/__private/core/ensure_transaction.py +++ b/clive/__private/core/ensure_transaction.py @@ -1,10 +1,11 @@ from __future__ import annotations from collections.abc import Iterable -from typing import Any +from typing import Any, TYPE_CHECKING -from clive.__private.models import Transaction -from clive.__private.models.schemas import OperationBase, convert_to_representation +if TYPE_CHECKING: + from clive.__private.models import Transaction + from clive.__private.models.operations import OperationBase, convert_to_representation type TransactionConvertibleType = OperationBase | Iterable[OperationBase] | Transaction @@ -26,6 +27,9 @@ def ensure_transaction(content: TransactionConvertibleType) -> Transaction: The transaction. """ + from clive.__private.models.operations import OperationBase, convert_to_representation + from clive.__private.models import Transaction + def __ensure_operation(item: Any) -> OperationBase: # noqa: ANN401 assert isinstance(item, OperationBase) return item diff --git a/clive/__private/core/formatters/humanize.py b/clive/__private/core/formatters/humanize.py index fa8697f1b797890ae9539d080bfde2bb8aa42658..26f9e3c4a18372c68cb52017c670d0f28efc594e 100644 --- a/clive/__private/core/formatters/humanize.py +++ b/clive/__private/core/formatters/humanize.py @@ -43,7 +43,8 @@ if TYPE_CHECKING: HpAPRProtocol, TotalVestingProtocol, ) - from clive.__private.models.schemas import HbdExchangeRate, OperationBase, PriceFeed + from clive.__private.models.schemas import HbdExchangeRate, PriceFeed + from clive.__private.models.operations import OperationBase def _round_to_precision(data: Decimal, precision: int) -> Decimal: diff --git a/clive/__private/core/iwax.py b/clive/__private/core/iwax.py index 7401eb752a474cdbfbb5e584a7f9a99603bea5ee..ed1933661dc525f5e9bb01e2575699d140fff8f5 100644 --- a/clive/__private/core/iwax.py +++ b/clive/__private/core/iwax.py @@ -9,10 +9,6 @@ import wax from clive.__private.core.constants.precision import HIVE_PERCENT_PRECISION_DOT_PLACES from clive.__private.core.decimal_conventer import DecimalConverter from clive.__private.core.percent_conversions import hive_percent_to_percent -from clive.__private.models.schemas import ( - HiveInt, - convert_to_representation, -) from clive.exceptions import CliveError if TYPE_CHECKING: @@ -26,6 +22,8 @@ if TYPE_CHECKING: def cast_hiveint_args[F: Callable[..., Any]](func: F) -> F: @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: # noqa: ANN401 + from clive.__private.models.schemas import HiveInt + def hiveint_to_int(value: Any) -> Any: # noqa: ANN401 return int(value) if isinstance(value, HiveInt) else value @@ -101,6 +99,7 @@ def __validate_wax_response(response: wax.python_result) -> None: def __as_binary_json(item: OperationUnion | Transaction) -> bytes: from clive.__private.models import Transaction # noqa: PLC0415 + from clive.__private.models.schemas import convert_to_representation # noqa: PLC0415 to_serialize = item if isinstance(item, Transaction) else convert_to_representation(item) return to_serialize.json().encode() diff --git a/clive/__private/core/profile.py b/clive/__private/core/profile.py index 20bf8a493422e5b7795e3fe1e772d402daae7b7d..e62e1a7f318163d7dfb9bbadb86e5867cc18a499 100644 --- a/clive/__private/core/profile.py +++ b/clive/__private/core/profile.py @@ -11,7 +11,7 @@ from clive.__private.core.formatters.humanize import humanize_validation_result from clive.__private.core.keys import KeyManager, PublicKeyAliased from clive.__private.logger import logger from clive.__private.models import Transaction -from clive.__private.models.schemas import ChainId, OperationRepresentationUnion, OperationUnion, is_matching_model +from clive.__private.models.schemas import ChainId, is_matching_model from clive.__private.settings import safe_settings from clive.__private.storage.runtime_to_storage_converter import RuntimeToStorageConverter from clive.__private.storage.service.service import PersistentStorageService @@ -25,7 +25,7 @@ if TYPE_CHECKING: from clive.__private.core.accounts.accounts import Account from clive.__private.core.encryption import EncryptionService - + from clive.__private.models.operations import OperationRepresentationUnion, OperationUnion class ProfileError(CliveError): """An error related to profile.""" diff --git a/clive/__private/core/url_utils.py b/clive/__private/core/url_utils.py index 5e63c24462dbaba70d53bb1a2010be4ce83922ba..4a5bb88c8e01bbdebbfe360061bf6897e5b1c001 100644 --- a/clive/__private/core/url_utils.py +++ b/clive/__private/core/url_utils.py @@ -2,7 +2,9 @@ from __future__ import annotations from typing import TYPE_CHECKING -import aiohttp +from beekeepy.communication import get_communicator_cls +from beekeepy.exceptions import CommunicationError +from beekeepy.handle.settings import RemoteHandleSettings if TYPE_CHECKING: from beekeepy.interfaces import HttpUrl @@ -19,7 +21,10 @@ async def is_url_reachable(url: HttpUrl) -> bool: True if the URL is reachable, False otherwise. """ try: - async with aiohttp.ClientSession() as session, session.get(str(url)): - return True - except aiohttp.ClientConnectorError: + s = RemoteHandleSettings() + c = get_communicator_cls()(settings=s) + await c.async_get(url=url) + except CommunicationError: return False + + return True diff --git a/clive/__private/core/wallet_container.py b/clive/__private/core/wallet_container.py index 6bc29612054f532426a1dd38918d8f5e5b95e3df..ed73ca52f7f0804f3a06b64dab55b0a169572912 100644 --- a/clive/__private/core/wallet_container.py +++ b/clive/__private/core/wallet_container.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING from clive.__private.core.encryption import EncryptionService if TYPE_CHECKING: - from beekeepy import AsyncUnlockedWallet + from clive.__private.core.beekeeper_manager import AsyncUnlockedWallet @dataclass diff --git a/clive/__private/models/asset.py b/clive/__private/models/asset.py index 45fb71badd5778f8ebce89dca3c64ada278c7d54..294d7a1e33fe6d5a76783f7fbae64afb99081bc4 100644 --- a/clive/__private/models/asset.py +++ b/clive/__private/models/asset.py @@ -10,8 +10,8 @@ from clive.__private.core.decimal_conventer import ( DecimalConverter, DecimalConvertible, ) -from clive.__private.models.schemas import AssetHbd, AssetHive, AssetVests from clive.exceptions import CliveError +from schemas.fields.assets import AssetHbd, AssetHive, AssetVests if TYPE_CHECKING: from decimal import Decimal diff --git a/clive/__private/models/operations.py b/clive/__private/models/operations.py new file mode 100644 index 0000000000000000000000000000000000000000..dcb76e1ac8d2e8381663fe89b3a25ce340373861 --- /dev/null +++ b/clive/__private/models/operations.py @@ -0,0 +1,139 @@ +from schemas.operation import Operation +from schemas.operations import ( + AccountCreateOperation, + AccountCreateWithDelegationOperation, + AccountUpdate2Operation, + AccountUpdateOperation, + AccountWitnessProxyOperation, + AccountWitnessVoteOperation, + CancelTransferFromSavingsOperation, + ChangeRecoveryAccountOperation, + ClaimAccountOperation, + ClaimRewardBalanceOperation, + CollateralizedConvertOperation, + CommentOperation, + CommentOptionsOperation, + ConvertOperation, + CreateClaimedAccountOperation, + CreateProposalOperation, + CustomBinaryOperation, + CustomJsonOperation, + CustomOperation, + DeclineVotingRightsOperation, + DelegateVestingSharesOperation, + DeleteCommentOperation, + EscrowApproveOperation, + EscrowDisputeOperation, + EscrowReleaseOperation, + EscrowTransferOperation, + FeedPublishOperation, + Hf26OperationRepresentation, + Hf26Operations, + LimitOrderCancelOperation, + LimitOrderCreate2Operation, + LimitOrderCreateOperation, + Pow2Operation, + PowOperation, + RecoverAccountOperation, + RemoveProposalOperation, + RequestAccountRecoveryOperation, + ResetAccountOperation, + SetResetAccountOperation, + SetWithdrawVestingRouteOperation, + TransferFromSavingsOperation, + TransferOperation, + TransferToSavingsOperation, + TransferToVestingOperation, + UpdateProposalOperation, + UpdateProposalVotesOperation, + VoteOperation, + WithdrawVestingOperation, + WitnessBlockApproveOperation, + WitnessSetPropertiesOperation, + WitnessUpdateOperation, + convert_to_representation, +) +from schemas.operations.extensions.recurrent_transfer_extensions import RecurrentTransferPairId +from schemas.operations.extensions.representation_types import ( + HF26RepresentationRecurrentTransferPairIdOperationExtension, +) +from schemas.operations.recurrent_transfer_operation import RecurrentTransferOperation + +from schemas.transaction import Transaction + +# operation BASIC aliases + +OperationBase = Operation +OperationRepresentationUnion = Hf26OperationRepresentation +OperationUnion = Hf26Operations + +# extensions + +RecurrentTransferPairIdExtension = RecurrentTransferPairId +RecurrentTransferPairIdRepresentation = HF26RepresentationRecurrentTransferPairIdOperationExtension + +__all__ = [ + # operation BASIC aliases + "OperationBase", + "OperationRepresentationUnion", + "OperationUnion", + + # operations + "AccountCreateOperation", + "AccountCreateWithDelegationOperation", + "AccountUpdate2Operation", + "AccountUpdateOperation", + "AccountWitnessProxyOperation", + "AccountWitnessVoteOperation", + "CancelTransferFromSavingsOperation", + "ChangeRecoveryAccountOperation", + "ClaimAccountOperation", + "ClaimRewardBalanceOperation", + "CollateralizedConvertOperation", + "CommentOperation", + "CommentOptionsOperation", + "ConvertOperation", + "CreateClaimedAccountOperation", + "CreateProposalOperation", + "CustomBinaryOperation", + "CustomJsonOperation", + "CustomOperation", + "DeclineVotingRightsOperation", + "DelegateVestingSharesOperation", + "DeleteCommentOperation", + "EscrowApproveOperation", + "EscrowDisputeOperation", + "EscrowReleaseOperation", + "EscrowTransferOperation", + "FeedPublishOperation", + "LimitOrderCancelOperation", + "LimitOrderCreate2Operation", + "LimitOrderCreateOperation", + "Pow2Operation", + "PowOperation", + "RecoverAccountOperation", + "RecurrentTransferOperation", + "RemoveProposalOperation", + "RequestAccountRecoveryOperation", + "ResetAccountOperation", + "SetResetAccountOperation", + "SetWithdrawVestingRouteOperation", + "TransferFromSavingsOperation", + "TransferOperation", + "TransferToSavingsOperation", + "TransferToVestingOperation", + "UpdateProposalOperation", + "UpdateProposalVotesOperation", + "VoteOperation", + "WithdrawVestingOperation", + "WitnessBlockApproveOperation", + "WitnessSetPropertiesOperation", + "WitnessUpdateOperation", + "convert_to_representation", + + # extensions + "RecurrentTransferPairIdExtension", + "RecurrentTransferPairIdRepresentation", + + "Transaction", +] diff --git a/clive/__private/models/policies.py b/clive/__private/models/policies.py new file mode 100644 index 0000000000000000000000000000000000000000..64d29bf99805bcbe8cc96a2c9d370de8a3f24164 --- /dev/null +++ b/clive/__private/models/policies.py @@ -0,0 +1,13 @@ +from schemas.policies import ( + ExtraFieldsPolicy, + MissingFieldsInGetConfigPolicy, + TestnetAssetsPolicy, + set_policies, +) + +__all__ = [ + "ExtraFieldsPolicy", + "MissingFieldsInGetConfigPolicy", + "TestnetAssetsPolicy", + "set_policies" +] \ No newline at end of file diff --git a/clive/__private/models/schemas.py b/clive/__private/models/schemas.py index 221b4c6d32ea469367701018b1d85afa844b0bf1..be3384c34d0f4f9c889cba523c3588b7a968a508 100644 --- a/clive/__private/models/schemas.py +++ b/clive/__private/models/schemas.py @@ -67,79 +67,9 @@ from schemas.fields.hive_datetime import HiveDateTime from schemas.fields.hive_int import HiveInt from schemas.fields.integers import Uint16t, Uint32t from schemas.fields.resolvables import JsonString -from schemas.operation import Operation -from schemas.operations import ( - AccountCreateOperation, - AccountCreateWithDelegationOperation, - AccountUpdate2Operation, - AccountUpdateOperation, - AccountWitnessProxyOperation, - AccountWitnessVoteOperation, - CancelTransferFromSavingsOperation, - ChangeRecoveryAccountOperation, - ClaimAccountOperation, - ClaimRewardBalanceOperation, - CollateralizedConvertOperation, - CommentOperation, - CommentOptionsOperation, - ConvertOperation, - CreateClaimedAccountOperation, - CreateProposalOperation, - CustomBinaryOperation, - CustomJsonOperation, - CustomOperation, - DeclineVotingRightsOperation, - DelegateVestingSharesOperation, - DeleteCommentOperation, - EscrowApproveOperation, - EscrowDisputeOperation, - EscrowReleaseOperation, - EscrowTransferOperation, - FeedPublishOperation, - Hf26OperationRepresentation, - Hf26Operations, - LimitOrderCancelOperation, - LimitOrderCreate2Operation, - LimitOrderCreateOperation, - Pow2Operation, - PowOperation, - RecoverAccountOperation, - RemoveProposalOperation, - RequestAccountRecoveryOperation, - ResetAccountOperation, - SetResetAccountOperation, - SetWithdrawVestingRouteOperation, - TransferFromSavingsOperation, - TransferOperation, - TransferToSavingsOperation, - TransferToVestingOperation, - UpdateProposalOperation, - UpdateProposalVotesOperation, - VoteOperation, - WithdrawVestingOperation, - WitnessBlockApproveOperation, - WitnessSetPropertiesOperation, - WitnessUpdateOperation, - convert_to_representation, -) -from schemas.operations.extensions.recurrent_transfer_extensions import RecurrentTransferPairId -from schemas.operations.extensions.representation_types import ( - HF26RepresentationRecurrentTransferPairIdOperationExtension, -) -from schemas.operations.recurrent_transfer_operation import RecurrentTransferOperation -from schemas.policies import ( - ExtraFieldsPolicy, - MissingFieldsInGetConfigPolicy, - TestnetAssetsPolicy, - set_policies, -) from schemas.transaction import Transaction __all__ = [ # noqa: RUF022 - # operation BASIC aliases - "OperationBase", - "OperationRepresentationUnion", - "OperationUnion", # list API responses (have nested list property which stores actual model) "ListChangeRecoveryAccountRequests", "ListDeclineVotingRightsRequests", @@ -166,60 +96,6 @@ __all__ = [ # noqa: RUF022 "HardforkProperties", "Version", "WitnessSchedule", - # operations - "AccountCreateOperation", - "AccountCreateWithDelegationOperation", - "AccountUpdate2Operation", - "AccountUpdateOperation", - "AccountWitnessProxyOperation", - "AccountWitnessVoteOperation", - "CancelTransferFromSavingsOperation", - "ChangeRecoveryAccountOperation", - "ClaimAccountOperation", - "ClaimRewardBalanceOperation", - "CollateralizedConvertOperation", - "CommentOperation", - "CommentOptionsOperation", - "ConvertOperation", - "CreateClaimedAccountOperation", - "CreateProposalOperation", - "CustomBinaryOperation", - "CustomJsonOperation", - "CustomOperation", - "DeclineVotingRightsOperation", - "DelegateVestingSharesOperation", - "DeleteCommentOperation", - "EscrowApproveOperation", - "EscrowDisputeOperation", - "EscrowReleaseOperation", - "EscrowTransferOperation", - "FeedPublishOperation", - "LimitOrderCancelOperation", - "LimitOrderCreate2Operation", - "LimitOrderCreateOperation", - "Pow2Operation", - "PowOperation", - "RecoverAccountOperation", - "RecurrentTransferOperation", - "RemoveProposalOperation", - "RequestAccountRecoveryOperation", - "ResetAccountOperation", - "SetResetAccountOperation", - "SetWithdrawVestingRouteOperation", - "TransferFromSavingsOperation", - "TransferOperation", - "TransferToSavingsOperation", - "TransferToVestingOperation", - "UpdateProposalOperation", - "UpdateProposalVotesOperation", - "VoteOperation", - "WithdrawVestingOperation", - "WitnessBlockApproveOperation", - "WitnessSetPropertiesOperation", - "WitnessUpdateOperation", - # extensions - "RecurrentTransferPairIdExtension", - "RecurrentTransferPairIdRepresentation", # assets "AssetHbd", "AssetHive", @@ -253,11 +129,6 @@ __all__ = [ # noqa: RUF022 "VestingDelegationExpiration", "WithdrawRoute", "Witness", - # policies - "ExtraFieldsPolicy", - "MissingFieldsInGetConfigPolicy", - "TestnetAssetsPolicy", - "set_policies", # exceptions "DecodeError", "ValidationError", @@ -269,12 +140,6 @@ __all__ = [ # noqa: RUF022 "field", ] -# operation BASIC aliases - -OperationBase = Operation -OperationRepresentationUnion = Hf26OperationRepresentation -OperationUnion = Hf26Operations - # find API response aliases (have nested list property which stores actual model) FindRcAccounts = SchemasFindRcAccounts @@ -288,11 +153,6 @@ HardforkProperties = GetHardforkProperties Version = GetVersion WitnessSchedule = GetWitnessSchedule -# extensions - -RecurrentTransferPairIdExtension = RecurrentTransferPairId -RecurrentTransferPairIdRepresentation = HF26RepresentationRecurrentTransferPairIdOperationExtension - # basic fields ChainId = Sha256 diff --git a/clive/__private/models/transaction.py b/clive/__private/models/transaction.py index 372a550fbb7de8fff6203c1900bc4fd6e8b27451..e1fd32e9055dbaad7f70bf2f8fe131c69dcfd42f 100644 --- a/clive/__private/models/transaction.py +++ b/clive/__private/models/transaction.py @@ -6,23 +6,21 @@ from typing import TYPE_CHECKING, Any from clive.__private.models.schemas import ( HiveDateTime, - OperationRepresentationUnion, - OperationUnion, Signature, TransactionId, Uint16t, Uint32t, - convert_to_representation, field, ) from clive.__private.models.schemas import Transaction as SchemasTransaction + if TYPE_CHECKING: from collections.abc import Iterator from clive.__private.core.accounts.accounts import KnownAccount from clive.__private.visitors.operation.operation_visitor import OperationVisitor - + from clive.__private.models.operations import OperationRepresentationUnion, OperationUnion class Transaction(SchemasTransaction): operations: list[OperationRepresentationUnion] = [] # noqa: RUF012 @@ -37,6 +35,7 @@ class Transaction(SchemasTransaction): return bool(self.operations) def __contains__(self, operation: OperationRepresentationUnion | OperationUnion) -> bool: # type: ignore[override] + from clive.__private.models.operations import OperationUnion if isinstance(operation, OperationUnion): return operation in self.operations_models return operation in self.operations @@ -63,6 +62,7 @@ class Transaction(SchemasTransaction): @classmethod def convert_operations(cls, value: Any) -> list[OperationRepresentationUnion]: # noqa: ANN401 assert isinstance(value, Iterable) + from clive.__private.models.operations import convert_to_representation return [convert_to_representation(op) for op in value] def add_operation(self, *operations: OperationUnion) -> None: diff --git a/clive/__private/settings/_safe_settings.py b/clive/__private/settings/_safe_settings.py index 1343a22ea07a1e69c257ce6ae2c07fe703efbb6b..3ffc1fb33d2f6eb72f1a5ba8f09ff9c73efbcfb9 100644 --- a/clive/__private/settings/_safe_settings.py +++ b/clive/__private/settings/_safe_settings.py @@ -7,8 +7,8 @@ from datetime import timedelta from pathlib import Path from typing import Final, Literal, cast, get_args, overload -from beekeepy import Settings as BeekeepySettings -from beekeepy.handle.remote import RemoteHandleSettings +from beekeepy.asynchronous import Settings as BeekeepySettings +from beekeepy.handle.settings import RemoteHandleSettings from beekeepy.interfaces import HttpUrl from inflection import underscore @@ -25,11 +25,11 @@ from clive.__private.core.constants.setting_identifiers import ( IS_DEV, LOG_DEBUG_LOOP, LOG_DEBUG_PERIOD_SECS, + LOG_DIRECTORY, LOG_KEEP_HISTORY, LOG_LEVEL_1ST_PARTY, LOG_LEVEL_3RD_PARTY, LOG_LEVELS, - LOG_PATH, MAX_NUMBER_OF_TRACKED_ACCOUNTS, NODE_CHAIN_ID, NODE_COMMUNICATION_ATTEMPTS_AMOUNT, @@ -41,7 +41,7 @@ from clive.__private.core.constants.setting_identifiers import ( SECRETS_NODE_ADDRESS, SELECT_FILE_ROOT_PATH, ) -from clive.__private.core.formatters.humanize import humanize_validation_result + from clive.__private.settings._settings import get_settings from clive.exceptions import CliveError @@ -148,10 +148,8 @@ class SafeSettings: return cast("_AvailableLogLevels", value) def _get_log_path(self) -> Path: - value = self._parent._get_value_from_settings(LOG_PATH) - message = "log path is set dynamically and always ensured, so should be available now" - assert isinstance(value, Path), message - return value + value = self._parent._get_path(LOG_DIRECTORY, default=self._parent.data_path) + return value / "logs" def _assert_log_levels(self, setting_name: str, *, value: list[object]) -> None: for log_level in value: @@ -443,6 +441,7 @@ class SafeSettings: self, setting_name: str, *, default: float | NotSet = NOT_SET, minimum: float | None = None ) -> float: from textual.validation import Number # noqa: PLC0415 + from clive.__private.core.formatters.humanize import humanize_validation_result value = self._get_value_from_settings(setting_name, default=default) value_ = str(value) @@ -515,3 +514,9 @@ class SafeSettings: safe_settings = SafeSettings() + +__all__ = [ + "BeekeepySettings", + "SafeSettings", + "safe_settings", +] diff --git a/clive/__private/settings/_settings.py b/clive/__private/settings/_settings.py index 228a3cea192c15294212f666261e869720293543..913362c45d4884f5752f738f86538a22cf809976 100644 --- a/clive/__private/settings/_settings.py +++ b/clive/__private/settings/_settings.py @@ -1,36 +1,335 @@ from __future__ import annotations +import copy +import os from functools import cache from pathlib import Path -from typing import TYPE_CHECKING, Final +from typing import TYPE_CHECKING, Any, Final + +import toml from clive.__private.core.constants.env import ENVVAR_PREFIX, ROOT_DIRECTORY -from clive.__private.core.constants.setting_identifiers import LOG_DIRECTORY, LOG_PATH if TYPE_CHECKING: - from dynaconf import Dynaconf # type: ignore[import-untyped] + from collections.abc import Sequence _DATA_DIRECTORY: Final[Path] = Path.home() / ".clive" # order matters - later paths override earlier values for the same key of earlier paths -_SETTINGS_FILES: Final[list[str]] = ["settings.toml", str(_DATA_DIRECTORY / "settings.toml")] +_SETTINGS_FILES: Final[list[Path]] = [ROOT_DIRECTORY / "settings.toml", _DATA_DIRECTORY / "settings.toml"] + +type KeyDottedNotation = str +"""A string representing a key in dotted notation format (e.g., 'NODE.CHAIN_ID').""" + +type EnvName = str +"""The name of the environment""" + +type EnvSettings = dict[str, Any] +"""A mapping representing environment settings (which may be nested).""" + +type EnvNameToEnvSettings = dict[str, EnvSettings] +"""A mapping between environment name and environment settings (which may be nested).""" + + +class Settings: + """ + A configuration settings manager for handling environment-specific settings. + + This class allows loading configuration from various sources such as files, environmental + variables, and programmatically set values. It supports managing environment-specific settings + with a precedence of overrides, environment variables, file-based values, and defaults. + + Attributes: + DEFAULT_ENV_NAME: The default environment name. + + Args: + files: Sequence of file paths containing settings. + prefix: String prefix for environment variables (must be alphabetic). + env: Name of the initial environment to use. + **defaults: Additional default values to use as base settings. + """ + + DEFAULT_ENV_NAME: Final[str] = "DEFAULT" + + def __init__( + self, + files: Sequence[str | Path], + prefix: str = ENVVAR_PREFIX, + env: str = DEFAULT_ENV_NAME, + **defaults: Any, + ) -> None: + assert prefix.isalpha(), "Prefix should be an alphabetic string" + + self._files = [Path(f) for f in files] + self._prefix = prefix + self._env = self._normalize_key(env) + self._defaults: EnvSettings = self._normalize_keys(defaults) + self._data: EnvNameToEnvSettings = {} + self._overrides: EnvNameToEnvSettings = {} + self.reload() + + @property + def env(self) -> EnvName: + """ + Get the currently active environment name. + + Returns: + Environment name. + """ + return self._env + + def setenv(self, env: EnvName) -> None: + """ + Change the active environment. + + Args: + env: Name of the environment to switch to (e.g., "dev", "default"). + """ + self._env = self._normalize_key(env) + + def get( + self, + key: KeyDottedNotation, + default: object | None = None, + ) -> object | None: + """ + Get a setting by key. + + Args: + key: Key of the setting to get. Use dot notation for nested values. + default: Default value to return if the key does not exist. + + Returns: + Value of the setting if found or `default`. + """ + merged = self._resolve() + value = self._resolve_from_dict(merged, key) + return value if value is not None else default + + def set( + self, + key: KeyDottedNotation, + value: object | None, + env: str | None = None, + ) -> None: + """ + Set a setting with a key in the active env (or given env) to a given value. + + Args: + key: Key of the setting to set. Use dot notation for nested values. + value: Value of the setting to set. + env: Environment to which the setting is to be set. + """ + target_env_name = self._normalize_key(env or self.env) + overrides_env = self._overrides.setdefault(target_env_name, {}) + self._set_nested(overrides_env, key, value) + + def reload(self) -> None: + """Clear the current state and reload from files.""" + self._data.clear() + self._data[self.DEFAULT_ENV_NAME] = copy.deepcopy(self._defaults) + for file in self._files: + self._load_file(file) + + def as_dict(self, env: EnvName | None = None) -> EnvSettings: + """ + Get a dictionary representation of the current settings. + + Args: + env: Environment to which the settings are to be reloaded from. Default to active. + + Returns: + Dictionary representation of the settings. + """ + return self._resolve(env) + + def _resolve(self, env: EnvName | None = None) -> EnvSettings: + """ + Resolve the current environment settings with the correct order. + + The priority order is: + 1. Dynamic overrides + 2. Environment variables + 3. File-based settings + 4. Defaults (given during init) + + Args: + env: Environment to which the settings are to be resolved. + + Returns: + Resolved environment settings. + """ + env = self._normalize_key(env or self.env) + + # 1. Start with defaults + merged = copy.deepcopy(self._data.get(self.DEFAULT_ENV_NAME, {})) + + # 2. Merge TOML values for environment + if env != self.DEFAULT_ENV_NAME: + env_data = self._data.get(env, {}) + self._merge(merged, copy.deepcopy(env_data)) + + # 3. Apply environment variables + self._merge(merged, self._parse_prefixed_envvars()) + + # 4. Apply dynamic overrides (they should overwrite everything) + overrides = self._overrides.get(env, {}) + self._merge(merged, copy.deepcopy(overrides)) + + return merged + + @property + def _full_prefix(self) -> str: + return f"{self._prefix}_" + + def _set_nested( + self, + target: dict[str, Any], + dotted_key: KeyDottedNotation, + value: object | None, + ) -> None: + """ + Set a value in a target dictionary using dotted notation. + + Args: + target: Target mapping to set the value to. + dotted_key: Key in dotted notation format. + value: Value to set. + """ + parts = self._dotted_key_notation_to_parts(dotted_key) + node = target + for part in parts[:-1]: + node = node.setdefault(self._normalize_key(part), {}) + node[self._normalize_key(parts[-1])] = value + + def _load_file(self, filepath: Path) -> None: + """ + Load settings from a given TOML file. + + Args: + filepath: Path to the TOML file. + """ + if not filepath.exists(): + return + + content = toml.loads(filepath.read_text()) + + for env_name_raw, env_data_raw in content.items(): + env_name_normalized = self._normalize_key(env_name_raw) + env_data_normalized = self._normalize_keys(env_data_raw) + current_env_data = self._data.setdefault(env_name_normalized, {}) + self._merge(current_env_data, env_data_normalized) + + def _merge(self, target: dict[str, Any], new_data: dict[str, Any]) -> None: + """ + Merges the content of one dictionary into another. + + Args: + target: The main dictionary that will be updated with the new data. + new_data: The dictionary containing new key-value pairs to merge into the target. + + Example: + >>> dict1 = {"a": {"x": 1}} + >>> dict2 = {"a": {"y": 2}} + >>> _merge(dict1, dict2) + >>> dict1 + {'a': {'x': 1, 'y': 2}} + """ + for key, value in new_data.items(): + if isinstance(value, dict): + node = target.setdefault(key, {}) + self._merge(node, value) + else: + target[key] = value + + def _resolve_from_dict(self, data: EnvSettings, dotted_key: KeyDottedNotation) -> object | None: + """ + Resolves a value from a nested dictionary using a dotted key notation. + + Args: + data: The dictionary to resolve the value from. + dotted_key: The dotted key notation representing the desired path. + + Returns: + The resolved value from the dictionary or None if the path cannot + be resolved. + """ + parts = self._dotted_key_notation_to_parts(dotted_key) + node: object | None = data + for part in parts: + if not isinstance(node, dict): + return None + node = node.get(self._normalize_key(part)) + if node is None: + return None + return node + + def _parse_prefixed_envvars(self) -> dict[str, Any]: + result: dict[str, Any] = {} + + for env_key, env_value in os.environ.items(): + if not env_key.startswith(self._full_prefix): + continue + + dotted_key = self._envvar_to_dotted_key_notation(env_key, self._full_prefix) + self._set_nested(result, dotted_key, env_value) + + return result + + def _dotted_key_notation_to_parts(self, dotted_key: str) -> list[str]: + """ + Converts a dotted key notation string into a list of its parts. + + Args: + dotted_key: Key in dotted notation format. + + Returns: + Parts of the original dotted key. + """ + return [self._normalize_key(part) for part in dotted_key.split(".")] + + def _envvar_to_dotted_key_notation(self, env_key: str, prefix: str) -> str: + """ + Converts an environment variable key with a given prefix to a dotted key notation. + + Args: + env_key: Environment variable name. + prefix: Environment variable prefix. + + Returns: + Dotted key notation of the environment variable. + """ + normalized = self._normalize_key(env_key) + stripped = normalized[len(prefix) :] + parts = stripped.split("__") + return ".".join(parts) + + def _normalize_key(self, key: str) -> str: + return key.upper() + + def _normalize_keys(self, data: dict[str, Any]) -> dict[str, Any]: + """ + Recursively normalize all dictionary keys. + + Args: + data: A dictionary whose keys will be normalized. + + Returns: + A new dictionary with normalized keys. + """ + normalized: dict[str, Any] = {} + for key, value in data.items(): + new_key = self._normalize_key(key) + if isinstance(value, dict): + normalized[new_key] = self._normalize_keys(value) + else: + normalized[new_key] = value + return normalized @cache -def get_settings() -> Dynaconf: - from dynaconf import Dynaconf # noqa: PLC0415 - - settings = Dynaconf( - envvar_prefix=ENVVAR_PREFIX, - root_path=ROOT_DIRECTORY, - settings_files=_SETTINGS_FILES, - environments=True, - # preconfigured settings +def get_settings() -> Settings: + return Settings( + files=_SETTINGS_FILES, data_path=_DATA_DIRECTORY, ) - - # preconfigured settings, but initialized with a value based on other settings - _log_directory = settings.get(LOG_DIRECTORY, "") or _DATA_DIRECTORY - _log_path = Path(_log_directory) / "logs" - settings.set(LOG_PATH, _log_path) - return settings diff --git a/clive/__private/storage/migrations/v0.py b/clive/__private/storage/migrations/v0.py index bfec61b90c5b422b02987ccda1cdbebd5cc3a607..6e8374edb0f6f7a2acb29a3a9cb9a42fecdbf876 100644 --- a/clive/__private/storage/migrations/v0.py +++ b/clive/__private/storage/migrations/v0.py @@ -14,7 +14,6 @@ from clive.__private.core.alarms.specific_alarms import ( from clive.__private.core.date_utils import utc_epoch from clive.__private.models.schemas import ( HiveDateTime, - OperationRepresentationUnion, PreconfiguredBaseModel, Signature, Uint16t, @@ -23,6 +22,7 @@ from clive.__private.models.schemas import ( ) from clive.__private.storage.migrations.base import AlarmStorageModelBase, ProfileStorageBase +from clive.__private.models.operations import OperationRepresentationUnion class ProfileStorageModel(ProfileStorageBase, kw_only=True): name: str diff --git a/clive/__private/ui/dialogs/raw_json_dialog.py b/clive/__private/ui/dialogs/raw_json_dialog.py index 213b6d5039972776f085b1b185df876712a75375..1d132f8fc247636ffc7e073e10ecdbdbe604fbac 100644 --- a/clive/__private/ui/dialogs/raw_json_dialog.py +++ b/clive/__private/ui/dialogs/raw_json_dialog.py @@ -6,14 +6,13 @@ from typing import TYPE_CHECKING from textual.containers import Center from textual.widgets import Pretty -from clive.__private.models.schemas import convert_to_representation from clive.__private.ui.dialogs.clive_base_dialogs import CliveInfoDialog from clive.__private.ui.widgets.section import Section if TYPE_CHECKING: from textual.app import ComposeResult - from clive.__private.models.schemas import OperationBase + from clive.__private.models.operations import OperationBase class RawJsonDialog(CliveInfoDialog): @@ -27,5 +26,6 @@ class RawJsonDialog(CliveInfoDialog): @staticmethod def _get_operation_representation_json(operation: OperationBase) -> str: + from clive.__private.models.operations import convert_to_representation representation = convert_to_representation(operation) return representation.json(order="sorted") diff --git a/clive/__private/ui/screens/cart_based_screen/cart_overview.py b/clive/__private/ui/screens/cart_based_screen/cart_overview.py index cd6f603efe218516f6207ba6f0ab28b0a34cbf0d..74989a338246c41d64717eae0dc95a7cc2a2dd80 100644 --- a/clive/__private/ui/screens/cart_based_screen/cart_overview.py +++ b/clive/__private/ui/screens/cart_based_screen/cart_overview.py @@ -21,7 +21,7 @@ if TYPE_CHECKING: from clive.__private.core.accounts.accounts import WorkingAccount from clive.__private.core.profile import Profile - from clive.__private.models.schemas import OperationBase + from clive.__private.models.operations import OperationBase class Resources(Grid): diff --git a/hive b/hive index 8b287d3990df722eccd4a81fc75b1a4b2fc50fc3..94cb02a00f172b69a4268a856d1e12c27cb24703 160000 --- a/hive +++ b/hive @@ -1 +1 @@ -Subproject commit 8b287d3990df722eccd4a81fc75b1a4b2fc50fc3 +Subproject commit 94cb02a00f172b69a4268a856d1e12c27cb24703 diff --git a/poetry.lock b/poetry.lock index 069e6eeb2958b6545a4c7ddafbeadc539ae974b0..3f5ba205ac24b582819c38489c3219bd5e33d55b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -411,28 +411,6 @@ files = [ {file = "docstring_parser_fork-0.0.12.tar.gz", hash = "sha256:b44c5e0be64ae80f395385f01497d381bd094a57221fd9ff020987d06857b2a0"}, ] -[[package]] -name = "dynaconf" -version = "3.2.10" -description = "The dynamic configurator for your Python Project" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "dynaconf-3.2.10-py2.py3-none-any.whl", hash = "sha256:7f70a4b8a8861efb88d8267aeb6f246c791dc34ecbb8299c26a19abd59113df6"}, - {file = "dynaconf-3.2.10.tar.gz", hash = "sha256:8dbeef31a2343c8342c9b679772c3d005b4801c587cf2f525f98f57ec2f607f1"}, -] - -[package.extras] -all = ["configobj", "hvac", "redis", "ruamel.yaml"] -configobj = ["configobj"] -ini = ["configobj"] -redis = ["redis"] -test = ["configobj", "django", "flask (>=0.12)", "hvac (>=1.1.0)", "pytest", "pytest-cov", "pytest-mock", "pytest-xdist", "python-dotenv", "radon", "redis", "toml"] -toml = ["toml"] -vault = ["hvac"] -yaml = ["ruamel.yaml"] - [[package]] name = "execnet" version = "2.1.1" @@ -630,13 +608,13 @@ hyperframe = ">=6.1,<7" [[package]] name = "hiveio-beekeepy" -version = "0.0.1.dev430+d766238" +version = "0.0.1.dev432+e5cab69" description = "All in one package for beekeeper interaction via Python interface." optional = false python-versions = ">=3.12,<4.0" groups = ["main", "dev", "embeddedtestnet"] files = [ - {file = "hiveio_beekeepy-0.0.1.dev430+d766238-py3-none-any.whl", hash = "sha256:530af9ac95801e50f41e714f00b533a22c75ab313b53d075062872961c350434"}, + {file = "hiveio_beekeepy-0.0.1.dev432+e5cab69-py3-none-any.whl", hash = "sha256:bff8619672fa17c90e053fb47e363f1251c597a1e67ffbe62e187295dd45d518"}, ] [package.dependencies] @@ -655,17 +633,17 @@ reference = "gitlab-beekeepy" [[package]] name = "hiveio-database-api" -version = "1.27.12rc3.dev3+4e61e68ce" +version = "1.27.12rc3.dev10+0a0c46ef4" description = "" optional = false python-versions = ">=3.12,<4.0" groups = ["main", "dev", "embeddedtestnet"] files = [ - {file = "hiveio_database_api-1.27.12rc3.dev3+4e61e68ce-py3-none-any.whl", hash = "sha256:f282879003f3f034a3eab60ece574cf399aeaabf758903fa8f76f9e47d65dd06"}, + {file = "hiveio_database_api-1.27.12rc3.dev10+0a0c46ef4-py3-none-any.whl", hash = "sha256:2058f3ab5ceaefe96caea6df8a0d581ccc9d19d18069d0e8a74cb6f7f9eee035"}, ] [package.dependencies] -hiveio-beekeepy = "0.0.1.dev430+d766238" +hiveio-beekeepy = "0.0.1.dev432+e5cab69" [package.source] type = "legacy" @@ -674,17 +652,17 @@ reference = "gitlab-hive" [[package]] name = "hiveio-network-broadcast-api" -version = "1.27.12rc3.dev3+4e61e68ce" +version = "1.27.12rc3.dev10+0a0c46ef4" description = "" optional = false python-versions = ">=3.12,<4.0" groups = ["main", "dev", "embeddedtestnet"] files = [ - {file = "hiveio_network_broadcast_api-1.27.12rc3.dev3+4e61e68ce-py3-none-any.whl", hash = "sha256:035f16492eb42fc2e488841d19355a713eb7153f638a88cbde435b7d40f385e1"}, + {file = "hiveio_network_broadcast_api-1.27.12rc3.dev10+0a0c46ef4-py3-none-any.whl", hash = "sha256:3a1fdc4394c11de464c146fa00129349a0ab32f467db863504e4f468f05a98d2"}, ] [package.dependencies] -hiveio-beekeepy = "0.0.1.dev430+d766238" +hiveio-beekeepy = "0.0.1.dev432+e5cab69" [package.source] type = "legacy" @@ -712,18 +690,18 @@ reference = "gitlab-schemas" [[package]] name = "hiveio-wax" -version = "0.3.10.dev898+fe053737" +version = "0.3.10.dev905+e8c045a2" description = "" optional = false python-versions = ">=3.12,<4.0" groups = ["main", "dev", "embeddedtestnet"] files = [ - {file = "hiveio_wax-0.3.10.dev898+fe053737-cp312-cp312-manylinux_2_39_x86_64.whl", hash = "sha256:755a608ce0e98f5baa0d33f156d939bef2f4760f97356cc89597c5761630ca6f"}, + {file = "hiveio_wax-0.3.10.dev905+e8c045a2-cp312-cp312-manylinux_2_39_x86_64.whl", hash = "sha256:811ebc42aad938bd14a9706fcbe027c4679f22a3cd2fd9174e1814982eb89154"}, ] [package.dependencies] -hiveio-database-api = "1.27.12rc3.dev3+4e61e68ce" -hiveio-network-broadcast-api = "1.27.12rc3.dev3+4e61e68ce" +hiveio-database-api = "1.27.12rc3.dev10+0a0c46ef4" +hiveio-network-broadcast-api = "1.27.12rc3.dev10+0a0c46ef4" httpx = {version = "0.23.3", extras = ["http2"]} loguru = "0.7.2" protobuf = "4.24.4" @@ -2199,7 +2177,7 @@ develop = false [package.dependencies] abstractcp = "0.9.9" -hiveio-wax = "0.3.10.dev898+fe053737" +hiveio-wax = "0.3.10.dev905+e8c045a2" loguru = "0.7.2" python-dateutil = "2.8.2" @@ -2519,4 +2497,4 @@ propcache = ">=0.2.1" [metadata] lock-version = "2.1" python-versions = ">=3.12,<3.13" -content-hash = "9935f43610c7bd15b33be15d5a37fbd4796eec3293c3760eb14879f4bdffd975" +content-hash = "6d38a1ab07ddc6cb791e323d0335168a4ddd1acc1452c6901c3e76cf80c2f42d" diff --git a/pyproject.toml b/pyproject.toml index ea3b3ad254e15f006fd22a0850d08073c834fdff..4bde774ebc40c06072a2bcad2deb4cc4f8bc9eb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ readme = "README.md" authors = [{ name = "Krzysztof Mochocki", email = "kmochocki@syncad.com" }, { name = "Mateusz Żebrak", email = "mzebrak@syncad.com" }] requires-python = '>=3.12,<3.13' # we are restricted to 3.12 because of wax dependencies = [ - 'dynaconf (==3.2.10)', 'loguru (==0.7.2)', 'textual (==4.0.0)', 'aiohttp (==3.11.15)', @@ -23,8 +22,8 @@ dependencies = [ 'toml (==0.10.2)', "pathvalidate (==3.3.1)", 'hiveio-schemas (==0.0.1.dev431+2255381)', - 'hiveio-beekeepy (==0.0.1.dev430+d766238)', - 'hiveio-wax (==0.3.10.dev898+fe053737)', + 'hiveio-beekeepy (==0.0.1.dev432+e5cab69)', + 'hiveio-wax (==0.3.10.dev905+e8c045a2)', ] [project.urls] diff --git a/tests/clive-local-tools/clive_local_tools/checkers/wallet_checkers.py b/tests/clive-local-tools/clive_local_tools/checkers/wallet_checkers.py index 076562332c6e903e9a46b61bd5c3f0d3b5d01714..70ba042b17da8b68c1cd62057fe961e1a5c7ebe1 100644 --- a/tests/clive-local-tools/clive_local_tools/checkers/wallet_checkers.py +++ b/tests/clive-local-tools/clive_local_tools/checkers/wallet_checkers.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING from clive.__private.core.commands.is_wallet_unlocked import IsWalletUnlocked if TYPE_CHECKING: - from beekeepy import AsyncBeekeeper + from beekeepy.asynchronous import AsyncBeekeeper async def assert_wallets_locked(beekeeper: AsyncBeekeeper) -> None: diff --git a/tests/clive-local-tools/clive_local_tools/storage_migration/regenerate_prepared_profiles.py b/tests/clive-local-tools/clive_local_tools/storage_migration/regenerate_prepared_profiles.py index a7362f67a310a7bf43aefa4295b10c4ccf2fbc25..96185f6bfd08913ef1f52d59404a2e82d51c44a5 100644 --- a/tests/clive-local-tools/clive_local_tools/storage_migration/regenerate_prepared_profiles.py +++ b/tests/clive-local-tools/clive_local_tools/storage_migration/regenerate_prepared_profiles.py @@ -16,7 +16,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Final import test_tools as tt -from beekeepy import AsyncBeekeeper +from beekeepy.asynchronous import AsyncBeekeeper from clive.__private.core.commands.create_encryption_wallet import CreateEncryptionWallet from clive.__private.core.commands.create_user_wallet import CreateUserWallet diff --git a/tests/conftest.py b/tests/conftest.py index 8143d717f92d53e8cd1e1cb8c6894cb46dd2af27..01ca3f4a8b6195e9638521cfc9ed50bf76be5202 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING import pytest import test_tools as tt -from beekeepy import AsyncBeekeeper +from beekeepy.asynchronous import AsyncBeekeeper from test_tools.__private.scope.scope_fixtures import * # noqa: F403 from clive.__private.before_launch import ( @@ -22,7 +22,7 @@ from clive.__private.core import iwax from clive.__private.core._thread import thread_pool from clive.__private.core.commands.create_profile_wallets import CreateProfileWallets from clive.__private.core.commands.import_key import ImportKey -from clive.__private.core.constants.setting_identifiers import DATA_PATH, LOG_LEVEL_1ST_PARTY, LOG_LEVELS, LOG_PATH +from clive.__private.core.constants.setting_identifiers import DATA_PATH, LOG_DIRECTORY, LOG_LEVEL_1ST_PARTY, LOG_LEVELS from clive.__private.core.world import World from clive.__private.logger import logger from clive.__private.models.schemas import ( @@ -43,7 +43,7 @@ from clive_local_tools.data.models import Keys, WalletInfo if TYPE_CHECKING: from collections.abc import AsyncIterator, Callable, Generator, Iterator - from beekeepy import AsyncBeekeeper + from beekeepy.asynchronous import AsyncBeekeeper from clive.__private.core.keys.keys import PrivateKey, PublicKey from clive.__private.core.profile import Profile @@ -79,7 +79,7 @@ def _prepare_settings() -> None: if profile_data_directory.exists(): shutil.rmtree(profile_data_directory) - settings.set(LOG_PATH, working_directory / "logs") + settings.set(LOG_DIRECTORY, working_directory) settings.set(LOG_LEVELS, ["DEBUG"]) settings.set(LOG_LEVEL_1ST_PARTY, "DEBUG") diff --git a/tests/functional/cli/configure/test_configure_key.py b/tests/functional/cli/configure/test_configure_key.py index e3da5b5eb5667a3f66b0db6cd4791ed4cadf7d9d..935e2d99e35ac3ad8f2199d2b5bd9d81040f95ef 100644 --- a/tests/functional/cli/configure/test_configure_key.py +++ b/tests/functional/cli/configure/test_configure_key.py @@ -9,7 +9,7 @@ from clive.__private.core.keys.keys import PrivateKey from clive_local_tools.cli.exceptions import CLITestCommandError if TYPE_CHECKING: - from beekeepy import AsyncUnlockedWallet + from beekeepy.asynchronous import AsyncUnlockedWallet from clive_local_tools.cli.cli_tester import CLITester diff --git a/tests/functional/cli/configure/test_configure_profile_delete_without_remote_address.py b/tests/functional/cli/configure/test_configure_profile_delete_without_remote_address.py index c52294c86fae2e2fd92caf413d0a04e5bd4b4734..93768839e614f23958748c661916c49b3ba0a289 100644 --- a/tests/functional/cli/configure/test_configure_profile_delete_without_remote_address.py +++ b/tests/functional/cli/configure/test_configure_profile_delete_without_remote_address.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import TYPE_CHECKING import pytest -from beekeepy import AsyncBeekeeper +from beekeepy.asynchronous import AsyncBeekeeper from beekeepy.exceptions.common import InvalidatedStateByClosingBeekeeperError from clive.__private.settings import safe_settings diff --git a/tests/functional/cli/conftest.py b/tests/functional/cli/conftest.py index dbe94ba6baafae55d67ac2218197c8243a05a90a..4cfb7920d9aa484f4e738a3e8cd51916059d3bf5 100644 --- a/tests/functional/cli/conftest.py +++ b/tests/functional/cli/conftest.py @@ -4,7 +4,7 @@ from contextlib import ExitStack from typing import TYPE_CHECKING import pytest -from beekeepy import AsyncBeekeeper +from beekeepy.asynchronous import AsyncBeekeeper from typer.testing import CliRunner from clive.__private.core.constants.terminal import TERMINAL_WIDTH diff --git a/tests/functional/commands/test_locking.py b/tests/functional/commands/test_locking.py index 34253f03a84926b0cc70551edd67c6180cfce415..c7227226c43292f7b6f08c45319e9410f97e5c42 100644 --- a/tests/functional/commands/test_locking.py +++ b/tests/functional/commands/test_locking.py @@ -12,7 +12,7 @@ from clive.__private.core.commands.unlock import Unlock from clive.__private.core.encryption import EncryptionService if TYPE_CHECKING: - from beekeepy import AsyncBeekeeper + from beekeepy.asynchronous import AsyncBeekeeper from clive.__private.core.profile import Profile from clive.__private.core.world import World diff --git a/tests/unit/profile/test_profile_loading.py b/tests/unit/profile/test_profile_loading.py index 2229aba0797d7c571bcf49ceb3157f773e5dce9e..5323a92a712ef6adcbbe5df963b5234706ac9a0f 100644 --- a/tests/unit/profile/test_profile_loading.py +++ b/tests/unit/profile/test_profile_loading.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import TYPE_CHECKING import pytest -from beekeepy import AsyncBeekeeper +from beekeepy.asynchronous import AsyncBeekeeper from clive.__private.cli.cli_world import CLIWorld from clive.__private.core.commands.create_profile_wallets import CreateProfileWallets diff --git a/tests/unit/storage/test_storage_structure.py b/tests/unit/storage/test_storage_structure.py index dd8fe6524a9fbea2882119f108a22893bd44d9ee..547c20305803002e0b1a4103f1447b0678093b85 100644 --- a/tests/unit/storage/test_storage_structure.py +++ b/tests/unit/storage/test_storage_structure.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import TYPE_CHECKING, Final import pytest -from beekeepy import AsyncBeekeeper +from beekeepy.asynchronous import AsyncBeekeeper from clive.__private.core.commands.create_profile_wallets import CreateProfileWallets from clive.__private.core.commands.save_profile import SaveProfile