From cecd0efa8915162ed3adcd5db3738987f57cca4d Mon Sep 17 00:00:00 2001 From: dustinface <35775977+xdustinface@users.noreply.github.com> Date: Wed, 20 Apr 2022 20:09:41 +0200 Subject: [PATCH] streamable: Enable `isort` + more `mypy` (#10539) * isort: Fix `streamable.py` and `test_streamable.py` * mypy: Drop `streamable.py` and `test_streamable.py` form exclusion And fix all the mypy issues. * Fix `pylint` * Introduce `ParseFunctionType` and `StreamFunctionType` * Use `object` instead of `Type[Any]` for `is_type_*` functions * Some `Any` -> `object` * Use `typing.overload` for `recurse_jsonify` * Move some comments * Drop `Union`, use `Literal` properly * Explicitly ignore the return of `f_type.parse` Co-authored-by: Kyle Altendorf * Merge two `recurse_jsonify` overloads * Typing for the base definition of `recurse_jsonify` Co-authored-by: Kyle Altendorf --- .isort.cfg | 2 - chia/util/streamable.py | 117 +++++++++++------ mypy.ini | 2 +- tests/core/util/test_streamable.py | 201 ++++++++++++++++------------- 4 files changed, 192 insertions(+), 130 deletions(-) diff --git a/.isort.cfg b/.isort.cfg index 9ed754a63a73..c96731587add 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -109,7 +109,6 @@ extend_skip= chia/util/profiler.py chia/util/service_groups.py chia/util/ssl_check.py - chia/util/streamable.py chia/util/ws_message.py chia/wallet/cat_wallet/cat_info.py chia/wallet/cat_wallet/cat_utils.py @@ -191,7 +190,6 @@ extend_skip= tests/core/util/test_files.py tests/core/util/test_keychain.py tests/core/util/test_keyring_wrapper.py - tests/core/util/test_streamable.py tests/generator/test_compression.py tests/generator/test_generator_types.py tests/generator/test_list_to_batches.py diff --git a/chia/util/streamable.py b/chia/util/streamable.py index cf545fd4833d..fd5fd468e337 100644 --- a/chia/util/streamable.py +++ b/chia/util/streamable.py @@ -5,7 +5,21 @@ import pprint import sys from enum import Enum -from typing import Any, BinaryIO, Dict, get_type_hints, List, Tuple, Type, TypeVar, Union, Callable, Optional, Iterator +from typing import ( + Any, + BinaryIO, + Callable, + Dict, + Iterator, + List, + Optional, + Tuple, + Type, + TypeVar, + Union, + get_type_hints, + overload, +) from blspy import G1Element, G2Element, PrivateKey from typing_extensions import Literal @@ -58,29 +72,32 @@ class DefinitionError(StreamableError): _T_Streamable = TypeVar("_T_Streamable", bound="Streamable") +ParseFunctionType = Callable[[BinaryIO], object] +StreamFunctionType = Callable[[object, BinaryIO], None] + # Caches to store the fields and (de)serialization methods for all available streamable classes. -FIELDS_FOR_STREAMABLE_CLASS = {} -STREAM_FUNCTIONS_FOR_STREAMABLE_CLASS = {} -PARSE_FUNCTIONS_FOR_STREAMABLE_CLASS = {} +FIELDS_FOR_STREAMABLE_CLASS: Dict[Type[object], Dict[str, Type[object]]] = {} +STREAM_FUNCTIONS_FOR_STREAMABLE_CLASS: Dict[Type[object], List[StreamFunctionType]] = {} +PARSE_FUNCTIONS_FOR_STREAMABLE_CLASS: Dict[Type[object], List[ParseFunctionType]] = {} -def is_type_List(f_type: Type) -> bool: +def is_type_List(f_type: object) -> bool: return get_origin(f_type) == list or f_type == list -def is_type_SpecificOptional(f_type) -> bool: +def is_type_SpecificOptional(f_type: object) -> bool: """ Returns true for types such as Optional[T], but not Optional, or T. """ return get_origin(f_type) == Union and get_args(f_type)[1]() is None -def is_type_Tuple(f_type: Type) -> bool: +def is_type_Tuple(f_type: object) -> bool: return get_origin(f_type) == tuple or f_type == tuple -def dataclass_from_dict(klass, d): +def dataclass_from_dict(klass: Type[Any], d: Any) -> Any: """ Converts a dictionary based on a dataclass, into an instance of that dataclass. Recursively goes through lists, optionals, and dictionaries. @@ -100,7 +117,8 @@ def dataclass_from_dict(klass, d): return tuple(klass_properties) elif dataclasses.is_dataclass(klass): # Type is a dataclass, data is a dictionary - fieldtypes = {f.name: f.type for f in dataclasses.fields(klass)} + hints = get_type_hints(klass) + fieldtypes = {f.name: hints.get(f.name, f.type) for f in dataclasses.fields(klass)} return klass(**{f: dataclass_from_dict(fieldtypes[f], d[f]) for f in d}) elif is_type_List(klass): # Type is a list, data is a list @@ -116,7 +134,17 @@ def dataclass_from_dict(klass, d): return klass(d) -def recurse_jsonify(d): +@overload +def recurse_jsonify(d: Union[List[Any], Tuple[Any, ...]]) -> List[Any]: + ... + + +@overload +def recurse_jsonify(d: Dict[str, Any]) -> Dict[str, Any]: + ... + + +def recurse_jsonify(d: Union[List[Any], Tuple[Any, ...], Dict[str, Any]]) -> Union[List[Any], Dict[str, Any]]: """ Makes bytes objects and unhashable types into strings with 0x, and makes large ints into strings. @@ -173,11 +201,11 @@ def parse_uint32(f: BinaryIO, byteorder: Literal["little", "big"] = "big") -> ui return uint32(int.from_bytes(size_bytes, byteorder)) -def write_uint32(f: BinaryIO, value: uint32, byteorder: Literal["little", "big"] = "big"): +def write_uint32(f: BinaryIO, value: uint32, byteorder: Literal["little", "big"] = "big") -> None: f.write(value.to_bytes(4, byteorder)) -def parse_optional(f: BinaryIO, parse_inner_type_f: Callable[[BinaryIO], Any]) -> Optional[Any]: +def parse_optional(f: BinaryIO, parse_inner_type_f: ParseFunctionType) -> Optional[object]: is_present_bytes = f.read(1) assert is_present_bytes is not None and len(is_present_bytes) == 1 # Checks for EOF if is_present_bytes == bytes([0]): @@ -195,8 +223,8 @@ def parse_bytes(f: BinaryIO) -> bytes: return bytes_read -def parse_list(f: BinaryIO, parse_inner_type_f: Callable[[BinaryIO], Any]) -> List[Any]: - full_list: List = [] +def parse_list(f: BinaryIO, parse_inner_type_f: ParseFunctionType) -> List[object]: + full_list: List[object] = [] # wjb assert inner_type != get_args(List)[0] list_size = parse_uint32(f) for list_index in range(list_size): @@ -204,14 +232,14 @@ def parse_list(f: BinaryIO, parse_inner_type_f: Callable[[BinaryIO], Any]) -> Li return full_list -def parse_tuple(f: BinaryIO, list_parse_inner_type_f: List[Callable[[BinaryIO], Any]]) -> Tuple[Any, ...]: - full_list = [] +def parse_tuple(f: BinaryIO, list_parse_inner_type_f: List[ParseFunctionType]) -> Tuple[object, ...]: + full_list: List[object] = [] for parse_f in list_parse_inner_type_f: full_list.append(parse_f(f)) return tuple(full_list) -def parse_size_hints(f: BinaryIO, f_type: Type, bytes_to_read: int) -> Any: +def parse_size_hints(f: BinaryIO, f_type: Type[Any], bytes_to_read: int) -> Any: bytes_read = f.read(bytes_to_read) assert bytes_read is not None and len(bytes_read) == bytes_to_read return f_type.from_bytes(bytes_read) @@ -224,7 +252,7 @@ def parse_str(f: BinaryIO) -> str: return bytes.decode(str_read_bytes, "utf-8") -def stream_optional(stream_inner_type_func: Callable[[Any, BinaryIO], None], item: Any, f: BinaryIO) -> None: +def stream_optional(stream_inner_type_func: StreamFunctionType, item: Any, f: BinaryIO) -> None: if item is None: f.write(bytes([0])) else: @@ -237,13 +265,13 @@ def stream_bytes(item: Any, f: BinaryIO) -> None: f.write(item) -def stream_list(stream_inner_type_func: Callable[[Any, BinaryIO], None], item: Any, f: BinaryIO) -> None: +def stream_list(stream_inner_type_func: StreamFunctionType, item: Any, f: BinaryIO) -> None: write_uint32(f, uint32(len(item))) for element in item: stream_inner_type_func(element, f) -def stream_tuple(stream_inner_type_funcs: List[Callable[[Any, BinaryIO], None]], item: Any, f: BinaryIO) -> None: +def stream_tuple(stream_inner_type_funcs: List[StreamFunctionType], item: Any, f: BinaryIO) -> None: assert len(stream_inner_type_funcs) == len(item) for i in range(len(item)): stream_inner_type_funcs[i](item[i], f) @@ -255,7 +283,19 @@ def stream_str(item: Any, f: BinaryIO) -> None: f.write(str_bytes) -def streamable(cls: Any): +def stream_bool(item: Any, f: BinaryIO) -> None: + f.write(int(item).to_bytes(1, "big")) + + +def stream_streamable(item: object, f: BinaryIO) -> None: + getattr(item, "stream")(f) + + +def stream_byte_convertible(item: object, f: BinaryIO) -> None: + f.write(getattr(item, "__bytes__")()) + + +def streamable(cls: Type[_T_Streamable]) -> Type[_T_Streamable]: """ This decorator forces correct streamable protocol syntax/usage and populates the caches for types hints and (de)serialization methods for all members of the class. The correct usage is: @@ -279,7 +319,9 @@ class Example(Streamable): raise DefinitionError(f"@dataclass(frozen=True) required first. {correct_usage_string}") try: - object.__new__(cls)._streamable_test_if_dataclass_frozen_ = None + # Ignore mypy here because we especially want to access a not available member to test if + # the dataclass is frozen. + object.__new__(cls)._streamable_test_if_dataclass_frozen_ = None # type: ignore[attr-defined] except dataclasses.FrozenInstanceError: pass else: @@ -352,10 +394,10 @@ class Streamable: Make sure to use the streamable decorator when inheriting from the Streamable class to prepare the streaming caches. """ - def post_init_parse(self, item: Any, f_name: str, f_type: Type) -> Any: + def post_init_parse(self, item: Any, f_name: str, f_type: Type[Any]) -> Any: if is_type_List(f_type): - collected_list: List = [] - inner_type: Type = get_args(f_type)[0] + collected_list: List[Any] = [] + inner_type: Type[Any] = get_args(f_type)[0] # wjb assert inner_type != get_args(List)[0] # type: ignore if not is_type_List(type(item)): raise ValueError(f"Wrong type for {f_name}, need a list.") @@ -391,7 +433,7 @@ def post_init_parse(self, item: Any, f_name: str, f_type: Type) -> Any: raise ValueError(f"Wrong type for {f_name}") return item - def __post_init__(self): + def __post_init__(self) -> None: try: fields = FIELDS_FOR_STREAMABLE_CLASS[type(self)] except Exception: @@ -408,12 +450,12 @@ def __post_init__(self): object.__setattr__(self, f_name, self.post_init_parse(data[f_name], f_name, f_type)) @classmethod - def function_to_parse_one_item(cls, f_type: Type) -> Callable[[BinaryIO], Any]: + def function_to_parse_one_item(cls, f_type: Type[Any]) -> ParseFunctionType: """ This function returns a function taking one argument `f: BinaryIO` that parses and returns a value of the given type. """ - inner_type: Type + inner_type: Type[Any] if f_type is bool: return parse_bool if is_type_SpecificOptional(f_type): @@ -421,7 +463,8 @@ def function_to_parse_one_item(cls, f_type: Type) -> Callable[[BinaryIO], Any]: parse_inner_type_f = cls.function_to_parse_one_item(inner_type) return lambda f: parse_optional(f, parse_inner_type_f) if hasattr(f_type, "parse"): - return f_type.parse + # Ignoring for now as the proper solution isn't obvious + return f_type.parse # type: ignore[no-any-return] if f_type == bytes: return parse_bytes if is_type_List(f_type): @@ -444,7 +487,7 @@ def parse(cls: Type[_T_Streamable], f: BinaryIO) -> _T_Streamable: # Create the object without calling __init__() to avoid unnecessary post-init checks in strictdataclass obj: _T_Streamable = object.__new__(cls) fields: Iterator[str] = iter(FIELDS_FOR_STREAMABLE_CLASS.get(cls, {})) - values: Iterator = (parse_f(f) for parse_f in PARSE_FUNCTIONS_FOR_STREAMABLE_CLASS[cls]) + values: Iterator[object] = (parse_f(f) for parse_f in PARSE_FUNCTIONS_FOR_STREAMABLE_CLASS[cls]) for field, value in zip(fields, values): object.__setattr__(obj, field, value) @@ -456,8 +499,8 @@ def parse(cls: Type[_T_Streamable], f: BinaryIO) -> _T_Streamable: return obj @classmethod - def function_to_stream_one_item(cls, f_type: Type) -> Callable[[Any, BinaryIO], Any]: - inner_type: Type + def function_to_stream_one_item(cls, f_type: Type[Any]) -> StreamFunctionType: + inner_type: Type[Any] if is_type_SpecificOptional(f_type): inner_type = get_args(f_type)[0] stream_inner_type_func = cls.function_to_stream_one_item(inner_type) @@ -465,9 +508,9 @@ def function_to_stream_one_item(cls, f_type: Type) -> Callable[[Any, BinaryIO], elif f_type == bytes: return stream_bytes elif hasattr(f_type, "stream"): - return lambda item, f: item.stream(f) + return stream_streamable elif hasattr(f_type, "__bytes__"): - return lambda item, f: f.write(bytes(item)) + return stream_byte_convertible elif is_type_List(f_type): inner_type = get_args(f_type)[0] stream_inner_type_func = cls.function_to_stream_one_item(inner_type) @@ -481,7 +524,7 @@ def function_to_stream_one_item(cls, f_type: Type) -> Callable[[Any, BinaryIO], elif f_type is str: return stream_str elif f_type is bool: - return lambda item, f: f.write(int(item).to_bytes(1, "big")) + return stream_bool else: raise NotImplementedError(f"can't stream {f_type}") @@ -518,9 +561,9 @@ def __str__(self: Any) -> str: def __repr__(self: Any) -> str: return pp.pformat(recurse_jsonify(dataclasses.asdict(self))) - def to_json_dict(self) -> Dict: + def to_json_dict(self) -> Dict[str, Any]: return recurse_jsonify(dataclasses.asdict(self)) @classmethod - def from_json_dict(cls: Any, json_dict: Dict) -> Any: + def from_json_dict(cls: Any, json_dict: Dict[str, Any]) -> Any: return dataclass_from_dict(cls, json_dict) diff --git a/mypy.ini b/mypy.ini index 4c3f96cbfd0f..795d940d34fd 100644 --- a/mypy.ini +++ b/mypy.ini @@ -17,7 +17,7 @@ no_implicit_reexport = True strict_equality = True # list created by: venv/bin/mypy | sed -n 's/.py:.*//p' | sort | uniq | tr '/' '.' | tr '\n' ',' -[mypy-benchmarks.block_ref,benchmarks.block_store,benchmarks.coin_store,benchmarks.utils,build_scripts.installer-version,chia.clvm.spend_sim,chia.cmds.configure,chia.cmds.db,chia.cmds.db_upgrade_func,chia.cmds.farm_funcs,chia.cmds.init,chia.cmds.init_funcs,chia.cmds.keys,chia.cmds.keys_funcs,chia.cmds.passphrase,chia.cmds.passphrase_funcs,chia.cmds.plotnft,chia.cmds.plotnft_funcs,chia.cmds.plots,chia.cmds.plotters,chia.cmds.show,chia.cmds.start_funcs,chia.cmds.wallet,chia.cmds.wallet_funcs,chia.consensus.block_body_validation,chia.consensus.blockchain,chia.consensus.blockchain_interface,chia.consensus.block_creation,chia.consensus.block_header_validation,chia.consensus.block_record,chia.consensus.block_root_validation,chia.consensus.coinbase,chia.consensus.constants,chia.consensus.difficulty_adjustment,chia.consensus.get_block_challenge,chia.consensus.multiprocess_validation,chia.consensus.pos_quality,chia.consensus.vdf_info_computation,chia.daemon.client,chia.daemon.keychain_proxy,chia.daemon.keychain_server,chia.daemon.server,chia.farmer.farmer,chia.farmer.farmer_api,chia.full_node.block_height_map,chia.full_node.block_store,chia.full_node.bundle_tools,chia.full_node.coin_store,chia.full_node.full_node,chia.full_node.full_node_api,chia.full_node.full_node_store,chia.full_node.generator,chia.full_node.hint_store,chia.full_node.lock_queue,chia.full_node.mempool,chia.full_node.mempool_check_conditions,chia.full_node.mempool_manager,chia.full_node.pending_tx_cache,chia.full_node.sync_store,chia.full_node.weight_proof,chia.harvester.harvester,chia.harvester.harvester_api,chia.introducer.introducer,chia.introducer.introducer_api,chia.plotters.bladebit,chia.plotters.chiapos,chia.plotters.install_plotter,chia.plotters.madmax,chia.plotters.plotters,chia.plotters.plotters_util,chia.plotting.check_plots,chia.plotting.create_plots,chia.plotting.manager,chia.plotting.util,chia.pools.pool_config,chia.pools.pool_puzzles,chia.pools.pool_wallet,chia.pools.pool_wallet_info,chia.protocols.pool_protocol,chia.rpc.crawler_rpc_api,chia.rpc.farmer_rpc_api,chia.rpc.farmer_rpc_client,chia.rpc.full_node_rpc_api,chia.rpc.full_node_rpc_client,chia.rpc.harvester_rpc_api,chia.rpc.harvester_rpc_client,chia.rpc.rpc_client,chia.rpc.rpc_server,chia.rpc.timelord_rpc_api,chia.rpc.util,chia.rpc.wallet_rpc_api,chia.rpc.wallet_rpc_client,chia.seeder.crawler,chia.seeder.crawler_api,chia.seeder.crawl_store,chia.seeder.dns_server,chia.seeder.peer_record,chia.seeder.start_crawler,chia.server.address_manager,chia.server.address_manager_store,chia.server.connection_utils,chia.server.introducer_peers,chia.server.node_discovery,chia.server.peer_store_resolver,chia.server.rate_limits,chia.server.reconnect_task,chia.server.server,chia.server.ssl_context,chia.server.start_farmer,chia.server.start_full_node,chia.server.start_harvester,chia.server.start_introducer,chia.server.start_service,chia.server.start_timelord,chia.server.start_wallet,chia.server.upnp,chia.server.ws_connection,chia.simulator.full_node_simulator,chia.simulator.start_simulator,chia.ssl.create_ssl,chia.timelord.iters_from_block,chia.timelord.timelord,chia.timelord.timelord_api,chia.timelord.timelord_launcher,chia.timelord.timelord_state,chia.types.announcement,chia.types.blockchain_format.classgroup,chia.types.blockchain_format.coin,chia.types.blockchain_format.program,chia.types.blockchain_format.proof_of_space,chia.types.blockchain_format.tree_hash,chia.types.blockchain_format.vdf,chia.types.full_block,chia.types.header_block,chia.types.mempool_item,chia.types.name_puzzle_condition,chia.types.peer_info,chia.types.spend_bundle,chia.types.transaction_queue_entry,chia.types.unfinished_block,chia.types.unfinished_header_block,chia.util.api_decorators,chia.util.block_cache,chia.util.byte_types,chia.util.cached_bls,chia.util.check_fork_next_block,chia.util.chia_logging,chia.util.config,chia.util.db_wrapper,chia.util.dump_keyring,chia.util.file_keyring,chia.util.files,chia.util.hash,chia.util.ints,chia.util.json_util,chia.util.keychain,chia.util.keyring_wrapper,chia.util.log_exceptions,chia.util.lru_cache,chia.util.make_test_constants,chia.util.merkle_set,chia.util.network,chia.util.partial_func,chia.util.pip_import,chia.util.profiler,chia.util.safe_cancel_task,chia.util.service_groups,chia.util.ssl_check,chia.util.streamable,chia.util.struct_stream,chia.util.validate_alert,chia.wallet.block_record,chia.wallet.cat_wallet.cat_utils,chia.wallet.cat_wallet.cat_wallet,chia.wallet.cat_wallet.lineage_store,chia.wallet.chialisp,chia.wallet.did_wallet.did_wallet,chia.wallet.did_wallet.did_wallet_puzzles,chia.wallet.key_val_store,chia.wallet.lineage_proof,chia.wallet.payment,chia.wallet.puzzles.load_clvm,chia.wallet.puzzles.p2_conditions,chia.wallet.puzzles.p2_delegated_conditions,chia.wallet.puzzles.p2_delegated_puzzle,chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle,chia.wallet.puzzles.p2_m_of_n_delegate_direct,chia.wallet.puzzles.p2_puzzle_hash,chia.wallet.puzzles.prefarm.spend_prefarm,chia.wallet.puzzles.puzzle_utils,chia.wallet.puzzles.rom_bootstrap_generator,chia.wallet.puzzles.singleton_top_layer,chia.wallet.puzzles.tails,chia.wallet.rl_wallet.rl_wallet,chia.wallet.rl_wallet.rl_wallet_puzzles,chia.wallet.secret_key_store,chia.wallet.settings.user_settings,chia.wallet.trade_manager,chia.wallet.trade_record,chia.wallet.trading.offer,chia.wallet.trading.trade_store,chia.wallet.transaction_record,chia.wallet.util.debug_spend_bundle,chia.wallet.util.new_peak_queue,chia.wallet.util.peer_request_cache,chia.wallet.util.wallet_sync_utils,chia.wallet.wallet,chia.wallet.wallet_action_store,chia.wallet.wallet_blockchain,chia.wallet.wallet_coin_store,chia.wallet.wallet_interested_store,chia.wallet.wallet_node,chia.wallet.wallet_node_api,chia.wallet.wallet_pool_store,chia.wallet.wallet_puzzle_store,chia.wallet.wallet_state_manager,chia.wallet.wallet_sync_store,chia.wallet.wallet_transaction_store,chia.wallet.wallet_user_store,chia.wallet.wallet_weight_proof_handler,installhelper,tests.blockchain.blockchain_test_utils,tests.blockchain.test_blockchain,tests.blockchain.test_blockchain_transactions,tests.block_tools,tests.build-init-files,tests.build-workflows,tests.clvm.coin_store,tests.clvm.test_chialisp_deserialization,tests.clvm.test_clvm_compilation,tests.clvm.test_program,tests.clvm.test_puzzle_compression,tests.clvm.test_puzzles,tests.clvm.test_serialized_program,tests.clvm.test_singletons,tests.clvm.test_spend_sim,tests.conftest,tests.connection_utils,tests.core.cmds.test_keys,tests.core.consensus.test_pot_iterations,tests.core.custom_types.test_coin,tests.core.custom_types.test_proof_of_space,tests.core.custom_types.test_spend_bundle,tests.core.daemon.test_daemon,tests.core.full_node.full_sync.test_full_sync,tests.core.full_node.stores.test_block_store,tests.core.full_node.stores.test_coin_store,tests.core.full_node.stores.test_full_node_store,tests.core.full_node.stores.test_hint_store,tests.core.full_node.stores.test_sync_store,tests.core.full_node.test_address_manager,tests.core.full_node.test_block_height_map,tests.core.full_node.test_conditions,tests.core.full_node.test_full_node,tests.core.full_node.test_mempool,tests.core.full_node.test_mempool_performance,tests.core.full_node.test_node_load,tests.core.full_node.test_peer_store_resolver,tests.core.full_node.test_performance,tests.core.full_node.test_transactions,tests.core.make_block_generator,tests.core.node_height,tests.core.server.test_dos,tests.core.server.test_rate_limits,tests.core.ssl.test_ssl,tests.core.test_cost_calculation,tests.core.test_crawler_rpc,tests.core.test_daemon_rpc,tests.core.test_db_conversion,tests.core.test_farmer_harvester_rpc,tests.core.test_filter,tests.core.test_full_node_rpc,tests.core.test_merkle_set,tests.core.test_setproctitle,tests.core.util.test_cached_bls,tests.core.util.test_config,tests.core.util.test_file_keyring_synchronization,tests.core.util.test_files,tests.core.util.test_keychain,tests.core.util.test_keyring_wrapper,tests.core.util.test_lru_cache,tests.core.util.test_significant_bits,tests.core.util.test_streamable,tests.farmer_harvester.test_farmer_harvester,tests.generator.test_compression,tests.generator.test_generator_types,tests.generator.test_list_to_batches,tests.generator.test_rom,tests.generator.test_scan,tests.plotting.test_plot_manager,tests.pools.test_pool_cmdline,tests.pools.test_pool_config,tests.pools.test_pool_puzzles_lifecycle,tests.pools.test_pool_rpc,tests.pools.test_wallet_pool_store,tests.setup_nodes,tests.setup_services,tests.simulation.test_simulation,tests.time_out_assert,tests.tools.test_full_sync,tests.tools.test_run_block,tests.util.alert_server,tests.util.benchmark_cost,tests.util.blockchain,tests.util.build_network_protocol_files,tests.util.db_connection,tests.util.generator_tools_testing,tests.util.keyring,tests.util.key_tool,tests.util.misc,tests.util.network,tests.util.rpc,tests.util.test_full_block_utils,tests.util.test_lock_queue,tests.util.test_network_protocol_files,tests.util.test_struct_stream,tests.wallet.cat_wallet.test_cat_lifecycle,tests.wallet.cat_wallet.test_cat_wallet,tests.wallet.cat_wallet.test_offer_lifecycle,tests.wallet.cat_wallet.test_trades,tests.wallet.did_wallet.test_did,tests.wallet.did_wallet.test_did_rpc,tests.wallet.rl_wallet.test_rl_rpc,tests.wallet.rl_wallet.test_rl_wallet,tests.wallet.rpc.test_wallet_rpc,tests.wallet.simple_sync.test_simple_sync_protocol,tests.wallet.sync.test_wallet_sync,tests.wallet.test_bech32m,tests.wallet.test_chialisp,tests.wallet.test_puzzle_store,tests.wallet.test_singleton,tests.wallet.test_singleton_lifecycle,tests.wallet.test_singleton_lifecycle_fast,tests.wallet.test_taproot,tests.wallet.test_wallet,tests.wallet.test_wallet_blockchain,tests.wallet.test_wallet_interested_store,tests.wallet.test_wallet_key_val_store,tests.wallet.test_wallet_user_store,tests.wallet_tools,tests.weight_proof.test_weight_proof,tools.analyze-chain,tools.run_block,tools.test_full_sync] +[mypy-benchmarks.block_ref,benchmarks.block_store,benchmarks.coin_store,benchmarks.utils,build_scripts.installer-version,chia.clvm.spend_sim,chia.cmds.configure,chia.cmds.db,chia.cmds.db_upgrade_func,chia.cmds.farm_funcs,chia.cmds.init,chia.cmds.init_funcs,chia.cmds.keys,chia.cmds.keys_funcs,chia.cmds.passphrase,chia.cmds.passphrase_funcs,chia.cmds.plotnft,chia.cmds.plotnft_funcs,chia.cmds.plots,chia.cmds.plotters,chia.cmds.show,chia.cmds.start_funcs,chia.cmds.wallet,chia.cmds.wallet_funcs,chia.consensus.block_body_validation,chia.consensus.blockchain,chia.consensus.blockchain_interface,chia.consensus.block_creation,chia.consensus.block_header_validation,chia.consensus.block_record,chia.consensus.block_root_validation,chia.consensus.coinbase,chia.consensus.constants,chia.consensus.difficulty_adjustment,chia.consensus.get_block_challenge,chia.consensus.multiprocess_validation,chia.consensus.pos_quality,chia.consensus.vdf_info_computation,chia.daemon.client,chia.daemon.keychain_proxy,chia.daemon.keychain_server,chia.daemon.server,chia.farmer.farmer,chia.farmer.farmer_api,chia.full_node.block_height_map,chia.full_node.block_store,chia.full_node.bundle_tools,chia.full_node.coin_store,chia.full_node.full_node,chia.full_node.full_node_api,chia.full_node.full_node_store,chia.full_node.generator,chia.full_node.hint_store,chia.full_node.lock_queue,chia.full_node.mempool,chia.full_node.mempool_check_conditions,chia.full_node.mempool_manager,chia.full_node.pending_tx_cache,chia.full_node.sync_store,chia.full_node.weight_proof,chia.harvester.harvester,chia.harvester.harvester_api,chia.introducer.introducer,chia.introducer.introducer_api,chia.plotters.bladebit,chia.plotters.chiapos,chia.plotters.install_plotter,chia.plotters.madmax,chia.plotters.plotters,chia.plotters.plotters_util,chia.plotting.check_plots,chia.plotting.create_plots,chia.plotting.manager,chia.plotting.util,chia.pools.pool_config,chia.pools.pool_puzzles,chia.pools.pool_wallet,chia.pools.pool_wallet_info,chia.protocols.pool_protocol,chia.rpc.crawler_rpc_api,chia.rpc.farmer_rpc_api,chia.rpc.farmer_rpc_client,chia.rpc.full_node_rpc_api,chia.rpc.full_node_rpc_client,chia.rpc.harvester_rpc_api,chia.rpc.harvester_rpc_client,chia.rpc.rpc_client,chia.rpc.rpc_server,chia.rpc.timelord_rpc_api,chia.rpc.util,chia.rpc.wallet_rpc_api,chia.rpc.wallet_rpc_client,chia.seeder.crawler,chia.seeder.crawler_api,chia.seeder.crawl_store,chia.seeder.dns_server,chia.seeder.peer_record,chia.seeder.start_crawler,chia.server.address_manager,chia.server.address_manager_store,chia.server.connection_utils,chia.server.introducer_peers,chia.server.node_discovery,chia.server.peer_store_resolver,chia.server.rate_limits,chia.server.reconnect_task,chia.server.server,chia.server.ssl_context,chia.server.start_farmer,chia.server.start_full_node,chia.server.start_harvester,chia.server.start_introducer,chia.server.start_service,chia.server.start_timelord,chia.server.start_wallet,chia.server.upnp,chia.server.ws_connection,chia.simulator.full_node_simulator,chia.simulator.start_simulator,chia.ssl.create_ssl,chia.timelord.iters_from_block,chia.timelord.timelord,chia.timelord.timelord_api,chia.timelord.timelord_launcher,chia.timelord.timelord_state,chia.types.announcement,chia.types.blockchain_format.classgroup,chia.types.blockchain_format.coin,chia.types.blockchain_format.program,chia.types.blockchain_format.proof_of_space,chia.types.blockchain_format.tree_hash,chia.types.blockchain_format.vdf,chia.types.full_block,chia.types.header_block,chia.types.mempool_item,chia.types.name_puzzle_condition,chia.types.peer_info,chia.types.spend_bundle,chia.types.transaction_queue_entry,chia.types.unfinished_block,chia.types.unfinished_header_block,chia.util.api_decorators,chia.util.block_cache,chia.util.byte_types,chia.util.cached_bls,chia.util.check_fork_next_block,chia.util.chia_logging,chia.util.config,chia.util.db_wrapper,chia.util.dump_keyring,chia.util.file_keyring,chia.util.files,chia.util.hash,chia.util.ints,chia.util.json_util,chia.util.keychain,chia.util.keyring_wrapper,chia.util.log_exceptions,chia.util.lru_cache,chia.util.make_test_constants,chia.util.merkle_set,chia.util.network,chia.util.partial_func,chia.util.pip_import,chia.util.profiler,chia.util.safe_cancel_task,chia.util.service_groups,chia.util.ssl_check,chia.util.struct_stream,chia.util.validate_alert,chia.wallet.block_record,chia.wallet.cat_wallet.cat_utils,chia.wallet.cat_wallet.cat_wallet,chia.wallet.cat_wallet.lineage_store,chia.wallet.chialisp,chia.wallet.did_wallet.did_wallet,chia.wallet.did_wallet.did_wallet_puzzles,chia.wallet.key_val_store,chia.wallet.lineage_proof,chia.wallet.payment,chia.wallet.puzzles.load_clvm,chia.wallet.puzzles.p2_conditions,chia.wallet.puzzles.p2_delegated_conditions,chia.wallet.puzzles.p2_delegated_puzzle,chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle,chia.wallet.puzzles.p2_m_of_n_delegate_direct,chia.wallet.puzzles.p2_puzzle_hash,chia.wallet.puzzles.prefarm.spend_prefarm,chia.wallet.puzzles.puzzle_utils,chia.wallet.puzzles.rom_bootstrap_generator,chia.wallet.puzzles.singleton_top_layer,chia.wallet.puzzles.tails,chia.wallet.rl_wallet.rl_wallet,chia.wallet.rl_wallet.rl_wallet_puzzles,chia.wallet.secret_key_store,chia.wallet.settings.user_settings,chia.wallet.trade_manager,chia.wallet.trade_record,chia.wallet.trading.offer,chia.wallet.trading.trade_store,chia.wallet.transaction_record,chia.wallet.util.debug_spend_bundle,chia.wallet.util.new_peak_queue,chia.wallet.util.peer_request_cache,chia.wallet.util.wallet_sync_utils,chia.wallet.wallet,chia.wallet.wallet_action_store,chia.wallet.wallet_blockchain,chia.wallet.wallet_coin_store,chia.wallet.wallet_interested_store,chia.wallet.wallet_node,chia.wallet.wallet_node_api,chia.wallet.wallet_pool_store,chia.wallet.wallet_puzzle_store,chia.wallet.wallet_state_manager,chia.wallet.wallet_sync_store,chia.wallet.wallet_transaction_store,chia.wallet.wallet_user_store,chia.wallet.wallet_weight_proof_handler,installhelper,tests.blockchain.blockchain_test_utils,tests.blockchain.test_blockchain,tests.blockchain.test_blockchain_transactions,tests.block_tools,tests.build-init-files,tests.build-workflows,tests.clvm.coin_store,tests.clvm.test_chialisp_deserialization,tests.clvm.test_clvm_compilation,tests.clvm.test_program,tests.clvm.test_puzzle_compression,tests.clvm.test_puzzles,tests.clvm.test_serialized_program,tests.clvm.test_singletons,tests.clvm.test_spend_sim,tests.conftest,tests.connection_utils,tests.core.cmds.test_keys,tests.core.consensus.test_pot_iterations,tests.core.custom_types.test_coin,tests.core.custom_types.test_proof_of_space,tests.core.custom_types.test_spend_bundle,tests.core.daemon.test_daemon,tests.core.full_node.full_sync.test_full_sync,tests.core.full_node.stores.test_block_store,tests.core.full_node.stores.test_coin_store,tests.core.full_node.stores.test_full_node_store,tests.core.full_node.stores.test_hint_store,tests.core.full_node.stores.test_sync_store,tests.core.full_node.test_address_manager,tests.core.full_node.test_block_height_map,tests.core.full_node.test_conditions,tests.core.full_node.test_full_node,tests.core.full_node.test_mempool,tests.core.full_node.test_mempool_performance,tests.core.full_node.test_node_load,tests.core.full_node.test_peer_store_resolver,tests.core.full_node.test_performance,tests.core.full_node.test_transactions,tests.core.make_block_generator,tests.core.node_height,tests.core.server.test_dos,tests.core.server.test_rate_limits,tests.core.ssl.test_ssl,tests.core.test_cost_calculation,tests.core.test_crawler_rpc,tests.core.test_daemon_rpc,tests.core.test_db_conversion,tests.core.test_farmer_harvester_rpc,tests.core.test_filter,tests.core.test_full_node_rpc,tests.core.test_merkle_set,tests.core.test_setproctitle,tests.core.util.test_cached_bls,tests.core.util.test_config,tests.core.util.test_file_keyring_synchronization,tests.core.util.test_files,tests.core.util.test_keychain,tests.core.util.test_keyring_wrapper,tests.core.util.test_lru_cache,tests.core.util.test_significant_bits,tests.farmer_harvester.test_farmer_harvester,tests.generator.test_compression,tests.generator.test_generator_types,tests.generator.test_list_to_batches,tests.generator.test_rom,tests.generator.test_scan,tests.plotting.test_plot_manager,tests.pools.test_pool_cmdline,tests.pools.test_pool_config,tests.pools.test_pool_puzzles_lifecycle,tests.pools.test_pool_rpc,tests.pools.test_wallet_pool_store,tests.setup_nodes,tests.setup_services,tests.simulation.test_simulation,tests.time_out_assert,tests.tools.test_full_sync,tests.tools.test_run_block,tests.util.alert_server,tests.util.benchmark_cost,tests.util.blockchain,tests.util.build_network_protocol_files,tests.util.db_connection,tests.util.generator_tools_testing,tests.util.keyring,tests.util.key_tool,tests.util.misc,tests.util.network,tests.util.rpc,tests.util.test_full_block_utils,tests.util.test_lock_queue,tests.util.test_network_protocol_files,tests.util.test_struct_stream,tests.wallet.cat_wallet.test_cat_lifecycle,tests.wallet.cat_wallet.test_cat_wallet,tests.wallet.cat_wallet.test_offer_lifecycle,tests.wallet.cat_wallet.test_trades,tests.wallet.did_wallet.test_did,tests.wallet.did_wallet.test_did_rpc,tests.wallet.rl_wallet.test_rl_rpc,tests.wallet.rl_wallet.test_rl_wallet,tests.wallet.rpc.test_wallet_rpc,tests.wallet.simple_sync.test_simple_sync_protocol,tests.wallet.sync.test_wallet_sync,tests.wallet.test_bech32m,tests.wallet.test_chialisp,tests.wallet.test_puzzle_store,tests.wallet.test_singleton,tests.wallet.test_singleton_lifecycle,tests.wallet.test_singleton_lifecycle_fast,tests.wallet.test_taproot,tests.wallet.test_wallet,tests.wallet.test_wallet_blockchain,tests.wallet.test_wallet_interested_store,tests.wallet.test_wallet_key_val_store,tests.wallet.test_wallet_user_store,tests.wallet_tools,tests.weight_proof.test_weight_proof,tools.analyze-chain,tools.run_block,tools.test_full_sync] disallow_any_generics = False disallow_subclassing_any = False disallow_untyped_calls = False diff --git a/tests/core/util/test_streamable.py b/tests/core/util/test_streamable.py index 65b3255212ee..28b0a3ba6644 100644 --- a/tests/core/util/test_streamable.py +++ b/tests/core/util/test_streamable.py @@ -1,10 +1,13 @@ +from __future__ import annotations + +import io from dataclasses import dataclass from typing import Dict, List, Optional, Tuple -import io -import pytest +import pytest from clvm_tools import binutils from pytest import raises +from typing_extensions import Literal from chia.protocols.wallet_protocol import RespondRemovals from chia.types.blockchain_format.coin import Coin @@ -16,19 +19,20 @@ from chia.util.streamable import ( DefinitionError, Streamable, - streamable, + is_type_List, + is_type_SpecificOptional, parse_bool, - parse_uint32, - write_uint32, - parse_optional, parse_bytes, parse_list, - parse_tuple, + parse_optional, parse_size_hints, parse_str, - is_type_List, - is_type_SpecificOptional, + parse_tuple, + parse_uint32, + streamable, + write_uint32, ) +from tests.block_tools import BlockTools from tests.setup_nodes import test_constants @@ -59,22 +63,26 @@ class TestClassDict(Streamable): a: Dict[str, str] +@dataclass(frozen=True) +class DataclassOnly: + a: uint8 + + def test_pure_dataclass_not_supported() -> None: - @dataclass(frozen=True) - class DataClassOnly: - a: uint8 with raises(NotImplementedError): @streamable @dataclass(frozen=True) class TestClassDataclass(Streamable): - a: DataClassOnly + a: DataclassOnly + + +class PlainClass: + a: uint8 def test_plain_class_not_supported() -> None: - class PlainClass: - a: uint8 with raises(NotImplementedError): @@ -84,74 +92,81 @@ class TestClassPlain(Streamable): a: PlainClass -def test_basic_list(): +def test_basic_list() -> None: a = [1, 2, 3] assert is_type_List(type(a)) assert is_type_List(List) assert is_type_List(List[int]) assert is_type_List(List[uint8]) assert is_type_List(list) - assert not is_type_List(Tuple) + assert not is_type_List(type(Tuple)) assert not is_type_List(tuple) assert not is_type_List(dict) -def test_not_lists(): +def test_not_lists() -> None: assert not is_type_List(Dict) -def test_basic_optional(): +def test_basic_optional() -> None: assert is_type_SpecificOptional(Optional[int]) assert is_type_SpecificOptional(Optional[Optional[int]]) assert not is_type_SpecificOptional(List[int]) -def test_StrictDataClass(): +def test_StrictDataClass() -> None: @streamable @dataclass(frozen=True) class TestClass1(Streamable): a: uint8 b: str - good: TestClass1 = TestClass1(24, "!@12") + # we want to test invalid here, hence the ignore. + good: TestClass1 = TestClass1(24, "!@12") # type: ignore[arg-type] assert TestClass1.__name__ == "TestClass1" assert good assert good.a == 24 assert good.b == "!@12" - good2 = TestClass1(52, bytes([1, 2, 3])) + # we want to test invalid here, hence the ignore. + good2 = TestClass1(52, bytes([1, 2, 3])) # type: ignore[arg-type] assert good2.b == str(bytes([1, 2, 3])) -def test_StrictDataClassBad(): +def test_StrictDataClassBad() -> None: @streamable @dataclass(frozen=True) class TestClass2(Streamable): a: uint8 b = 0 - assert TestClass2(25) + # we want to test invalid here, hence the ignore. + assert TestClass2(25) # type: ignore[arg-type] + # we want to test invalid here, hence the ignore. with raises(TypeError): - TestClass2(1, 2) # pylint: disable=too-many-function-args + TestClass2(1, 2) # type: ignore[call-arg,arg-type] # pylint: disable=too-many-function-args -def test_StrictDataClassLists(): +def test_StrictDataClassLists() -> None: @streamable @dataclass(frozen=True) class TestClass(Streamable): a: List[uint8] b: List[List[uint8]] - assert TestClass([1, 2, 3], [[uint8(200), uint8(25)], [uint8(25)]]) + # we want to test invalid here, hence the ignore. + assert TestClass([1, 2, 3], [[uint8(200), uint8(25)], [uint8(25)]]) # type: ignore[list-item] + # we want to test invalid here, hence the ignore. with raises(ValueError): - TestClass({"1": 1}, [[uint8(200), uint8(25)], [uint8(25)]]) + TestClass({"1": 1}, [[uint8(200), uint8(25)], [uint8(25)]]) # type: ignore[arg-type] + # we want to test invalid here, hence the ignore. with raises(ValueError): - TestClass([1, 2, 3], [uint8(200), uint8(25)]) + TestClass([1, 2, 3], [uint8(200), uint8(25)]) # type: ignore[list-item] -def test_StrictDataClassOptional(): +def test_StrictDataClassOptional() -> None: @streamable @dataclass(frozen=True) class TestClass(Streamable): @@ -160,11 +175,12 @@ class TestClass(Streamable): c: Optional[Optional[uint8]] d: Optional[Optional[uint8]] - good = TestClass(12, None, 13, None) + # we want to test invalid here, hence the ignore. + good = TestClass(12, None, 13, None) # type: ignore[arg-type] assert good -def test_basic(): +def test_basic() -> None: @streamable @dataclass(frozen=True) class TestClass(Streamable): @@ -176,13 +192,14 @@ class TestClass(Streamable): f: Optional[uint32] g: Tuple[uint32, str, bytes] - a = TestClass(24, 352, [1, 2, 4], [[1, 2, 3], [3, 4]], 728, None, (383, "hello", b"goodbye")) + # we want to test invalid here, hence the ignore. + a = TestClass(24, 352, [1, 2, 4], [[1, 2, 3], [3, 4]], 728, None, (383, "hello", b"goodbye")) # type: ignore[arg-type,list-item] # noqa: E501 b: bytes = bytes(a) assert a == TestClass.from_bytes(b) -def test_variable_size(): +def test_variable_size() -> None: @streamable @dataclass(frozen=True) class TestClass2(Streamable): @@ -201,7 +218,7 @@ class TestClass3(Streamable): a: int -def test_json(bt): +def test_json(bt: BlockTools) -> None: block = bt.create_genesis_block(test_constants, bytes32([0] * 32), uint64(0)) dict_block = block.to_json_dict() assert FullBlock.from_json_dict(dict_block) == block @@ -226,42 +243,44 @@ class OptionalTestClass(Streamable): (None, None, None), ], ) -def test_optional_json(a: Optional[str], b: Optional[bool], c: Optional[List[Optional[str]]]): +def test_optional_json(a: Optional[str], b: Optional[bool], c: Optional[List[Optional[str]]]) -> None: obj: OptionalTestClass = OptionalTestClass.from_json_dict({"a": a, "b": b, "c": c}) assert obj.a == a assert obj.b == b assert obj.c == c -def test_recursive_json(): - @streamable - @dataclass(frozen=True) - class TestClass1(Streamable): - a: List[uint32] +@streamable +@dataclass(frozen=True) +class TestClassRecursive1(Streamable): + a: List[uint32] + + +@streamable +@dataclass(frozen=True) +class TestClassRecursive2(Streamable): + a: uint32 + b: List[Optional[List[TestClassRecursive1]]] + c: bytes32 - @streamable - @dataclass(frozen=True) - class TestClass2(Streamable): - a: uint32 - b: List[Optional[List[TestClass1]]] - c: bytes32 - tc1_a = TestClass1([uint32(1), uint32(2)]) - tc1_b = TestClass1([uint32(4), uint32(5)]) - tc1_c = TestClass1([uint32(7), uint32(8)]) +def test_recursive_json() -> None: + tc1_a = TestClassRecursive1([uint32(1), uint32(2)]) + tc1_b = TestClassRecursive1([uint32(4), uint32(5)]) + tc1_c = TestClassRecursive1([uint32(7), uint32(8)]) - tc2 = TestClass2(uint32(5), [[tc1_a], [tc1_b, tc1_c], None], bytes32(bytes([1] * 32))) - assert TestClass2.from_json_dict(tc2.to_json_dict()) == tc2 + tc2 = TestClassRecursive2(uint32(5), [[tc1_a], [tc1_b, tc1_c], None], bytes32(bytes([1] * 32))) + assert TestClassRecursive2.from_json_dict(tc2.to_json_dict()) == tc2 -def test_recursive_types(): +def test_recursive_types() -> None: coin: Optional[Coin] = None l1 = [(bytes32([2] * 32), coin)] rr = RespondRemovals(uint32(1), bytes32([1] * 32), l1, None) RespondRemovals(rr.height, rr.header_hash, rr.coins, rr.proofs) -def test_ambiguous_deserialization_optionals(): +def test_ambiguous_deserialization_optionals() -> None: with raises(AssertionError): SubEpochChallengeSegment.from_bytes(b"\x00\x00\x00\x03\xff\xff\xff\xff") @@ -278,7 +297,7 @@ class TestClassOptional(Streamable): TestClassOptional.from_bytes(bytes([1, 2])) -def test_ambiguous_deserialization_int(): +def test_ambiguous_deserialization_int() -> None: @streamable @dataclass(frozen=True) class TestClassUint(Streamable): @@ -289,7 +308,7 @@ class TestClassUint(Streamable): TestClassUint.from_bytes(b"\x00\x00") -def test_ambiguous_deserialization_list(): +def test_ambiguous_deserialization_list() -> None: @streamable @dataclass(frozen=True) class TestClassList(Streamable): @@ -300,7 +319,7 @@ class TestClassList(Streamable): TestClassList.from_bytes(bytes([0, 0, 100, 24])) -def test_ambiguous_deserialization_tuple(): +def test_ambiguous_deserialization_tuple() -> None: @streamable @dataclass(frozen=True) class TestClassTuple(Streamable): @@ -311,7 +330,7 @@ class TestClassTuple(Streamable): TestClassTuple.from_bytes(bytes([0, 0, 100, 24])) -def test_ambiguous_deserialization_str(): +def test_ambiguous_deserialization_str() -> None: @streamable @dataclass(frozen=True) class TestClassStr(Streamable): @@ -322,7 +341,7 @@ class TestClassStr(Streamable): TestClassStr.from_bytes(bytes([0, 0, 100, 24, 52])) -def test_ambiguous_deserialization_bytes(): +def test_ambiguous_deserialization_bytes() -> None: @streamable @dataclass(frozen=True) class TestClassBytes(Streamable): @@ -339,7 +358,7 @@ class TestClassBytes(Streamable): TestClassBytes.from_bytes(bytes([0, 0, 0, 2, 52, 21])) -def test_ambiguous_deserialization_bool(): +def test_ambiguous_deserialization_bool() -> None: @streamable @dataclass(frozen=True) class TestClassBool(Streamable): @@ -353,13 +372,13 @@ class TestClassBool(Streamable): TestClassBool.from_bytes(bytes([1])) -def test_ambiguous_deserialization_program(): +def test_ambiguous_deserialization_program() -> None: @streamable @dataclass(frozen=True) class TestClassProgram(Streamable): a: Program - program = Program.to(binutils.assemble("()")) + program = Program.to(binutils.assemble("()")) # type: ignore[no-untyped-call] # TODO, add typing in clvm_tools TestClassProgram.from_bytes(bytes(program)) @@ -367,7 +386,7 @@ class TestClassProgram(Streamable): TestClassProgram.from_bytes(bytes(program) + b"9") -def test_streamable_empty(): +def test_streamable_empty() -> None: @streamable @dataclass(frozen=True) class A(Streamable): @@ -376,7 +395,7 @@ class A(Streamable): assert A.from_bytes(bytes(A())) == A() -def test_parse_bool(): +def test_parse_bool() -> None: assert not parse_bool(io.BytesIO(b"\x00")) assert parse_bool(io.BytesIO(b"\x01")) @@ -391,7 +410,7 @@ def test_parse_bool(): parse_bool(io.BytesIO(b"\x02")) -def test_uint32(): +def test_uint32() -> None: assert parse_uint32(io.BytesIO(b"\x00\x00\x00\x00")) == 0 assert parse_uint32(io.BytesIO(b"\x00\x00\x00\x01")) == 1 assert parse_uint32(io.BytesIO(b"\x00\x00\x00\x01"), "little") == 16777216 @@ -399,7 +418,7 @@ def test_uint32(): assert parse_uint32(io.BytesIO(b"\x01\x00\x00\x00"), "little") == 1 assert parse_uint32(io.BytesIO(b"\xff\xff\xff\xff"), "little") == 4294967295 - def test_write(value, byteorder): + def test_write(value: int, byteorder: Literal["little", "big"]) -> None: f = io.BytesIO() write_uint32(f, uint32(value), byteorder) f.seek(0) @@ -420,7 +439,7 @@ def test_write(value, byteorder): parse_uint32(io.BytesIO(b"\x00\x00\x00")) -def test_parse_optional(): +def test_parse_optional() -> None: assert parse_optional(io.BytesIO(b"\x00"), parse_bool) is None assert parse_optional(io.BytesIO(b"\x01\x01"), parse_bool) assert not parse_optional(io.BytesIO(b"\x01\x00"), parse_bool) @@ -437,7 +456,7 @@ def test_parse_optional(): parse_optional(io.BytesIO(b"\xff\x00"), parse_bool) -def test_parse_bytes(): +def test_parse_bytes() -> None: assert parse_bytes(io.BytesIO(b"\x00\x00\x00\x00")) == b"" assert parse_bytes(io.BytesIO(b"\x00\x00\x00\x01\xff")) == b"\xff" @@ -463,7 +482,7 @@ def test_parse_bytes(): parse_bytes(io.BytesIO(b"\x00\x00\x02\x01" + b"a" * 512)) -def test_parse_list(): +def test_parse_list() -> None: assert parse_list(io.BytesIO(b"\x00\x00\x00\x00"), parse_bool) == [] assert parse_list(io.BytesIO(b"\x00\x00\x00\x01\x01"), parse_bool) == [True] @@ -484,7 +503,7 @@ def test_parse_list(): parse_list(io.BytesIO(b"\x00\x00\x00\x01\x02"), parse_bool) -def test_parse_tuple(): +def test_parse_tuple() -> None: assert parse_tuple(io.BytesIO(b""), []) == () assert parse_tuple(io.BytesIO(b"\x00\x00"), [parse_bool, parse_bool]) == (False, False) @@ -499,33 +518,35 @@ def test_parse_tuple(): parse_tuple(io.BytesIO(b"\x00"), [parse_bool, parse_bool]) -def test_parse_size_hints(): - class TestFromBytes: - b: bytes +class TestFromBytes: + b: bytes - @classmethod - def from_bytes(cls, b): - ret = TestFromBytes() - ret.b = b - return ret + @classmethod + def from_bytes(cls, b: bytes) -> TestFromBytes: + ret = TestFromBytes() + ret.b = b + return ret + +class FailFromBytes: + @classmethod + def from_bytes(cls, b: bytes) -> FailFromBytes: + raise ValueError() + + +def test_parse_size_hints() -> None: assert parse_size_hints(io.BytesIO(b"1337"), TestFromBytes, 4).b == b"1337" # EOF with raises(AssertionError): parse_size_hints(io.BytesIO(b"133"), TestFromBytes, 4) - class FailFromBytes: - @classmethod - def from_bytes(cls, b): - raise ValueError() - # error in underlying type with raises(ValueError): parse_size_hints(io.BytesIO(b"1337"), FailFromBytes, 4) -def test_parse_str(): +def test_parse_str() -> None: assert parse_str(io.BytesIO(b"\x00\x00\x00\x00")) == "" assert parse_str(io.BytesIO(b"\x00\x00\x00\x01a")) == "a" @@ -551,7 +572,7 @@ def test_parse_str(): parse_str(io.BytesIO(b"\x00\x00\x02\x01" + b"a" * 512)) -def test_wrong_decorator_order(): +def test_wrong_decorator_order() -> None: with raises(DefinitionError): @@ -561,7 +582,7 @@ class WrongDecoratorOrder(Streamable): pass -def test_dataclass_not_frozen(): +def test_dataclass_not_frozen() -> None: with raises(DefinitionError): @@ -571,7 +592,7 @@ class DataclassNotFrozen(Streamable): pass -def test_dataclass_missing(): +def test_dataclass_missing() -> None: with raises(DefinitionError): @@ -580,11 +601,11 @@ class DataclassMissing(Streamable): pass -def test_streamable_inheritance_missing(): +def test_streamable_inheritance_missing() -> None: with raises(DefinitionError): - + # we want to test invalid here, hence the ignore. @streamable @dataclass(frozen=True) - class StreamableInheritanceMissing: + class StreamableInheritanceMissing: # type: ignore[type-var] pass