diff --git a/extras/custom_checks.sh b/extras/custom_checks.sh index b3c635d3d..66b899636 100644 --- a/extras/custom_checks.sh +++ b/extras/custom_checks.sh @@ -89,12 +89,25 @@ function check_do_not_import_tests_in_hathor() { return 0 } +function check_do_not_import_from_hathor_in_entrypoints() { + PATTERN='^import .*hathor.*\|^from .*hathor.* import' + + if grep -R "$PATTERN" "hathor/cli" | grep -v '# no-custom-check'; then + echo 'do not import from `hathor` in the module-level of a CLI entrypoint.' + echo 'instead, import locally inside the function that uses the import.' + echo 'alternatively, comment `# no-custom-check` to exclude a line.' + return 1 + fi + return 0 +} + # List of functions to be executed checks=( check_version_match check_do_not_use_builtin_random_in_tests check_deprecated_typing check_do_not_import_tests_in_hathor + check_do_not_import_from_hathor_in_entrypoints ) # Initialize a variable to track if any check fails diff --git a/hathor/builder/cli_builder.py b/hathor/builder/cli_builder.py index 0e9ea9d04..4782a6350 100644 --- a/hathor/builder/cli_builder.py +++ b/hathor/builder/cli_builder.py @@ -21,7 +21,7 @@ from structlog import get_logger -from hathor.cli.run_node import RunNodeArgs +from hathor.cli.run_node_args import RunNodeArgs from hathor.consensus import ConsensusAlgorithm from hathor.daa import DifficultyAdjustmentAlgorithm from hathor.event import EventManager diff --git a/hathor/cli/db_export.py b/hathor/cli/db_export.py index 1a13afd9e..081127826 100644 --- a/hathor/cli/db_export.py +++ b/hathor/cli/db_export.py @@ -17,7 +17,7 @@ from argparse import ArgumentParser, FileType from typing import TYPE_CHECKING, Iterator, Optional -from hathor.cli.run_node import RunNode +from hathor.cli.run_node import RunNode # no-custom-check if TYPE_CHECKING: from hathor.transaction import BaseTransaction diff --git a/hathor/cli/db_import.py b/hathor/cli/db_import.py index 84a51d185..7b3ca11a0 100644 --- a/hathor/cli/db_import.py +++ b/hathor/cli/db_import.py @@ -18,8 +18,7 @@ from argparse import ArgumentParser, FileType from typing import TYPE_CHECKING, Iterator -from hathor.cli.db_export import MAGIC_HEADER -from hathor.cli.run_node import RunNode +from hathor.cli.run_node import RunNode # no-custom-check if TYPE_CHECKING: from hathor.transaction import BaseTransaction @@ -46,6 +45,7 @@ def prepare(self, *, register_resources: bool = True) -> None: self.in_file = io.BufferedReader(self._args.import_file) def run(self) -> None: + from hathor.cli.db_export import MAGIC_HEADER from hathor.util import tx_progress header = self.in_file.read(len(MAGIC_HEADER)) diff --git a/hathor/cli/events_simulator/event_forwarding_websocket_factory.py b/hathor/cli/events_simulator/event_forwarding_websocket_factory.py index 15e5e70d1..2af78d9b5 100644 --- a/hathor/cli/events_simulator/event_forwarding_websocket_factory.py +++ b/hathor/cli/events_simulator/event_forwarding_websocket_factory.py @@ -12,21 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any +from typing import TYPE_CHECKING, Any from twisted.internet.interfaces import IAddress -from hathor.cli.events_simulator.event_forwarding_websocket_protocol import EventForwardingWebsocketProtocol -from hathor.event.websocket import EventWebsocketFactory -from hathor.simulator import Simulator +from hathor.event.websocket import EventWebsocketFactory # no-custom-check + +if TYPE_CHECKING: + from hathor.cli.events_simulator.event_forwarding_websocket_protocol import EventForwardingWebsocketProtocol + from hathor.simulator import Simulator class EventForwardingWebsocketFactory(EventWebsocketFactory): - def __init__(self, simulator: Simulator, *args: Any, **kwargs: Any) -> None: + def __init__(self, simulator: 'Simulator', *args: Any, **kwargs: Any) -> None: self._simulator = simulator super().__init__(*args, **kwargs) - def buildProtocol(self, _: IAddress) -> EventForwardingWebsocketProtocol: + def buildProtocol(self, _: IAddress) -> 'EventForwardingWebsocketProtocol': protocol = EventForwardingWebsocketProtocol(self._simulator) protocol.factory = self return protocol diff --git a/hathor/cli/events_simulator/event_forwarding_websocket_protocol.py b/hathor/cli/events_simulator/event_forwarding_websocket_protocol.py index da3530572..4f7c79022 100644 --- a/hathor/cli/events_simulator/event_forwarding_websocket_protocol.py +++ b/hathor/cli/events_simulator/event_forwarding_websocket_protocol.py @@ -16,17 +16,17 @@ from autobahn.websocket import ConnectionRequest -from hathor.event.websocket import EventWebsocketProtocol -from hathor.simulator import Simulator +from hathor.event.websocket import EventWebsocketProtocol # no-custom-check if TYPE_CHECKING: from hathor.cli.events_simulator.event_forwarding_websocket_factory import EventForwardingWebsocketFactory + from hathor.simulator import Simulator class EventForwardingWebsocketProtocol(EventWebsocketProtocol): factory: 'EventForwardingWebsocketFactory' - def __init__(self, simulator: Simulator) -> None: + def __init__(self, simulator: 'Simulator') -> None: self._simulator = simulator super().__init__() diff --git a/hathor/cli/mining.py b/hathor/cli/mining.py index 63ab8757c..1fbd8a927 100644 --- a/hathor/cli/mining.py +++ b/hathor/cli/mining.py @@ -24,8 +24,6 @@ import requests -from hathor.conf.get_settings import get_settings - _SLEEP_ON_ERROR_SECONDS = 5 _MAX_CONN_RETRIES = math.inf @@ -137,6 +135,7 @@ def execute(args: Namespace) -> None: block.nonce, block.weight)) try: + from hathor.conf.get_settings import get_settings from hathor.daa import DifficultyAdjustmentAlgorithm from hathor.verification.verification_service import VerificationService, VertexVerifiers settings = get_settings() diff --git a/hathor/cli/multisig_spend.py b/hathor/cli/multisig_spend.py index cd9600097..6b7fcdc57 100644 --- a/hathor/cli/multisig_spend.py +++ b/hathor/cli/multisig_spend.py @@ -14,8 +14,6 @@ from argparse import ArgumentParser, Namespace -from hathor.mining.cpu_mining_service import CpuMiningService - def create_parser() -> ArgumentParser: from hathor.cli.util import create_parser @@ -29,6 +27,7 @@ def create_parser() -> ArgumentParser: def execute(args: Namespace) -> None: + from hathor.mining.cpu_mining_service import CpuMiningService from hathor.transaction import Transaction from hathor.transaction.scripts import MultiSig diff --git a/hathor/cli/nginx_config.py b/hathor/cli/nginx_config.py index 18a6f4afe..974d0f74c 100644 --- a/hathor/cli/nginx_config.py +++ b/hathor/cli/nginx_config.py @@ -17,8 +17,6 @@ from enum import Enum from typing import Any, NamedTuple, Optional, TextIO -from hathor.cli.openapi_json import get_openapi_dict - BASE_PATH = os.path.join(os.path.dirname(__file__), 'nginx_files') @@ -26,6 +24,7 @@ def get_openapi(src_file: Optional[TextIO] = None) -> dict[str, Any]: """ Open and parse the json file or generate OpenAPI dict on-the-fly """ if src_file is None: + from hathor.cli.openapi_json import get_openapi_dict return get_openapi_dict() else: return json.load(src_file) diff --git a/hathor/cli/openapi_files/register.py b/hathor/cli/openapi_files/register.py index 733f56848..527747002 100644 --- a/hathor/cli/openapi_files/register.py +++ b/hathor/cli/openapi_files/register.py @@ -14,7 +14,7 @@ from typing import TypeVar -from hathor.api_util import Resource +from hathor.api_util import Resource # no-custom-check _registered_resources: list[type[Resource]] = [] diff --git a/hathor/cli/quick_test.py b/hathor/cli/quick_test.py index 1c4fa056a..11eca07ed 100644 --- a/hathor/cli/quick_test.py +++ b/hathor/cli/quick_test.py @@ -14,7 +14,7 @@ from argparse import ArgumentParser -from hathor.cli.run_node import RunNode +from hathor.cli.run_node import RunNode # no-custom-check class QuickTest(RunNode): diff --git a/hathor/cli/run_node.py b/hathor/cli/run_node.py index 40d1004ca..1010796c9 100644 --- a/hathor/cli/run_node.py +++ b/hathor/cli/run_node.py @@ -15,22 +15,20 @@ import os import sys from argparse import SUPPRESS, ArgumentParser, Namespace -from typing import Any, Callable, Optional +from typing import TYPE_CHECKING, Any, Callable, Optional from pydantic import ValidationError from structlog import get_logger -from hathor.cli.run_node_args import RunNodeArgs -from hathor.conf import TESTNET_SETTINGS_FILEPATH, HathorSettings -from hathor.exception import PreInitializationError -from hathor.feature_activation.feature import Feature - logger = get_logger() # LOGGING_CAPTURE_STDOUT = True +if TYPE_CHECKING: + from hathor.cli.run_node_args import RunNodeArgs + class RunNode: - UNSAFE_ARGUMENTS: list[tuple[str, Callable[[RunNodeArgs], bool]]] = [ + UNSAFE_ARGUMENTS: list[tuple[str, Callable[['RunNodeArgs'], bool]]] = [ ('--test-mode-tx-weight', lambda args: bool(args.test_mode_tx_weight)), ('--enable-crash-api', lambda args: bool(args.enable_crash_api)), ('--x-sync-bridge', lambda args: bool(args.x_sync_bridge)), @@ -45,6 +43,7 @@ def create_parser(cls) -> ArgumentParser: Arguments must also be added to hathor.cli.run_node_args.RunNodeArgs """ from hathor.cli.util import create_parser + from hathor.feature_activation.feature import Feature parser = create_parser() parser.add_argument('--hostname', help='Hostname used to be accessed by other peers') @@ -346,6 +345,9 @@ def check_python_version(self) -> None: ])) def __init__(self, *, argv=None): + from hathor.cli.run_node_args import RunNodeArgs + from hathor.conf import TESTNET_SETTINGS_FILEPATH + from hathor.conf.get_settings import get_settings self.log = logger.new() if argv is None: @@ -363,8 +365,9 @@ def __init__(self, *, argv=None): os.environ['HATHOR_CONFIG_YAML'] = TESTNET_SETTINGS_FILEPATH try: - HathorSettings() + get_settings() except (TypeError, ValidationError) as e: + from hathor.exception import PreInitializationError raise PreInitializationError( 'An error was found while trying to initialize HathorSettings. See above for details.' ) from e diff --git a/hathor/cli/run_node_args.py b/hathor/cli/run_node_args.py index bde32a6e8..cedde578d 100644 --- a/hathor/cli/run_node_args.py +++ b/hathor/cli/run_node_args.py @@ -16,8 +16,8 @@ from pydantic import Extra -from hathor.feature_activation.feature import Feature -from hathor.utils.pydantic import BaseModel +from hathor.feature_activation.feature import Feature # no-custom-check +from hathor.utils.pydantic import BaseModel # no-custom-check class RunNodeArgs(BaseModel, extra=Extra.allow): diff --git a/hathor/cli/shell.py b/hathor/cli/shell.py index 0a1de97d8..c51bd1537 100644 --- a/hathor/cli/shell.py +++ b/hathor/cli/shell.py @@ -15,7 +15,7 @@ from argparse import Namespace from typing import Any, Callable -from hathor.cli.run_node import RunNode +from hathor.cli.run_node import RunNode # no-custom-check def get_ipython(extra_args: list[Any], imported_objects: dict[str, Any]) -> Callable[[], None]: diff --git a/hathor/cli/twin_tx.py b/hathor/cli/twin_tx.py index f55274368..f57c4ee97 100644 --- a/hathor/cli/twin_tx.py +++ b/hathor/cli/twin_tx.py @@ -19,8 +19,6 @@ import requests -from hathor.mining.cpu_mining_service import CpuMiningService - def create_parser() -> ArgumentParser: from hathor.cli.util import create_parser @@ -36,6 +34,7 @@ def create_parser() -> ArgumentParser: def execute(args: Namespace) -> None: + from hathor.mining.cpu_mining_service import CpuMiningService from hathor.transaction import Transaction # Get tx you want to create a twin