From bcd3f5272762e6438a40b49764da11dcd7f62762 Mon Sep 17 00:00:00 2001 From: Tobias Sterbak Date: Mon, 13 Feb 2023 10:32:19 +0000 Subject: [PATCH] Improve typehints --- Makefile | 3 + openandroidinstaller/app_state.py | 21 ++++- openandroidinstaller/installer_config.py | 16 ++-- openandroidinstaller/openandroidinstaller.py | 25 +++--- openandroidinstaller/py.typed | 0 openandroidinstaller/tooling.py | 80 +++++++++++--------- openandroidinstaller/utils.py | 4 +- openandroidinstaller/views/py.typed | 0 openandroidinstaller/views/step_view.py | 2 +- openandroidinstaller/widgets.py | 4 +- poetry.lock | 49 +++++++++++- pyproject.toml | 1 + tests/test_app.py | 3 +- 13 files changed, 143 insertions(+), 65 deletions(-) create mode 100644 openandroidinstaller/py.typed create mode 100644 openandroidinstaller/views/py.typed diff --git a/Makefile b/Makefile index e219737e..4b7aeae7 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ format: lint: poetry run ruff openandroidinstaller/ --ignore E501 +typing: + poetry run mypy openandroidinstaller/. --ignore-missing-imports + test: format lint PYTHONPATH=openandroidinstaller:$(PYTHONPATH) poetry run pytest --cov=openandroidinstaller tests/ diff --git a/openandroidinstaller/app_state.py b/openandroidinstaller/app_state.py index 9687c535..e81cedd3 100644 --- a/openandroidinstaller/app_state.py +++ b/openandroidinstaller/app_state.py @@ -15,6 +15,7 @@ import copy from pathlib import Path +from typing import List, Optional from installer_config import _load_config @@ -28,7 +29,7 @@ def __init__( config_path: Path, bin_path: Path, test: bool = False, - test_config: str = None, + test_config: Optional[str] = None, ): self.platform = platform self.config_path = config_path @@ -44,8 +45,22 @@ def __init__( self.recovery_path = None self.is_ab = None - # is this still needed? - self.steps = None + # store views + self.default_views: List = [] + self.addon_views: List = [] + self.final_default_views: List = [] + + def add_default_views(self, views: List): + """Add default views to store""" + self.default_views.extend(views) + + def add_addon_views(self, views: List): + """Add addon views to store""" + self.addon_views.extend(views) + + def add_final_default_views(self, views: List): + """Add final default views to store""" + self.final_default_views.extend(views) def load_config(self, device_code: str): """Load the config from file to state by device code.""" diff --git a/openandroidinstaller/installer_config.py b/openandroidinstaller/installer_config.py index c60e0934..62aa1a01 100644 --- a/openandroidinstaller/installer_config.py +++ b/openandroidinstaller/installer_config.py @@ -14,7 +14,7 @@ # Author: Tobias Sterbak from pathlib import Path -from typing import List, Optional +from typing import List, Optional, Dict import schema import yaml @@ -34,10 +34,10 @@ def __init__( title: str, type: str, content: str, - command: str = None, - img: str = None, allow_skip: bool = False, - link: str = None, + command: Optional[str] = None, + img: Optional[str] = None, + link: Optional[str] = None, ): self.title = title self.type = type @@ -51,7 +51,7 @@ def __init__( class InstallerConfig: # map some detected device codes to their real code. - device_code_mapping = { + device_code_mapping: Dict[str, str] = { # Sony issues "C6603": "yuga", # OnePlus issues @@ -80,9 +80,11 @@ def __init__( self.requirements = requirements self.device_code = metadata.get("devicecode") self.twrp_link = metadata.get("twrp-link") - inverted_mapping = dict(map(reversed, self.device_code_mapping.items())) + + # manage device codes and alternative device codes/names + inverted_mapping: Dict[str, str] = dict(map(reversed, self.device_code_mapping.items())) # type: ignore self.alternative_device_code = inverted_mapping.get( - self.device_code, self.device_code + self.device_code, self.device_code # type: ignore ) @classmethod diff --git a/openandroidinstaller/openandroidinstaller.py b/openandroidinstaller/openandroidinstaller.py index fb62c760..6750ad5b 100644 --- a/openandroidinstaller/openandroidinstaller.py +++ b/openandroidinstaller/openandroidinstaller.py @@ -19,6 +19,7 @@ import click import functools from pathlib import Path +from typing import List import flet as ft from flet import ( @@ -114,13 +115,6 @@ def __init__(self, state: AppState): self.install_view, ] - self.state.default_views = self.default_views - self.state.final_default_views = self.final_default_views - self.state.final_view = self.final_view - - # stack of previous default views for the back-button - self.previous_views = [] - # initialize the addon view self.select_addon_view = AddonsView( on_confirm=self.to_next_view, state=self.state @@ -128,10 +122,19 @@ def __init__(self, state: AppState): self.install_addons_view = InstallAddonsView( on_confirm=self.to_next_view, state=self.state ) - self.state.addon_views = [ - self.install_addons_view, - self.select_addon_view, - ] + + # attach some views to the state to modify and reuse later + self.state.add_default_views(views=self.default_views) + self.state.add_addon_views( + views=[ + self.install_addons_view, + self.select_addon_view, + ] + ) + self.state.add_final_default_views(views=self.final_default_views) + + # stack of previous default views for the back-button + self.previous_views: List = [] def build(self): self.view.controls.append(self.default_views.pop()) diff --git a/openandroidinstaller/py.typed b/openandroidinstaller/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/openandroidinstaller/tooling.py b/openandroidinstaller/tooling.py index 04199322..be4578e9 100644 --- a/openandroidinstaller/tooling.py +++ b/openandroidinstaller/tooling.py @@ -24,42 +24,46 @@ ) import shlex from time import sleep -from typing import List, Optional, Union +from typing import List, Optional, Union, Generator, Callable from loguru import logger + +TerminalResponse = Generator[Union[str, bool], None, None] + + PLATFORM = sys.platform def run_command( - command: str, bin_path: Path, enable_logging: bool = True -) -> Union[str, bool]: + full_command: str, bin_path: Path, enable_logging: bool = True +) -> TerminalResponse: """Run a command with a tool (adb, fastboot, heimdall).""" - yield f"${command}" + yield f"${full_command}" # split the command and extract the tool part - tool, *command = shlex.split(command) + tool, *command = shlex.split(full_command) if tool not in ["adb", "fastboot", "heimdall"]: raise Exception(f"Unknown tool {tool}. Use adb, fastboot or heimdall.") if PLATFORM == "win32": - full_command = [str(bin_path.joinpath(Path(f"{tool}"))) + ".exe"] + command + command_list = [str(bin_path.joinpath(Path(f"{tool}"))) + ".exe"] + command # prevent Windows from opening terminal windows - si = subprocess.STARTUPINFO() - si.dwFlags |= subprocess.STARTF_USESHOWWINDOW + si = subprocess.STARTUPINFO() # type: ignore + si.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore else: - full_command = [str(bin_path.joinpath(Path(f"{tool}")))] + command + command_list = [str(bin_path.joinpath(Path(f"{tool}")))] + command si = None if enable_logging: - logger.info(f"Run command: {full_command}") + logger.info(f"Run command: {command_list}") # run the command with subprocess.Popen( - full_command, + command_list, stdout=PIPE, stderr=STDOUT, bufsize=1, universal_newlines=True, startupinfo=si, ) as p: - for line in p.stdout: + for line in p.stdout: # type: ignore if enable_logging: logger.info(line.strip()) yield line.strip() @@ -68,14 +72,14 @@ def run_command( yield p.returncode == 0 -def add_logging(step_desc: str, return_if_fail: bool = False): +def add_logging(step_desc: str, return_if_fail: bool = False) -> Callable: """Logging decorator to wrap functions that yield lines. Logs the `step_desc`. """ - def logging_decorator(func): - def logging(*args, **kwargs): + def logging_decorator(func) -> Callable: + def logging(*args, **kwargs) -> TerminalResponse: logger.info(f"{step_desc} - Paramters: {kwargs}") for line in func(*args, **kwargs): if (type(line) == bool) and not line: @@ -91,14 +95,14 @@ def logging(*args, **kwargs): @add_logging("Rebooting device with adb.") -def adb_reboot(bin_path: Path) -> bool: +def adb_reboot(bin_path: Path) -> TerminalResponse: """Run adb reboot on the device and return success.""" for line in run_command("adb reboot", bin_path): yield line @add_logging("Rebooting device into bootloader with adb.", return_if_fail=True) -def adb_reboot_bootloader(bin_path: Path) -> Union[str, bool]: +def adb_reboot_bootloader(bin_path: Path) -> TerminalResponse: """Reboot the device into bootloader and return success.""" for line in run_command("adb reboot bootloader", bin_path): yield line @@ -106,27 +110,27 @@ def adb_reboot_bootloader(bin_path: Path) -> Union[str, bool]: @add_logging("Rebooting device into download mode with adb.") -def adb_reboot_download(bin_path: Path) -> Union[str, bool]: +def adb_reboot_download(bin_path: Path) -> TerminalResponse: """Reboot the device into download mode of samsung devices and return success.""" for line in run_command("adb reboot download", bin_path): yield line @add_logging("Sideload the target to device with adb.") -def adb_sideload(bin_path: Path, target: str) -> Union[str, bool]: +def adb_sideload(bin_path: Path, target: str) -> TerminalResponse: """Sideload the target to device and return success.""" for line in run_command(f"adb sideload {target}", bin_path): yield line @add_logging("Activate sideloading in TWRP.", return_if_fail=True) -def activate_sideload(bin_path: Path) -> Union[str, bool]: +def activate_sideload(bin_path: Path) -> TerminalResponse: """Activate sideload with adb shell in twrp.""" for line in run_command("adb shell twrp sideload", bin_path): yield line -def adb_twrp_copy_partitions(bin_path: Path, config_path: Path): +def adb_twrp_copy_partitions(bin_path: Path, config_path: Path) -> TerminalResponse: # some devices like one plus 6t or motorola moto g7 power need the partitions copied to prevent a hard brick logger.info("Sideload copy_partitions script with adb.") # activate sideload @@ -146,18 +150,18 @@ def adb_twrp_copy_partitions(bin_path: Path, config_path: Path): yield line sleep(7) # Copy partitions end # - return True + yield True @add_logging("Perform a factory reset with adb and twrp.", return_if_fail=True) -def adb_twrp_format_data(bin_path: Path): +def adb_twrp_format_data(bin_path: Path) -> TerminalResponse: """Perform a factory reset with twrp and adb.""" for line in run_command("adb shell twrp format data", bin_path): yield line @add_logging("Wipe the selected partition with adb and twrp.", return_if_fail=True) -def adb_twrp_wipe_partition(bin_path: Path, partition: str): +def adb_twrp_wipe_partition(bin_path: Path, partition: str) -> TerminalResponse: """Perform a factory reset with twrp and adb.""" for line in run_command(f"adb shell twrp wipe {partition}", bin_path): yield line @@ -169,8 +173,8 @@ def adb_twrp_wipe_and_install( config_path: Path, is_ab: bool, install_addons=True, - recovery: str = None, -) -> bool: + recovery: Optional[str] = None, +) -> TerminalResponse: """Wipe and format data with twrp, then flash os image with adb. Only works for twrp recovery. @@ -237,7 +241,9 @@ def adb_twrp_wipe_and_install( yield line -def adb_twrp_install_addons(bin_path: Path, addons: List[str], is_ab: bool) -> bool: +def adb_twrp_install_addons( + bin_path: Path, addons: List[str], is_ab: bool +) -> TerminalResponse: """Flash addons through adb and twrp. Only works for twrp recovery. @@ -279,42 +285,42 @@ def adb_twrp_install_addons(bin_path: Path, addons: List[str], is_ab: bool) -> b @add_logging("Switch active boot partitions.", return_if_fail=True) -def fastboot_switch_partition(bin_path: Path) -> Union[str, bool]: +def fastboot_switch_partition(bin_path: Path) -> TerminalResponse: """Switch the active boot partition with fastboot.""" for line in run_command("fastboot set_active other", bin_path): yield line @add_logging("Unlock the device with fastboot and code.") -def fastboot_unlock_with_code(bin_path: Path, unlock_code: str) -> Union[str, bool]: +def fastboot_unlock_with_code(bin_path: Path, unlock_code: str) -> TerminalResponse: """Unlock the device with fastboot and code given.""" for line in run_command(f"fastboot oem unlock {unlock_code}", bin_path): yield line @add_logging("Unlock the device with fastboot without code.") -def fastboot_unlock(bin_path: Path) -> Union[str, bool]: +def fastboot_unlock(bin_path: Path) -> TerminalResponse: """Unlock the device with fastboot and without code.""" for line in run_command("fastboot flashing unlock", bin_path): yield line @add_logging("OEM unlocking the device with fastboot.") -def fastboot_oem_unlock(bin_path: Path) -> Union[str, bool]: +def fastboot_oem_unlock(bin_path: Path) -> TerminalResponse: """OEM unlock the device with fastboot and without code.""" for line in run_command("fastboot oem unlock", bin_path): yield line @add_logging("Get unlock data with fastboot") -def fastboot_get_unlock_data(bin_path: Path) -> Union[str, bool]: +def fastboot_get_unlock_data(bin_path: Path) -> TerminalResponse: """Get the unlock data with fastboot""" for line in run_command("fastboot oem get_unlock_data", bin_path): yield line @add_logging("Rebooting device with fastboot.") -def fastboot_reboot(bin_path: Path) -> Union[str, bool]: +def fastboot_reboot(bin_path: Path) -> TerminalResponse: """Reboot with fastboot""" for line in run_command("fastboot reboot", bin_path): yield line @@ -323,7 +329,7 @@ def fastboot_reboot(bin_path: Path) -> Union[str, bool]: @add_logging("Flash or boot custom recovery with fastboot.") def fastboot_flash_recovery( bin_path: Path, recovery: str, is_ab: bool = True -) -> Union[str, bool]: +) -> TerminalResponse: """Temporarily, flash custom recovery with fastboot.""" if is_ab: logger.info("Boot custom recovery with fastboot.") @@ -344,7 +350,7 @@ def fastboot_flash_recovery( yield line -def fastboot_flash_boot(bin_path: Path, recovery: str) -> bool: +def fastboot_flash_boot(bin_path: Path, recovery: str) -> TerminalResponse: """Temporarily, flash custom recovery with fastboot to boot partition.""" logger.info("Flash custom recovery with fastboot.") for line in run_command(f"fastboot flash boot {recovery}", bin_path): @@ -366,7 +372,7 @@ def fastboot_flash_boot(bin_path: Path, recovery: str) -> bool: @add_logging("Flash custom recovery with heimdall.") -def heimdall_flash_recovery(bin_path: Path, recovery: str) -> Union[str, bool]: +def heimdall_flash_recovery(bin_path: Path, recovery: str) -> TerminalResponse: """Temporarily, flash custom recovery with heimdall.""" for line in run_command( f"heimdall flash --no-reboot --RECOVERY {recovery}", bin_path @@ -414,7 +420,7 @@ def search_device(platform: str, bin_path: Path) -> Optional[str]: return None -def check_ab_partition(platform: str, bin_path: Path) -> Optional[str]: +def check_ab_partition(platform: str, bin_path: Path) -> Optional[bool]: """Figure out, if its an a/b-partitioned device.""" logger.info(f"Run on {platform} with {bin_path}...") try: diff --git a/openandroidinstaller/utils.py b/openandroidinstaller/utils.py index 3fa9fd17..7a83cb83 100644 --- a/openandroidinstaller/utils.py +++ b/openandroidinstaller/utils.py @@ -33,10 +33,10 @@ def get_download_link(devicecode: str) -> Optional[str]: return url else: logger.info(f"{url} doesn't exist, status_code: {res.status_code}") - return + return None except requests.exceptions.RequestException as e: logger.error(f"{url} doesn't exist, error: {e}") - return + return None def image_works_with_device( diff --git a/openandroidinstaller/views/py.typed b/openandroidinstaller/views/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/openandroidinstaller/views/step_view.py b/openandroidinstaller/views/step_view.py index c226ef5c..86e5ef23 100644 --- a/openandroidinstaller/views/step_view.py +++ b/openandroidinstaller/views/step_view.py @@ -234,7 +234,7 @@ def call_to_phone(self, e, command: str): # run the right command if command in cmd_mapping.keys(): - for line in cmd_mapping.get(command)(bin_path=self.state.bin_path): + for line in cmd_mapping.get(command)(bin_path=self.state.bin_path): # type: ignore # write the line to advanced output terminal self.terminal_box.write_line(line) self.progress_indicator.display_progress_ring() diff --git a/openandroidinstaller/widgets.py b/openandroidinstaller/widgets.py index 7b2b562b..fe479767 100644 --- a/openandroidinstaller/widgets.py +++ b/openandroidinstaller/widgets.py @@ -16,7 +16,7 @@ import webbrowser import regex as re from functools import partial -from typing import Callable +from typing import Callable, Optional from flet import ( UserControl, @@ -151,7 +151,7 @@ def update(self): def get_title( - title: str, info_button: IconButton = None, step_indicator_img: str = None + title: str, info_button: IconButton = None, step_indicator_img: Optional[str] = None ) -> Container: """Function to get the title header element for the right side view.""" if info_button: diff --git a/poetry.lock b/poetry.lock index 307a3078..a11fc8f2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -305,6 +305,25 @@ check = ["check-manifest", "flake8", "flake8-black", "isort (>=5.0.3)", "pygment test = ["coverage[toml] (>=5.2)", "coveralls (>=2.1.1)", "hypothesis", "pyannotate", "pytest", "pytest-cov"] type = ["mypy", "mypy-extensions"] +[[package]] +name = "mypy" +version = "1.0.0" +description = "Optional static typing for Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + [[package]] name = "mypy-extensions" version = "0.4.3" @@ -765,7 +784,7 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "1.1" python-versions = "<3.11,>=3.9" -content-hash = "68d8e8e1fffc47b22e117cba8553b7a9577b91b706f752c43e317a45cc9a46bd" +content-hash = "bf94fcfbcd81689566a339905fc5ce6d48ddea9697488703057d4a2c991c5eca" [metadata.files] altgraph = [ @@ -1241,6 +1260,34 @@ multivolumefile = [ {file = "multivolumefile-0.2.3-py3-none-any.whl", hash = "sha256:237f4353b60af1703087cf7725755a1f6fcaeeea48421e1896940cd1c920d678"}, {file = "multivolumefile-0.2.3.tar.gz", hash = "sha256:a0648d0aafbc96e59198d5c17e9acad7eb531abea51035d08ce8060dcad709d6"}, ] +mypy = [ + {file = "mypy-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0626db16705ab9f7fa6c249c017c887baf20738ce7f9129da162bb3075fc1af"}, + {file = "mypy-1.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1ace23f6bb4aec4604b86c4843276e8fa548d667dbbd0cb83a3ae14b18b2db6c"}, + {file = "mypy-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87edfaf344c9401942883fad030909116aa77b0fa7e6e8e1c5407e14549afe9a"}, + {file = "mypy-1.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0ab090d9240d6b4e99e1fa998c2d0aa5b29fc0fb06bd30e7ad6183c95fa07593"}, + {file = "mypy-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:7cc2c01dfc5a3cbddfa6c13f530ef3b95292f926329929001d45e124342cd6b7"}, + {file = "mypy-1.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14d776869a3e6c89c17eb943100f7868f677703c8a4e00b3803918f86aafbc52"}, + {file = "mypy-1.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb2782a036d9eb6b5a6efcdda0986774bf798beef86a62da86cb73e2a10b423d"}, + {file = "mypy-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cfca124f0ac6707747544c127880893ad72a656e136adc935c8600740b21ff5"}, + {file = "mypy-1.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8845125d0b7c57838a10fd8925b0f5f709d0e08568ce587cc862aacce453e3dd"}, + {file = "mypy-1.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b1b9e1ed40544ef486fa8ac022232ccc57109f379611633ede8e71630d07d2"}, + {file = "mypy-1.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c7cf862aef988b5fbaa17764ad1d21b4831436701c7d2b653156a9497d92c83c"}, + {file = "mypy-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd187d92b6939617f1168a4fe68f68add749902c010e66fe574c165c742ed88"}, + {file = "mypy-1.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4e5175026618c178dfba6188228b845b64131034ab3ba52acaffa8f6c361f805"}, + {file = "mypy-1.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2f6ac8c87e046dc18c7d1d7f6653a66787a4555085b056fe2d599f1f1a2a2d21"}, + {file = "mypy-1.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7306edca1c6f1b5fa0bc9aa645e6ac8393014fa82d0fa180d0ebc990ebe15964"}, + {file = "mypy-1.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3cfad08f16a9c6611e6143485a93de0e1e13f48cfb90bcad7d5fde1c0cec3d36"}, + {file = "mypy-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67cced7f15654710386e5c10b96608f1ee3d5c94ca1da5a2aad5889793a824c1"}, + {file = "mypy-1.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a86b794e8a56ada65c573183756eac8ac5b8d3d59daf9d5ebd72ecdbb7867a43"}, + {file = "mypy-1.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:50979d5efff8d4135d9db293c6cb2c42260e70fb010cbc697b1311a4d7a39ddb"}, + {file = "mypy-1.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ae4c7a99e5153496243146a3baf33b9beff714464ca386b5f62daad601d87af"}, + {file = "mypy-1.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e398652d005a198a7f3c132426b33c6b85d98aa7dc852137a2a3be8890c4072"}, + {file = "mypy-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be78077064d016bc1b639c2cbcc5be945b47b4261a4f4b7d8923f6c69c5c9457"}, + {file = "mypy-1.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92024447a339400ea00ac228369cd242e988dd775640755fa4ac0c126e49bb74"}, + {file = "mypy-1.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:fe523fcbd52c05040c7bee370d66fee8373c5972171e4fbc323153433198592d"}, + {file = "mypy-1.0.0-py3-none-any.whl", hash = "sha256:2efa963bdddb27cb4a0d42545cd137a8d2b883bd181bbc4525b568ef6eca258f"}, + {file = "mypy-1.0.0.tar.gz", hash = "sha256:f34495079c8d9da05b183f9f7daec2878280c2ad7cc81da686ef0b484cea2ecf"}, +] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, diff --git a/pyproject.toml b/pyproject.toml index 5b78472f..87963e9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ pytest-cov = "^4.0.0" pytest-mock = "^3.10.0" bandit = "^1.7.4" pytest-subprocess = "^1.5.0" +mypy = "^1.0.0" [tool.poetry.dev-dependencies] diff --git a/tests/test_app.py b/tests/test_app.py index c719fbf1..eed85256 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -43,6 +43,7 @@ def test_app(): state = page.controls[0].state state.load_config(device_code="sargo") state.default_views.extend(state.addon_views) - for _ in range(len(state.steps) + 7): + number_of_steps = 12 + for _ in range(number_of_steps): page.controls[0].to_next_view(None) assert "SuccessView" in str(page.controls[0].view.controls[0])