ragger 1.37.1__py3-none-any.whl → 1.40.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ragger/__version__.py +16 -3
- ragger/backend/interface.py +7 -7
- ragger/backend/ledgercomm.py +2 -2
- ragger/backend/ledgerwallet.py +2 -2
- ragger/conftest/base_conftest.py +67 -6
- ragger/conftest/configuration.py +24 -19
- ragger/firmware/structs.py +2 -0
- ragger/firmware/touch/layouts.py +0 -12
- ragger/firmware/touch/positions.py +151 -15
- ragger/gui/interface.py +10 -2
- {ragger-1.37.1.dist-info → ragger-1.40.0.dist-info}/METADATA +2 -2
- {ragger-1.37.1.dist-info → ragger-1.40.0.dist-info}/RECORD +15 -15
- {ragger-1.37.1.dist-info → ragger-1.40.0.dist-info}/WHEEL +0 -0
- {ragger-1.37.1.dist-info → ragger-1.40.0.dist-info}/licenses/LICENSE +0 -0
- {ragger-1.37.1.dist-info → ragger-1.40.0.dist-info}/top_level.txt +0 -0
ragger/__version__.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '1.
|
|
21
|
-
__version_tuple__ = version_tuple = (1,
|
|
31
|
+
__version__ = version = '1.40.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 40, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
ragger/backend/interface.py
CHANGED
|
@@ -144,8 +144,8 @@ class BackendInterface(ABC):
|
|
|
144
144
|
:type ins: int
|
|
145
145
|
:param p1: First instruction parameter, defaults to 0
|
|
146
146
|
:type p1: int
|
|
147
|
-
:param
|
|
148
|
-
:type
|
|
147
|
+
:param p2: Second instruction parameter, defaults to 0
|
|
148
|
+
:type p2: int
|
|
149
149
|
:param data: Command data
|
|
150
150
|
:type data: bytes
|
|
151
151
|
|
|
@@ -205,8 +205,8 @@ class BackendInterface(ABC):
|
|
|
205
205
|
:type ins: int
|
|
206
206
|
:param p1: First instruction parameter, defaults to 0
|
|
207
207
|
:type p1: int
|
|
208
|
-
:param
|
|
209
|
-
:type
|
|
208
|
+
:param p2: Second instruction parameter, defaults to 0
|
|
209
|
+
:type p2: int
|
|
210
210
|
:param data: Command data
|
|
211
211
|
:type data: bytes
|
|
212
212
|
|
|
@@ -262,8 +262,8 @@ class BackendInterface(ABC):
|
|
|
262
262
|
:type ins: int
|
|
263
263
|
:param p1: First instruction parameter, defaults to 0
|
|
264
264
|
:type p1: int
|
|
265
|
-
:param
|
|
266
|
-
:type
|
|
265
|
+
:param p2: Second instruction parameter, defaults to 0
|
|
266
|
+
:type p2: int
|
|
267
267
|
:param data: Command data
|
|
268
268
|
:type data: bytes
|
|
269
269
|
|
|
@@ -292,7 +292,7 @@ class BackendInterface(ABC):
|
|
|
292
292
|
|
|
293
293
|
:raises ExceptionRAPDU: If the `raises` attribute is True, this method
|
|
294
294
|
will raise if the backend returns a status code
|
|
295
|
-
not registered
|
|
295
|
+
not registered as a `valid_statuses`
|
|
296
296
|
|
|
297
297
|
:return: None
|
|
298
298
|
:rtype: NoneType
|
ragger/backend/ledgercomm.py
CHANGED
|
@@ -106,7 +106,7 @@ class LedgerCommBackend(PhysicalBackend):
|
|
|
106
106
|
return result
|
|
107
107
|
|
|
108
108
|
@contextmanager
|
|
109
|
-
def exchange_async_raw(self, data: bytes = b"") -> Generator[
|
|
109
|
+
def exchange_async_raw(self, data: bytes = b"") -> Generator[bool, None, None]:
|
|
110
110
|
self.send_raw(data)
|
|
111
|
-
yield
|
|
111
|
+
yield True
|
|
112
112
|
self._last_async_response = self.receive()
|
ragger/backend/ledgerwallet.py
CHANGED
|
@@ -98,7 +98,7 @@ class LedgerWalletBackend(PhysicalBackend):
|
|
|
98
98
|
return result
|
|
99
99
|
|
|
100
100
|
@contextmanager
|
|
101
|
-
def exchange_async_raw(self, data: bytes = b"") -> Generator[
|
|
101
|
+
def exchange_async_raw(self, data: bytes = b"") -> Generator[bool, None, None]:
|
|
102
102
|
self.send_raw(data)
|
|
103
|
-
yield
|
|
103
|
+
yield True
|
|
104
104
|
self._last_async_response = self.receive()
|
ragger/conftest/base_conftest.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import pytest
|
|
2
3
|
import logging
|
|
3
4
|
from dataclasses import fields
|
|
@@ -39,7 +40,12 @@ def pytest_addoption(parser):
|
|
|
39
40
|
action="store_true",
|
|
40
41
|
default=False,
|
|
41
42
|
help="Have Speculos accept prod PKI certificates instead of test")
|
|
42
|
-
parser.addoption("--log_apdu_file",
|
|
43
|
+
parser.addoption("--log_apdu_file",
|
|
44
|
+
action="store",
|
|
45
|
+
default=None,
|
|
46
|
+
nargs="?",
|
|
47
|
+
const="apdu.log",
|
|
48
|
+
help="Log the APDU in a file. If no pattern provided, uses 'apdu_xxx.log'.")
|
|
43
49
|
parser.addoption("--seed", action="store", default=None, help="Set a custom seed")
|
|
44
50
|
# Always allow "default" even if application conftest does not define it
|
|
45
51
|
allowed_setups = conf.OPTIONAL.ALLOWED_SETUPS
|
|
@@ -72,10 +78,23 @@ def golden_run(pytestconfig):
|
|
|
72
78
|
return pytestconfig.getoption("golden_run")
|
|
73
79
|
|
|
74
80
|
|
|
75
|
-
@pytest.fixture(scope=
|
|
76
|
-
def log_apdu_file(pytestconfig):
|
|
81
|
+
@pytest.fixture(scope=conf.OPTIONAL.BACKEND_SCOPE)
|
|
82
|
+
def log_apdu_file(request, pytestconfig, full_test_name: str):
|
|
77
83
|
filename = pytestconfig.getoption("log_apdu_file")
|
|
78
|
-
|
|
84
|
+
if filename is None:
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
path = Path(filename)
|
|
88
|
+
# Get nb of collected tests to be executed
|
|
89
|
+
collected_items = len(request.session.items)
|
|
90
|
+
if collected_items == 1:
|
|
91
|
+
# Single test - use filename directly
|
|
92
|
+
return path.resolve()
|
|
93
|
+
# Multiple tests - create a file per test
|
|
94
|
+
MAX_TEST_NAME_LENGTH = 100 # Define a safe maximum length for test names
|
|
95
|
+
truncated_test_name = full_test_name[:MAX_TEST_NAME_LENGTH] # Truncate if necessary
|
|
96
|
+
new_filename = f"{path.stem}_{truncated_test_name}{path.suffix}"
|
|
97
|
+
return Path(new_filename).resolve()
|
|
79
98
|
|
|
80
99
|
|
|
81
100
|
@pytest.fixture(scope="session")
|
|
@@ -112,6 +131,37 @@ def default_screenshot_path(root_pytest_dir: Path) -> Path:
|
|
|
112
131
|
return root_pytest_dir
|
|
113
132
|
|
|
114
133
|
|
|
134
|
+
@pytest.fixture(scope=conf.OPTIONAL.BACKEND_SCOPE)
|
|
135
|
+
def full_test_name(request) -> str:
|
|
136
|
+
# Get the name of current pytest test
|
|
137
|
+
test_name = request.node.name
|
|
138
|
+
|
|
139
|
+
if '[' in test_name:
|
|
140
|
+
# Split all parameters
|
|
141
|
+
base_name, params = test_name.rsplit('[', 1)
|
|
142
|
+
params = params.rstrip(']')
|
|
143
|
+
|
|
144
|
+
# Split parameters by '-' and filter out device names
|
|
145
|
+
param_list = [p for p in params.split('-') if p not in DEVICES]
|
|
146
|
+
|
|
147
|
+
# Rebuild test name with remaining parameters
|
|
148
|
+
if param_list:
|
|
149
|
+
test_name = f"{base_name}[{'-'.join(param_list)}]"
|
|
150
|
+
else:
|
|
151
|
+
test_name = base_name
|
|
152
|
+
|
|
153
|
+
# Clean up for filename friendliness by replacing special characters with underscores
|
|
154
|
+
translation_table = str.maketrans({
|
|
155
|
+
'[': '_',
|
|
156
|
+
']': '',
|
|
157
|
+
'-': '_',
|
|
158
|
+
'/': '_',
|
|
159
|
+
"'": '',
|
|
160
|
+
})
|
|
161
|
+
clean_name = test_name.translate(translation_table)
|
|
162
|
+
return clean_name
|
|
163
|
+
|
|
164
|
+
|
|
115
165
|
@pytest.fixture
|
|
116
166
|
def test_name(request) -> str:
|
|
117
167
|
# Get the name of current pytest test
|
|
@@ -225,15 +275,16 @@ def prepare_speculos_args(root_pytest_dir: Path,
|
|
|
225
275
|
main_app_path = find_application(project_root_dir / manifest.app.build_directory,
|
|
226
276
|
device_name, manifest.app.sdk)
|
|
227
277
|
|
|
228
|
-
#
|
|
278
|
+
# If this repository does not hold the main app, then we need to load this repository's application as a library
|
|
229
279
|
if conf.OPTIONAL.MAIN_APP_DIR is not None:
|
|
230
280
|
# This repo holds the library, not the standalone app: search in root_dir/build
|
|
231
281
|
lib_path = find_application(project_root_dir, device_name, manifest.app.sdk)
|
|
232
282
|
speculos_args.append(f"-l{lib_path}")
|
|
233
283
|
|
|
284
|
+
# Legacy lib method, remove once exchange is ported
|
|
234
285
|
if len(conf.OPTIONAL.SIDELOADED_APPS) != 0:
|
|
235
286
|
# We are testing a a standalone app that needs libraries: search in SIDELOADED_APPS_DIR
|
|
236
|
-
if conf.OPTIONAL.SIDELOADED_APPS_DIR
|
|
287
|
+
if conf.OPTIONAL.SIDELOADED_APPS_DIR is None:
|
|
237
288
|
raise ValueError("Configuration \"SIDELOADED_APPS_DIR\" is mandatory if "
|
|
238
289
|
"\"SIDELOADED_APPS\" is used")
|
|
239
290
|
libs_dir = Path(project_root_dir / conf.OPTIONAL.SIDELOADED_APPS_DIR)
|
|
@@ -241,6 +292,16 @@ def prepare_speculos_args(root_pytest_dir: Path,
|
|
|
241
292
|
for coin_name, lib_name in conf.OPTIONAL.SIDELOADED_APPS.items():
|
|
242
293
|
lib_path = find_library_application(libs_dir, coin_name, device_name)
|
|
243
294
|
speculos_args.append(f"-l{lib_name}:{lib_path}")
|
|
295
|
+
else:
|
|
296
|
+
# Keep this method instead
|
|
297
|
+
# Find all external libraries that have to be sideloaded
|
|
298
|
+
if conf.OPTIONAL.SIDELOADED_APPS_DIR is not None:
|
|
299
|
+
sideloaded_dir = project_root_dir / conf.OPTIONAL.SIDELOADED_APPS_DIR
|
|
300
|
+
subdirs = sorted(
|
|
301
|
+
filter(lambda d: (sideloaded_dir / d).is_dir(), os.listdir(sideloaded_dir)))
|
|
302
|
+
for subdir in subdirs:
|
|
303
|
+
lib_path = find_application(sideloaded_dir / subdir, device_name, manifest.app.sdk)
|
|
304
|
+
speculos_args.append(f"-l{lib_path}")
|
|
244
305
|
|
|
245
306
|
# Check if custom user seed has been provided through CLI or optional configuration.
|
|
246
307
|
# CLI user seed has priority over the optional configuration seed.
|
ragger/conftest/configuration.py
CHANGED
|
@@ -7,37 +7,39 @@ class OptionalOptions:
|
|
|
7
7
|
APP_NAME: str
|
|
8
8
|
MAIN_APP_DIR: Optional[str]
|
|
9
9
|
SIDELOADED_APPS: dict
|
|
10
|
-
SIDELOADED_APPS_DIR: str
|
|
10
|
+
SIDELOADED_APPS_DIR: Optional[str]
|
|
11
11
|
BACKEND_SCOPE: str
|
|
12
12
|
CUSTOM_SEED: str
|
|
13
13
|
ALLOWED_SETUPS: List[str]
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
OPTIONAL = OptionalOptions(
|
|
17
|
-
# Use this parameter if you want
|
|
18
|
-
#
|
|
17
|
+
# Use this parameter if you want physical Ragger backends (LedgerWallet and LedgerComm) to start
|
|
18
|
+
# your application from the Dashboard at test start.
|
|
19
19
|
APP_NAME=str(),
|
|
20
20
|
|
|
21
|
-
# If not None, the
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
21
|
+
# If not None, the application being tested with Ragger should be loaded as a library and not as
|
|
22
|
+
# a standalone application. This parameter points to the repository holding the "main app", i.e
|
|
23
|
+
# the application started from the Dashboard, which will then use the "local app" as a library.
|
|
24
|
+
# Example use case: your application is an Ethereum plugin, which will be used as a library by
|
|
25
|
+
# the Ethereum application.
|
|
26
|
+
# MAIN_APP_DIR is the directory where the Ethereum application is cloned.
|
|
27
|
+
#
|
|
28
|
+
# example: configuration.OPTIONAL.MAIN_APP_DIR = "tests/.test_dependencies/"
|
|
29
|
+
# Speculos will then start "tests/.test_dependencies/ethereum/build/<device>/bin/app.elf"
|
|
30
|
+
# There must be exactly one application cloned inside this directory.
|
|
27
31
|
MAIN_APP_DIR=None,
|
|
28
32
|
|
|
29
|
-
#
|
|
30
|
-
# Useful for Ethereum main app and exchange app, for example
|
|
31
|
-
# example: {"bitcoin": "Bitcoin", "ethereum": "Ethereum"}
|
|
32
|
-
# this would result in Speculos being launched with -lbitcoin:/path/to/bitcoin_device.elf
|
|
33
|
-
# Mutually exclusive with LOAD_MAIN_APP_AS_LIBRARY
|
|
33
|
+
# Deprecated
|
|
34
34
|
SIDELOADED_APPS=dict(),
|
|
35
35
|
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
SIDELOADED_APPS_DIR=
|
|
36
|
+
# Relative path to the directory that will store library applications needed for the test.
|
|
37
|
+
# They will be sideloaded by Speculos and can then be called by the main application. This
|
|
38
|
+
# emulates the applications being installed on the device alongside the main application.
|
|
39
|
+
#
|
|
40
|
+
# example: configuration.OPTIONAL.SIDELOADED_APPS_DIR = "tests/.test_dependencies/libraries"
|
|
41
|
+
# Speculos will then sideload "tests/.test_dependencies/libraries/*/build/<device>/bin/app.elf"
|
|
42
|
+
SIDELOADED_APPS_DIR=None,
|
|
41
43
|
|
|
42
44
|
# As the backend instantiation may take some time, Ragger supports multiple backend scopes.
|
|
43
45
|
# You can choose to share the backend instance between {session / module / class / function}
|
|
@@ -48,8 +50,10 @@ OPTIONAL = OptionalOptions(
|
|
|
48
50
|
# Use this parameter if you want speculos to use a custom seed instead of the default one.
|
|
49
51
|
# This would result in speculos being launched with --seed <CUSTOM_SEED>
|
|
50
52
|
# If a seed is provided through the "--seed" pytest command line option, it will override this one.
|
|
53
|
+
# /!\ DO NOT USE SEEDS WITH REAL FUNDS /!\
|
|
51
54
|
CUSTOM_SEED=str(),
|
|
52
55
|
|
|
56
|
+
# /!\ DEPRECATED /!\
|
|
53
57
|
# Use this parameter if you want ragger to handle running different test suites depending on setup
|
|
54
58
|
# Useful when some tests need certain build options and other tests need other build options, or a
|
|
55
59
|
# different Speculos command line
|
|
@@ -59,5 +63,6 @@ OPTIONAL = OptionalOptions(
|
|
|
59
63
|
#
|
|
60
64
|
# "default" setup is always allowed, all tests without explicit decoration depend on default
|
|
61
65
|
# and the --setup option defaults to "default"
|
|
66
|
+
# /!\ DEPRECATED /!\
|
|
62
67
|
ALLOWED_SETUPS=["default"],
|
|
63
68
|
)
|
ragger/firmware/structs.py
CHANGED
ragger/firmware/touch/layouts.py
CHANGED
|
@@ -88,18 +88,6 @@ class TappableCenter(_TappableElement):
|
|
|
88
88
|
pass
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
class KeyboardConfirmationButton(Element):
|
|
92
|
-
"""
|
|
93
|
-
This layout is to be used as the confirmation button when coupled with a keyboard.
|
|
94
|
-
|
|
95
|
-
On Stax devices, the screen is high enough that this is equivalent to TappableCenter, however
|
|
96
|
-
on Flex, this button is not centered, but slightly closer to the top of the screen.
|
|
97
|
-
"""
|
|
98
|
-
|
|
99
|
-
def confirm(self):
|
|
100
|
-
self.client.finger_touch(*self.positions)
|
|
101
|
-
|
|
102
|
-
|
|
103
91
|
# Headers
|
|
104
92
|
#########
|
|
105
93
|
class RightHeader(_TappableElement):
|
|
@@ -28,42 +28,62 @@ class Position:
|
|
|
28
28
|
|
|
29
29
|
_stax_res: Resolution = Devices.get_by_type(DeviceType.STAX).resolution
|
|
30
30
|
_flex_res: Resolution = Devices.get_by_type(DeviceType.FLEX).resolution
|
|
31
|
+
_apex_p_res: Resolution = Devices.get_by_type(DeviceType.APEX_P).resolution
|
|
32
|
+
_apex_m_res: Resolution = Devices.get_by_type(DeviceType.APEX_M).resolution
|
|
31
33
|
|
|
32
34
|
# Floor division '//' required, else the result will be a float, which can lead to issues when
|
|
33
35
|
# using Speculos, which performs actions such as `var.to_bytes()` which does not work with a float.
|
|
34
36
|
STAX_X_CENTER = _stax_res.x // 2
|
|
35
37
|
FLEX_X_CENTER = _flex_res.x // 2
|
|
38
|
+
APEX_P_X_CENTER = _apex_p_res.x // 2
|
|
39
|
+
APEX_M_X_CENTER = _apex_m_res.x // 2
|
|
36
40
|
|
|
37
41
|
STAX_CENTER = Position(STAX_X_CENTER, _stax_res.y // 2)
|
|
38
42
|
FLEX_CENTER = Position(FLEX_X_CENTER, _flex_res.y // 2)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
FLEX_BUTTON_UPPER_CENTER_MIDDLE = Position(FLEX_X_CENTER, 250)
|
|
43
|
+
APEX_P_CENTER = Position(APEX_P_X_CENTER, _apex_p_res.y // 2)
|
|
44
|
+
APEX_M_CENTER = Position(APEX_M_X_CENTER, _apex_m_res.y // 2)
|
|
42
45
|
|
|
43
46
|
STAX_BUTTON_UPPER_LEFT = Position(36, 36)
|
|
44
47
|
FLEX_BUTTON_UPPER_LEFT = Position(45, 45)
|
|
48
|
+
APEX_P_BUTTON_UPPER_LEFT = Position(30, 30)
|
|
49
|
+
APEX_M_BUTTON_UPPER_LEFT = Position(30, 30)
|
|
45
50
|
|
|
46
51
|
STAX_BUTTON_UPPER_RIGHT = Position(342, 55)
|
|
47
52
|
FLEX_BUTTON_UPPER_RIGHT = Position(405, 75)
|
|
53
|
+
APEX_P_BUTTON_UPPER_RIGHT = Position(256, 43)
|
|
54
|
+
APEX_M_BUTTON_UPPER_RIGHT = Position(256, 43)
|
|
48
55
|
|
|
49
56
|
STAX_BUTTON_LOWER_LEFT = Position(36, 606)
|
|
50
57
|
FLEX_BUTTON_LOWER_LEFT = Position(55, 530)
|
|
58
|
+
APEX_P_BUTTON_LOWER_LEFT = Position(56, 370)
|
|
59
|
+
APEX_M_BUTTON_LOWER_LEFT = Position(56, 370)
|
|
51
60
|
|
|
52
61
|
STAX_BUTTON_LOWER_MIDDLE = Position(STAX_X_CENTER, 606)
|
|
53
62
|
FLEX_BUTTON_LOWER_MIDDLE = Position(FLEX_X_CENTER, 550)
|
|
63
|
+
APEX_P_BUTTON_LOWER_MIDDLE = Position(APEX_P_X_CENTER, 370)
|
|
64
|
+
APEX_M_BUTTON_LOWER_MIDDLE = Position(APEX_M_X_CENTER, 370)
|
|
54
65
|
|
|
55
66
|
STAX_BUTTON_LOWER_RIGHT = Position(342, 606)
|
|
56
67
|
FLEX_BUTTON_LOWER_RIGHT = Position(430, 550)
|
|
68
|
+
APEX_P_BUTTON_LOWER_RIGHT = Position(270, 370)
|
|
69
|
+
APEX_M_BUTTON_LOWER_RIGHT = Position(270, 370)
|
|
70
|
+
|
|
57
71
|
STAX_BUTTON_LOWER_MIDDLE_RIGHT = Position(266, 615)
|
|
58
72
|
FLEX_BUTTON_LOWER_MIDDLE_RIGHT = Position(320, 550)
|
|
73
|
+
APEX_P_BUTTON_LOWER_MIDDLE_RIGHT = Position(207, 370)
|
|
74
|
+
APEX_M_BUTTON_LOWER_MIDDLE_RIGHT = Position(207, 370)
|
|
59
75
|
|
|
60
|
-
STAX_BUTTON_ABOVE_LOWER_MIDDLE = Position(
|
|
61
|
-
FLEX_BUTTON_ABOVE_LOWER_MIDDLE = Position(
|
|
76
|
+
STAX_BUTTON_ABOVE_LOWER_MIDDLE = Position(STAX_X_CENTER, 515)
|
|
77
|
+
FLEX_BUTTON_ABOVE_LOWER_MIDDLE = Position(FLEX_X_CENTER, 435)
|
|
78
|
+
APEX_P_BUTTON_ABOVE_LOWER_MIDDLE = Position(APEX_P_X_CENTER, 312)
|
|
79
|
+
APEX_M_BUTTON_ABOVE_LOWER_MIDDLE = Position(APEX_M_X_CENTER, 312)
|
|
62
80
|
|
|
63
81
|
POSITIONS = {
|
|
64
82
|
"Center": {
|
|
65
83
|
DeviceType.STAX: STAX_CENTER,
|
|
66
84
|
DeviceType.FLEX: FLEX_CENTER,
|
|
85
|
+
DeviceType.APEX_P: APEX_P_CENTER,
|
|
86
|
+
DeviceType.APEX_M: APEX_M_CENTER,
|
|
67
87
|
},
|
|
68
88
|
"ChoiceList": {
|
|
69
89
|
DeviceType.STAX: {
|
|
@@ -81,7 +101,23 @@ POSITIONS = {
|
|
|
81
101
|
3: Position(FLEX_X_CENTER, 330),
|
|
82
102
|
4: Position(FLEX_X_CENTER, 420),
|
|
83
103
|
5: Position(FLEX_X_CENTER, 510),
|
|
84
|
-
}
|
|
104
|
+
},
|
|
105
|
+
DeviceType.APEX_P: {
|
|
106
|
+
# Up to 5 choices in a list
|
|
107
|
+
1: Position(APEX_P_X_CENTER, 90),
|
|
108
|
+
2: Position(APEX_P_X_CENTER, 160),
|
|
109
|
+
3: Position(APEX_P_X_CENTER, 230),
|
|
110
|
+
4: Position(APEX_P_X_CENTER, 300),
|
|
111
|
+
5: Position(APEX_P_X_CENTER, 370),
|
|
112
|
+
},
|
|
113
|
+
DeviceType.APEX_M: {
|
|
114
|
+
# Up to 5 choices in a list
|
|
115
|
+
1: Position(APEX_M_X_CENTER, 90),
|
|
116
|
+
2: Position(APEX_M_X_CENTER, 160),
|
|
117
|
+
3: Position(APEX_M_X_CENTER, 230),
|
|
118
|
+
4: Position(APEX_M_X_CENTER, 300),
|
|
119
|
+
5: Position(APEX_M_X_CENTER, 370),
|
|
120
|
+
},
|
|
85
121
|
},
|
|
86
122
|
"Suggestions": {
|
|
87
123
|
DeviceType.STAX: {
|
|
@@ -382,30 +418,38 @@ POSITIONS = {
|
|
|
382
418
|
"TappableCenter": {
|
|
383
419
|
DeviceType.STAX: STAX_CENTER,
|
|
384
420
|
DeviceType.FLEX: FLEX_CENTER,
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
DeviceType.STAX: STAX_BUTTON_UPPER_CENTER_MIDDLE,
|
|
388
|
-
DeviceType.FLEX: FLEX_BUTTON_UPPER_CENTER_MIDDLE,
|
|
421
|
+
DeviceType.APEX_P: APEX_P_CENTER,
|
|
422
|
+
DeviceType.APEX_M: APEX_M_CENTER
|
|
389
423
|
},
|
|
390
424
|
"RightHeader": {
|
|
391
425
|
DeviceType.STAX: STAX_BUTTON_UPPER_RIGHT,
|
|
392
|
-
DeviceType.FLEX: FLEX_BUTTON_UPPER_RIGHT
|
|
426
|
+
DeviceType.FLEX: FLEX_BUTTON_UPPER_RIGHT,
|
|
427
|
+
DeviceType.APEX_P: APEX_P_BUTTON_UPPER_RIGHT,
|
|
428
|
+
DeviceType.APEX_M: APEX_M_BUTTON_UPPER_RIGHT
|
|
393
429
|
},
|
|
394
430
|
"LeftHeader": {
|
|
395
431
|
DeviceType.STAX: STAX_BUTTON_UPPER_LEFT,
|
|
396
|
-
DeviceType.FLEX: FLEX_BUTTON_UPPER_LEFT
|
|
432
|
+
DeviceType.FLEX: FLEX_BUTTON_UPPER_LEFT,
|
|
433
|
+
DeviceType.APEX_P: APEX_P_BUTTON_UPPER_LEFT,
|
|
434
|
+
DeviceType.APEX_M: APEX_M_BUTTON_UPPER_LEFT
|
|
397
435
|
},
|
|
398
436
|
"CenteredFooter": {
|
|
399
437
|
DeviceType.STAX: STAX_BUTTON_LOWER_MIDDLE,
|
|
400
|
-
DeviceType.FLEX: FLEX_BUTTON_LOWER_MIDDLE
|
|
438
|
+
DeviceType.FLEX: FLEX_BUTTON_LOWER_MIDDLE,
|
|
439
|
+
DeviceType.APEX_P: APEX_P_BUTTON_LOWER_MIDDLE,
|
|
440
|
+
DeviceType.APEX_M: APEX_M_BUTTON_LOWER_MIDDLE
|
|
401
441
|
},
|
|
402
442
|
"LeftFooter": {
|
|
403
443
|
DeviceType.STAX: STAX_BUTTON_LOWER_LEFT,
|
|
404
|
-
DeviceType.FLEX: FLEX_BUTTON_LOWER_LEFT
|
|
444
|
+
DeviceType.FLEX: FLEX_BUTTON_LOWER_LEFT,
|
|
445
|
+
DeviceType.APEX_P: APEX_P_BUTTON_LOWER_LEFT,
|
|
446
|
+
DeviceType.APEX_M: APEX_M_BUTTON_LOWER_LEFT
|
|
405
447
|
},
|
|
406
448
|
"CancelFooter": {
|
|
407
449
|
DeviceType.STAX: STAX_BUTTON_LOWER_LEFT,
|
|
408
|
-
DeviceType.FLEX: FLEX_BUTTON_LOWER_LEFT
|
|
450
|
+
DeviceType.FLEX: FLEX_BUTTON_LOWER_LEFT,
|
|
451
|
+
DeviceType.APEX_P: APEX_P_BUTTON_LOWER_LEFT,
|
|
452
|
+
DeviceType.APEX_M: APEX_M_BUTTON_LOWER_LEFT
|
|
409
453
|
},
|
|
410
454
|
"UseCaseHome": {
|
|
411
455
|
DeviceType.STAX: {
|
|
@@ -417,6 +461,16 @@ POSITIONS = {
|
|
|
417
461
|
"info": FLEX_BUTTON_UPPER_RIGHT,
|
|
418
462
|
"settings": FLEX_BUTTON_UPPER_RIGHT,
|
|
419
463
|
"quit": FLEX_BUTTON_LOWER_MIDDLE
|
|
464
|
+
},
|
|
465
|
+
DeviceType.APEX_P: {
|
|
466
|
+
"info": APEX_P_BUTTON_UPPER_RIGHT,
|
|
467
|
+
"settings": APEX_P_BUTTON_UPPER_RIGHT,
|
|
468
|
+
"quit": APEX_P_BUTTON_LOWER_MIDDLE
|
|
469
|
+
},
|
|
470
|
+
DeviceType.APEX_M: {
|
|
471
|
+
"info": APEX_M_BUTTON_UPPER_RIGHT,
|
|
472
|
+
"settings": APEX_M_BUTTON_UPPER_RIGHT,
|
|
473
|
+
"quit": APEX_M_BUTTON_LOWER_MIDDLE
|
|
420
474
|
}
|
|
421
475
|
},
|
|
422
476
|
"UseCaseHomeExt": {
|
|
@@ -431,6 +485,18 @@ POSITIONS = {
|
|
|
431
485
|
"settings": FLEX_BUTTON_UPPER_RIGHT,
|
|
432
486
|
"action": FLEX_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
433
487
|
"quit": FLEX_BUTTON_LOWER_MIDDLE
|
|
488
|
+
},
|
|
489
|
+
DeviceType.APEX_P: {
|
|
490
|
+
"info": APEX_P_BUTTON_UPPER_RIGHT,
|
|
491
|
+
"settings": APEX_P_BUTTON_UPPER_RIGHT,
|
|
492
|
+
"action": APEX_P_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
493
|
+
"quit": APEX_P_BUTTON_LOWER_MIDDLE
|
|
494
|
+
},
|
|
495
|
+
DeviceType.APEX_M: {
|
|
496
|
+
"info": APEX_M_BUTTON_UPPER_RIGHT,
|
|
497
|
+
"settings": APEX_M_BUTTON_UPPER_RIGHT,
|
|
498
|
+
"action": APEX_M_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
499
|
+
"quit": APEX_M_BUTTON_LOWER_MIDDLE
|
|
434
500
|
}
|
|
435
501
|
},
|
|
436
502
|
"UseCaseSettings": {
|
|
@@ -445,6 +511,18 @@ POSITIONS = {
|
|
|
445
511
|
"multi_page_exit": FLEX_BUTTON_UPPER_LEFT,
|
|
446
512
|
"previous": FLEX_BUTTON_LOWER_MIDDLE_RIGHT,
|
|
447
513
|
"next": FLEX_BUTTON_LOWER_RIGHT,
|
|
514
|
+
},
|
|
515
|
+
DeviceType.APEX_P: {
|
|
516
|
+
"single_page_exit": APEX_P_BUTTON_UPPER_LEFT,
|
|
517
|
+
"multi_page_exit": APEX_P_BUTTON_UPPER_LEFT,
|
|
518
|
+
"previous": APEX_P_BUTTON_LOWER_MIDDLE_RIGHT,
|
|
519
|
+
"next": APEX_P_BUTTON_LOWER_RIGHT,
|
|
520
|
+
},
|
|
521
|
+
DeviceType.APEX_M: {
|
|
522
|
+
"single_page_exit": APEX_M_BUTTON_UPPER_LEFT,
|
|
523
|
+
"multi_page_exit": APEX_M_BUTTON_UPPER_LEFT,
|
|
524
|
+
"previous": APEX_M_BUTTON_LOWER_MIDDLE_RIGHT,
|
|
525
|
+
"next": APEX_M_BUTTON_LOWER_RIGHT,
|
|
448
526
|
}
|
|
449
527
|
},
|
|
450
528
|
"UseCaseSubSettings": {
|
|
@@ -457,6 +535,16 @@ POSITIONS = {
|
|
|
457
535
|
"exit": FLEX_BUTTON_UPPER_LEFT,
|
|
458
536
|
"previous": FLEX_BUTTON_LOWER_LEFT,
|
|
459
537
|
"next": FLEX_BUTTON_LOWER_RIGHT,
|
|
538
|
+
},
|
|
539
|
+
DeviceType.APEX_P: {
|
|
540
|
+
"exit": APEX_P_BUTTON_UPPER_LEFT,
|
|
541
|
+
"previous": APEX_P_BUTTON_LOWER_LEFT,
|
|
542
|
+
"next": APEX_P_BUTTON_LOWER_RIGHT,
|
|
543
|
+
},
|
|
544
|
+
DeviceType.APEX_M: {
|
|
545
|
+
"exit": APEX_M_BUTTON_UPPER_LEFT,
|
|
546
|
+
"previous": APEX_M_BUTTON_LOWER_LEFT,
|
|
547
|
+
"next": APEX_M_BUTTON_LOWER_RIGHT,
|
|
460
548
|
}
|
|
461
549
|
},
|
|
462
550
|
"UseCaseChoice": {
|
|
@@ -467,6 +555,14 @@ POSITIONS = {
|
|
|
467
555
|
DeviceType.FLEX: {
|
|
468
556
|
"confirm": FLEX_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
469
557
|
"reject": FLEX_BUTTON_LOWER_LEFT,
|
|
558
|
+
},
|
|
559
|
+
DeviceType.APEX_P: {
|
|
560
|
+
"confirm": APEX_P_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
561
|
+
"reject": APEX_P_BUTTON_LOWER_LEFT,
|
|
562
|
+
},
|
|
563
|
+
DeviceType.APEX_M: {
|
|
564
|
+
"confirm": APEX_M_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
565
|
+
"reject": APEX_M_BUTTON_LOWER_LEFT,
|
|
470
566
|
}
|
|
471
567
|
},
|
|
472
568
|
"UseCaseStatus": {
|
|
@@ -475,6 +571,12 @@ POSITIONS = {
|
|
|
475
571
|
},
|
|
476
572
|
DeviceType.FLEX: {
|
|
477
573
|
"dismiss": FLEX_CENTER,
|
|
574
|
+
},
|
|
575
|
+
DeviceType.APEX_P: {
|
|
576
|
+
"dismiss": APEX_P_CENTER,
|
|
577
|
+
},
|
|
578
|
+
DeviceType.APEX_M: {
|
|
579
|
+
"dismiss": APEX_M_CENTER,
|
|
478
580
|
}
|
|
479
581
|
},
|
|
480
582
|
"UseCaseReview": {
|
|
@@ -489,6 +591,18 @@ POSITIONS = {
|
|
|
489
591
|
"previous": FLEX_BUTTON_LOWER_MIDDLE,
|
|
490
592
|
"confirm": FLEX_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
491
593
|
"reject": FLEX_BUTTON_LOWER_LEFT,
|
|
594
|
+
},
|
|
595
|
+
DeviceType.APEX_P: {
|
|
596
|
+
"tap": APEX_P_BUTTON_LOWER_RIGHT,
|
|
597
|
+
"previous": APEX_P_BUTTON_LOWER_MIDDLE,
|
|
598
|
+
"confirm": APEX_P_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
599
|
+
"reject": APEX_P_BUTTON_LOWER_LEFT,
|
|
600
|
+
},
|
|
601
|
+
DeviceType.APEX_M: {
|
|
602
|
+
"tap": APEX_M_BUTTON_LOWER_RIGHT,
|
|
603
|
+
"previous": APEX_M_BUTTON_LOWER_MIDDLE,
|
|
604
|
+
"confirm": APEX_M_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
605
|
+
"reject": APEX_M_BUTTON_LOWER_LEFT,
|
|
492
606
|
}
|
|
493
607
|
},
|
|
494
608
|
"UseCaseViewDetails": {
|
|
@@ -501,6 +615,16 @@ POSITIONS = {
|
|
|
501
615
|
"exit": FLEX_BUTTON_LOWER_LEFT,
|
|
502
616
|
"previous": FLEX_BUTTON_LOWER_MIDDLE,
|
|
503
617
|
"next": FLEX_BUTTON_LOWER_RIGHT,
|
|
618
|
+
},
|
|
619
|
+
DeviceType.APEX_P: {
|
|
620
|
+
"exit": APEX_P_BUTTON_LOWER_LEFT,
|
|
621
|
+
"previous": APEX_P_BUTTON_LOWER_MIDDLE,
|
|
622
|
+
"next": APEX_P_BUTTON_LOWER_RIGHT,
|
|
623
|
+
},
|
|
624
|
+
DeviceType.APEX_M: {
|
|
625
|
+
"exit": APEX_M_BUTTON_LOWER_LEFT,
|
|
626
|
+
"previous": APEX_M_BUTTON_LOWER_MIDDLE,
|
|
627
|
+
"next": APEX_M_BUTTON_LOWER_RIGHT,
|
|
504
628
|
}
|
|
505
629
|
},
|
|
506
630
|
"UseCaseAddressConfirmation": {
|
|
@@ -515,6 +639,18 @@ POSITIONS = {
|
|
|
515
639
|
"exit_qr": FLEX_BUTTON_LOWER_MIDDLE,
|
|
516
640
|
"confirm": FLEX_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
517
641
|
"cancel": FLEX_BUTTON_LOWER_LEFT,
|
|
642
|
+
},
|
|
643
|
+
DeviceType.APEX_P: {
|
|
644
|
+
"tap": APEX_P_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
645
|
+
"exit_qr": APEX_P_BUTTON_LOWER_MIDDLE,
|
|
646
|
+
"confirm": APEX_P_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
647
|
+
"cancel": APEX_P_BUTTON_LOWER_LEFT,
|
|
648
|
+
},
|
|
649
|
+
DeviceType.APEX_M: {
|
|
650
|
+
"tap": APEX_M_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
651
|
+
"exit_qr": APEX_M_BUTTON_LOWER_MIDDLE,
|
|
652
|
+
"confirm": APEX_M_BUTTON_ABOVE_LOWER_MIDDLE,
|
|
653
|
+
"cancel": APEX_M_BUTTON_LOWER_LEFT,
|
|
518
654
|
}
|
|
519
655
|
},
|
|
520
656
|
}
|
ragger/gui/interface.py
CHANGED
|
@@ -79,7 +79,15 @@ class RaggerMainWindow(QMainWindow):
|
|
|
79
79
|
self._screenshot.setObjectName("screenshot")
|
|
80
80
|
self._screenshot.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
81
81
|
self._screenshot.setAlignment(Qt.AlignmentFlag.AlignVCenter)
|
|
82
|
-
dict_margin = {
|
|
82
|
+
dict_margin = {
|
|
83
|
+
"nanos": 75,
|
|
84
|
+
"nanox": 90,
|
|
85
|
+
"nanosp": 55,
|
|
86
|
+
"stax": 65,
|
|
87
|
+
"flex": 65,
|
|
88
|
+
"apex_p": 65,
|
|
89
|
+
"apex_m": 65
|
|
90
|
+
}
|
|
83
91
|
margin = dict_margin[self._device]
|
|
84
92
|
self._screenshot.setStyleSheet(f"QLabel {{margin-left: {margin}px;}}")
|
|
85
93
|
|
|
@@ -233,7 +241,7 @@ class RaggerMainWindow(QMainWindow):
|
|
|
233
241
|
self._init_screenshot()
|
|
234
242
|
self._init_validation_buttons()
|
|
235
243
|
|
|
236
|
-
if self._device in ["stax", "flex"]:
|
|
244
|
+
if self._device in ["stax", "flex", "apex_p", "apex_m"]:
|
|
237
245
|
self._devicebody.raise_()
|
|
238
246
|
self._touch.raise_()
|
|
239
247
|
self._swipe_left.raise_()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ragger
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.40.0
|
|
4
4
|
Summary: Testing framework using Speculos and LedgerComm as backends
|
|
5
5
|
Author-email: Ledger <hello@ledger.fr>
|
|
6
6
|
Project-URL: Homepage, https://github.com/LedgerHQ/ragger
|
|
@@ -79,7 +79,7 @@ It mainly consists of an interface which is implemented by three backends:
|
|
|
79
79
|
|
|
80
80
|
- two physical backends (although technically they are agnostic, but the
|
|
81
81
|
`SpeculosClient` is superior with an emulator), `LedgerCommBackend` and
|
|
82
|
-
`
|
|
82
|
+
`LedgerWalletBackend`, which use respectively the
|
|
83
83
|
[`LedgerComm` library](https://github.com/LedgerHQ/ledgercomm) or the
|
|
84
84
|
[`LedgerWallet` library](https://github.com/LedgerHQ/ledgerctl/) to discuss
|
|
85
85
|
with a physical device. In these cases, the physical device must be started,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
ragger/__init__.py,sha256=Vbk78M7VtDVMTu02zYQquYSTxtgbieknkvr3uXONrig,713
|
|
2
|
-
ragger/__version__.py,sha256=
|
|
2
|
+
ragger/__version__.py,sha256=dxZI2xWJYica5UvRI6U6kh8KsX350KFePNKSMlGyDEQ,706
|
|
3
3
|
ragger/error.py,sha256=kd9yldPMis080jID6QjyDiCh7TDAVUtF5eczUH5pcKw,1251
|
|
4
4
|
ragger/logger.py,sha256=XF3DsHDLGOHAG7cqVj_7BQlHKj9J8zw8A9soFHIydc8,2457
|
|
5
5
|
ragger/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
ragger/backend/__init__.py,sha256=IQlMre2Pi5QWyYBTROMTbKuonNRUODKrrhj5UxcqQx4,1930
|
|
7
|
-
ragger/backend/interface.py,sha256=
|
|
8
|
-
ragger/backend/ledgercomm.py,sha256=
|
|
9
|
-
ragger/backend/ledgerwallet.py,sha256=
|
|
7
|
+
ragger/backend/interface.py,sha256=nKAp0Q7IYyfyta0__HAxJ3L9BlKlZsqvMsBdUX7jpgQ,21485
|
|
8
|
+
ragger/backend/ledgercomm.py,sha256=XhG2GszkfjrJTPAECqUJ35PCkDs9mHnVn4ThbQZhQPg,3882
|
|
9
|
+
ragger/backend/ledgerwallet.py,sha256=b8p6vTPCddAfIk9uT9bJbPqE8e4UqfL3w10ufqPdROc,3733
|
|
10
10
|
ragger/backend/physical_backend.py,sha256=Y5BRhsKliqCyYFFce7D7swRlT3dkwsXptrUq3zm2Oks,5955
|
|
11
11
|
ragger/backend/speculos.py,sha256=6HZ_BsVA19vFOOo91nI__VecMhIPHPUqxruC51lKqpE,16053
|
|
12
12
|
ragger/backend/stub.py,sha256=p06nUL0S5z14rd9ZihVwpPylYPcIaAtD-WKaHTpDyIQ,3213
|
|
@@ -14,18 +14,18 @@ ragger/bip/__init__.py,sha256=7gY5V8gkJfct1g4OgaLg8bNpgoITGaqU9gTKC4tHbAM,920
|
|
|
14
14
|
ragger/bip/path.py,sha256=uX69L3U8vteIHJy_PE5yPloGaiiYYMq_jLbBSENiRqs,1709
|
|
15
15
|
ragger/bip/seed.py,sha256=yKGM_fkFCh6hNAl7vOMrEv5kEoQoDmVPhBCIMtO8dNk,1758
|
|
16
16
|
ragger/conftest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
ragger/conftest/base_conftest.py,sha256=
|
|
18
|
-
ragger/conftest/configuration.py,sha256=
|
|
17
|
+
ragger/conftest/base_conftest.py,sha256=I2J0rvBY4W9G9OI3mE-qVeAM5vV3b9m_oSWqrceL-iM,19100
|
|
18
|
+
ragger/conftest/configuration.py,sha256=jE_zbvDWSc7jQQ4VEJBo8m_3kME09i2YXK6PLigPAes,3297
|
|
19
19
|
ragger/firmware/__init__.py,sha256=3g_-n2b0qEgVlP42lOQiZzBPux6PCUtZnydkQeEn_Vk,687
|
|
20
|
-
ragger/firmware/structs.py,sha256=
|
|
20
|
+
ragger/firmware/structs.py,sha256=pkUzEkq-kiUntWK2mt1Vkalgoe-3tbvBcLfe12L-CNo,1804
|
|
21
21
|
ragger/firmware/touch/__init__.py,sha256=qI5Hff1FKY_5CpBQFIOHoN8AaL9IGMwmhbNjOer5X9c,672
|
|
22
22
|
ragger/firmware/touch/element.py,sha256=9HmV0pbKGFrNp0nOTJmeyUV7dOLu2_ejeLltmtYPgRA,1337
|
|
23
|
-
ragger/firmware/touch/layouts.py,sha256=
|
|
24
|
-
ragger/firmware/touch/positions.py,sha256=
|
|
23
|
+
ragger/firmware/touch/layouts.py,sha256=XB1jLcJCy_PlnEr9QdSTXOF8hL9B3nRalpMMbalBu0w,2646
|
|
24
|
+
ragger/firmware/touch/positions.py,sha256=kuodm-xeQqI0gErghEB60NsK615YDDec08eomPfXGCU,23498
|
|
25
25
|
ragger/firmware/touch/screen.py,sha256=-t8mRceda9XDl7djZIrpWNsdrIq3Gy2AQbERsOsimUg,7033
|
|
26
26
|
ragger/firmware/touch/use_cases.py,sha256=s8vOumOMxWfs5IRfOIq4i2O-n_ft2RdFdCSRHJgtH4E,3092
|
|
27
27
|
ragger/gui/__init__.py,sha256=m3w6D_46oAKlRFMMsBwdvTvdnshUFDgcjWn_OT06hbE,962
|
|
28
|
-
ragger/gui/interface.py,sha256=
|
|
28
|
+
ragger/gui/interface.py,sha256=lwya2ZE5FfP6fqQJr4FCazP3UdUCE8M099Uw7Lwi0IU,14016
|
|
29
29
|
ragger/gui/process.py,sha256=Uu60zAH6g3qlyh6W-EPj8yOjYJgo1T2y_45g5cWxFgg,5683
|
|
30
30
|
ragger/gui/assets/nanos_body.png,sha256=wBmRW6rOJmcMJ_Dg2xYL7v0PaDIr5A8S_4C06D2h-2w,8394
|
|
31
31
|
ragger/gui/assets/nanos_leftbutton.png,sha256=L7iLeksppZchDq7nJtkqcF5gwze7iridlRC32AALnu0,1194
|
|
@@ -50,8 +50,8 @@ ragger/utils/__init__.py,sha256=PUabSv1qx0XyKWovIxvGBI71sd3O3bKp3gCsUxlWm1E,997
|
|
|
50
50
|
ragger/utils/misc.py,sha256=_ft_CrwEcZ-VVZCBG-_QjYQuTZn-Fht36k3C6BXhHOs,6930
|
|
51
51
|
ragger/utils/packing.py,sha256=2xaRR-FhwVfknP74ZGo-O4JTE6R0HpNqhxKJ9aMrns4,766
|
|
52
52
|
ragger/utils/structs.py,sha256=JMfuX5u-4gSZfqH0SER05B15-mj0YyHjnxLAgxAYtAM,1413
|
|
53
|
-
ragger-1.
|
|
54
|
-
ragger-1.
|
|
55
|
-
ragger-1.
|
|
56
|
-
ragger-1.
|
|
57
|
-
ragger-1.
|
|
53
|
+
ragger-1.40.0.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
54
|
+
ragger-1.40.0.dist-info/METADATA,sha256=aQatMB9sCrPq7J-PKztd4r4V9eTOskrTGbPNze_gZCI,10660
|
|
55
|
+
ragger-1.40.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
56
|
+
ragger-1.40.0.dist-info/top_level.txt,sha256=kqJEoAZ6qn0T3iuVa-710gBK7Ik1euCwNwBbyFraRQg,7
|
|
57
|
+
ragger-1.40.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|