mirror of
https://gitlab.com/buildroot.org/buildroot.git
synced 2026-09-26 03:50:44 -09:00
package/depot-tools: fix python 3.14 support
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] 80d6ca1b1a
Cc: Adam Duskett <adam.duskett@amarulasolutions.com>
Signed-off-by: Romain Naour <romain.naour@smile.fr>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
This commit is contained in:
committed by
Thomas Petazzoni
parent
8e4c663529
commit
bc2d04f30d
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user