idf-build-apps 2.4.2__py3-none-any.whl → 2.5.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.
@@ -1,6 +1,5 @@
1
1
  # SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2
2
  # SPDX-License-Identifier: Apache-2.0
3
-
4
3
  import operator
5
4
  import os
6
5
  from ast import (
@@ -16,6 +15,7 @@ from packaging.version import (
16
15
  from pyparsing import (
17
16
  Keyword,
18
17
  Literal,
18
+ MatchFirst,
19
19
  ParseResults,
20
20
  QuotedString,
21
21
  Suppress,
@@ -35,6 +35,7 @@ from ..constants import (
35
35
  IDF_VERSION_PATCH,
36
36
  )
37
37
  from ..utils import (
38
+ InvalidIfClause,
38
39
  InvalidInput,
39
40
  to_version,
40
41
  )
@@ -177,22 +178,23 @@ class BoolExpr(Stmt):
177
178
  pass
178
179
 
179
180
 
180
- class BoolAnd(BoolExpr):
181
+ class BoolOrAnd(BoolExpr):
181
182
  def __init__(self, t: ParseResults):
183
+ if len(t[0]) > 3:
184
+ raise InvalidIfClause(
185
+ 'Chaining "and"/"or" is not allowed. Please use paratheses instead. '
186
+ 'For example: "a and b and c" should be "(a and b) and c".'
187
+ )
182
188
  self.left: BoolStmt = t[0][0]
183
189
  self.right: BoolStmt = t[0][2]
184
190
 
185
- def get_value(self, target: str, config_name: str) -> Any:
186
- return self.left.get_value(target, config_name) and self.right.get_value(target, config_name)
187
-
188
-
189
- class BoolOr(BoolExpr):
190
- def __init__(self, t: ParseResults):
191
- self.left: BoolStmt = t[0][0]
192
- self.right: BoolStmt = t[0][2]
191
+ if t[0][1] == 'and':
192
+ self.operation = lambda l, r: l and r # noqa: E741
193
+ if t[0][1] == 'or':
194
+ self.operation = lambda l, r: l or r # noqa: E741
193
195
 
194
196
  def get_value(self, target: str, config_name: str) -> Any:
195
- return self.left.get_value(target, config_name) or self.right.get_value(target, config_name)
197
+ return self.operation(self.left.get_value(target, config_name), self.right.get_value(target, config_name))
196
198
 
197
199
 
198
200
  CAP_WORD = Word(alphas.upper(), nums + alphas.upper() + '_').setParseAction(ChipAttr)
@@ -225,7 +227,6 @@ OR = Keyword('or')
225
227
  BOOL_EXPR = infixNotation(
226
228
  BOOL_STMT,
227
229
  [
228
- (AND, 2, opAssoc.LEFT, BoolAnd),
229
- (OR, 2, opAssoc.LEFT, BoolOr),
230
+ (MatchFirst((AND, OR)), 2, opAssoc.LEFT, BoolOrAnd),
230
231
  ],
231
232
  )
@@ -1,10 +1,10 @@
1
1
  # SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2
2
  # SPDX-License-Identifier: Apache-2.0
3
-
4
3
  import logging
5
4
  import os
5
+ import pickle
6
6
  import typing as t
7
- import warnings
7
+ from hashlib import sha512
8
8
 
9
9
  from pyparsing import (
10
10
  ParseException,
@@ -17,6 +17,8 @@ from ..constants import (
17
17
  from ..utils import (
18
18
  InvalidIfClause,
19
19
  InvalidManifest,
20
+ PathLike,
21
+ to_absolute_path,
20
22
  )
21
23
  from ..yaml import (
22
24
  parse,
@@ -33,14 +35,21 @@ class IfClause:
33
35
  def __init__(self, stmt: str, temporary: bool = False, reason: t.Optional[str] = None) -> None:
34
36
  try:
35
37
  self.stmt: BoolStmt = BOOL_EXPR.parseString(stmt)[0]
36
- except ParseException:
37
- raise InvalidIfClause(f'Invalid if statement: {stmt}')
38
+ except (ParseException, InvalidIfClause) as ex:
39
+ raise InvalidIfClause(f'Invalid if clause: {stmt}. {ex}')
38
40
 
39
41
  self.temporary = temporary
40
42
  self.reason = reason
41
43
 
42
44
  if self.temporary is True and not self.reason:
43
- raise InvalidIfClause('"reason" must be set when "temporary: true"')
45
+ raise InvalidIfClause(
46
+ f'Invalid if clause "{stmt}". '
47
+ f'"reason" must be set when "temporary: true". '
48
+ f'For example:\n'
49
+ f' - if: {stmt}\n'
50
+ f' temporary: true\n'
51
+ f' reason: lack of ci runners'
52
+ )
44
53
 
45
54
  def get_value(self, target: str, config_name: str) -> t.Any:
46
55
  return self.stmt.get_value(target, config_name)
@@ -127,7 +136,26 @@ class FolderRule:
127
136
  self.depends_filepatterns = _clause_to_switch_or_list(depends_filepatterns)
128
137
 
129
138
  def __hash__(self) -> int:
130
- return hash(self.folder)
139
+ return hash(self.sha)
140
+
141
+ @property
142
+ def sha(self) -> str:
143
+ """
144
+ SHA of the FolderRule instance
145
+
146
+ :return: SHA value
147
+ """
148
+ sha = sha512()
149
+ for obj in [
150
+ self.enable,
151
+ self.disable,
152
+ self.disable_test,
153
+ self.depends_components,
154
+ self.depends_filepatterns,
155
+ ]:
156
+ sha.update(pickle.dumps(obj, protocol=4)) # protocol 4 by default is set in Python 3.8
157
+
158
+ return sha.hexdigest()
131
159
 
132
160
  def __repr__(self) -> str:
133
161
  return f'FolderRule({self.folder})'
@@ -207,23 +235,28 @@ class DefaultRule(FolderRule):
207
235
 
208
236
  class Manifest:
209
237
  # could be reassigned later
210
- ROOTPATH = os.curdir
211
238
  CHECK_MANIFEST_RULES = False
212
239
 
213
- def __init__(
214
- self,
215
- rules: t.Iterable[FolderRule],
216
- ) -> None:
240
+ def __init__(self, rules: t.Iterable[FolderRule], *, root_path: str = os.curdir) -> None:
217
241
  self.rules = sorted(rules, key=lambda x: x.folder)
218
242
 
243
+ self._root_path = to_absolute_path(root_path)
244
+
219
245
  @classmethod
220
- def from_files(cls, paths: t.List[str]) -> 'Manifest':
221
- # folder, defined_at dict
222
- _known_folders: t.Dict[str, str] = dict()
246
+ def from_files(cls, paths: t.Iterable[PathLike], *, root_path: str = os.curdir) -> 'Manifest':
247
+ """
248
+ Create a Manifest instance from multiple manifest files
249
+
250
+ :param paths: manifest file paths
251
+ :param root_path: root path for relative paths in manifest files
252
+ :return: Manifest instance
253
+ """
254
+ # folder, defined as dict
255
+ _known_folders: t.Dict[str, PathLike] = dict()
223
256
 
224
257
  rules: t.List[FolderRule] = []
225
258
  for path in paths:
226
- _manifest = cls.from_file(path)
259
+ _manifest = cls.from_file(path, root_path=root_path)
227
260
 
228
261
  for rule in _manifest.rules:
229
262
  if rule.folder in _known_folders:
@@ -231,43 +264,106 @@ class Manifest:
231
264
  if cls.CHECK_MANIFEST_RULES:
232
265
  raise InvalidManifest(msg)
233
266
  else:
234
- warnings.warn(msg)
267
+ LOGGER.warning(msg)
235
268
 
236
269
  _known_folders[rule.folder] = path
237
270
 
238
271
  rules.extend(_manifest.rules)
239
272
 
240
- return Manifest(rules)
273
+ return Manifest(rules, root_path=root_path)
241
274
 
242
275
  @classmethod
243
- def from_file(cls, path: str) -> 'Manifest':
276
+ def from_file(cls, path: PathLike, *, root_path: str = os.curdir) -> 'Manifest':
277
+ """
278
+ Create a Manifest instance from a manifest file
279
+
280
+ :param path: path to the manifest file
281
+ :param root_path: root path for relative paths in manifest file
282
+ :return: Manifest instance
283
+ """
244
284
  manifest_dict = parse(path)
245
285
 
246
286
  rules: t.List[FolderRule] = []
247
287
  for folder, folder_rule in manifest_dict.items():
248
- # not a folder, but a anchor
288
+ # not a folder, but an anchor
249
289
  if folder.startswith('.'):
250
290
  continue
251
291
 
252
292
  if not os.path.isabs(folder):
253
- folder = os.path.join(cls.ROOTPATH, folder)
293
+ folder = os.path.join(root_path, folder)
254
294
 
255
295
  if not os.path.exists(folder):
256
296
  msg = f'Folder "{folder}" does not exist. Please check your manifest file {path}'
257
297
  if cls.CHECK_MANIFEST_RULES:
258
298
  raise InvalidManifest(msg)
259
299
  else:
260
- warnings.warn(msg)
300
+ LOGGER.warning(msg)
261
301
 
262
302
  try:
263
303
  rules.append(FolderRule(folder, **folder_rule if folder_rule else {}))
264
304
  except InvalidIfClause as e:
265
305
  raise InvalidManifest(f'Invalid manifest file {path}: {e}')
266
306
 
267
- return Manifest(rules)
307
+ return Manifest(rules, root_path=root_path)
308
+
309
+ def dump_sha_values(self, sha_filepath: str) -> None:
310
+ """
311
+ Dump the (relative path of the folder, SHA of the FolderRule instance) pairs
312
+ for all rules to the file in format: ``<relative_path>:<SHA>``
313
+
314
+ :param sha_filepath: output file path
315
+ :return: None
316
+ """
317
+ with open(sha_filepath, 'w') as fw:
318
+ for rule in self.rules:
319
+ fw.write(f'{os.path.relpath(rule.folder, self._root_path)}:{rule.sha}\n')
320
+
321
+ def diff_sha_with_filepath(self, sha_filepath: str, use_abspath: bool = False) -> t.Set[str]:
322
+ """
323
+ Compare the SHA recorded in the file with the current Manifest instance.
324
+
325
+ :param sha_filepath: dumped SHA file path
326
+ :param use_abspath: whether to return the absolute path of the folders
327
+ :return: Set of folders that have different SHA values
328
+ """
329
+ recorded__rel_folder__sha__dict = dict()
330
+ with open(sha_filepath) as fr:
331
+ for line in fr:
332
+ line = line.strip()
333
+ if line:
334
+ try:
335
+ folder, sha_value = line.strip().rsplit(':', maxsplit=1)
336
+ except ValueError:
337
+ raise InvalidManifest(f'Invalid line in SHA file: {line}. Expected format: <folder>:<SHA>')
338
+
339
+ recorded__rel_folder__sha__dict[folder] = sha_value
340
+
341
+ self__rel_folder__sha__dict = {os.path.relpath(rule.folder, self._root_path): rule.sha for rule in self.rules}
342
+
343
+ diff_folders = set()
344
+ if use_abspath:
345
+
346
+ def _path(x):
347
+ return os.path.join(self._root_path, x)
348
+ else:
349
+
350
+ def _path(x):
351
+ return x
352
+
353
+ for folder, sha_value in recorded__rel_folder__sha__dict.items():
354
+ if folder not in self__rel_folder__sha__dict:
355
+ diff_folders.add(_path(folder))
356
+ elif sha_value != self__rel_folder__sha__dict[folder]:
357
+ diff_folders.add(_path(folder))
358
+
359
+ for folder in self__rel_folder__sha__dict:
360
+ if folder not in recorded__rel_folder__sha__dict:
361
+ diff_folders.add(_path(folder))
362
+
363
+ return diff_folders
268
364
 
269
- def _most_suitable_rule(self, _folder: str) -> FolderRule:
270
- folder = os.path.abspath(_folder)
365
+ def most_suitable_rule(self, _folder: str) -> FolderRule:
366
+ folder = to_absolute_path(_folder)
271
367
  for rule in self.rules[::-1]:
272
368
  if os.path.commonpath([folder, rule.folder]) == rule.folder:
273
369
  return rule
@@ -277,17 +373,17 @@ class Manifest:
277
373
  def enable_build_targets(
278
374
  self, folder: str, default_sdkconfig_target: t.Optional[str] = None, config_name: t.Optional[str] = None
279
375
  ) -> t.List[str]:
280
- return self._most_suitable_rule(folder).enable_build_targets(default_sdkconfig_target, config_name)
376
+ return self.most_suitable_rule(folder).enable_build_targets(default_sdkconfig_target, config_name)
281
377
 
282
378
  def enable_test_targets(
283
379
  self, folder: str, default_sdkconfig_target: t.Optional[str] = None, config_name: t.Optional[str] = None
284
380
  ) -> t.List[str]:
285
- return self._most_suitable_rule(folder).enable_test_targets(default_sdkconfig_target, config_name)
381
+ return self.most_suitable_rule(folder).enable_test_targets(default_sdkconfig_target, config_name)
286
382
 
287
383
  def depends_components(
288
384
  self, folder: str, default_sdkconfig_target: t.Optional[str] = None, config_name: t.Optional[str] = None
289
385
  ) -> t.List[str]:
290
- res = self._most_suitable_rule(folder).depends_components
386
+ res = self.most_suitable_rule(folder).depends_components
291
387
  if isinstance(res, list):
292
388
  return res
293
389
  return res.get_value(default_sdkconfig_target or '', config_name or '')
@@ -295,7 +391,7 @@ class Manifest:
295
391
  def depends_filepatterns(
296
392
  self, folder: str, default_sdkconfig_target: t.Optional[str] = None, config_name: t.Optional[str] = None
297
393
  ) -> t.List[str]:
298
- res = self._most_suitable_rule(folder).depends_filepatterns
394
+ res = self.most_suitable_rule(folder).depends_filepatterns
299
395
  if isinstance(res, list):
300
396
  return res
301
397
  return res.get_value(default_sdkconfig_target or '', config_name or '')
idf_build_apps/utils.py CHANGED
@@ -13,6 +13,7 @@ import typing as t
13
13
  from copy import (
14
14
  deepcopy,
15
15
  )
16
+ from pathlib import Path
16
17
 
17
18
  from packaging.version import (
18
19
  Version,
@@ -21,6 +22,24 @@ from pydantic import BaseModel as _BaseModel
21
22
 
22
23
  LOGGER = logging.getLogger(__name__)
23
24
 
25
+ if sys.version_info < (3, 8):
26
+ from typing_extensions import (
27
+ Literal,
28
+ )
29
+ else:
30
+ from typing import (
31
+ Literal, # noqa
32
+ )
33
+
34
+ if sys.version_info < (3, 11):
35
+ from typing_extensions import (
36
+ Self,
37
+ )
38
+ else:
39
+ from typing import (
40
+ Self, # noqa
41
+ )
42
+
24
43
 
25
44
  class ConfigRule:
26
45
  def __init__(self, file_name: str, config_name: str = '') -> None:
@@ -106,7 +125,7 @@ class InvalidManifest(SystemExit):
106
125
  """Invalid manifest file"""
107
126
 
108
127
 
109
- def rmdir(path: str, exclude_file_patterns: t.Union[t.List[str], str, None] = None) -> None:
128
+ def rmdir(path: t.Union[Path, str], exclude_file_patterns: t.Union[t.List[str], str, None] = None) -> None:
110
129
  if not exclude_file_patterns:
111
130
  shutil.rmtree(path, ignore_errors=True)
112
131
  return
@@ -365,3 +384,10 @@ class BaseModel(_BaseModel):
365
384
  hash_list.append(v)
366
385
 
367
386
  return hash((type(self), *tuple(hash_list)))
387
+
388
+
389
+ def drop_none_kwargs(d: dict) -> dict:
390
+ return {k: v for k, v in d.items() if v is not None}
391
+
392
+
393
+ PathLike = t.Union[str, Path]
File without changes
@@ -0,0 +1,120 @@
1
+ # SPDX-FileCopyrightText: 2022 Samuel Colvin and other contributors
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ Partially copied from https://github.com/pydantic/pydantic-settings v2.5.2
6
+ since python 3.7 version got dropped at pydantic-settings 2.1.0
7
+ but the feature we need introduced in 2.2.0
8
+
9
+ For contributing history please refer to the original github page
10
+ For the full license text refer to
11
+ https://github.com/pydantic/pydantic-settings/blob/9b73e924cab136d876907af0c6836dcca09ac35c/LICENSE
12
+
13
+ Modifications:
14
+ - use toml instead of tomli when python < 3.11
15
+ - stop using global variables
16
+ - fix some warnings
17
+ """
18
+
19
+ import os
20
+ import sys
21
+ from abc import ABC, abstractmethod
22
+ from pathlib import Path
23
+ from typing import Any, Dict, List, Optional, Tuple, Type, Union
24
+
25
+ from pydantic_settings import InitSettingsSource
26
+ from pydantic_settings.main import BaseSettings
27
+
28
+ PathType = Union[Path, str, List[Union[Path, str]], Tuple[Union[Path, str], ...]]
29
+ DEFAULT_PATH: PathType = Path('')
30
+
31
+
32
+ class ConfigFileSourceMixin(ABC):
33
+ def _read_files(self, files: Optional[PathType]) -> Dict[str, Any]:
34
+ if files is None:
35
+ return {}
36
+ if isinstance(files, (str, os.PathLike)):
37
+ files = [files]
38
+ kwargs: Dict[str, Any] = {}
39
+ for file in files:
40
+ file_path = Path(file).expanduser()
41
+ if file_path.is_file():
42
+ kwargs.update(self._read_file(file_path))
43
+ return kwargs
44
+
45
+ @abstractmethod
46
+ def _read_file(self, path: Path) -> Dict[str, Any]:
47
+ pass
48
+
49
+
50
+ class TomlConfigSettingsSource(InitSettingsSource, ConfigFileSourceMixin):
51
+ """
52
+ A source class that loads variables from a TOML file
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ settings_cls: Type[BaseSettings],
58
+ toml_file: Optional[PathType] = DEFAULT_PATH,
59
+ ):
60
+ self.toml_file_path = toml_file if toml_file != DEFAULT_PATH else settings_cls.model_config.get('toml_file')
61
+ self.toml_data = self._read_files(self.toml_file_path)
62
+ super().__init__(settings_cls, self.toml_data)
63
+
64
+ def _read_file(self, file_path: Path) -> Dict[str, Any]:
65
+ if sys.version_info < (3, 11):
66
+ import toml
67
+
68
+ with open(file_path) as toml_file:
69
+ return toml.load(toml_file)
70
+ else:
71
+ import tomllib
72
+
73
+ with open(file_path, 'rb') as toml_file:
74
+ return tomllib.load(toml_file)
75
+
76
+
77
+ class PyprojectTomlConfigSettingsSource(TomlConfigSettingsSource):
78
+ """
79
+ A source class that loads variables from a `pyproject.toml` file.
80
+ """
81
+
82
+ def __init__(
83
+ self,
84
+ settings_cls: Type[BaseSettings],
85
+ toml_file: Optional[Path] = None,
86
+ ) -> None:
87
+ self.toml_file_path = self._pick_pyproject_toml_file(
88
+ toml_file, settings_cls.model_config.get('pyproject_toml_depth', 0)
89
+ )
90
+ self.toml_table_header: Tuple[str, ...] = settings_cls.model_config.get(
91
+ 'pyproject_toml_table_header', ('tool', 'pydantic-settings')
92
+ )
93
+ self.toml_data = self._read_files(self.toml_file_path)
94
+ for key in self.toml_table_header:
95
+ self.toml_data = self.toml_data.get(key, {})
96
+ super(TomlConfigSettingsSource, self).__init__(settings_cls, self.toml_data)
97
+
98
+ @staticmethod
99
+ def _pick_pyproject_toml_file(provided: Optional[Path], depth: int) -> Path:
100
+ """Pick a `pyproject.toml` file path to use.
101
+
102
+ Args:
103
+ provided: Explicit path provided when instantiating this class.
104
+ depth: Number of directories up the tree to check of a pyproject.toml.
105
+
106
+ """
107
+ if provided:
108
+ return provided.resolve()
109
+ rv = Path.cwd() / 'pyproject.toml'
110
+ count = 0
111
+ if not rv.is_file():
112
+ child = rv.parent.parent / 'pyproject.toml'
113
+ while count < depth:
114
+ if child.is_file():
115
+ return child
116
+ if str(child.parent) == rv.root:
117
+ break # end discovery after checking system root once
118
+ child = child.parent.parent / 'pyproject.toml'
119
+ count += 1
120
+ return rv
@@ -5,6 +5,8 @@ import typing as t
5
5
 
6
6
  import yaml
7
7
 
8
+ from ..utils import PathLike
9
+
8
10
 
9
11
  def parse_postfixes(manifest_dict: t.Dict):
10
12
  for folder, folder_rule in manifest_dict.items():
@@ -60,7 +62,7 @@ def parse_postfixes(manifest_dict: t.Dict):
60
62
  manifest_dict[folder] = updated_folder
61
63
 
62
64
 
63
- def parse(path: str) -> t.Dict:
65
+ def parse(path: PathLike) -> t.Dict:
64
66
  with open(path) as f:
65
67
  manifest_dict = yaml.safe_load(f) or {}
66
68
  parse_postfixes(manifest_dict)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: idf-build-apps
3
- Version: 2.4.2
3
+ Version: 2.5.0
4
4
  Summary: Tools for building ESP-IDF related apps.
5
5
  Author-email: Fu Hanxi <fuhanxi@espressif.com>
6
6
  Requires-Python: >=3.7
@@ -18,8 +18,9 @@ Requires-Dist: pyyaml
18
18
  Requires-Dist: packaging
19
19
  Requires-Dist: toml; python_version < '3.11'
20
20
  Requires-Dist: pydantic~=2.0
21
+ Requires-Dist: pydantic_settings
21
22
  Requires-Dist: argcomplete>=3
22
- Requires-Dist: typing-extensions ; extra == "dev" and ( python_version < '3.8')
23
+ Requires-Dist: typing-extensions; python_version < '3.11'
23
24
  Requires-Dist: sphinx ; extra == "doc"
24
25
  Requires-Dist: sphinx-rtd-theme ; extra == "doc"
25
26
  Requires-Dist: sphinx_copybutton ; extra == "doc"
@@ -32,7 +33,6 @@ Project-URL: changelog, https://github.com/espressif/idf-build-apps/blob/master/
32
33
  Project-URL: documentation, https://docs.espressif.com/projects/idf-build-apps
33
34
  Project-URL: homepage, https://github.com/espressif/idf-build-apps
34
35
  Project-URL: repository, https://github.com/espressif/idf-build-apps
35
- Provides-Extra: dev
36
36
  Provides-Extra: doc
37
37
  Provides-Extra: test
38
38
 
@@ -113,5 +113,5 @@ Thanks for your contribution! Please refer to our [Contributing Guide](CONTRIBUT
113
113
  [hello-world]: https://github.com/espressif/esp-idf/tree/master/examples/get-started/hello_world
114
114
  [supported-targets]: https://github.com/espressif/esp-idf/tree/v5.0#esp-idf-release-and-soc-compatibility
115
115
  [doc]: https://docs.espressif.com/projects/idf-build-apps/en/latest/
116
- [api-doc]: https://docs.espressif.com/projects/idf-build-apps/en/latest/api/modules.html
116
+ [api-doc]: https://docs.espressif.com/projects/idf-build-apps/en/latest/references/api/modules.html
117
117
 
@@ -0,0 +1,27 @@
1
+ idf_build_apps/__init__.py,sha256=1tAmsSMb7Trrua4-819N1AqwwqDEfk9YN4iWCmwUGOU,650
2
+ idf_build_apps/__main__.py,sha256=8E-5xHm2MlRun0L88XJleNh5U50dpE0Q1nK5KqomA7I,182
3
+ idf_build_apps/app.py,sha256=F-MKOsaz7cJ0H2wsEE4gpO4kkkEdkyFmIZBHDoM2qgs,37359
4
+ idf_build_apps/args.py,sha256=Y4Wwoi8XYLjf8lWmCUm197NSzSBa4eC95QAyx4q7-6Q,31668
5
+ idf_build_apps/autocompletions.py,sha256=g-bx0pzXoFKI0VQqftkHyGVWN6MLjuFOdozeuAf45yo,2138
6
+ idf_build_apps/constants.py,sha256=07ve2FtWuLBuc_6LFzbs1XncB1VNi9HJUqGjQQauRNM,3952
7
+ idf_build_apps/finder.py,sha256=kfZaGWJfPUwWAbaOj_W3Fu97SIIFEsv1R_dJucjbFHw,5691
8
+ idf_build_apps/log.py,sha256=pyvT7N4MWzGjIXph5mThQCGBiSt53RNPW0WrFfLr0Kw,2650
9
+ idf_build_apps/main.py,sha256=Z_hetbOavgCJZQPaP01_jx57fR1w0DefiFz0J2cCwp0,16498
10
+ idf_build_apps/session_args.py,sha256=2WDTy40IFAc0KQ57HaeBcYj_k10eUXRKkDOWLrFCaHY,2985
11
+ idf_build_apps/utils.py,sha256=s4D8P7QA17XcaCUQ_EoiNOW_VpU3cPQgiZVV9KQ8I30,10171
12
+ idf_build_apps/junit/__init__.py,sha256=IxvdaS6eSXp7kZxRuXqyZyGxuA_A1nOW1jF1HMi8Gns,231
13
+ idf_build_apps/junit/report.py,sha256=T7dVU3Sz5tqjfbcFW7wjsb65PDH6C2HFf73ePJqBhMs,6555
14
+ idf_build_apps/junit/utils.py,sha256=j0PYhFTZjXtTwkENdeL4bFJcX24ktf1CsOOVXz65yNo,1297
15
+ idf_build_apps/manifest/__init__.py,sha256=Q2-cb3ngNjnl6_zWhUfzZZB10f_-Rv2JYNck3Lk7UkQ,133
16
+ idf_build_apps/manifest/if_parser.py,sha256=XUXN-lemfvR93XOUedO8JybSgLCD71EdkDBGuOE8jnQ,6526
17
+ idf_build_apps/manifest/manifest.py,sha256=1RpD6k-u-51dJIKl4PT3JtQd_3_vKBTwrK4f2a6zFf0,14360
18
+ idf_build_apps/manifest/soc_header.py,sha256=PzJ37xFspt5f0AXWvAFNA_avHZA9fMXHBrwDYLi3qEI,4344
19
+ idf_build_apps/vendors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ idf_build_apps/vendors/pydantic_sources.py,sha256=2IN6opo6qjCwaqhERFbgA4PtEwqKaTtEkccy5_fYAT0,4130
21
+ idf_build_apps/yaml/__init__.py,sha256=W-3z5no07RQ6eYKGyOAPA8Z2CLiMPob8DD91I4URjrA,162
22
+ idf_build_apps/yaml/parser.py,sha256=b3LvogO6do-eJPRsYzT-8xk8AT2MnXpLCzQutJqyC7M,2128
23
+ idf_build_apps-2.5.0.dist-info/entry_points.txt,sha256=3pVUirUEsb6jsDRikkQWNUt4hqLK2ci1HvW_Vf8b6uE,59
24
+ idf_build_apps-2.5.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
25
+ idf_build_apps-2.5.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
26
+ idf_build_apps-2.5.0.dist-info/METADATA,sha256=1qLRKtlKQmat-zA054RMia_mMilScx-nClcbMZPdtfg,4610
27
+ idf_build_apps-2.5.0.dist-info/RECORD,,
@@ -1,64 +0,0 @@
1
- # SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
2
- # SPDX-License-Identifier: Apache-2.0
3
-
4
- import typing as t
5
-
6
- from pydantic import (
7
- computed_field,
8
- )
9
-
10
- from .utils import (
11
- BaseModel,
12
- )
13
-
14
-
15
- class BuildAppsArgs(BaseModel):
16
- PARALLEL_INDEX_PLACEHOLDER: t.ClassVar[str] = '@p' # replace it with the parallel index
17
-
18
- parallel_index: int = 1
19
- parallel_count: int = 1
20
-
21
- _junitxml: t.Optional[str] = None
22
- _collect_app_info: t.Optional[str] = None
23
- _collect_size_info: t.Optional[str] = None
24
-
25
- def __init__(
26
- self,
27
- *,
28
- collect_app_info: t.Optional[str] = None,
29
- collect_size_info: t.Optional[str] = None,
30
- junitxml: t.Optional[str] = None,
31
- **kwargs,
32
- ):
33
- super().__init__(**kwargs)
34
-
35
- self._junitxml = junitxml
36
- self._collect_app_info = collect_app_info
37
- self._collect_size_info = collect_size_info
38
-
39
- @computed_field # type: ignore
40
- @property
41
- def collect_app_info(self) -> t.Optional[str]:
42
- if self._collect_app_info:
43
- return self.expand(self._collect_app_info)
44
-
45
- return None
46
-
47
- @computed_field # type: ignore
48
- @property
49
- def collect_size_info(self) -> t.Optional[str]:
50
- if self._collect_size_info:
51
- return self.expand(self._collect_size_info)
52
-
53
- return None
54
-
55
- @computed_field # type: ignore
56
- @property
57
- def junitxml(self) -> t.Optional[str]:
58
- if self._junitxml:
59
- return self.expand(self._junitxml)
60
-
61
- return None
62
-
63
- def expand(self, path):
64
- return path.replace(self.PARALLEL_INDEX_PLACEHOLDER, str(self.parallel_index))