ledgered 0.8.1.dev4__tar.gz → 0.9.0__tar.gz

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.
Files changed (56) hide show
  1. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/CHANGELOG.md +8 -1
  2. {ledgered-0.8.1.dev4/src/ledgered.egg-info → ledgered-0.9.0}/PKG-INFO +1 -1
  3. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/__version__.py +2 -2
  4. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/github.py +79 -7
  5. {ledgered-0.8.1.dev4 → ledgered-0.9.0/src/ledgered.egg-info}/PKG-INFO +1 -1
  6. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/functional/test_github.py +5 -1
  7. ledgered-0.9.0/tests/unit/test_github.py +81 -0
  8. ledgered-0.8.1.dev4/tests/unit/test_github.py +0 -45
  9. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/.codecov.yml +0 -0
  10. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/.github/workflows/build_and_tests.yml +0 -0
  11. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/.github/workflows/codeql-analysis.yml +0 -0
  12. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/.github/workflows/fast-checks.yml +0 -0
  13. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/.gitignore +0 -0
  14. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/.pre-commit-config.yaml +0 -0
  15. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/LICENSE +0 -0
  16. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/README.md +0 -0
  17. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/doc/binary.md +0 -0
  18. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/doc/manifest.md +0 -0
  19. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/pyproject.toml +0 -0
  20. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/setup.cfg +0 -0
  21. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/__init__.py +0 -0
  22. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/binary.py +0 -0
  23. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/__init__.py +0 -0
  24. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/app.py +0 -0
  25. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/cli.py +0 -0
  26. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/constants.py +0 -0
  27. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/errors.py +0 -0
  28. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/manifest.py +0 -0
  29. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/tests.py +0 -0
  30. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/use_cases.py +0 -0
  31. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/manifest/utils.py +0 -0
  32. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/serializers.py +0 -0
  33. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered/utils/__init__.py +0 -0
  34. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered.egg-info/SOURCES.txt +0 -0
  35. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered.egg-info/dependency_links.txt +0 -0
  36. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered.egg-info/entry_points.txt +0 -0
  37. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered.egg-info/requires.txt +0 -0
  38. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/src/ledgered.egg-info/top_level.txt +0 -0
  39. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/_data/Cargo.toml +0 -0
  40. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/_data/Makefile +0 -0
  41. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/_data/full_correct.toml +0 -0
  42. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/_data/ledger_app.toml +0 -0
  43. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/_data/minimal.toml +0 -0
  44. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/_data/one_leaf.toml +0 -0
  45. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/functional/__init__.py +0 -0
  46. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/functional/conftest.py +0 -0
  47. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/functional/manifest/__init__.py +0 -0
  48. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/functional/manifest/test_cli.py +0 -0
  49. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/__init__.py +0 -0
  50. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/manifest/__init__.py +0 -0
  51. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/manifest/test_app.py +0 -0
  52. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/manifest/test_manifest.py +0 -0
  53. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/manifest/test_tests.py +0 -0
  54. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/manifest/test_use_cases.py +0 -0
  55. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/test_binary.py +0 -0
  56. {ledgered-0.8.1.dev4 → ledgered-0.9.0}/tests/unit/test_serializers.py +0 -0
@@ -5,12 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.9.0] - 2025-03-??
8
+ ## [0.9.0] - 2025-03-25
9
9
 
10
10
  ### Added
11
11
 
12
12
  - `ledger-manifest`: new `--token` argument, allowing to provide a PAT to evade GitHub API
13
13
  limitations when parsing remote manifest (with the `--url` argument).
14
+ - New _property_ to get more info for variants: `variant_param`
15
+ - New filtering options:
16
+ - `legacy`: to select or not the Apps whose name contains _legacy_ in their name (disabled by default)
17
+ - `plugin`: to select or not the Apps whose name starts by _app-plugin-_ (disabled by default)
18
+ - `only_list`: to select only a predefined list of Apps
19
+ - `exclude_list`: to exclude a predefined list of Apps
20
+ - `sdk`: to filter apps, based on their SDK (C or Rust)
14
21
 
15
22
  ## [0.8.0] - 2025-03-06
16
23
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ledgered
3
- Version: 0.8.1.dev4
3
+ Version: 0.9.0
4
4
  Summary: Python tools, utils, libraries, to be used with Ledger cryptodevices
5
5
  Author-email: Ledger <hello@ledger.fr>
6
6
  License: MIT License
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.8.1.dev4'
21
- __version_tuple__ = version_tuple = (0, 8, 1, 'dev4')
20
+ __version__ = version = '0.9.0'
21
+ __version_tuple__ = version_tuple = (0, 9, 0)
@@ -8,6 +8,7 @@ from unittest.mock import patch
8
8
  from ledgered.manifest import MANIFEST_FILE_NAME, Manifest
9
9
 
10
10
  LEDGER_ORG_NAME = "ledgerhq"
11
+ APP_PLUGIN_PREFIX = "app-plugin-"
11
12
 
12
13
 
13
14
  class Condition(IntEnum):
@@ -30,6 +31,8 @@ class AppRepository(PyRepository.Repository):
30
31
  self._manifest: Optional[Manifest] = None
31
32
  self._makefile: Optional[str] = None
32
33
  self._branch: str = self.default_branch
34
+ self._variant_param: Optional[str] = None
35
+ self._variant_values: List[str] = []
33
36
 
34
37
  @property
35
38
  def manifest(self) -> Manifest:
@@ -70,13 +73,15 @@ class AppRepository(PyRepository.Repository):
70
73
 
71
74
  @property
72
75
  def variants(self) -> List[str]:
73
- variants = []
74
- for line in self.makefile.splitlines():
75
- if "VARIANTS" in line:
76
- variants.extend(line.split(" ")[3:])
77
- elif "VARIANT_VALUES = " in line:
78
- variants.extend(line.split(" = ")[1].split(" "))
79
- return variants
76
+ if not self._variant_values:
77
+ self.__set_variants()
78
+ return self._variant_values
79
+
80
+ @property
81
+ def variant_param(self) -> Optional[str]:
82
+ if self._variant_param is None:
83
+ self.__set_variants()
84
+ return self._variant_param
80
85
 
81
86
  @property
82
87
  def current_branch(self) -> str:
@@ -88,6 +93,39 @@ class AppRepository(PyRepository.Repository):
88
93
  # invalidating previously fetched info, as they may differ on another branch
89
94
  self._manifest = None
90
95
  self._makefile = None
96
+ self._variant_param = None
97
+ self._variant_values.clear()
98
+
99
+ def __set_variants(self) -> None:
100
+ """Extracts the variants from the app Makefile"""
101
+
102
+ for line in self.makefile.splitlines():
103
+ if "VARIANTS" in line:
104
+ # Ex: `@echo VARIANTS COIN ACA ACA_XL`
105
+ parts = line.split(" ")
106
+ if len(parts) >= 3:
107
+ self._variant_param = parts[2]
108
+ self._variant_values = parts[3:]
109
+ elif "VARIANT_PARAM" in line and "=" in line:
110
+ # There should be a single word here, ex: `VARIANT_PARAM = COIN`
111
+ self._variant_param = line.split("=")[1].split()[0]
112
+ elif "VARIANT_VALUES" in line and "=" in line:
113
+ # We can have multiple values here, ex: `VARIANT_VALUES = bitcoin_testnet bitcoin`
114
+ # Sometimes, it can be a computed value in the Makefile, ex: `VARIANT_VALUES = $(SUPPORTED_CHAINS)`
115
+ # => No solution to get them for now
116
+ self._variant_values = [
117
+ val.strip() for val in line.split("=")[1].split() if not val.startswith("$(")
118
+ ]
119
+
120
+ if self._variant_param is not None and self._variant_values:
121
+ break
122
+ else:
123
+ # No variant found
124
+ self._variant_values = []
125
+
126
+ if not self._variant_values:
127
+ # Invalid configuration, reset the name
128
+ self._variant_param = None
91
129
 
92
130
 
93
131
  class GitHubApps(list):
@@ -99,8 +137,20 @@ class GitHubApps(list):
99
137
  name: Optional[str] = None,
100
138
  archived: Condition = Condition.WITH,
101
139
  private: Condition = Condition.WITH,
140
+ legacy: Condition = Condition.WITH,
141
+ plugin: Condition = Condition.WITH,
142
+ only_list: Optional[List[str]] = None,
143
+ exclude_list: Optional[List[str]] = None,
144
+ sdk: Optional[List[str]] = None,
102
145
  ) -> "GitHubApps":
103
146
  new_list = [i for i in self]
147
+ # only_list filtering (takes precedence on exclude_list)
148
+ if only_list:
149
+ new_list = [r for r in new_list if r.name in only_list]
150
+ # exclude_list filtering
151
+ elif exclude_list:
152
+ new_list = [r for r in new_list if r.name not in exclude_list]
153
+ # sdk filtering
104
154
  # archived filtering
105
155
  if archived == Condition.WITHOUT:
106
156
  new_list = [r for r in new_list if not r.archived]
@@ -114,6 +164,28 @@ class GitHubApps(list):
114
164
  # name filtering
115
165
  if name is not None:
116
166
  new_list = [r for r in new_list if name.lower() in r.name.lower()]
167
+ # legacy apps filtering
168
+ if legacy == Condition.WITHOUT:
169
+ new_list = [r for r in new_list if "legacy" not in r.name.lower()]
170
+ elif legacy == Condition.ONLY:
171
+ new_list = [r for r in new_list if "legacy" in r.name.lower()]
172
+ # plugin apps filtering
173
+ if plugin == Condition.WITHOUT:
174
+ new_list = [r for r in new_list if not r.name.lower().startswith(APP_PLUGIN_PREFIX)]
175
+ elif plugin == Condition.ONLY:
176
+ new_list = [r for r in new_list if r.name.lower().startswith(APP_PLUGIN_PREFIX)]
177
+ if sdk is not None:
178
+ # Check list of sdk
179
+ sdk_list = [s.lower() for s in sdk]
180
+ res_list = []
181
+ for r in new_list:
182
+ try:
183
+ if r.manifest.app.sdk in sdk_list:
184
+ res_list.append(r)
185
+ except NoManifestException:
186
+ pass
187
+ new_list = res_list
188
+
117
189
  return GitHubApps(new_list)
118
190
 
119
191
  def first(self, *args, **kwargs) -> Optional[AppRepository]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ledgered
3
- Version: 0.8.1.dev4
3
+ Version: 0.9.0
4
4
  Summary: Python tools, utils, libraries, to be used with Ledger cryptodevices
5
5
  Author-email: Ledger <hello@ledger.fr>
6
6
  License: MIT License
@@ -43,10 +43,14 @@ def test_exchange_branches(exchange):
43
43
  exchange.current_branch = "does not exists"
44
44
 
45
45
 
46
- def test_exchange_variant(exchange):
46
+ def test_exchange_variant_values(exchange):
47
47
  assert exchange.variants == ["exchange"]
48
48
 
49
49
 
50
+ def test_exchange_variant_param(exchange):
51
+ assert exchange.variant_param == "COIN"
52
+
53
+
50
54
  def test_starknet_makefile_path(gh):
51
55
  app = gh.get_app("app-starknet")
52
56
  assert app.makefile_path == Path("./starknet/Cargo.toml")
@@ -0,0 +1,81 @@
1
+ from typing import Optional
2
+ from unittest import TestCase
3
+ from unittest.mock import MagicMock
4
+
5
+ from ledgered.github import Condition, GitHubApps, GitHubLedgerHQ, NoManifestException
6
+
7
+
8
+ class AppRepositoryMock:
9
+ def __init__(
10
+ self, name: str, sdk: Optional[str] = "c", archived: bool = False, private: bool = False
11
+ ):
12
+ self.name = name
13
+ self.archived = archived
14
+ self.private = private
15
+ self._sdk = sdk
16
+
17
+ @property
18
+ def manifest(self) -> str:
19
+ if self._sdk:
20
+ mock = MagicMock()
21
+ mock.app.sdk = self._sdk
22
+ return mock
23
+ else:
24
+ raise NoManifestException(MagicMock())
25
+
26
+
27
+ class TestGitHubApps(TestCase):
28
+ def setUp(self):
29
+ self.app1 = AppRepositoryMock("app-1", sdk="rust")
30
+ self.app2 = AppRepositoryMock("not-app")
31
+ self.app3 = AppRepositoryMock("app-3", private=True)
32
+ self.app4 = AppRepositoryMock("app-4", archived=True)
33
+ self.app5 = AppRepositoryMock("app-plugin-foo")
34
+ self.app6 = AppRepositoryMock("app-foo-legacy")
35
+ self.apps = GitHubApps([self.app1, self.app2, self.app3, self.app4, self.app5, self.app6])
36
+
37
+ def test___init__(self):
38
+ self.assertListEqual(self.apps, [self.app1, self.app3, self.app4, self.app5, self.app6])
39
+
40
+ def test_filter(self):
41
+ self.assertCountEqual(self.apps.filter(), self.apps)
42
+ self.assertCountEqual(self.apps.filter(name="3"), [self.app3])
43
+ self.assertCountEqual(self.apps.filter(name="app"), self.apps)
44
+ self.assertCountEqual(
45
+ self.apps.filter(archived=Condition.WITHOUT),
46
+ [self.app1, self.app3, self.app5, self.app6],
47
+ )
48
+ self.assertCountEqual(self.apps.filter(archived=Condition.ONLY), [self.app4])
49
+ self.assertCountEqual(
50
+ self.apps.filter(private=Condition.WITHOUT),
51
+ [self.app1, self.app4, self.app5, self.app6],
52
+ )
53
+ self.assertCountEqual(self.apps.filter(private=Condition.ONLY), [self.app3])
54
+ self.assertCountEqual(
55
+ self.apps.filter(legacy=Condition.WITHOUT), [self.app1, self.app3, self.app4, self.app5]
56
+ )
57
+ self.assertCountEqual(self.apps.filter(legacy=Condition.ONLY), [self.app6])
58
+ self.assertCountEqual(
59
+ self.apps.filter(plugin=Condition.WITHOUT), [self.app1, self.app3, self.app4, self.app6]
60
+ )
61
+ self.assertCountEqual(self.apps.filter(plugin=Condition.ONLY), [self.app5])
62
+ self.assertCountEqual(
63
+ self.apps.filter(only_list=["app-1", "app-3"]), [self.app1, self.app3]
64
+ )
65
+ self.assertCountEqual(
66
+ self.apps.filter(exclude_list=["app-1", "app-3"]), [self.app4, self.app5, self.app6]
67
+ )
68
+ self.assertCountEqual(self.apps.filter(sdk=["rust"]), [self.app1])
69
+
70
+ def test_first(self):
71
+ self.assertEqual(self.apps.first("3"), self.app3)
72
+ self.assertEqual(self.apps.first(), self.app1)
73
+
74
+
75
+ class TestGitHubLedgerHQ(TestCase):
76
+ def setUp(self):
77
+ self.g = GitHubLedgerHQ()
78
+
79
+ def test_get_app_wrong_name(self):
80
+ with self.assertRaises(AssertionError):
81
+ self.g.get_app("not-starting-with-app-")
@@ -1,45 +0,0 @@
1
- from dataclasses import dataclass
2
- from unittest import TestCase
3
-
4
- from ledgered.github import Condition, GitHubApps, GitHubLedgerHQ
5
-
6
-
7
- @dataclass
8
- class AppRepositoryMock:
9
- name: str
10
- archived: bool = False
11
- private: bool = False
12
-
13
-
14
- class TestGitHubApps(TestCase):
15
- def setUp(self):
16
- self.app1 = AppRepositoryMock("app-1")
17
- self.app2 = AppRepositoryMock("not-app")
18
- self.app3 = AppRepositoryMock("app-3", private=True)
19
- self.app4 = AppRepositoryMock("app-4", archived=True)
20
- self.apps = GitHubApps([self.app1, self.app2, self.app3, self.app4])
21
-
22
- def test___init__(self):
23
- self.assertListEqual(self.apps, [self.app1, self.app3, self.app4])
24
-
25
- def test_filter(self):
26
- self.assertCountEqual(self.apps.filter(), self.apps)
27
- self.assertCountEqual(self.apps.filter(name="3"), [self.app3])
28
- self.assertCountEqual(self.apps.filter(name="app"), self.apps)
29
- self.assertCountEqual(self.apps.filter(archived=Condition.WITHOUT), [self.app1, self.app3])
30
- self.assertCountEqual(self.apps.filter(archived=Condition.ONLY), [self.app4])
31
- self.assertCountEqual(self.apps.filter(private=Condition.WITHOUT), [self.app1, self.app4])
32
- self.assertCountEqual(self.apps.filter(private=Condition.ONLY), [self.app3])
33
-
34
- def test_first(self):
35
- self.assertEqual(self.apps.first("3"), self.app3)
36
- self.assertEqual(self.apps.first(), self.app1)
37
-
38
-
39
- class TestGitHubLedgerHQ(TestCase):
40
- def setUp(self):
41
- self.g = GitHubLedgerHQ()
42
-
43
- def test_get_app_wrong_name(self):
44
- with self.assertRaises(AssertionError):
45
- self.g.get_app("not-starting-with-app-")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes