idf-build-apps 2.5.0rc2__py3-none-any.whl → 2.5.1__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.
@@ -8,7 +8,7 @@ Tools for building ESP-IDF related apps.
8
8
  # ruff: noqa: E402
9
9
  # avoid circular imports
10
10
 
11
- __version__ = '2.5.0rc2'
11
+ __version__ = '2.5.1'
12
12
 
13
13
  from .session_args import (
14
14
  SessionArgs,
idf_build_apps/args.py CHANGED
@@ -11,6 +11,7 @@ import sys
11
11
  import typing as t
12
12
  from copy import deepcopy
13
13
  from dataclasses import dataclass
14
+ from io import TextIOWrapper
14
15
  from pathlib import Path
15
16
  from typing import Any
16
17
 
@@ -51,6 +52,8 @@ class FieldMetadata:
51
52
  :param choices: choices for the argument, used in argparse
52
53
  :param type: type for the argument, used in argparse
53
54
  :param required: whether the argument is required, used in argparse
55
+ :param default: default value for the argument, used in argparse
56
+ :param hidden: whether the argument is hidden, used in argparse
54
57
  """
55
58
 
56
59
  # validate method
@@ -66,6 +69,8 @@ class FieldMetadata:
66
69
  required: bool = False
67
70
  # usually default is not needed. only set it when different from the default value of the field
68
71
  default: t.Any = None
72
+ # hidden field, use deprecated instead, or hide it in the argparse
73
+ hidden: bool = False
69
74
 
70
75
 
71
76
  P = ParamSpec('P')
@@ -195,7 +200,9 @@ class DependencyDrivenBuildArguments(GlobalArguments):
195
200
  validate_method=[ValidateMethod.TO_LIST],
196
201
  type=semicolon_separated_str_to_list,
197
202
  ),
198
- description='semicolon-separated list of modified components',
203
+ description='semicolon-separated list of modified components. '
204
+ 'If set to "", the value would be considered as None. '
205
+ 'If set to ";", the value would be considered as an empty list.',
199
206
  default=None,
200
207
  )
201
208
  modified_files: t.Optional[t.List[str]] = field(
@@ -203,7 +210,9 @@ class DependencyDrivenBuildArguments(GlobalArguments):
203
210
  validate_method=[ValidateMethod.TO_LIST],
204
211
  type=semicolon_separated_str_to_list,
205
212
  ),
206
- description='semicolon-separated list of modified files',
213
+ description='semicolon-separated list of modified files. '
214
+ 'If set to "", the value would be considered as None. '
215
+ 'If set to ";", the value would be considered as an empty list.',
207
216
  default=None,
208
217
  )
209
218
  deactivate_dependency_driven_build_by_components: t.Optional[t.List[str]] = field(
@@ -219,7 +228,10 @@ class DependencyDrivenBuildArguments(GlobalArguments):
219
228
  shorthand='-dc',
220
229
  ),
221
230
  description='semicolon-separated list of components. '
222
- 'dependency-driven build feature will be deactivated when any of these components are modified',
231
+ 'dependency-driven build feature will be deactivated when any of these components are modified. '
232
+ 'Must be specified together with --modified-components. '
233
+ 'If set to "", the value would be considered as None. '
234
+ 'If set to ";", the value would be considered as an empty list.',
223
235
  validation_alias=AliasChoices(
224
236
  'deactivate_dependency_driven_build_by_components', 'ignore_app_dependencies_components'
225
237
  ),
@@ -238,7 +250,10 @@ class DependencyDrivenBuildArguments(GlobalArguments):
238
250
  shorthand='-df',
239
251
  ),
240
252
  description='semicolon-separated list of file patterns. '
241
- 'dependency-driven build feature will be deactivated when any of matched files are modified',
253
+ 'dependency-driven build feature will be deactivated when any of matched files are modified. '
254
+ 'Must be specified together with --modified-files. '
255
+ 'If set to "", the value would be considered as None. '
256
+ 'If set to ";", the value would be considered as an empty list.',
242
257
  validation_alias=AliasChoices(
243
258
  'deactivate_dependency_driven_build_by_filepatterns', 'ignore_app_dependencies_filepatterns'
244
259
  ),
@@ -443,7 +458,10 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
443
458
  default=False,
444
459
  )
445
460
  default_build_targets: t.Optional[t.List[str]] = field(
446
- None,
461
+ FieldMetadata(
462
+ validate_method=[ValidateMethod.TO_LIST],
463
+ nargs='+',
464
+ ),
447
465
  description='space-separated list of the default enabled build targets for the apps. '
448
466
  'When not specified, the default value is the targets listed by `idf.py --list-targets`',
449
467
  default=None,
@@ -602,10 +620,16 @@ class BuildArguments(FindBuildArguments):
602
620
  validation_alias=AliasChoices('ignore_warning_strs', 'ignore_warning_str'),
603
621
  default=None,
604
622
  )
605
- ignore_warning_files: t.Optional[t.List[str]] = field(
623
+ ignore_warning_files: t.Optional[t.List[t.Union[str, TextIOWrapper]]] = field(
606
624
  FieldMetadata(
607
- deprecates={'ignore_warning_file': {}},
625
+ validate_method=[ValidateMethod.TO_LIST],
626
+ deprecates={
627
+ 'ignore_warning_file': {
628
+ 'type': argparse.FileType('r'),
629
+ }
630
+ },
608
631
  nargs='+',
632
+ type=argparse.FileType('r'),
609
633
  ),
610
634
  description='Path to the files containing the patterns to ignore the warnings in the build output',
611
635
  validation_alias=AliasChoices('ignore_warning_files', 'ignore_warning_file'),
@@ -621,7 +645,10 @@ class BuildArguments(FindBuildArguments):
621
645
 
622
646
  # Attrs that support placeholders
623
647
  collect_size_info_filename: t.Optional[str] = field(
624
- None,
648
+ FieldMetadata(
649
+ deprecates={'collect_size_info': {}},
650
+ hidden=True,
651
+ ),
625
652
  description='Record size json filepath of the built apps to the specified file. '
626
653
  'Each line is a json string. Can expand placeholders @p',
627
654
  validation_alias=AliasChoices('collect_size_info_filename', 'collect_size_info'),
@@ -629,7 +656,10 @@ class BuildArguments(FindBuildArguments):
629
656
  exclude=True, # computed field is used
630
657
  )
631
658
  collect_app_info_filename: t.Optional[str] = field(
632
- None,
659
+ FieldMetadata(
660
+ deprecates={'collect_app_info': {}},
661
+ hidden=True,
662
+ ),
633
663
  description='Record serialized app model of the built apps to the specified file. '
634
664
  'Each line is a json string. Can expand placeholders @p',
635
665
  validation_alias=AliasChoices('collect_app_info_filename', 'collect_app_info'),
@@ -637,7 +667,10 @@ class BuildArguments(FindBuildArguments):
637
667
  exclude=True, # computed field is used
638
668
  )
639
669
  junitxml_filename: t.Optional[str] = field(
640
- None,
670
+ FieldMetadata(
671
+ deprecates={'junitxml': {}},
672
+ hidden=True,
673
+ ),
641
674
  description='Path to the junitxml file to record the build results. Can expand placeholder @p',
642
675
  validation_alias=AliasChoices('junitxml_filename', 'junitxml'),
643
676
  default=None,
@@ -654,8 +687,14 @@ class BuildArguments(FindBuildArguments):
654
687
  for s in self.ignore_warning_strs:
655
688
  ignore_warnings_regexes.append(re.compile(s))
656
689
  if self.ignore_warning_files:
657
- for s in self.ignore_warning_files:
658
- ignore_warnings_regexes.append(re.compile(s.strip()))
690
+ for f in self.ignore_warning_files:
691
+ if isinstance(f, str):
692
+ with open(f) as fr:
693
+ for s in fr:
694
+ ignore_warnings_regexes.append(re.compile(s.strip()))
695
+ else:
696
+ for s in f:
697
+ ignore_warnings_regexes.append(re.compile(s.strip()))
659
698
  App.IGNORE_WARNS_REGEXES = ignore_warnings_regexes
660
699
 
661
700
  @computed_field # type: ignore
@@ -734,12 +773,20 @@ def add_args_to_parser(argument_cls: t.Type[BaseArguments], parser: argparse.Arg
734
773
  if _shorthand:
735
774
  _names.append(_shorthand)
736
775
 
776
+ if f_meta.hidden: # f is hidden, use deprecated field instead
777
+ help_msg = f.description
778
+ else:
779
+ help_msg = f'[Deprecated] Use {_snake_case_to_cli_arg_name(f_name)} instead'
780
+
737
781
  parser.add_argument(
738
782
  *_names,
739
783
  **dep_f_kwargs,
740
- help=f'[Deprecated] Use {_snake_case_to_cli_arg_name(f_name)} instead',
784
+ help=help_msg,
741
785
  )
742
786
 
787
+ if f_meta and f_meta.hidden:
788
+ continue
789
+
743
790
  names = [_snake_case_to_cli_arg_name(f_name)]
744
791
  if f_meta and f_meta.shorthand:
745
792
  names.append(f_meta.shorthand)
idf_build_apps/main.py CHANGED
@@ -70,6 +70,15 @@ def find_apps(
70
70
  """
71
71
  apply_config_file(config_file)
72
72
 
73
+ # compatible with old usage
74
+ ## `preserve`
75
+ if 'preserve' in kwargs:
76
+ LOGGER.warning(
77
+ 'Passing "preserve" directly is deprecated. '
78
+ 'Pass "no_preserve" instead to disable preserving the build directory'
79
+ )
80
+ kwargs['no_preserve'] = not kwargs.pop('preserve')
81
+
73
82
  if find_arguments is None:
74
83
  find_arguments = FindArguments(
75
84
  paths=to_list(paths), # type: ignore
@@ -125,7 +134,8 @@ def build_apps(
125
134
  """
126
135
  apply_config_file(config_file)
127
136
 
128
- apps = to_list(apps)
137
+ # compatible with old usage
138
+ ## `check_app_dependencies`
129
139
  if 'check_app_dependencies' in kwargs:
130
140
  LOGGER.warning(
131
141
  'Passing "check_app_dependencies" directly is deprecated. '
@@ -138,6 +148,7 @@ def build_apps(
138
148
  **kwargs,
139
149
  )
140
150
 
151
+ apps = to_list(apps)
141
152
  if apps is None:
142
153
  apps = find_apps(
143
154
  find_arguments=FindArguments(
@@ -431,7 +442,8 @@ def main():
431
442
  for app in failed_apps:
432
443
  print(f' {app}')
433
444
 
434
- sys.exit(ret_code)
445
+ if ret_code != 0:
446
+ sys.exit(ret_code)
435
447
 
436
448
 
437
449
  def json_to_app(json_str: str, extra_classes: t.Optional[t.List[t.Type[App]]] = None) -> App:
@@ -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,31 @@ class BoolExpr(Stmt):
177
178
  pass
178
179
 
179
180
 
180
- class BoolAnd(BoolExpr):
181
- def __init__(self, t: ParseResults):
182
- self.left: BoolStmt = t[0][0]
183
- self.right: BoolStmt = t[0][2]
181
+ def _and(_l, _r):
182
+ return _l and _r
184
183
 
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)
184
+
185
+ def _or(_l, _r):
186
+ return _l or _r
187
187
 
188
188
 
189
- class BoolOr(BoolExpr):
189
+ class BoolOrAnd(BoolExpr):
190
190
  def __init__(self, t: ParseResults):
191
+ if len(t[0]) > 3:
192
+ raise InvalidIfClause(
193
+ 'Chaining "and"/"or" is not allowed. Please use paratheses instead. '
194
+ 'For example: "a and b and c" should be "(a and b) and c".'
195
+ )
191
196
  self.left: BoolStmt = t[0][0]
192
197
  self.right: BoolStmt = t[0][2]
193
198
 
199
+ if t[0][1] == 'and':
200
+ self.operation = _and
201
+ if t[0][1] == 'or':
202
+ self.operation = _or
203
+
194
204
  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)
205
+ return self.operation(self.left.get_value(target, config_name), self.right.get_value(target, config_name))
196
206
 
197
207
 
198
208
  CAP_WORD = Word(alphas.upper(), nums + alphas.upper() + '_').setParseAction(ChipAttr)
@@ -225,7 +235,6 @@ OR = Keyword('or')
225
235
  BOOL_EXPR = infixNotation(
226
236
  BOOL_STMT,
227
237
  [
228
- (AND, 2, opAssoc.LEFT, BoolAnd),
229
- (OR, 2, opAssoc.LEFT, BoolOr),
238
+ (MatchFirst((AND, OR)), 2, opAssoc.LEFT, BoolOrAnd),
230
239
  ],
231
240
  )
@@ -35,14 +35,21 @@ class IfClause:
35
35
  def __init__(self, stmt: str, temporary: bool = False, reason: t.Optional[str] = None) -> None:
36
36
  try:
37
37
  self.stmt: BoolStmt = BOOL_EXPR.parseString(stmt)[0]
38
- except ParseException:
39
- raise InvalidIfClause(f'Invalid if statement: {stmt}')
38
+ except (ParseException, InvalidIfClause) as ex:
39
+ raise InvalidIfClause(f'Invalid if clause: {stmt}. {ex}')
40
40
 
41
41
  self.temporary = temporary
42
42
  self.reason = reason
43
43
 
44
44
  if self.temporary is True and not self.reason:
45
- 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
+ )
46
53
 
47
54
  def get_value(self, target: str, config_name: str) -> t.Any:
48
55
  return self.stmt.get_value(target, config_name)
@@ -249,6 +256,7 @@ class Manifest:
249
256
 
250
257
  rules: t.List[FolderRule] = []
251
258
  for path in paths:
259
+ LOGGER.debug('Loading manifest file %s', path)
252
260
  _manifest = cls.from_file(path, root_path=root_path)
253
261
 
254
262
  for rule in _manifest.rules:
@@ -344,11 +352,14 @@ class Manifest:
344
352
  return x
345
353
 
346
354
  for folder, sha_value in recorded__rel_folder__sha__dict.items():
355
+ # removed
347
356
  if folder not in self__rel_folder__sha__dict:
348
357
  diff_folders.add(_path(folder))
358
+ # modified
349
359
  elif sha_value != self__rel_folder__sha__dict[folder]:
350
360
  diff_folders.add(_path(folder))
351
361
 
362
+ # new
352
363
  for folder in self__rel_folder__sha__dict:
353
364
  if folder not in recorded__rel_folder__sha__dict:
354
365
  diff_folders.add(_path(folder))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: idf-build-apps
3
- Version: 2.5.0rc2
3
+ Version: 2.5.1
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
@@ -1,27 +1,27 @@
1
- idf_build_apps/__init__.py,sha256=qNCNTH1dk1j7euO_o2AVw2usSipP9euNQd2j5_sDuY4,653
1
+ idf_build_apps/__init__.py,sha256=hPsqVwLnkcGIEQNAReIvWhXRDoov8t70997wSn1zJ0g,650
2
2
  idf_build_apps/__main__.py,sha256=8E-5xHm2MlRun0L88XJleNh5U50dpE0Q1nK5KqomA7I,182
3
3
  idf_build_apps/app.py,sha256=F-MKOsaz7cJ0H2wsEE4gpO4kkkEdkyFmIZBHDoM2qgs,37359
4
- idf_build_apps/args.py,sha256=bNVrFsB3V1vhukNGgF3YOL-92GHqQZF3rOkJhqIDDvU,29627
4
+ idf_build_apps/args.py,sha256=Y4Wwoi8XYLjf8lWmCUm197NSzSBa4eC95QAyx4q7-6Q,31668
5
5
  idf_build_apps/autocompletions.py,sha256=g-bx0pzXoFKI0VQqftkHyGVWN6MLjuFOdozeuAf45yo,2138
6
6
  idf_build_apps/constants.py,sha256=07ve2FtWuLBuc_6LFzbs1XncB1VNi9HJUqGjQQauRNM,3952
7
7
  idf_build_apps/finder.py,sha256=kfZaGWJfPUwWAbaOj_W3Fu97SIIFEsv1R_dJucjbFHw,5691
8
8
  idf_build_apps/log.py,sha256=pyvT7N4MWzGjIXph5mThQCGBiSt53RNPW0WrFfLr0Kw,2650
9
- idf_build_apps/main.py,sha256=OeWzXkA-68MIv6MmgBN_8XhDJQUvYjJiYxR5zkdQiT0,16094
9
+ idf_build_apps/main.py,sha256=Z_hetbOavgCJZQPaP01_jx57fR1w0DefiFz0J2cCwp0,16498
10
10
  idf_build_apps/session_args.py,sha256=2WDTy40IFAc0KQ57HaeBcYj_k10eUXRKkDOWLrFCaHY,2985
11
11
  idf_build_apps/utils.py,sha256=s4D8P7QA17XcaCUQ_EoiNOW_VpU3cPQgiZVV9KQ8I30,10171
12
12
  idf_build_apps/junit/__init__.py,sha256=IxvdaS6eSXp7kZxRuXqyZyGxuA_A1nOW1jF1HMi8Gns,231
13
13
  idf_build_apps/junit/report.py,sha256=T7dVU3Sz5tqjfbcFW7wjsb65PDH6C2HFf73ePJqBhMs,6555
14
14
  idf_build_apps/junit/utils.py,sha256=j0PYhFTZjXtTwkENdeL4bFJcX24ktf1CsOOVXz65yNo,1297
15
15
  idf_build_apps/manifest/__init__.py,sha256=Q2-cb3ngNjnl6_zWhUfzZZB10f_-Rv2JYNck3Lk7UkQ,133
16
- idf_build_apps/manifest/if_parser.py,sha256=r0pivV9gmniPn3Ia6sTMbW5tFAKInhOXk-Lfd6GokqE,6381
17
- idf_build_apps/manifest/manifest.py,sha256=5BekZkLutVrpe6HaUYeBiNqbxkRAFjQpUo9hG1eN1zg,14090
16
+ idf_build_apps/manifest/if_parser.py,sha256=AAEyYPgcBWL2ToCmcvhx3fl8ebYdC5-LMvvDkYtWn8o,6546
17
+ idf_build_apps/manifest/manifest.py,sha256=6F6Nt93eaoBOHlGHZtv2hHT8Zw0HmJf0d_MESlgye6M,14478
18
18
  idf_build_apps/manifest/soc_header.py,sha256=PzJ37xFspt5f0AXWvAFNA_avHZA9fMXHBrwDYLi3qEI,4344
19
19
  idf_build_apps/vendors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  idf_build_apps/vendors/pydantic_sources.py,sha256=2IN6opo6qjCwaqhERFbgA4PtEwqKaTtEkccy5_fYAT0,4130
21
21
  idf_build_apps/yaml/__init__.py,sha256=W-3z5no07RQ6eYKGyOAPA8Z2CLiMPob8DD91I4URjrA,162
22
22
  idf_build_apps/yaml/parser.py,sha256=b3LvogO6do-eJPRsYzT-8xk8AT2MnXpLCzQutJqyC7M,2128
23
- idf_build_apps-2.5.0rc2.dist-info/entry_points.txt,sha256=3pVUirUEsb6jsDRikkQWNUt4hqLK2ci1HvW_Vf8b6uE,59
24
- idf_build_apps-2.5.0rc2.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
25
- idf_build_apps-2.5.0rc2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
26
- idf_build_apps-2.5.0rc2.dist-info/METADATA,sha256=i65JKj_Ul2N4ItjFbehykUlkzxKyjy1hSudWtnSPliw,4613
27
- idf_build_apps-2.5.0rc2.dist-info/RECORD,,
23
+ idf_build_apps-2.5.1.dist-info/entry_points.txt,sha256=3pVUirUEsb6jsDRikkQWNUt4hqLK2ci1HvW_Vf8b6uE,59
24
+ idf_build_apps-2.5.1.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
25
+ idf_build_apps-2.5.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
26
+ idf_build_apps-2.5.1.dist-info/METADATA,sha256=lvliMyMStV-5w_77UputZgbH9ZL2aDagexjxU6OUi-I,4610
27
+ idf_build_apps-2.5.1.dist-info/RECORD,,