passagemath-objects 10.6.45__cp313-cp313-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of passagemath-objects might be problematic. Click here for more details.

Files changed (280) hide show
  1. passagemath_objects/__init__.py +3 -0
  2. passagemath_objects-10.6.45.dist-info/METADATA +115 -0
  3. passagemath_objects-10.6.45.dist-info/RECORD +280 -0
  4. passagemath_objects-10.6.45.dist-info/WHEEL +5 -0
  5. passagemath_objects-10.6.45.dist-info/top_level.txt +3 -0
  6. passagemath_objects.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
  7. sage/all__sagemath_objects.py +37 -0
  8. sage/arith/all__sagemath_objects.py +5 -0
  9. sage/arith/long.pxd +411 -0
  10. sage/arith/numerical_approx.cpython-313-x86_64-linux-musl.so +0 -0
  11. sage/arith/numerical_approx.pxd +35 -0
  12. sage/arith/numerical_approx.pyx +75 -0
  13. sage/arith/power.cpython-313-x86_64-linux-musl.so +0 -0
  14. sage/arith/power.pxd +31 -0
  15. sage/arith/power.pyx +127 -0
  16. sage/categories/action.cpython-313-x86_64-linux-musl.so +0 -0
  17. sage/categories/action.pxd +29 -0
  18. sage/categories/action.pyx +641 -0
  19. sage/categories/algebra_functor.py +745 -0
  20. sage/categories/all__sagemath_objects.py +33 -0
  21. sage/categories/basic.py +62 -0
  22. sage/categories/cartesian_product.py +295 -0
  23. sage/categories/category.py +3401 -0
  24. sage/categories/category_cy_helper.cpython-313-x86_64-linux-musl.so +0 -0
  25. sage/categories/category_cy_helper.pxd +8 -0
  26. sage/categories/category_cy_helper.pyx +322 -0
  27. sage/categories/category_singleton.cpython-313-x86_64-linux-musl.so +0 -0
  28. sage/categories/category_singleton.pxd +3 -0
  29. sage/categories/category_singleton.pyx +342 -0
  30. sage/categories/category_types.py +637 -0
  31. sage/categories/category_with_axiom.py +2876 -0
  32. sage/categories/covariant_functorial_construction.py +703 -0
  33. sage/categories/facade_sets.py +228 -0
  34. sage/categories/functor.cpython-313-x86_64-linux-musl.so +0 -0
  35. sage/categories/functor.pxd +7 -0
  36. sage/categories/functor.pyx +691 -0
  37. sage/categories/homset.py +1338 -0
  38. sage/categories/homsets.py +364 -0
  39. sage/categories/isomorphic_objects.py +73 -0
  40. sage/categories/map.cpython-313-x86_64-linux-musl.so +0 -0
  41. sage/categories/map.pxd +34 -0
  42. sage/categories/map.pyx +2106 -0
  43. sage/categories/morphism.cpython-313-x86_64-linux-musl.so +0 -0
  44. sage/categories/morphism.pxd +14 -0
  45. sage/categories/morphism.pyx +895 -0
  46. sage/categories/objects.py +167 -0
  47. sage/categories/primer.py +1696 -0
  48. sage/categories/pushout.py +4834 -0
  49. sage/categories/quotients.py +64 -0
  50. sage/categories/realizations.py +200 -0
  51. sage/categories/sets_cat.py +3290 -0
  52. sage/categories/sets_with_partial_maps.py +52 -0
  53. sage/categories/subobjects.py +64 -0
  54. sage/categories/subquotients.py +21 -0
  55. sage/categories/with_realizations.py +311 -0
  56. sage/cpython/__init__.py +19 -0
  57. sage/cpython/_py2_random.py +619 -0
  58. sage/cpython/all.py +3 -0
  59. sage/cpython/atexit.cpython-313-x86_64-linux-musl.so +0 -0
  60. sage/cpython/atexit.pyx +269 -0
  61. sage/cpython/builtin_types.cpython-313-x86_64-linux-musl.so +0 -0
  62. sage/cpython/builtin_types.pyx +7 -0
  63. sage/cpython/cython_metaclass.cpython-313-x86_64-linux-musl.so +0 -0
  64. sage/cpython/cython_metaclass.h +117 -0
  65. sage/cpython/cython_metaclass.pxd +3 -0
  66. sage/cpython/cython_metaclass.pyx +130 -0
  67. sage/cpython/debug.cpython-313-x86_64-linux-musl.so +0 -0
  68. sage/cpython/debug.pyx +302 -0
  69. sage/cpython/dict_del_by_value.cpython-313-x86_64-linux-musl.so +0 -0
  70. sage/cpython/dict_del_by_value.pxd +9 -0
  71. sage/cpython/dict_del_by_value.pyx +191 -0
  72. sage/cpython/dict_internal.h +245 -0
  73. sage/cpython/getattr.cpython-313-x86_64-linux-musl.so +0 -0
  74. sage/cpython/getattr.pxd +9 -0
  75. sage/cpython/getattr.pyx +439 -0
  76. sage/cpython/pycore_long.h +97 -0
  77. sage/cpython/pycore_long.pxd +10 -0
  78. sage/cpython/python_debug.h +44 -0
  79. sage/cpython/python_debug.pxd +47 -0
  80. sage/cpython/pyx_visit.h +13 -0
  81. sage/cpython/string.cpython-313-x86_64-linux-musl.so +0 -0
  82. sage/cpython/string.pxd +76 -0
  83. sage/cpython/string.pyx +34 -0
  84. sage/cpython/string_impl.h +60 -0
  85. sage/cpython/type.cpython-313-x86_64-linux-musl.so +0 -0
  86. sage/cpython/type.pxd +2 -0
  87. sage/cpython/type.pyx +40 -0
  88. sage/cpython/wrapperdescr.pxd +67 -0
  89. sage/ext/all__sagemath_objects.py +3 -0
  90. sage/ext/ccobject.h +64 -0
  91. sage/ext/cplusplus.pxd +17 -0
  92. sage/ext/mod_int.h +30 -0
  93. sage/ext/mod_int.pxd +24 -0
  94. sage/ext/stdsage.pxd +39 -0
  95. sage/groups/all__sagemath_objects.py +1 -0
  96. sage/groups/group.cpython-313-x86_64-linux-musl.so +0 -0
  97. sage/groups/group.pxd +14 -0
  98. sage/groups/group.pyx +322 -0
  99. sage/groups/old.cpython-313-x86_64-linux-musl.so +0 -0
  100. sage/groups/old.pxd +14 -0
  101. sage/groups/old.pyx +219 -0
  102. sage/libs/all__sagemath_objects.py +3 -0
  103. sage/libs/gmp/__init__.py +1 -0
  104. sage/libs/gmp/all.pxd +6 -0
  105. sage/libs/gmp/binop.pxd +23 -0
  106. sage/libs/gmp/misc.pxd +8 -0
  107. sage/libs/gmp/mpf.pxd +88 -0
  108. sage/libs/gmp/mpn.pxd +57 -0
  109. sage/libs/gmp/mpq.pxd +57 -0
  110. sage/libs/gmp/mpz.pxd +202 -0
  111. sage/libs/gmp/pylong.cpython-313-x86_64-linux-musl.so +0 -0
  112. sage/libs/gmp/pylong.pxd +12 -0
  113. sage/libs/gmp/pylong.pyx +150 -0
  114. sage/libs/gmp/random.pxd +25 -0
  115. sage/libs/gmp/randomize.pxd +59 -0
  116. sage/libs/gmp/types.pxd +53 -0
  117. sage/libs/gmpxx.pxd +19 -0
  118. sage/misc/abstract_method.py +276 -0
  119. sage/misc/all__sagemath_objects.py +43 -0
  120. sage/misc/bindable_class.py +253 -0
  121. sage/misc/c3_controlled.cpython-313-x86_64-linux-musl.so +0 -0
  122. sage/misc/c3_controlled.pxd +2 -0
  123. sage/misc/c3_controlled.pyx +1402 -0
  124. sage/misc/cachefunc.cpython-313-x86_64-linux-musl.so +0 -0
  125. sage/misc/cachefunc.pxd +43 -0
  126. sage/misc/cachefunc.pyx +3781 -0
  127. sage/misc/call.py +188 -0
  128. sage/misc/classcall_metaclass.cpython-313-x86_64-linux-musl.so +0 -0
  129. sage/misc/classcall_metaclass.pxd +14 -0
  130. sage/misc/classcall_metaclass.pyx +599 -0
  131. sage/misc/constant_function.cpython-313-x86_64-linux-musl.so +0 -0
  132. sage/misc/constant_function.pyx +130 -0
  133. sage/misc/decorators.py +747 -0
  134. sage/misc/fast_methods.cpython-313-x86_64-linux-musl.so +0 -0
  135. sage/misc/fast_methods.pxd +20 -0
  136. sage/misc/fast_methods.pyx +351 -0
  137. sage/misc/flatten.py +90 -0
  138. sage/misc/fpickle.cpython-313-x86_64-linux-musl.so +0 -0
  139. sage/misc/fpickle.pyx +177 -0
  140. sage/misc/function_mangling.cpython-313-x86_64-linux-musl.so +0 -0
  141. sage/misc/function_mangling.pxd +11 -0
  142. sage/misc/function_mangling.pyx +308 -0
  143. sage/misc/inherit_comparison.cpython-313-x86_64-linux-musl.so +0 -0
  144. sage/misc/inherit_comparison.pxd +5 -0
  145. sage/misc/inherit_comparison.pyx +105 -0
  146. sage/misc/instancedoc.cpython-313-x86_64-linux-musl.so +0 -0
  147. sage/misc/instancedoc.pyx +331 -0
  148. sage/misc/lazy_attribute.cpython-313-x86_64-linux-musl.so +0 -0
  149. sage/misc/lazy_attribute.pyx +607 -0
  150. sage/misc/lazy_format.py +135 -0
  151. sage/misc/lazy_import.cpython-313-x86_64-linux-musl.so +0 -0
  152. sage/misc/lazy_import.pyx +1299 -0
  153. sage/misc/lazy_import_cache.py +36 -0
  154. sage/misc/lazy_list.cpython-313-x86_64-linux-musl.so +0 -0
  155. sage/misc/lazy_list.pxd +19 -0
  156. sage/misc/lazy_list.pyx +1187 -0
  157. sage/misc/lazy_string.cpython-313-x86_64-linux-musl.so +0 -0
  158. sage/misc/lazy_string.pxd +7 -0
  159. sage/misc/lazy_string.pyx +546 -0
  160. sage/misc/misc.py +1066 -0
  161. sage/misc/misc_c.cpython-313-x86_64-linux-musl.so +0 -0
  162. sage/misc/misc_c.pxd +3 -0
  163. sage/misc/misc_c.pyx +766 -0
  164. sage/misc/namespace_package.py +37 -0
  165. sage/misc/nested_class.cpython-313-x86_64-linux-musl.so +0 -0
  166. sage/misc/nested_class.pxd +3 -0
  167. sage/misc/nested_class.pyx +394 -0
  168. sage/misc/persist.cpython-313-x86_64-linux-musl.so +0 -0
  169. sage/misc/persist.pyx +1251 -0
  170. sage/misc/prandom.py +418 -0
  171. sage/misc/randstate.cpython-313-x86_64-linux-musl.so +0 -0
  172. sage/misc/randstate.pxd +30 -0
  173. sage/misc/randstate.pyx +1059 -0
  174. sage/misc/repr.py +203 -0
  175. sage/misc/reset.cpython-313-x86_64-linux-musl.so +0 -0
  176. sage/misc/reset.pyx +196 -0
  177. sage/misc/sage_ostools.cpython-313-x86_64-linux-musl.so +0 -0
  178. sage/misc/sage_ostools.pyx +323 -0
  179. sage/misc/sage_timeit.py +275 -0
  180. sage/misc/sage_timeit_class.cpython-313-x86_64-linux-musl.so +0 -0
  181. sage/misc/sage_timeit_class.pyx +120 -0
  182. sage/misc/sage_unittest.py +637 -0
  183. sage/misc/sageinspect.py +2768 -0
  184. sage/misc/session.cpython-313-x86_64-linux-musl.so +0 -0
  185. sage/misc/session.pyx +392 -0
  186. sage/misc/superseded.py +557 -0
  187. sage/misc/test_nested_class.py +228 -0
  188. sage/misc/timing.py +264 -0
  189. sage/misc/unknown.py +222 -0
  190. sage/misc/verbose.py +253 -0
  191. sage/misc/weak_dict.cpython-313-x86_64-linux-musl.so +0 -0
  192. sage/misc/weak_dict.pxd +15 -0
  193. sage/misc/weak_dict.pyx +1231 -0
  194. sage/modules/all__sagemath_objects.py +1 -0
  195. sage/modules/module.cpython-313-x86_64-linux-musl.so +0 -0
  196. sage/modules/module.pxd +5 -0
  197. sage/modules/module.pyx +329 -0
  198. sage/rings/all__sagemath_objects.py +3 -0
  199. sage/rings/integer_fake.h +22 -0
  200. sage/rings/integer_fake.pxd +55 -0
  201. sage/sets/all__sagemath_objects.py +3 -0
  202. sage/sets/pythonclass.cpython-313-x86_64-linux-musl.so +0 -0
  203. sage/sets/pythonclass.pxd +9 -0
  204. sage/sets/pythonclass.pyx +247 -0
  205. sage/structure/__init__.py +4 -0
  206. sage/structure/all.py +30 -0
  207. sage/structure/category_object.cpython-313-x86_64-linux-musl.so +0 -0
  208. sage/structure/category_object.pxd +28 -0
  209. sage/structure/category_object.pyx +1087 -0
  210. sage/structure/coerce.cpython-313-x86_64-linux-musl.so +0 -0
  211. sage/structure/coerce.pxd +44 -0
  212. sage/structure/coerce.pyx +2107 -0
  213. sage/structure/coerce_actions.cpython-313-x86_64-linux-musl.so +0 -0
  214. sage/structure/coerce_actions.pxd +27 -0
  215. sage/structure/coerce_actions.pyx +988 -0
  216. sage/structure/coerce_dict.cpython-313-x86_64-linux-musl.so +0 -0
  217. sage/structure/coerce_dict.pxd +51 -0
  218. sage/structure/coerce_dict.pyx +1557 -0
  219. sage/structure/coerce_exceptions.py +23 -0
  220. sage/structure/coerce_maps.cpython-313-x86_64-linux-musl.so +0 -0
  221. sage/structure/coerce_maps.pxd +28 -0
  222. sage/structure/coerce_maps.pyx +718 -0
  223. sage/structure/debug_options.cpython-313-x86_64-linux-musl.so +0 -0
  224. sage/structure/debug_options.pxd +6 -0
  225. sage/structure/debug_options.pyx +54 -0
  226. sage/structure/dynamic_class.py +541 -0
  227. sage/structure/element.cpython-313-x86_64-linux-musl.so +0 -0
  228. sage/structure/element.pxd +272 -0
  229. sage/structure/element.pyx +4772 -0
  230. sage/structure/element_wrapper.cpython-313-x86_64-linux-musl.so +0 -0
  231. sage/structure/element_wrapper.pxd +12 -0
  232. sage/structure/element_wrapper.pyx +582 -0
  233. sage/structure/factorization.py +1422 -0
  234. sage/structure/factorization_integer.py +105 -0
  235. sage/structure/factory.cpython-313-x86_64-linux-musl.so +0 -0
  236. sage/structure/factory.pyx +786 -0
  237. sage/structure/formal_sum.py +489 -0
  238. sage/structure/gens_py.py +73 -0
  239. sage/structure/global_options.py +1743 -0
  240. sage/structure/indexed_generators.py +863 -0
  241. sage/structure/list_clone.cpython-313-x86_64-linux-musl.so +0 -0
  242. sage/structure/list_clone.pxd +65 -0
  243. sage/structure/list_clone.pyx +1867 -0
  244. sage/structure/list_clone_demo.cpython-313-x86_64-linux-musl.so +0 -0
  245. sage/structure/list_clone_demo.pyx +248 -0
  246. sage/structure/list_clone_timings.py +179 -0
  247. sage/structure/list_clone_timings_cy.cpython-313-x86_64-linux-musl.so +0 -0
  248. sage/structure/list_clone_timings_cy.pyx +86 -0
  249. sage/structure/mutability.cpython-313-x86_64-linux-musl.so +0 -0
  250. sage/structure/mutability.pxd +21 -0
  251. sage/structure/mutability.pyx +348 -0
  252. sage/structure/nonexact.py +69 -0
  253. sage/structure/parent.cpython-313-x86_64-linux-musl.so +0 -0
  254. sage/structure/parent.pxd +112 -0
  255. sage/structure/parent.pyx +3093 -0
  256. sage/structure/parent_base.cpython-313-x86_64-linux-musl.so +0 -0
  257. sage/structure/parent_base.pxd +13 -0
  258. sage/structure/parent_base.pyx +44 -0
  259. sage/structure/parent_gens.cpython-313-x86_64-linux-musl.so +0 -0
  260. sage/structure/parent_gens.pxd +22 -0
  261. sage/structure/parent_gens.pyx +377 -0
  262. sage/structure/parent_old.cpython-313-x86_64-linux-musl.so +0 -0
  263. sage/structure/parent_old.pxd +25 -0
  264. sage/structure/parent_old.pyx +294 -0
  265. sage/structure/proof/__init__.py +1 -0
  266. sage/structure/proof/all.py +243 -0
  267. sage/structure/proof/proof.py +300 -0
  268. sage/structure/richcmp.cpython-313-x86_64-linux-musl.so +0 -0
  269. sage/structure/richcmp.pxd +213 -0
  270. sage/structure/richcmp.pyx +495 -0
  271. sage/structure/sage_object.cpython-313-x86_64-linux-musl.so +0 -0
  272. sage/structure/sage_object.pxd +3 -0
  273. sage/structure/sage_object.pyx +988 -0
  274. sage/structure/sage_object_test.py +19 -0
  275. sage/structure/sequence.py +937 -0
  276. sage/structure/set_factories.py +1178 -0
  277. sage/structure/set_factories_example.py +527 -0
  278. sage/structure/support_view.py +179 -0
  279. sage/structure/test_factory.py +56 -0
  280. sage/structure/unique_representation.py +1359 -0
sage/misc/misc.py ADDED
@@ -0,0 +1,1066 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ """
3
+ Miscellaneous functions
4
+
5
+ AUTHORS:
6
+
7
+ - William Stein
8
+
9
+ - William Stein (2006-04-26): added workaround for Windows where most
10
+ users' home directory has a space in it.
11
+
12
+ - Robert Bradshaw (2007-09-20): Ellipsis range/iterator.
13
+
14
+ TESTS:
15
+
16
+ The following test, verifying that :issue:`16181` has been resolved, needs
17
+ to stay at the beginning of this file so that its context is not
18
+ poisoned by other tests::
19
+
20
+ sage: sage.misc.misc.inject_variable('a', 0)
21
+ sage: a
22
+ 0
23
+
24
+ Check the fix from :issue:`8323`::
25
+
26
+ sage: 'name' in globals()
27
+ False
28
+ sage: 'func' in globals()
29
+ False
30
+ """
31
+
32
+ # ****************************************************************************
33
+ # Copyright (C) 2006 William Stein <wstein@gmail.com>
34
+ #
35
+ # This program is free software: you can redistribute it and/or modify
36
+ # it under the terms of the GNU General Public License as published by
37
+ # the Free Software Foundation, either version 2 of the License, or
38
+ # (at your option) any later version.
39
+ # https://www.gnu.org/licenses/
40
+ # ****************************************************************************
41
+
42
+ import contextlib
43
+ import functools
44
+ import os
45
+ import pdb
46
+ import sys
47
+ import warnings
48
+
49
+ from sage.env import DOT_SAGE, HOSTNAME
50
+ from sage.misc.lazy_import import lazy_import
51
+
52
+ lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"],
53
+ deprecation=35564)
54
+
55
+ lazy_import(
56
+ "sage.misc.timing", ["cputime", "GlobalCputime", "walltime"],
57
+ deprecation=35816
58
+ )
59
+
60
+ LOCAL_IDENTIFIER = '%s.%s' % (HOSTNAME, os.getpid())
61
+
62
+ #################################################################
63
+ # File and directory utilities
64
+ #################################################################
65
+
66
+ # We create the DOT_SAGE directory (if it does not exist yet; note in particular
67
+ # that it may already have been created by the bin/sage script) with
68
+ # restrictive permissions, since otherwise possibly just anybody can easily see
69
+ # every command you type.
70
+
71
+ os.makedirs(DOT_SAGE, mode=0o700, exist_ok=True)
72
+
73
+
74
+ def try_read(obj, splitlines=False):
75
+ r"""
76
+ Determine if a given object is a readable file-like object and if so
77
+ read and return its contents.
78
+
79
+ That is, the object has a callable method named ``read()`` which takes
80
+ no arguments (except ``self``) then the method is executed and the
81
+ contents are returned.
82
+
83
+ Alternatively, if the ``splitlines=True`` is given, first ``splitlines()``
84
+ is tried, then if that fails ``read().splitlines()``.
85
+
86
+ If either method fails, ``None`` is returned.
87
+
88
+ INPUT:
89
+
90
+ - ``obj`` -- typically a `file` or `io.BaseIO` object, but any other
91
+ object with a ``read()`` method is accepted
92
+
93
+ - ``splitlines`` -- boolean (default: ``False``); if ``True``, return a
94
+ list of lines instead of a string
95
+
96
+ EXAMPLES::
97
+
98
+ sage: import io
99
+ sage: filename = tmp_filename()
100
+ sage: from sage.misc.misc import try_read
101
+ sage: with open(filename, 'w') as fobj:
102
+ ....: _ = fobj.write('a\nb\nc')
103
+ sage: with open(filename) as fobj:
104
+ ....: print(try_read(fobj))
105
+ a
106
+ b
107
+ c
108
+ sage: with open(filename) as fobj:
109
+ ....: try_read(fobj, splitlines=True)
110
+ ['a\n', 'b\n', 'c']
111
+
112
+ The following example is identical to the above example on Python 3,
113
+ but different on Python 2 where ``open != io.open``::
114
+
115
+ sage: with io.open(filename) as fobj:
116
+ ....: print(try_read(fobj))
117
+ a
118
+ b
119
+ c
120
+
121
+ I/O buffers::
122
+
123
+ sage: buf = io.StringIO('a\nb\nc')
124
+ sage: print(try_read(buf))
125
+ a
126
+ b
127
+ c
128
+ sage: _ = buf.seek(0); try_read(buf, splitlines=True)
129
+ ['a\n', 'b\n', 'c']
130
+ sage: buf = io.BytesIO(b'a\nb\nc')
131
+ sage: try_read(buf) == b'a\nb\nc'
132
+ True
133
+ sage: _ = buf.seek(0)
134
+ sage: try_read(buf, splitlines=True) == [b'a\n', b'b\n', b'c']
135
+ True
136
+
137
+ Custom readable::
138
+
139
+ sage: class MyFile():
140
+ ....: def read(self): return 'Hello world!'
141
+ sage: try_read(MyFile())
142
+ 'Hello world!'
143
+ sage: try_read(MyFile(), splitlines=True)
144
+ ['Hello world!']
145
+
146
+ Not readable::
147
+
148
+ sage: try_read(1) is None
149
+ True
150
+ """
151
+
152
+ if splitlines:
153
+ try:
154
+ return obj.readlines()
155
+ except (AttributeError, TypeError):
156
+ pass
157
+
158
+ try:
159
+ data = obj.read()
160
+ except (AttributeError, TypeError):
161
+ return
162
+
163
+ if splitlines:
164
+ try:
165
+ data = data.splitlines()
166
+ except (AttributeError, TypeError):
167
+ # Not a string??
168
+ data = [data]
169
+
170
+ return data
171
+
172
+
173
+ try:
174
+ # Create the matplotlib config directory.
175
+ os.makedirs(os.environ["MPLCONFIGDIR"], exist_ok=True)
176
+ except KeyError:
177
+ pass
178
+
179
+
180
+ def exactly_one_is_true(iterable):
181
+ r"""
182
+ Return whether exactly one element of ``iterable`` evaluates ``True``.
183
+
184
+ INPUT:
185
+
186
+ - ``iterable`` -- an iterable object
187
+
188
+ OUTPUT: boolean
189
+
190
+ .. NOTE::
191
+
192
+ The implementation is suggested by
193
+ `stackoverflow entry <https://stackoverflow.com/a/16801605/1052778>`_.
194
+
195
+ EXAMPLES::
196
+
197
+ sage: from sage.misc.misc import exactly_one_is_true
198
+ sage: exactly_one_is_true([])
199
+ False
200
+ sage: exactly_one_is_true([True])
201
+ True
202
+ sage: exactly_one_is_true([False])
203
+ False
204
+ sage: exactly_one_is_true([True, True])
205
+ False
206
+ sage: exactly_one_is_true([False, True])
207
+ True
208
+ sage: exactly_one_is_true([True, False, True])
209
+ False
210
+ sage: exactly_one_is_true([False, True, False])
211
+ True
212
+ """
213
+ it = iter(iterable)
214
+ return any(it) and not any(it)
215
+
216
+
217
+ def strunc(s, n=60):
218
+ """
219
+ Truncate at first space after position n, adding '...' if
220
+ nontrivial truncation.
221
+ """
222
+ n = int(n)
223
+ s = str(s)
224
+ if len(s) > n:
225
+ i = n
226
+ while i < len(s) and s[i] != ' ':
227
+ i += 1
228
+ return s[:i] + " ..."
229
+ return s
230
+
231
+
232
+ def newton_method_sizes(N):
233
+ r"""
234
+ Return a sequence of integers
235
+ `1 = a_1 \leq a_2 \leq \cdots \leq a_n = N` such that
236
+ `a_j = \lceil a_{j+1} / 2 \rceil` for all `j`.
237
+
238
+ This is useful for Newton-style algorithms that double the
239
+ precision at each stage. For example if you start at precision 1
240
+ and want an answer to precision 17, then it's better to use the
241
+ intermediate stages 1, 2, 3, 5, 9, 17 than to use 1, 2, 4, 8, 16,
242
+ 17.
243
+
244
+ INPUT:
245
+
246
+ - ``N`` -- positive integer
247
+
248
+ EXAMPLES::
249
+
250
+ sage: newton_method_sizes(17)
251
+ [1, 2, 3, 5, 9, 17]
252
+ sage: newton_method_sizes(16)
253
+ [1, 2, 4, 8, 16]
254
+ sage: newton_method_sizes(1)
255
+ [1]
256
+
257
+ AUTHORS:
258
+
259
+ - David Harvey (2006-09-09)
260
+ """
261
+
262
+ N = int(N)
263
+ if N < 1:
264
+ raise ValueError("N (={}) must be a positive integer".format(N))
265
+
266
+ output = []
267
+ while N > 1:
268
+ output.append(N)
269
+ N = (N + 1) >> 1
270
+
271
+ output.append(1)
272
+ output.reverse()
273
+ return output
274
+
275
+
276
+ #################################################################
277
+ # Generally useful
278
+ #################################################################
279
+
280
+
281
+ def compose(f, g):
282
+ r"""
283
+ Return the composition of one-variable functions: `f \circ g`.
284
+
285
+ See also :func:`nest()`
286
+
287
+ INPUT:
288
+
289
+ - ``f`` -- a function of one variable
290
+ - ``g`` -- another function of one variable
291
+
292
+ OUTPUT: a function, such that compose(f,g)(x) = f(g(x))
293
+
294
+ EXAMPLES::
295
+
296
+ sage: def g(x): return 3*x
297
+ sage: def f(x): return x + 1
298
+ sage: h1 = compose(f, g)
299
+ sage: h2 = compose(g, f)
300
+ sage: _ = var('x') # needs sage.symbolic
301
+ sage: h1(x) # needs sage.symbolic
302
+ 3*x + 1
303
+ sage: h2(x) # needs sage.symbolic
304
+ 3*x + 3
305
+
306
+ ::
307
+
308
+ sage: _ = function('f g') # needs sage.symbolic
309
+ sage: _ = var('x') # needs sage.symbolic
310
+ sage: compose(f, g)(x) # needs sage.symbolic
311
+ f(g(x))
312
+ """
313
+ return lambda x: f(g(x))
314
+
315
+
316
+ def nest(f, n, x):
317
+ """
318
+ Return `f(f(...f(x)...))`, where the composition occurs n times.
319
+
320
+ See also :func:`compose()` and :func:`self_compose()`
321
+
322
+ INPUT:
323
+
324
+ - ``f`` -- a function of one variable
325
+ - ``n`` -- nonnegative integer
326
+ - ``x`` -- any input for `f`
327
+
328
+ OUTPUT: `f(f(...f(x)...))`, where the composition occurs n times
329
+
330
+ EXAMPLES::
331
+
332
+ sage: def f(x): return x^2 + 1
333
+ sage: x = var('x') # needs sage.symbolic
334
+ sage: nest(f, 3, x) # needs sage.symbolic
335
+ ((x^2 + 1)^2 + 1)^2 + 1
336
+
337
+ ::
338
+
339
+ sage: _ = function('f') # needs sage.symbolic
340
+ sage: _ = var('x') # needs sage.symbolic
341
+ sage: nest(f, 10, x) # needs sage.symbolic
342
+ f(f(f(f(f(f(f(f(f(f(x))))))))))
343
+
344
+ ::
345
+
346
+ sage: _ = function('f') # needs sage.symbolic
347
+ sage: _ = var('x') # needs sage.symbolic
348
+ sage: nest(f, 0, x) # needs sage.symbolic
349
+ x
350
+ """
351
+ from sage.rings.integer import Integer
352
+
353
+ n = Integer(n)
354
+
355
+ if n < 0:
356
+ raise ValueError("n must be a nonnegative integer, not {}.".format(n))
357
+
358
+ for i in range(n):
359
+ x = f(x)
360
+ return x
361
+
362
+
363
+ #################################################################
364
+ # The A \ b operator
365
+ #################################################################
366
+
367
+
368
+ class BackslashOperator:
369
+ r"""
370
+ Implement Matlab-style backslash operator for solving systems::
371
+
372
+ A \ b
373
+
374
+ The preparser converts this to multiplications using
375
+ ``BackslashOperator()``.
376
+
377
+ EXAMPLES::
378
+
379
+ sage: preparse("A \\ matrix(QQ,2,1,[1/3,'2/3'])")
380
+ "A * BackslashOperator() * matrix(QQ,Integer(2),Integer(1),[Integer(1)/Integer(3),'2/3'])"
381
+ sage: preparse("A \\ matrix(QQ,2,1,[1/3,2*3])")
382
+ 'A * BackslashOperator() * matrix(QQ,Integer(2),Integer(1),[Integer(1)/Integer(3),Integer(2)*Integer(3)])'
383
+ sage: preparse("A \\ B + C")
384
+ 'A * BackslashOperator() * B + C'
385
+ sage: preparse("A \\ eval('C+D')")
386
+ "A * BackslashOperator() * eval('C+D')"
387
+ sage: preparse("A \\ x / 5")
388
+ 'A * BackslashOperator() * x / Integer(5)'
389
+ sage: preparse("A^3 \\ b")
390
+ 'A**Integer(3) * BackslashOperator() * b'
391
+ """
392
+
393
+ def __rmul__(self, left):
394
+ """
395
+ EXAMPLES::
396
+
397
+ sage: # needs sage.modules
398
+ sage: A = random_matrix(ZZ, 4)
399
+ sage: while A.rank() != 4:
400
+ ....: A = random_matrix(ZZ, 4)
401
+ sage: B = random_matrix(ZZ, 4)
402
+ sage: temp = A * BackslashOperator()
403
+ doctest:...:
404
+ DeprecationWarning: the backslash operator has been deprecated
405
+ See https://github.com/sagemath/sage/issues/36394 for details.
406
+ sage: temp.left is A
407
+ True
408
+ sage: X = temp * B
409
+ doctest:...:
410
+ DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
411
+ See https://github.com/sagemath/sage/issues/36394 for details.
412
+ sage: A * X == B
413
+ True
414
+ """
415
+ from sage.misc.superseded import deprecation
416
+
417
+ deprecation(36394, 'the backslash operator has been deprecated')
418
+ self.left = left
419
+ return self
420
+
421
+ def __mul__(self, right):
422
+ r"""
423
+ EXAMPLES::
424
+
425
+ sage: # needs scipy sage.modules
426
+ sage: A = matrix(RDF, 5, 5, 2)
427
+ sage: b = vector(RDF, 5, range(5))
428
+ sage: v = A \ b
429
+ doctest:...:
430
+ DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
431
+ See https://github.com/sagemath/sage/issues/36394 for details.
432
+ sage: v.zero_at(1e-19) # On at least one platform, we get a "negative zero"
433
+ (0.0, 0.5, 1.0, 1.5, 2.0)
434
+ sage: v = A._backslash_(b)
435
+ doctest:...:
436
+ DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
437
+ See https://github.com/sagemath/sage/issues/36394 for details.
438
+ sage: v.zero_at(1e-19)
439
+ (0.0, 0.5, 1.0, 1.5, 2.0)
440
+ sage: v = A * BackslashOperator() * b
441
+ doctest:...:
442
+ DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
443
+ See https://github.com/sagemath/sage/issues/36394 for details.
444
+ sage: v.zero_at(1e-19)
445
+ (0.0, 0.5, 1.0, 1.5, 2.0)
446
+ """
447
+ from sage.misc.superseded import deprecation
448
+
449
+ deprecation(36394, 'the backslash operator has been deprecated')
450
+ return self.left._backslash_(right)
451
+
452
+
453
+ #################################################################
454
+ # is_iterator function
455
+ #################################################################
456
+ def is_iterator(it) -> bool:
457
+ """
458
+ Test if it is an iterator.
459
+
460
+ The mantra ``if hasattr(it, 'next')`` was used to tests if ``it`` is an
461
+ iterator. This is not quite correct since ``it`` could have a ``next``
462
+ methods with a different semantic.
463
+
464
+ EXAMPLES::
465
+
466
+ sage: it = iter([1,2,3])
467
+ sage: is_iterator(it)
468
+ True
469
+
470
+ sage: class wrong():
471
+ ....: def __init__(self): self.n = 5
472
+ ....: def __next__(self):
473
+ ....: self.n -= 1
474
+ ....: if self.n == 0: raise StopIteration
475
+ ....: return self.n
476
+ sage: x = wrong()
477
+ sage: is_iterator(x)
478
+ False
479
+ sage: list(x)
480
+ Traceback (most recent call last):
481
+ ...
482
+ TypeError: 'wrong' object is not iterable
483
+
484
+ sage: class good(wrong):
485
+ ....: def __iter__(self): return self
486
+ sage: x = good()
487
+ sage: is_iterator(x)
488
+ True
489
+ sage: list(x)
490
+ [4, 3, 2, 1]
491
+
492
+ sage: P = Partitions(3)
493
+ sage: is_iterator(P)
494
+ False
495
+ sage: is_iterator(iter(P))
496
+ True
497
+ """
498
+ # see trac #7398 for a discussion
499
+ try:
500
+ return it is iter(it)
501
+ except Exception:
502
+ return False
503
+
504
+
505
+ #################################################################
506
+ # Useful but hard to classify
507
+ #################################################################
508
+
509
+
510
+ def random_sublist(X, s):
511
+ """
512
+ Return a pseudo-random sublist of the list X where the probability
513
+ of including a particular element is s.
514
+
515
+ INPUT:
516
+
517
+ - ``X`` -- list
518
+
519
+ - ``s`` -- floating point number between 0 and 1
520
+
521
+ OUTPUT: list
522
+
523
+ EXAMPLES::
524
+
525
+ sage: from sage.misc.misc import is_sublist
526
+ sage: S = [1,7,3,4,18]
527
+ sage: sublist = random_sublist(S, 0.5); sublist # random
528
+ [1, 3, 4]
529
+ sage: is_sublist(sublist, S)
530
+ True
531
+ sage: sublist = random_sublist(S, 0.5); sublist # random
532
+ [1, 3]
533
+ sage: is_sublist(sublist, S)
534
+ True
535
+ """
536
+ import sage.misc.prandom as random
537
+
538
+ return [a for a in X if random.random() <= s]
539
+
540
+
541
+ def is_sublist(X, Y):
542
+ """
543
+ Test whether ``X`` is a sublist of ``Y``.
544
+
545
+ EXAMPLES::
546
+
547
+ sage: from sage.misc.misc import is_sublist
548
+ sage: S = [1, 7, 3, 4, 18]
549
+ sage: is_sublist([1, 7], S)
550
+ True
551
+ sage: is_sublist([1, 3, 4], S)
552
+ True
553
+ sage: is_sublist([1, 4, 3], S)
554
+ False
555
+ sage: is_sublist(S, S)
556
+ True
557
+ """
558
+ X_i = 0
559
+ for Y_i, y in enumerate(Y):
560
+ if X_i == len(X):
561
+ return True
562
+ if y == X[X_i]:
563
+ X_i += 1
564
+ return X_i == len(X)
565
+
566
+
567
+ def some_tuples(elements, repeat, bound, max_samples=None):
568
+ r"""
569
+ Return an iterator over at most ``bound`` number of ``repeat``-tuples of
570
+ ``elements``.
571
+
572
+ INPUT:
573
+
574
+ - ``elements`` -- an iterable
575
+ - ``repeat`` -- integer (default: ``None``); the length of the tuples to be returned.
576
+ If ``None``, just returns entries from ``elements``.
577
+ - ``bound`` -- the maximum number of tuples returned (ignored if ``max_samples`` given)
578
+ - ``max_samples`` -- nonnegative integer (default: ``None``); if given,
579
+ then a sample of the possible tuples will be returned,
580
+ instead of the first few in the standard order
581
+
582
+ OUTPUT:
583
+
584
+ If ``max_samples`` is not provided, an iterator over the first
585
+ ``bound`` tuples of length ``repeat``, in the standard nested-for-loop order.
586
+
587
+ If ``max_samples`` is provided, a list of at most ``max_samples`` tuples,
588
+ sampled uniformly from the possibilities. In this case, ``elements``
589
+ must be finite.
590
+
591
+ TESTS::
592
+
593
+ sage: from sage.misc.misc import some_tuples
594
+ sage: l = some_tuples([0,1,2,3], 2, 3)
595
+ sage: l
596
+ <itertools.islice object at ...>
597
+ sage: len(list(l))
598
+ 3
599
+
600
+ sage: l = some_tuples(range(50), 3, 10)
601
+ sage: len(list(l))
602
+ 10
603
+
604
+ sage: l = some_tuples(range(3), 2, None, max_samples=10)
605
+ sage: len(list(l))
606
+ 9
607
+ """
608
+ if max_samples is None:
609
+ from itertools import islice, product
610
+
611
+ P = elements if repeat is None else product(elements, repeat=repeat)
612
+ return islice(P, int(bound))
613
+ else:
614
+ if not (hasattr(elements, '__len__') and hasattr(elements, '__getitem__')):
615
+ elements = list(elements)
616
+ n = len(elements)
617
+ N = n if repeat is None else n**repeat
618
+ if N <= max_samples:
619
+ from itertools import product
620
+
621
+ return elements if repeat is None else product(elements, repeat=repeat)
622
+ return _some_tuples_sampling(elements, repeat, max_samples, n)
623
+
624
+
625
+ def _some_tuples_sampling(elements, repeat, max_samples, n):
626
+ """
627
+ Internal function for :func:`some_tuples`.
628
+
629
+ TESTS::
630
+
631
+ sage: from sage.misc.misc import _some_tuples_sampling
632
+ sage: l = list(_some_tuples_sampling(range(3), 3, 2, 3))
633
+ sage: len(l)
634
+ 2
635
+ sage: all(len(tup) == 3 for tup in l)
636
+ True
637
+ sage: all(el in range(3) for tup in l for el in tup)
638
+ True
639
+ sage: l = list(_some_tuples_sampling(range(20), None, 4, 20))
640
+ sage: len(l)
641
+ 4
642
+ sage: all(el in range(20) for el in l)
643
+ True
644
+ """
645
+ from sage.rings.integer import Integer
646
+ import sage.misc.prandom as random
647
+
648
+ N = n if repeat is None else n**repeat
649
+ # We sample on range(N) and create tuples manually since we don't want to create the list of all possible tuples in memory
650
+ for a in random.sample(range(N), max_samples):
651
+ if repeat is None:
652
+ yield elements[a]
653
+ else:
654
+ yield tuple(elements[j] for j in Integer(a).digits(n, padto=repeat))
655
+
656
+
657
+ #################################################################
658
+ # Misc.
659
+ #################################################################
660
+
661
+
662
+ def exists(S, P):
663
+ """
664
+ If S contains an element x such that P(x) is ``True``, this function
665
+ returns ``True`` and the element x. Otherwise it returns ``False`` and
666
+ None.
667
+
668
+ Note that this function is NOT suitable to be used in an
669
+ if-statement or in any place where a boolean expression is
670
+ expected. For those situations, use the Python built-in
671
+
672
+ any(P(x) for x in S)
673
+
674
+ INPUT:
675
+
676
+ - ``S`` -- object (that supports enumeration)
677
+
678
+ - ``P`` -- function that returns ``True`` or ``False``
679
+
680
+ OUTPUT:
681
+
682
+ - ``bool`` -- whether or not P is ``True`` for some element
683
+ x of S
684
+
685
+ - ``object`` -- x
686
+
687
+ EXAMPLES: lambda functions are very useful when using the exists
688
+ function::
689
+
690
+ sage: exists([1,2,5], lambda x : x > 7)
691
+ (False, None)
692
+ sage: exists([1,2,5], lambda x : x > 3)
693
+ (True, 5)
694
+
695
+ The following example is similar to one in the MAGMA handbook. We
696
+ check whether certain integers are a sum of two (small) cubes::
697
+
698
+ sage: cubes = [t**3 for t in range(-10,11)]
699
+ sage: exists([(x,y) for x in cubes for y in cubes], lambda v : v[0]+v[1] == 218)
700
+ (True, (-125, 343))
701
+ sage: exists([(x,y) for x in cubes for y in cubes], lambda v : v[0]+v[1] == 219)
702
+ (False, None)
703
+ """
704
+ for x in S:
705
+ if P(x):
706
+ return True, x
707
+ return False, None
708
+
709
+
710
+ def forall(S, P):
711
+ """
712
+ If `P(x)` is true every x in S, return ``True`` and ``None``. If there is
713
+ some element x in S such that P is not ``True``, return ``False`` and `x`.
714
+
715
+ Note that this function is NOT suitable to be used in an
716
+ if-statement or in any place where a boolean expression is
717
+ expected. For those situations, use the Python built-in
718
+
719
+ all(P(x) for x in S)
720
+
721
+ INPUT:
722
+
723
+ - ``S`` -- object (that supports enumeration)
724
+
725
+ - ``P`` -- function that returns ``True`` or ``False``
726
+
727
+ OUTPUT:
728
+
729
+ - ``bool`` -- whether or not P is ``True`` for all elements
730
+ of S
731
+
732
+ - ``object`` -- x
733
+
734
+ EXAMPLES: lambda functions are very useful when using the forall
735
+ function. As a toy example we test whether certain integers are
736
+ greater than 3.
737
+
738
+ ::
739
+
740
+ sage: forall([1,2,5], lambda x : x > 3)
741
+ (False, 1)
742
+ sage: forall([1,2,5], lambda x : x > 0)
743
+ (True, None)
744
+
745
+ Next we ask whether every positive integer less than 100 is a
746
+ product of at most 2 prime factors::
747
+
748
+ sage: forall(range(1,100), lambda n : len(factor(n)) <= 2)
749
+ (False, 30)
750
+
751
+ The answer is no, and 30 is a counterexample. However, every
752
+ positive integer 100 is a product of at most 3 primes.
753
+
754
+ ::
755
+
756
+ sage: forall(range(1,100), lambda n : len(factor(n)) <= 3)
757
+ (True, None)
758
+ """
759
+ for x in S:
760
+ if not P(x):
761
+ return False, x
762
+ return True, None
763
+
764
+
765
+ #################################################################
766
+ # debug tracing
767
+ #################################################################
768
+ set_trace = pdb.set_trace
769
+
770
+
771
+ #################################################################
772
+ # Word wrap lines
773
+ #################################################################
774
+ def word_wrap(s, ncols=85):
775
+ t = []
776
+ if ncols == 0:
777
+ return s
778
+ for x in s.split('\n'):
779
+ if not x or x.lstrip()[:5] == 'sage:':
780
+ t.append(x)
781
+ continue
782
+ while len(x) > ncols:
783
+ k = ncols
784
+ while k > 0 and x[k] != ' ':
785
+ k -= 1
786
+ if k == 0:
787
+ k = ncols
788
+ end = '\\'
789
+ else:
790
+ end = ''
791
+ t.append(x[:k] + end)
792
+ x = x[k:]
793
+ k = 0
794
+ while k < len(x) and x[k] == ' ':
795
+ k += 1
796
+ x = x[k:]
797
+ t.append(x)
798
+ return '\n'.join(t)
799
+
800
+
801
+ def pad_zeros(s, size=3):
802
+ """
803
+ EXAMPLES::
804
+
805
+ sage: pad_zeros(100)
806
+ '100'
807
+ sage: pad_zeros(10)
808
+ '010'
809
+ sage: pad_zeros(10, 5)
810
+ '00010'
811
+ sage: pad_zeros(389, 5)
812
+ '00389'
813
+ sage: pad_zeros(389, 10)
814
+ '0000000389'
815
+ """
816
+ return "0" * (size - len(str(s))) + str(s)
817
+
818
+
819
+ def is_in_string(line, pos):
820
+ r"""
821
+ Return ``True`` if the character at position ``pos`` in ``line`` occurs
822
+ within a string.
823
+
824
+ EXAMPLES::
825
+
826
+ sage: from sage.misc.misc import is_in_string
827
+ sage: line = 'test(\'#\')'
828
+ sage: is_in_string(line, line.rfind('#'))
829
+ True
830
+ sage: is_in_string(line, line.rfind(')'))
831
+ False
832
+ """
833
+ i = 0
834
+ in_single_quote = False
835
+ in_double_quote = False
836
+ in_triple_quote = False
837
+
838
+ def in_quote():
839
+ return in_single_quote or in_double_quote or in_triple_quote
840
+
841
+ while i < pos:
842
+ # Update quote parsing
843
+ # We only do this if this quote isn't backquoted itself,
844
+ # which is the case if the previous character isn't
845
+ # a backslash, or it is but both previous characters
846
+ # are backslashes.
847
+ if line[i - 1 : i] != '\\' or line[i - 2 : i] == '\\\\':
848
+ if line[i : i + 3] in ['"""', "'''"]:
849
+ if not in_quote():
850
+ in_triple_quote = True
851
+ elif in_triple_quote:
852
+ in_triple_quote = False
853
+ elif line[i] == "'":
854
+ if not in_quote():
855
+ in_single_quote = True
856
+ elif in_single_quote:
857
+ in_single_quote = False
858
+ elif line[i] == '"':
859
+ if not in_quote():
860
+ in_double_quote = True
861
+ elif in_double_quote:
862
+ in_double_quote = False
863
+ i += 1
864
+ return in_quote()
865
+
866
+
867
+ def get_main_globals():
868
+ """
869
+ Return the main global namespace.
870
+
871
+ EXAMPLES::
872
+
873
+ sage: from sage.misc.misc import get_main_globals
874
+ sage: G = get_main_globals()
875
+ sage: bla = 1
876
+ sage: G['bla']
877
+ 1
878
+ sage: bla = 2
879
+ sage: G['bla']
880
+ 2
881
+ sage: G['ble'] = 5
882
+ sage: ble
883
+ 5
884
+
885
+ This is analogous to :func:`globals`, except that it can be called
886
+ from any function, even if it is in a Python module::
887
+
888
+ sage: def f():
889
+ ....: G = get_main_globals()
890
+ ....: assert G['bli'] == 14
891
+ ....: G['blo'] = 42
892
+ sage: bli = 14
893
+ sage: f()
894
+ sage: blo
895
+ 42
896
+
897
+ ALGORITHM:
898
+
899
+ The main global namespace is discovered by going up the frame
900
+ stack until the frame for the :mod:`__main__` module is found.
901
+ Should this frame not be found (this should not occur in normal
902
+ operation), an exception "ValueError: call stack is not deep
903
+ enough" will be raised by ``_getframe``.
904
+
905
+ See :meth:`inject_variable_test` for a real test that this works
906
+ within deeply nested calls in a function defined in a Python
907
+ module.
908
+ """
909
+ import sys
910
+
911
+ depth = 0
912
+ while True:
913
+ G = sys._getframe(depth).f_globals
914
+ if G.get("__name__", None) == "__main__":
915
+ break
916
+ depth += 1
917
+ return G
918
+
919
+
920
+ def inject_variable(name, value, warn=True):
921
+ """
922
+ Inject a variable into the main global namespace.
923
+
924
+ INPUT:
925
+
926
+ - ``name`` -- string
927
+ - ``value`` -- anything
928
+ - ``warn`` -- boolean (default: ``False``)
929
+
930
+ EXAMPLES::
931
+
932
+ sage: from sage.misc.misc import inject_variable
933
+ sage: inject_variable("a", 314)
934
+ sage: a
935
+ 314
936
+
937
+ A warning is issued the first time an existing value is overwritten::
938
+
939
+ sage: inject_variable("a", 271)
940
+ doctest:...: RuntimeWarning: redefining global value `a`
941
+ sage: a
942
+ 271
943
+ sage: inject_variable("a", 272)
944
+ sage: a
945
+ 272
946
+
947
+ That's because warn seem to not reissue twice the same warning::
948
+
949
+ sage: from warnings import warn
950
+ sage: warn("blah")
951
+ doctest:...: UserWarning: blah
952
+ sage: warn("blah")
953
+
954
+ Warnings can be disabled::
955
+
956
+ sage: b = 3
957
+ sage: inject_variable("b", 42, warn=False)
958
+ sage: b
959
+ 42
960
+
961
+ Use with care!
962
+ """
963
+ assert isinstance(name, str)
964
+ # Using globals() does not work, even in Cython, because
965
+ # inject_variable is called not only from the interpreter, but
966
+ # also from functions in various modules.
967
+ G = get_main_globals()
968
+ if name in G and warn:
969
+ warnings.warn(
970
+ "redefining global value `%s`" % name, RuntimeWarning, stacklevel=2
971
+ )
972
+ G[name] = value
973
+
974
+
975
+ def inject_variable_test(name, value, depth):
976
+ """
977
+ A function for testing deep calls to ``inject_variable``.
978
+
979
+ EXAMPLES::
980
+
981
+ sage: from sage.misc.misc import inject_variable_test
982
+ sage: inject_variable_test("a0", 314, 0)
983
+ sage: a0
984
+ 314
985
+ sage: inject_variable_test("a1", 314, 1)
986
+ sage: a1
987
+ 314
988
+ sage: inject_variable_test("a2", 314, 2)
989
+ sage: a2
990
+ 314
991
+ sage: inject_variable_test("a2", 271, 2)
992
+ doctest:...: RuntimeWarning: redefining global value `a2`
993
+ sage: a2
994
+ 271
995
+ """
996
+ if depth == 0:
997
+ inject_variable(name, value)
998
+ else:
999
+ inject_variable_test(name, value, depth - 1)
1000
+
1001
+
1002
+ # from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop
1003
+ def run_once(func):
1004
+ """
1005
+ Run a function (successfully) only once.
1006
+
1007
+ The running can be reset by setting the ``has_run`` attribute to False
1008
+
1009
+ TESTS::
1010
+
1011
+ sage: from sage.repl.ipython_extension import run_once
1012
+ sage: @run_once
1013
+ ....: def foo(work):
1014
+ ....: if work:
1015
+ ....: return 'foo worked'
1016
+ ....: raise RuntimeError("foo didn't work")
1017
+ sage: foo(False)
1018
+ Traceback (most recent call last):
1019
+ ...
1020
+ RuntimeError: foo didn't work
1021
+ sage: foo(True)
1022
+ 'foo worked'
1023
+ sage: foo(False)
1024
+ sage: foo(True)
1025
+ """
1026
+
1027
+ @functools.wraps(func)
1028
+ def wrapper(*args, **kwargs):
1029
+ if not wrapper.has_run:
1030
+ result = func(*args, **kwargs)
1031
+ wrapper.has_run = True
1032
+ return result
1033
+
1034
+ wrapper.has_run = False
1035
+ return wrapper
1036
+
1037
+
1038
+ @contextlib.contextmanager
1039
+ def increase_recursion_limit(increment):
1040
+ r"""
1041
+ Context manager to temporarily change the Python maximum recursion depth.
1042
+
1043
+ INPUT:
1044
+
1045
+ - ``increment`` -- increment to add to the current limit
1046
+
1047
+ EXAMPLES::
1048
+
1049
+ sage: from sage.misc.misc import increase_recursion_limit
1050
+ sage: def rec(n): None if n == 0 else rec(n-1)
1051
+ sage: rec(10000)
1052
+ Traceback (most recent call last):
1053
+ ...
1054
+ RecursionError: maximum recursion depth exceeded...
1055
+ sage: with increase_recursion_limit(10000): rec(10000)
1056
+ sage: rec(10000)
1057
+ Traceback (most recent call last):
1058
+ ...
1059
+ RecursionError: maximum recursion depth exceeded...
1060
+ """
1061
+ old_limit = sys.getrecursionlimit()
1062
+ sys.setrecursionlimit(old_limit + increment)
1063
+ try:
1064
+ yield
1065
+ finally:
1066
+ sys.setrecursionlimit(old_limit)