Buildroot Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [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