All of 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.