File: 0004-python3-14.patch

package info (click to toggle)
compyle 0.9.1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,080 kB
  • sloc: python: 12,898; makefile: 21
file content (223 lines) | stat: -rw-r--r-- 7,884 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
Origin: https://github.com/pypr/compyle/pull/124
From: Bastian Germann <bage@debian.org>
Date: Tue, 24 Feb 2026 23:40:24 +0100
Subject: Support Python 3.14 AST: handle ast.Constant and use ast_utils helpers
---
diff --git a/compyle/ast_utils.py b/compyle/ast_utils.py
index e622142..b27aad0 100644
--- a/compyle/ast_utils.py
+++ b/compyle/ast_utils.py
@@ -174,3 +174,27 @@ def has_return(code):
     """Returns True of the node has a return statement.
     """
     return has_node(code, ast.Return)
+
+
+def is_str_node(node):
+    """Return True if the AST node represents a string literal.
+
+    Works on both older ASTs (ast.Str) and newer ones (ast.Constant).
+    """
+    if isinstance(node, ast.Constant):
+        return isinstance(node.value, str)
+    Str = getattr(ast, 'Str', None)
+    return Str is not None and isinstance(node, Str)
+
+
+def get_str_value(node):
+    """Return the string value for a string AST node.
+
+    Returns None if the node is not a string node.
+    """
+    if isinstance(node, ast.Constant):
+        return node.value if isinstance(node.value, str) else None
+    Str = getattr(ast, 'Str', None)
+    if Str is not None and isinstance(node, Str):
+        return node.s
+    return None
diff --git a/compyle/cython_generator.py b/compyle/cython_generator.py
index a0e7e51..d84c23c 100644
--- a/compyle/cython_generator.py
+++ b/compyle/cython_generator.py
@@ -21,7 +21,7 @@
 
 from .types import KnownType, Undefined, get_declare_info
 from .config import get_config
-from .ast_utils import get_assigned, has_return
+from .ast_utils import get_assigned, has_return, get_str_value, is_str_node
 from .utils import getsourcelines
 
 logger = logging.getLogger(__name__)
@@ -247,11 +247,12 @@ def parse_declare(code):
     if call.func.id != 'declare':
         raise CodeGenerationError('Unknown declare statement: %s' % code)
     arg0 = call.args[0]
-    if not isinstance(arg0, ast.Str):
-        err = 'Type should be a string, given :%r' % arg0.s
+    typestr = get_str_value(arg0)
+    if typestr is None:
+        err = 'Type should be a string, given :%r' % getattr(arg0, 's', getattr(arg0, 'value', arg0))
         raise CodeGenerationError(err)
 
-    return get_declare_info(arg0.s)
+    return get_declare_info(typestr)
 
 
 class CythonGenerator(object):
diff --git a/compyle/jit.py b/compyle/jit.py
index 080fd42..21292a8 100644
--- a/compyle/jit.py
+++ b/compyle/jit.py
@@ -15,6 +15,7 @@
 from .extern import Extern
 from .utils import getsourcelines
 from .profile import profile
+from .ast_utils import get_str_value
 
 from . import array
 from . import parallel
@@ -198,15 +199,18 @@ def warn(self, message, node):
         warnings.warn(msg)
 
     def visit_declare(self, node):
-        if not isinstance(node.args[0], ast.Str):
+        arg0 = node.args[0]
+        type_str = get_str_value(arg0)
+        if type_str is None:
             self.error("Argument to declare should be a string.", node)
-        type_str = node.args[0].s
         return self.get_declare_type(type_str)
 
     def visit_cast(self, node):
-        if not isinstance(node.args[1], ast.Str):
+        arg1 = node.args[1]
+        typestr = get_str_value(arg1)
+        if typestr is None:
             self.error("Cast type should be a string.", node)
-        return node.args[1].s
+        return typestr
 
     def visit_address(self, node):
         base_type = self.visit(node.args[0])
@@ -294,6 +298,13 @@ def visit_BinOp(self, node):
     def visit_Num(self, node):
         return get_ctype_from_arg(node.n)
 
+    def visit_Constant(self, node):
+        val = node.value
+        if isinstance(val, (int, float)):
+            return get_ctype_from_arg(val)
+        # For other constants (e.g., strings/None/bool), we return None
+        return None
+
     def visit_UnaryOp(self, node):
         return self.visit(node.operand)
 
diff --git a/compyle/template.py b/compyle/template.py
index 55e6a78..d9ff609 100644
--- a/compyle/template.py
+++ b/compyle/template.py
@@ -4,6 +4,7 @@
 
 from .types import kwtype_to_annotation
 import mako.template
+from .ast_utils import get_str_value
 
 
 getfullargspec = inspect.getfullargspec
@@ -45,8 +46,14 @@ def _get_code(self):
         args += extra_args
         arg_string = ', '.join(args)
         body = m.body[0].body
-        template = body[-1].value.s
-        docstring = body[0].value.s if len(body) == 2 else ''
+        # Extract template and docstring in an AST-version-agnostic way
+        last_val = body[-1].value
+        template = get_str_value(last_val) or ''
+
+        docstring = ''
+        if len(body) == 2:
+            first_val = body[0].value
+            docstring = get_str_value(first_val) or ''
         name = self.name
         sig = 'def {name}({args}):\n    """{docs}\n    """'.format(
             name=name, args=arg_string, docs=docstring
diff --git a/compyle/translator.py b/compyle/translator.py
index 7a10a92..6d46fa9 100644
--- a/compyle/translator.py
+++ b/compyle/translator.py
@@ -26,6 +26,7 @@
     CodeGenerationError, KnownType, Undefined, all_numeric
 )
 from .utils import getsource
+from .ast_utils import is_str_node, get_str_value
 
 PY_VER = sys.version_info.major
 
@@ -234,11 +235,11 @@ def _indent_block(self, code):
         return '\n'.join(pad + x for x in lines)
 
     def _remove_docstring(self, body):
-        if body and isinstance(body[0], ast.Expr) and \
-                isinstance(body[0].value, ast.Str):
-            return body[1:]
-        else:
-            return body
+        if body and isinstance(body[0], ast.Expr):
+            val = body[0].value
+            if is_str_node(val):
+                return body[1:]
+        return body
 
     def _get_local_info(self, obj):
         return None
@@ -351,9 +352,11 @@ def visit_Assign(self, node):
         left, right = node.targets[0], node.value
         if isinstance(right, ast.Call) and \
            isinstance(right.func, ast.Name) and right.func.id == 'declare':
-            if not isinstance(right.args[0], ast.Str):
+            arg0 = right.args[0]
+            s = get_str_value(arg0)
+            if s is None:
                 self.error("Argument to declare should be a string.", node)
-            type = right.args[0].s
+            type = s
             if isinstance(left, ast.Name):
                 self._known.add(left.id)
                 return self._get_variable_declaration(type, [self.visit(left)])
@@ -395,7 +398,11 @@ def visit_Call(self, node):
             elif 'atomic' in node.func.id:
                 return self.render_atomic(node.func.id, node.args[0])
             elif node.func.id == 'cast':
-                return '(%s) (%s)' % (node.args[1].s, self.visit(node.args[0]))
+                arg1 = node.args[1]
+                typestr = get_str_value(arg1)
+                if typestr is None:
+                    self.error("Argument to cast should be a string.", node)
+                return '(%s) (%s)' % (typestr, self.visit(node.args[0]))
             else:
                 return '{func}({args})'.format(
                     func=node.func.id,
@@ -691,6 +698,22 @@ def visit_NotEq(self, node):
     def visit_Num(self, node):
         return literal_to_float(node.n, self._use_double)
 
+    def visit_Constant(self, node):
+        val = node.value
+        # Handle booleans explicitly first
+        if isinstance(val, bool):
+            return self._replacements[val]
+        # Numbers: int/float
+        if isinstance(val, (int, float)):
+            return literal_to_float(val, self._use_double)
+        # Strings
+        if isinstance(val, str):
+            return r'"%s"' % val
+        # None and other constants
+        if val in self._replacements:
+            return self._replacements[val]
+        return repr(val)
+
     def visit_Or(self, node):
         return '||'