* [Buildroot] [PATCH] package/depot-tools: fix python 3.14 support
@ 2026-02-03 8:04 Romain Naour via buildroot
2026-02-03 10:37 ` Thomas Petazzoni via buildroot
0 siblings, 1 reply; 2+ messages in thread
From: Romain Naour via buildroot @ 2026-02-03 8:04 UTC (permalink / raw)
To: buildroot; +Cc: Romain Naour, Adam Duskett
Backport a fix to support python 3.14 [1].
depot-tools is used to build flutter package but it doesn't run due to
deprecated ast.Str et al. (since Py3.8) that was removed from python
3.14.
Fixes:
https://gitlab.com/buildroot.org/buildroot/-/jobs/12944797062
[1] https://chromium.googlesource.com/chromium/tools/depot_tools/+/80d6ca1b1ac55fbd9dd8f506417824591251b8eb
Cc: Adam Duskett <adam.duskett@amarulasolutions.com>
Signed-off-by: Romain Naour <romain.naour@smile.fr>
---
For now, just backport a single patch instead of a version bump.
The depot-tools project doesn't seems to do releases.
---
...precated-ast-types-with-ast.Constant.patch | 244 ++++++++++++++++++
1 file changed, 244 insertions(+)
create mode 100644 package/depot-tools/0002-Replace-deprecated-ast-types-with-ast.Constant.patch
diff --git a/package/depot-tools/0002-Replace-deprecated-ast-types-with-ast.Constant.patch b/package/depot-tools/0002-Replace-deprecated-ast-types-with-ast.Constant.patch
new file mode 100644
index 0000000000..09e88d04a2
--- /dev/null
+++ b/package/depot-tools/0002-Replace-deprecated-ast-types-with-ast.Constant.patch
@@ -0,0 +1,244 @@
+From 7d467257a7cd57e746885ea73ccbda903450b461 Mon Sep 17 00:00:00 2001
+From: jj <jj@imput.net>
+Date: Fri, 5 Dec 2025 11:47:42 -0800
+Subject: [PATCH] Replace deprecated ast types with ast.Constant
+
+ast.Str et al. have been deprecated since Py3.8 and have been
+completely removed in 3.14. Replace their usage with ast.Constant.
+
+This change should not have any functional impact, since
+according to [1]:
+> Changed in version 3.8: Class ast.Constant is now used for
+> all constants.
+> Deprecated since version 3.8: Old classes ast.Num, ast.Str,
+> [...] instantiating them will return an instance of a
+> different class.
+
+[1] https://docs.python.org/3/library/ast.html
+
+Bug: 40283283
+Change-Id: I0ed8ef3910f921483bff118976f516c5a935e0fc
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/7228507
+Reviewed-by: Gavin Mak <gavinmak@google.com>
+Reviewed-by: Yiwei Zhang <yiwzhang@google.com>
+Commit-Queue: jj <jj@chromium.org>
+
+Upstream: https://chromium.googlesource.com/chromium/tools/depot_tools/+/80d6ca1b1ac55fbd9dd8f506417824591251b8eb
+[Romain: backport to 097e2072377]
+Signed-off-by: Romain Naour <romain.naour@smile.fr>
+---
+ gclient_eval.py | 72 ++++++++++++++++++++--------------
+ tests/gclient_eval_unittest.py | 6 +++
+ 2 files changed, 49 insertions(+), 29 deletions(-)
+
+diff --git a/gclient_eval.py b/gclient_eval.py
+index f8a05d78a..94874e3ce 100644
+--- a/gclient_eval.py
++++ b/gclient_eval.py
+@@ -101,6 +101,24 @@ def _NodeDictSchema(dict_schema):
+ return validate
+
+
++def _IsConstant(node):
++ return isinstance(node, ast.Constant)
++
++
++def _IsStringConstant(node):
++ return _IsConstant(node) and isinstance(node.value, str)
++
++
++def _IsNameConstant(node):
++ return _IsConstant(node) \
++ and isinstance(node.value, (bool, type(None)))
++
++
++def _IsNumericConstant(node):
++ return _IsConstant(node) \
++ and isinstance(node.value, (int, float, complex)) \
++ and not isinstance(node.value, bool)
++
+ # See https://github.com/keleshev/schema for docs how to configure schema.
+ _GCLIENT_DEPS_SCHEMA = _NodeDictSchema({
+ schema.Optional(str):
+@@ -316,18 +334,18 @@ def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
+ node_or_string = node_or_string.body
+
+ def _convert(node):
+- if isinstance(node, ast.Str):
++ if _IsStringConstant(node):
+ if vars_dict is None:
+- return node.s
++ return node.value
+ try:
+- return node.s.format(**vars_dict)
++ return node.value.format(**vars_dict)
+ except KeyError as e:
+ raise KeyError(
+ '%s was used as a variable, but was not declared in the vars dict '
+ '(file %r, line %s)' %
+ (e.args[0], filename, getattr(node, 'lineno', '<unknown>')))
+- elif isinstance(node, ast.Num):
+- return node.n
++ elif _IsNameConstant(node) or _IsNumericConstant(node):
++ return node.value
+ elif isinstance(node, ast.Tuple):
+ return tuple(map(_convert, node.elts))
+ elif isinstance(node, ast.List):
+@@ -349,9 +367,6 @@ def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
+ 'invalid name %r (file %r, line %s)' %
+ (node.id, filename, getattr(node, 'lineno', '<unknown>')))
+ return _allowed_names[node.id]
+- elif not sys.version_info[:2] < (3, 4) and isinstance(
+- node, ast.NameConstant): # Since Python 3.4
+- return node.value
+ elif isinstance(node, ast.Call):
+ if (not isinstance(node.func, ast.Name)
+ or (node.func.id not in ('Str', 'Var'))):
+@@ -366,8 +381,8 @@ def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
+ '<unknown>')))
+
+ if node.func.id == 'Str':
+- if isinstance(node.args[0], ast.Str):
+- return ConstantString(node.args[0].s)
++ if _IsStringConstant(node.args[0]):
++ return ConstantString(node.args[0].value)
+ raise ValueError(
+ 'Passed a non-string to Str() (file %r, line%s)' %
+ (filename, getattr(node, 'lineno', '<unknown>')))
+@@ -594,8 +609,8 @@ def EvaluateCondition(condition, variables, referenced_variables=None):
+ main_node = main_node.body
+
+ def _convert(node, allow_tuple=False):
+- if isinstance(node, ast.Str):
+- return node.s
++ if _IsStringConstant(node):
++ return node.value
+
+ if isinstance(node, ast.Tuple) and allow_tuple:
+ return tuple(map(_convert, node.elts))
+@@ -627,8 +642,7 @@ def EvaluateCondition(condition, variables, referenced_variables=None):
+ # be evaluated.
+ return node.id
+
+- if not sys.version_info[:2] < (3, 4) and isinstance(
+- node, ast.NameConstant): # Since Python 3.4
++ if _IsNameConstant(node):
+ return node.value
+
+ if isinstance(node, ast.BoolOp) and isinstance(node.op, ast.Or):
+@@ -696,11 +710,11 @@ def _UpdateAstString(tokens, node, value):
+ node = node.args[0]
+ position = node.lineno, node.col_offset
+ quote_char = ''
+- if isinstance(node, ast.Str):
++ if _IsStringConstant(node):
+ quote_char = tokens[position][1][0]
+ value = value.encode('unicode_escape').decode('utf-8')
+ tokens[position][1] = quote_char + value + quote_char
+- node.s = value
++ node.value = value
+
+
+ def _ShiftLinesInTokens(tokens, delta, start):
+@@ -793,11 +807,11 @@ def SetVar(gclient_dict, var_name, value):
+
+ def _GetVarName(node):
+ if isinstance(node, ast.Call):
+- return node.args[0].s
++ return node.args[0].value
+
+- if node.s.endswith('}'):
+- last_brace = node.s.rfind('{')
+- return node.s[last_brace + 1:-1]
++ if node.value.endswith('}'):
++ last_brace = node.value.rfind('{')
++ return node.value[last_brace + 1:-1]
+ return None
+
+
+@@ -821,9 +835,9 @@ def SetGCS(gclient_dict, dep_name, new_objects):
+ keys_to_update = ('object_name', 'sha256sum', 'size_bytes', 'generation')
+ for index, object_node in enumerate(objects_node.elts):
+ for key, value in zip(object_node.keys, object_node.values):
+- if key.s not in keys_to_update:
++ if key.value not in keys_to_update:
+ continue
+- _UpdateAstString(tokens, value, new_objects[index][key.s])
++ _UpdateAstString(tokens, value, new_objects[index][key.value])
+
+ node.SetNode('objects', new_objects, objects_node)
+
+@@ -855,7 +869,7 @@ def SetCIPD(gclient_dict, dep_name, package_name, new_version):
+ "The deps entry for %s:%s has no formatting information." %
+ (dep_name, package_name))
+
+- if not isinstance(node, ast.Call) and not isinstance(node, ast.Str):
++ if not isinstance(node, ast.Call) and not _IsStringConstant(node):
+ raise ValueError(
+ "Unsupported dependency revision format. Please file a bug to the "
+ "Infra>SDK component in crbug.com")
+@@ -880,15 +894,15 @@ def SetRevision(gclient_dict, dep_name, new_revision):
+ if isinstance(node, ast.BinOp):
+ node = node.right
+
+- if isinstance(node, ast.Str):
++ if _IsStringConstant(node):
+ token = _gclient_eval(tokens[node.lineno, node.col_offset][1])
+- if token != node.s:
++ if token != node.value:
+ raise ValueError(
+ 'Can\'t update value for %s. Multiline strings and implicitly '
+ 'concatenated strings are not supported.\n'
+ 'Consider reformatting the DEPS file.' % dep_key)
+
+- if not isinstance(node, ast.Call) and not isinstance(node, ast.Str):
++ if not isinstance(node, ast.Call) and not _IsStringConstant(node):
+ raise ValueError(
+ "Unsupported dependency revision format. Please file a bug to the "
+ "Infra>SDK component in crbug.com")
+@@ -897,15 +911,15 @@ def SetRevision(gclient_dict, dep_name, new_revision):
+ if var_name is not None:
+ SetVar(gclient_dict, var_name, new_revision)
+ else:
+- if '@' in node.s:
++ if '@' in node.value:
+ # '@' is part of the last string, which we want to modify.
+ # Discard whatever was after the '@' and put the new revision in
+ # its place.
+- new_revision = node.s.split('@')[0] + '@' + new_revision
++ new_revision = node.value.split('@')[0] + '@' + new_revision
+ elif '@' not in dep_dict[dep_key]:
+ # '@' is not part of the URL at all. This mean the dependency is
+ # unpinned and we should pin it.
+- new_revision = node.s + '@' + new_revision
++ new_revision = node.value + '@' + new_revision
+ _UpdateAstString(tokens, node, new_revision)
+ dep_dict.SetNode(dep_key, new_revision, node)
+
+diff --git a/tests/gclient_eval_unittest.py b/tests/gclient_eval_unittest.py
+index 03decdf30..3aed06156 100755
+--- a/tests/gclient_eval_unittest.py
++++ b/tests/gclient_eval_unittest.py
+@@ -30,6 +30,11 @@ class GClientEvalTest(unittest.TestCase):
+ def test_str(self):
+ self.assertEqual('foo', gclient_eval._gclient_eval('"foo"'))
+
++ def test_num(self):
++ self.assertEqual(42, gclient_eval._gclient_eval('42'))
++ self.assertEqual(1024.0, gclient_eval._gclient_eval('1024.0'))
++ self.assertEqual(42j, gclient_eval._gclient_eval('42j'))
++
+ def test_tuple(self):
+ self.assertEqual(('a', 'b'), gclient_eval._gclient_eval('("a", "b")'))
+
+@@ -40,6 +45,7 @@ class GClientEvalTest(unittest.TestCase):
+ self.assertEqual({'a': 'b'}, gclient_eval._gclient_eval('{"a": "b"}'))
+
+ def test_name_safe(self):
++ self.assertEqual(None, gclient_eval._gclient_eval('None'))
+ self.assertEqual(True, gclient_eval._gclient_eval('True'))
+
+ def test_name_unsafe(self):
+--
+2.52.0
+
--
2.52.0
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-02-03 10:38 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-03 8:04 [Buildroot] [PATCH] package/depot-tools: fix python 3.14 support Romain Naour via buildroot
2026-02-03 10:37 ` Thomas Petazzoni via buildroot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox