Coverage for /usr/lib/python3/dist-packages/sympy/printing/repr.py: 30%

216 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1""" 

2A Printer for generating executable code. 

3 

4The most important function here is srepr that returns a string so that the 

5relation eval(srepr(expr))=expr holds in an appropriate environment. 

6""" 

7 

8from __future__ import annotations 

9from typing import Any 

10 

11from sympy.core.function import AppliedUndef 

12from sympy.core.mul import Mul 

13from mpmath.libmp import repr_dps, to_str as mlib_to_str 

14 

15from .printer import Printer, print_function 

16 

17 

18class ReprPrinter(Printer): 

19 printmethod = "_sympyrepr" 

20 

21 _default_settings: dict[str, Any] = { 

22 "order": None, 

23 "perm_cyclic" : True, 

24 } 

25 

26 def reprify(self, args, sep): 

27 """ 

28 Prints each item in `args` and joins them with `sep`. 

29 """ 

30 return sep.join([self.doprint(item) for item in args]) 

31 

32 def emptyPrinter(self, expr): 

33 """ 

34 The fallback printer. 

35 """ 

36 if isinstance(expr, str): 

37 return expr 

38 elif hasattr(expr, "__srepr__"): 

39 return expr.__srepr__() 

40 elif hasattr(expr, "args") and hasattr(expr.args, "__iter__"): 

41 l = [] 

42 for o in expr.args: 

43 l.append(self._print(o)) 

44 return expr.__class__.__name__ + '(%s)' % ', '.join(l) 

45 elif hasattr(expr, "__module__") and hasattr(expr, "__name__"): 

46 return "<'%s.%s'>" % (expr.__module__, expr.__name__) 

47 else: 

48 return str(expr) 

49 

50 def _print_Add(self, expr, order=None): 

51 args = self._as_ordered_terms(expr, order=order) 

52 args = map(self._print, args) 

53 clsname = type(expr).__name__ 

54 return clsname + "(%s)" % ", ".join(args) 

55 

56 def _print_Cycle(self, expr): 

57 return expr.__repr__() 

58 

59 def _print_Permutation(self, expr): 

60 from sympy.combinatorics.permutations import Permutation, Cycle 

61 from sympy.utilities.exceptions import sympy_deprecation_warning 

62 

63 perm_cyclic = Permutation.print_cyclic 

64 if perm_cyclic is not None: 

65 sympy_deprecation_warning( 

66 f""" 

67 Setting Permutation.print_cyclic is deprecated. Instead use 

68 init_printing(perm_cyclic={perm_cyclic}). 

69 """, 

70 deprecated_since_version="1.6", 

71 active_deprecations_target="deprecated-permutation-print_cyclic", 

72 stacklevel=7, 

73 ) 

74 else: 

75 perm_cyclic = self._settings.get("perm_cyclic", True) 

76 

77 if perm_cyclic: 

78 if not expr.size: 

79 return 'Permutation()' 

80 # before taking Cycle notation, see if the last element is 

81 # a singleton and move it to the head of the string 

82 s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):] 

83 last = s.rfind('(') 

84 if not last == 0 and ',' not in s[last:]: 

85 s = s[last:] + s[:last] 

86 return 'Permutation%s' %s 

87 else: 

88 s = expr.support() 

89 if not s: 

90 if expr.size < 5: 

91 return 'Permutation(%s)' % str(expr.array_form) 

92 return 'Permutation([], size=%s)' % expr.size 

93 trim = str(expr.array_form[:s[-1] + 1]) + ', size=%s' % expr.size 

94 use = full = str(expr.array_form) 

95 if len(trim) < len(full): 

96 use = trim 

97 return 'Permutation(%s)' % use 

98 

99 def _print_Function(self, expr): 

100 r = self._print(expr.func) 

101 r += '(%s)' % ', '.join([self._print(a) for a in expr.args]) 

102 return r 

103 

104 def _print_Heaviside(self, expr): 

105 # Same as _print_Function but uses pargs to suppress default value for 

106 # 2nd arg. 

107 r = self._print(expr.func) 

108 r += '(%s)' % ', '.join([self._print(a) for a in expr.pargs]) 

109 return r 

110 

111 def _print_FunctionClass(self, expr): 

112 if issubclass(expr, AppliedUndef): 

113 return 'Function(%r)' % (expr.__name__) 

114 else: 

115 return expr.__name__ 

116 

117 def _print_Half(self, expr): 

118 return 'Rational(1, 2)' 

119 

120 def _print_RationalConstant(self, expr): 

121 return str(expr) 

122 

123 def _print_AtomicExpr(self, expr): 

124 return str(expr) 

125 

126 def _print_NumberSymbol(self, expr): 

127 return str(expr) 

128 

129 def _print_Integer(self, expr): 

130 return 'Integer(%i)' % expr.p 

131 

132 def _print_Complexes(self, expr): 

133 return 'Complexes' 

134 

135 def _print_Integers(self, expr): 

136 return 'Integers' 

137 

138 def _print_Naturals(self, expr): 

139 return 'Naturals' 

140 

141 def _print_Naturals0(self, expr): 

142 return 'Naturals0' 

143 

144 def _print_Rationals(self, expr): 

145 return 'Rationals' 

146 

147 def _print_Reals(self, expr): 

148 return 'Reals' 

149 

150 def _print_EmptySet(self, expr): 

151 return 'EmptySet' 

152 

153 def _print_UniversalSet(self, expr): 

154 return 'UniversalSet' 

155 

156 def _print_EmptySequence(self, expr): 

157 return 'EmptySequence' 

158 

159 def _print_list(self, expr): 

160 return "[%s]" % self.reprify(expr, ", ") 

161 

162 def _print_dict(self, expr): 

163 sep = ", " 

164 dict_kvs = ["%s: %s" % (self.doprint(key), self.doprint(value)) for key, value in expr.items()] 

165 return "{%s}" % sep.join(dict_kvs) 

166 

167 def _print_set(self, expr): 

168 if not expr: 

169 return "set()" 

170 return "{%s}" % self.reprify(expr, ", ") 

171 

172 def _print_MatrixBase(self, expr): 

173 # special case for some empty matrices 

174 if (expr.rows == 0) ^ (expr.cols == 0): 

175 return '%s(%s, %s, %s)' % (expr.__class__.__name__, 

176 self._print(expr.rows), 

177 self._print(expr.cols), 

178 self._print([])) 

179 l = [] 

180 for i in range(expr.rows): 

181 l.append([]) 

182 for j in range(expr.cols): 

183 l[-1].append(expr[i, j]) 

184 return '%s(%s)' % (expr.__class__.__name__, self._print(l)) 

185 

186 def _print_BooleanTrue(self, expr): 

187 return "true" 

188 

189 def _print_BooleanFalse(self, expr): 

190 return "false" 

191 

192 def _print_NaN(self, expr): 

193 return "nan" 

194 

195 def _print_Mul(self, expr, order=None): 

196 if self.order not in ('old', 'none'): 

197 args = expr.as_ordered_factors() 

198 else: 

199 # use make_args in case expr was something like -x -> x 

200 args = Mul.make_args(expr) 

201 

202 args = map(self._print, args) 

203 clsname = type(expr).__name__ 

204 return clsname + "(%s)" % ", ".join(args) 

205 

206 def _print_Rational(self, expr): 

207 return 'Rational(%s, %s)' % (self._print(expr.p), self._print(expr.q)) 

208 

209 def _print_PythonRational(self, expr): 

210 return "%s(%d, %d)" % (expr.__class__.__name__, expr.p, expr.q) 

211 

212 def _print_Fraction(self, expr): 

213 return 'Fraction(%s, %s)' % (self._print(expr.numerator), self._print(expr.denominator)) 

214 

215 def _print_Float(self, expr): 

216 r = mlib_to_str(expr._mpf_, repr_dps(expr._prec)) 

217 return "%s('%s', precision=%i)" % (expr.__class__.__name__, r, expr._prec) 

218 

219 def _print_Sum2(self, expr): 

220 return "Sum2(%s, (%s, %s, %s))" % (self._print(expr.f), self._print(expr.i), 

221 self._print(expr.a), self._print(expr.b)) 

222 

223 def _print_Str(self, s): 

224 return "%s(%s)" % (s.__class__.__name__, self._print(s.name)) 

225 

226 def _print_Symbol(self, expr): 

227 d = expr._assumptions_orig 

228 # print the dummy_index like it was an assumption 

229 if expr.is_Dummy: 

230 d['dummy_index'] = expr.dummy_index 

231 

232 if d == {}: 

233 return "%s(%s)" % (expr.__class__.__name__, self._print(expr.name)) 

234 else: 

235 attr = ['%s=%s' % (k, v) for k, v in d.items()] 

236 return "%s(%s, %s)" % (expr.__class__.__name__, 

237 self._print(expr.name), ', '.join(attr)) 

238 

239 def _print_CoordinateSymbol(self, expr): 

240 d = expr._assumptions.generator 

241 

242 if d == {}: 

243 return "%s(%s, %s)" % ( 

244 expr.__class__.__name__, 

245 self._print(expr.coord_sys), 

246 self._print(expr.index) 

247 ) 

248 else: 

249 attr = ['%s=%s' % (k, v) for k, v in d.items()] 

250 return "%s(%s, %s, %s)" % ( 

251 expr.__class__.__name__, 

252 self._print(expr.coord_sys), 

253 self._print(expr.index), 

254 ', '.join(attr) 

255 ) 

256 

257 def _print_Predicate(self, expr): 

258 return "Q.%s" % expr.name 

259 

260 def _print_AppliedPredicate(self, expr): 

261 # will be changed to just expr.args when args overriding is removed 

262 args = expr._args 

263 return "%s(%s)" % (expr.__class__.__name__, self.reprify(args, ", ")) 

264 

265 def _print_str(self, expr): 

266 return repr(expr) 

267 

268 def _print_tuple(self, expr): 

269 if len(expr) == 1: 

270 return "(%s,)" % self._print(expr[0]) 

271 else: 

272 return "(%s)" % self.reprify(expr, ", ") 

273 

274 def _print_WildFunction(self, expr): 

275 return "%s('%s')" % (expr.__class__.__name__, expr.name) 

276 

277 def _print_AlgebraicNumber(self, expr): 

278 return "%s(%s, %s)" % (expr.__class__.__name__, 

279 self._print(expr.root), self._print(expr.coeffs())) 

280 

281 def _print_PolyRing(self, ring): 

282 return "%s(%s, %s, %s)" % (ring.__class__.__name__, 

283 self._print(ring.symbols), self._print(ring.domain), self._print(ring.order)) 

284 

285 def _print_FracField(self, field): 

286 return "%s(%s, %s, %s)" % (field.__class__.__name__, 

287 self._print(field.symbols), self._print(field.domain), self._print(field.order)) 

288 

289 def _print_PolyElement(self, poly): 

290 terms = list(poly.terms()) 

291 terms.sort(key=poly.ring.order, reverse=True) 

292 return "%s(%s, %s)" % (poly.__class__.__name__, self._print(poly.ring), self._print(terms)) 

293 

294 def _print_FracElement(self, frac): 

295 numer_terms = list(frac.numer.terms()) 

296 numer_terms.sort(key=frac.field.order, reverse=True) 

297 denom_terms = list(frac.denom.terms()) 

298 denom_terms.sort(key=frac.field.order, reverse=True) 

299 numer = self._print(numer_terms) 

300 denom = self._print(denom_terms) 

301 return "%s(%s, %s, %s)" % (frac.__class__.__name__, self._print(frac.field), numer, denom) 

302 

303 def _print_FractionField(self, domain): 

304 cls = domain.__class__.__name__ 

305 field = self._print(domain.field) 

306 return "%s(%s)" % (cls, field) 

307 

308 def _print_PolynomialRingBase(self, ring): 

309 cls = ring.__class__.__name__ 

310 dom = self._print(ring.domain) 

311 gens = ', '.join(map(self._print, ring.gens)) 

312 order = str(ring.order) 

313 if order != ring.default_order: 

314 orderstr = ", order=" + order 

315 else: 

316 orderstr = "" 

317 return "%s(%s, %s%s)" % (cls, dom, gens, orderstr) 

318 

319 def _print_DMP(self, p): 

320 cls = p.__class__.__name__ 

321 rep = self._print(p.rep) 

322 dom = self._print(p.dom) 

323 if p.ring is not None: 

324 ringstr = ", ring=" + self._print(p.ring) 

325 else: 

326 ringstr = "" 

327 return "%s(%s, %s%s)" % (cls, rep, dom, ringstr) 

328 

329 def _print_MonogenicFiniteExtension(self, ext): 

330 # The expanded tree shown by srepr(ext.modulus) 

331 # is not practical. 

332 return "FiniteExtension(%s)" % str(ext.modulus) 

333 

334 def _print_ExtensionElement(self, f): 

335 rep = self._print(f.rep) 

336 ext = self._print(f.ext) 

337 return "ExtElem(%s, %s)" % (rep, ext) 

338 

339@print_function(ReprPrinter) 

340def srepr(expr, **settings): 

341 """return expr in repr form""" 

342 return ReprPrinter(settings).doprint(expr)