passagemath-objects 10.8.1a3__cp314-cp314-win_amd64.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.
Files changed (283) hide show
  1. passagemath_objects/__init__.py +3 -0
  2. passagemath_objects-10.8.1a3.dist-info/DELVEWHEEL +2 -0
  3. passagemath_objects-10.8.1a3.dist-info/METADATA +114 -0
  4. passagemath_objects-10.8.1a3.dist-info/RECORD +283 -0
  5. passagemath_objects-10.8.1a3.dist-info/WHEEL +5 -0
  6. passagemath_objects-10.8.1a3.dist-info/top_level.txt +3 -0
  7. passagemath_objects.libs/libgmp-10-60021eeab4282b29024e43b2b1412b53.dll +0 -0
  8. sage/all__sagemath_objects.py +46 -0
  9. sage/arith/all__sagemath_objects.py +5 -0
  10. sage/arith/long.pxd +411 -0
  11. sage/arith/numerical_approx.cp314-win_amd64.pyd +0 -0
  12. sage/arith/numerical_approx.pxd +35 -0
  13. sage/arith/numerical_approx.pyx +75 -0
  14. sage/arith/power.cp314-win_amd64.pyd +0 -0
  15. sage/arith/power.pxd +31 -0
  16. sage/arith/power.pyx +127 -0
  17. sage/categories/action.cp314-win_amd64.pyd +0 -0
  18. sage/categories/action.pxd +29 -0
  19. sage/categories/action.pyx +641 -0
  20. sage/categories/algebra_functor.py +745 -0
  21. sage/categories/all__sagemath_objects.py +33 -0
  22. sage/categories/basic.py +71 -0
  23. sage/categories/cartesian_product.py +292 -0
  24. sage/categories/category.py +3379 -0
  25. sage/categories/category_cy_helper.cp314-win_amd64.pyd +0 -0
  26. sage/categories/category_cy_helper.pxd +8 -0
  27. sage/categories/category_cy_helper.pyx +322 -0
  28. sage/categories/category_singleton.cp314-win_amd64.pyd +0 -0
  29. sage/categories/category_singleton.pxd +3 -0
  30. sage/categories/category_singleton.pyx +343 -0
  31. sage/categories/category_types.py +637 -0
  32. sage/categories/category_with_axiom.py +2889 -0
  33. sage/categories/covariant_functorial_construction.py +700 -0
  34. sage/categories/facade_sets.py +228 -0
  35. sage/categories/functor.cp314-win_amd64.pyd +0 -0
  36. sage/categories/functor.pxd +7 -0
  37. sage/categories/functor.pyx +659 -0
  38. sage/categories/homset.py +1289 -0
  39. sage/categories/homsets.py +364 -0
  40. sage/categories/isomorphic_objects.py +73 -0
  41. sage/categories/map.cp314-win_amd64.pyd +0 -0
  42. sage/categories/map.pxd +34 -0
  43. sage/categories/map.pyx +2106 -0
  44. sage/categories/morphism.cp314-win_amd64.pyd +0 -0
  45. sage/categories/morphism.pxd +14 -0
  46. sage/categories/morphism.pyx +895 -0
  47. sage/categories/objects.py +167 -0
  48. sage/categories/primer.py +1695 -0
  49. sage/categories/pushout.py +4847 -0
  50. sage/categories/quotients.py +64 -0
  51. sage/categories/realizations.py +200 -0
  52. sage/categories/sets_cat.py +3305 -0
  53. sage/categories/sets_with_partial_maps.py +52 -0
  54. sage/categories/subobjects.py +64 -0
  55. sage/categories/subquotients.py +21 -0
  56. sage/categories/with_realizations.py +311 -0
  57. sage/cpython/__init__.py +22 -0
  58. sage/cpython/_py2_random.py +619 -0
  59. sage/cpython/all.py +3 -0
  60. sage/cpython/atexit.cp314-win_amd64.pyd +0 -0
  61. sage/cpython/atexit.pyx +269 -0
  62. sage/cpython/builtin_types.cp314-win_amd64.pyd +0 -0
  63. sage/cpython/builtin_types.pyx +7 -0
  64. sage/cpython/cython_metaclass.cp314-win_amd64.pyd +0 -0
  65. sage/cpython/cython_metaclass.h +117 -0
  66. sage/cpython/cython_metaclass.pxd +3 -0
  67. sage/cpython/cython_metaclass.pyx +130 -0
  68. sage/cpython/debug.cp314-win_amd64.pyd +0 -0
  69. sage/cpython/debug.pyx +302 -0
  70. sage/cpython/dict_del_by_value.cp314-win_amd64.pyd +0 -0
  71. sage/cpython/dict_del_by_value.pxd +9 -0
  72. sage/cpython/dict_del_by_value.pyx +191 -0
  73. sage/cpython/dict_internal.h +80 -0
  74. sage/cpython/getattr.cp314-win_amd64.pyd +0 -0
  75. sage/cpython/getattr.pxd +9 -0
  76. sage/cpython/getattr.pyx +439 -0
  77. sage/cpython/pycore_long.h +97 -0
  78. sage/cpython/pycore_long.pxd +10 -0
  79. sage/cpython/python_debug.h +44 -0
  80. sage/cpython/python_debug.pxd +47 -0
  81. sage/cpython/pyx_visit.h +13 -0
  82. sage/cpython/string.cp314-win_amd64.pyd +0 -0
  83. sage/cpython/string.pxd +76 -0
  84. sage/cpython/string.pyx +34 -0
  85. sage/cpython/string_impl.h +60 -0
  86. sage/cpython/type.cp314-win_amd64.pyd +0 -0
  87. sage/cpython/type.pxd +2 -0
  88. sage/cpython/type.pyx +40 -0
  89. sage/cpython/wrapperdescr.pxd +67 -0
  90. sage/ext/all__sagemath_objects.py +3 -0
  91. sage/ext/ccobject.h +64 -0
  92. sage/ext/cplusplus.pxd +17 -0
  93. sage/ext/mod_int.h +30 -0
  94. sage/ext/mod_int.pxd +24 -0
  95. sage/ext/stdsage.pxd +39 -0
  96. sage/groups/all__sagemath_objects.py +1 -0
  97. sage/groups/group.cp314-win_amd64.pyd +0 -0
  98. sage/groups/group.pxd +14 -0
  99. sage/groups/group.pyx +296 -0
  100. sage/groups/old.cp314-win_amd64.pyd +0 -0
  101. sage/groups/old.pxd +14 -0
  102. sage/groups/old.pyx +219 -0
  103. sage/libs/all__sagemath_objects.py +3 -0
  104. sage/libs/gmp/__init__.py +1 -0
  105. sage/libs/gmp/all.pxd +6 -0
  106. sage/libs/gmp/binop.pxd +23 -0
  107. sage/libs/gmp/misc.pxd +8 -0
  108. sage/libs/gmp/mpf.pxd +88 -0
  109. sage/libs/gmp/mpn.pxd +57 -0
  110. sage/libs/gmp/mpq.pxd +57 -0
  111. sage/libs/gmp/mpz.pxd +202 -0
  112. sage/libs/gmp/pylong.cp314-win_amd64.pyd +0 -0
  113. sage/libs/gmp/pylong.pxd +12 -0
  114. sage/libs/gmp/pylong.pyx +150 -0
  115. sage/libs/gmp/random.pxd +25 -0
  116. sage/libs/gmp/randomize.pxd +59 -0
  117. sage/libs/gmp/types.pxd +53 -0
  118. sage/libs/gmpxx.pxd +19 -0
  119. sage/misc/abstract_method.py +276 -0
  120. sage/misc/all__sagemath_objects.py +43 -0
  121. sage/misc/bindable_class.py +253 -0
  122. sage/misc/c3_controlled.cp314-win_amd64.pyd +0 -0
  123. sage/misc/c3_controlled.pxd +2 -0
  124. sage/misc/c3_controlled.pyx +1402 -0
  125. sage/misc/cachefunc.cp314-win_amd64.pyd +0 -0
  126. sage/misc/cachefunc.pxd +43 -0
  127. sage/misc/cachefunc.pyx +3801 -0
  128. sage/misc/call.py +188 -0
  129. sage/misc/classcall_metaclass.cp314-win_amd64.pyd +0 -0
  130. sage/misc/classcall_metaclass.pxd +14 -0
  131. sage/misc/classcall_metaclass.pyx +599 -0
  132. sage/misc/constant_function.cp314-win_amd64.pyd +0 -0
  133. sage/misc/constant_function.pyx +130 -0
  134. sage/misc/decorators.py +739 -0
  135. sage/misc/fast_methods.cp314-win_amd64.pyd +0 -0
  136. sage/misc/fast_methods.pxd +20 -0
  137. sage/misc/fast_methods.pyx +351 -0
  138. sage/misc/flatten.py +90 -0
  139. sage/misc/fpickle.cp314-win_amd64.pyd +0 -0
  140. sage/misc/fpickle.pyx +176 -0
  141. sage/misc/function_mangling.cp314-win_amd64.pyd +0 -0
  142. sage/misc/function_mangling.pxd +11 -0
  143. sage/misc/function_mangling.pyx +308 -0
  144. sage/misc/inherit_comparison.cp314-win_amd64.pyd +0 -0
  145. sage/misc/inherit_comparison.pxd +5 -0
  146. sage/misc/inherit_comparison.pyx +105 -0
  147. sage/misc/instancedoc.cp314-win_amd64.pyd +0 -0
  148. sage/misc/instancedoc.pyx +331 -0
  149. sage/misc/lazy_attribute.cp314-win_amd64.pyd +0 -0
  150. sage/misc/lazy_attribute.pyx +607 -0
  151. sage/misc/lazy_format.py +132 -0
  152. sage/misc/lazy_import.cp314-win_amd64.pyd +0 -0
  153. sage/misc/lazy_import.pxd +13 -0
  154. sage/misc/lazy_import.pyx +1307 -0
  155. sage/misc/lazy_import_cache.py +36 -0
  156. sage/misc/lazy_list.cp314-win_amd64.pyd +0 -0
  157. sage/misc/lazy_list.pxd +19 -0
  158. sage/misc/lazy_list.pyx +1187 -0
  159. sage/misc/lazy_string.cp314-win_amd64.pyd +0 -0
  160. sage/misc/lazy_string.pxd +7 -0
  161. sage/misc/lazy_string.pyx +546 -0
  162. sage/misc/misc.py +980 -0
  163. sage/misc/misc_c.cp314-win_amd64.pyd +0 -0
  164. sage/misc/misc_c.pxd +3 -0
  165. sage/misc/misc_c.pyx +765 -0
  166. sage/misc/namespace_package.py +37 -0
  167. sage/misc/nested_class.cp314-win_amd64.pyd +0 -0
  168. sage/misc/nested_class.pxd +3 -0
  169. sage/misc/nested_class.pyx +394 -0
  170. sage/misc/persist.cp314-win_amd64.pyd +0 -0
  171. sage/misc/persist.pyx +1279 -0
  172. sage/misc/prandom.py +418 -0
  173. sage/misc/randstate.cp314-win_amd64.pyd +0 -0
  174. sage/misc/randstate.pxd +31 -0
  175. sage/misc/randstate.pyx +1096 -0
  176. sage/misc/repr.py +203 -0
  177. sage/misc/reset.cp314-win_amd64.pyd +0 -0
  178. sage/misc/reset.pyx +196 -0
  179. sage/misc/sage_ostools.cp314-win_amd64.pyd +0 -0
  180. sage/misc/sage_ostools.pyx +323 -0
  181. sage/misc/sage_timeit.py +275 -0
  182. sage/misc/sage_timeit_class.cp314-win_amd64.pyd +0 -0
  183. sage/misc/sage_timeit_class.pyx +120 -0
  184. sage/misc/sage_unittest.py +639 -0
  185. sage/misc/sageinspect.py +2792 -0
  186. sage/misc/session.cp314-win_amd64.pyd +0 -0
  187. sage/misc/session.pyx +392 -0
  188. sage/misc/superseded.py +576 -0
  189. sage/misc/test_nested_class.py +228 -0
  190. sage/misc/timing.py +264 -0
  191. sage/misc/unknown.py +222 -0
  192. sage/misc/verbose.py +253 -0
  193. sage/misc/weak_dict.cp314-win_amd64.pyd +0 -0
  194. sage/misc/weak_dict.pxd +15 -0
  195. sage/misc/weak_dict.pyx +1197 -0
  196. sage/modules/all__sagemath_objects.py +1 -0
  197. sage/modules/module.cp314-win_amd64.pyd +0 -0
  198. sage/modules/module.pxd +5 -0
  199. sage/modules/module.pyx +329 -0
  200. sage/rings/all__sagemath_objects.py +3 -0
  201. sage/rings/integer_fake.h +22 -0
  202. sage/rings/integer_fake.pxd +55 -0
  203. sage/rings/integer_fake.pyi +8 -0
  204. sage/sets/all__sagemath_objects.py +3 -0
  205. sage/sets/pythonclass.cp314-win_amd64.pyd +0 -0
  206. sage/sets/pythonclass.pxd +9 -0
  207. sage/sets/pythonclass.pyx +247 -0
  208. sage/structure/__init__.py +13 -0
  209. sage/structure/all.py +30 -0
  210. sage/structure/category_object.cp314-win_amd64.pyd +0 -0
  211. sage/structure/category_object.pxd +28 -0
  212. sage/structure/category_object.pyx +1090 -0
  213. sage/structure/coerce.cp314-win_amd64.pyd +0 -0
  214. sage/structure/coerce.pxd +44 -0
  215. sage/structure/coerce.pyx +2113 -0
  216. sage/structure/coerce_actions.cp314-win_amd64.pyd +0 -0
  217. sage/structure/coerce_actions.pxd +27 -0
  218. sage/structure/coerce_actions.pyx +988 -0
  219. sage/structure/coerce_dict.cp314-win_amd64.pyd +0 -0
  220. sage/structure/coerce_dict.pxd +51 -0
  221. sage/structure/coerce_dict.pyx +1557 -0
  222. sage/structure/coerce_exceptions.py +23 -0
  223. sage/structure/coerce_maps.cp314-win_amd64.pyd +0 -0
  224. sage/structure/coerce_maps.pxd +24 -0
  225. sage/structure/coerce_maps.pyx +656 -0
  226. sage/structure/debug_options.cp314-win_amd64.pyd +0 -0
  227. sage/structure/debug_options.pxd +6 -0
  228. sage/structure/debug_options.pyx +54 -0
  229. sage/structure/dynamic_class.py +541 -0
  230. sage/structure/element.cp314-win_amd64.pyd +0 -0
  231. sage/structure/element.pxd +271 -0
  232. sage/structure/element.pyx +4584 -0
  233. sage/structure/element_wrapper.cp314-win_amd64.pyd +0 -0
  234. sage/structure/element_wrapper.pxd +12 -0
  235. sage/structure/element_wrapper.pyx +582 -0
  236. sage/structure/factorization.py +1457 -0
  237. sage/structure/factorization_integer.py +154 -0
  238. sage/structure/factory.cp314-win_amd64.pyd +0 -0
  239. sage/structure/factory.pyx +863 -0
  240. sage/structure/formal_sum.py +489 -0
  241. sage/structure/gens_py.py +73 -0
  242. sage/structure/global_options.py +1725 -0
  243. sage/structure/indexed_generators.py +863 -0
  244. sage/structure/list_clone.cp314-win_amd64.pyd +0 -0
  245. sage/structure/list_clone.pxd +65 -0
  246. sage/structure/list_clone.pyx +1867 -0
  247. sage/structure/list_clone_demo.cp314-win_amd64.pyd +0 -0
  248. sage/structure/list_clone_demo.pyx +248 -0
  249. sage/structure/list_clone_timings.py +179 -0
  250. sage/structure/list_clone_timings_cy.cp314-win_amd64.pyd +0 -0
  251. sage/structure/list_clone_timings_cy.pyx +86 -0
  252. sage/structure/mutability.cp314-win_amd64.pyd +0 -0
  253. sage/structure/mutability.pxd +21 -0
  254. sage/structure/mutability.pyx +346 -0
  255. sage/structure/nonexact.py +69 -0
  256. sage/structure/parent.cp314-win_amd64.pyd +0 -0
  257. sage/structure/parent.pxd +112 -0
  258. sage/structure/parent.pyx +3087 -0
  259. sage/structure/parent_base.cp314-win_amd64.pyd +0 -0
  260. sage/structure/parent_base.pxd +13 -0
  261. sage/structure/parent_base.pyx +35 -0
  262. sage/structure/parent_gens.cp314-win_amd64.pyd +0 -0
  263. sage/structure/parent_gens.pxd +22 -0
  264. sage/structure/parent_gens.pyx +374 -0
  265. sage/structure/parent_old.cp314-win_amd64.pyd +0 -0
  266. sage/structure/parent_old.pxd +24 -0
  267. sage/structure/parent_old.pyx +278 -0
  268. sage/structure/proof/__init__.py +1 -0
  269. sage/structure/proof/all.py +243 -0
  270. sage/structure/proof/proof.py +300 -0
  271. sage/structure/richcmp.cp314-win_amd64.pyd +0 -0
  272. sage/structure/richcmp.pxd +212 -0
  273. sage/structure/richcmp.pyx +494 -0
  274. sage/structure/sage_object.cp314-win_amd64.pyd +0 -0
  275. sage/structure/sage_object.pxd +3 -0
  276. sage/structure/sage_object.pyx +1088 -0
  277. sage/structure/sage_object_test.py +19 -0
  278. sage/structure/sequence.py +937 -0
  279. sage/structure/set_factories.py +1178 -0
  280. sage/structure/set_factories_example.py +527 -0
  281. sage/structure/support_view.py +164 -0
  282. sage/structure/test_factory.py +56 -0
  283. sage/structure/unique_representation.py +1443 -0
@@ -0,0 +1,1307 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Lazy imports
4
+
5
+ This module allows one to lazily import objects into a namespace,
6
+ where the actual import is delayed until the object is actually called
7
+ or inspected. This is useful for modules that are expensive to import
8
+ or may cause circular references, though there is some overhead in its
9
+ use.
10
+
11
+ EXAMPLES::
12
+
13
+ sage: lazy_import('sage.rings.integer_ring', 'ZZ')
14
+ sage: type(ZZ)
15
+ <class 'sage.misc.lazy_import.LazyImport'>
16
+ sage: ZZ(4.0)
17
+ 4
18
+
19
+ By default, a warning is issued if a lazy import module is resolved
20
+ during Sage's startup. In case a lazy import's sole purpose is to
21
+ break a circular reference and it is known to be resolved at startup
22
+ time, one can use the ``at_startup`` option::
23
+
24
+ sage: lazy_import('sage.rings.integer_ring', 'ZZ', at_startup=True)
25
+
26
+ This option can also be used as an intermediate step toward not
27
+ importing by default a module that is used in several places, some of
28
+ which can already afford to lazy import the module but not all.
29
+
30
+ A lazy import that is marked as "at_startup" will print a message if
31
+ it is actually resolved after the startup, so that the developer knows
32
+ that (s)he can remove the flag::
33
+
34
+ sage: ZZ # needs sage.all
35
+ doctest:warning...
36
+ UserWarning: Option ``at_startup=True`` for lazy import ZZ not needed anymore
37
+ Integer Ring
38
+
39
+ .. WARNING::
40
+
41
+ After the first usage, the imported object is directly injected into the
42
+ namespace; however, before that, the :class:`LazyImport` object
43
+ is not exactly equivalent to the actual imported object. For example::
44
+
45
+ sage: from sage.misc.lazy_import import LazyImport
46
+ sage: my_qqbar = LazyImport('sage.rings.qqbar', 'QQbar')
47
+ sage: my_qqbar(5) == QQbar(5) # good
48
+ True
49
+ sage: isinstance(QQbar, Parent)
50
+ True
51
+ sage: isinstance(my_qqbar, Parent) # fails!
52
+ False
53
+
54
+ To avoid this issue, you may execute the import inside the function instead.
55
+
56
+ .. SEEALSO:: :func:`lazy_import`, :class:`LazyImport`
57
+
58
+ AUTHOR:
59
+
60
+ - Robert Bradshaw
61
+ """
62
+
63
+ # ****************************************************************************
64
+ # Copyright (C) 2009 Robert Bradshaw <robertwb@math.washington.edu>
65
+ #
66
+ # This program is free software: you can redistribute it and/or modify
67
+ # it under the terms of the GNU General Public License as published by
68
+ # the Free Software Foundation, either version 2 of the License, or
69
+ # (at your option) any later version.
70
+ # https://www.gnu.org/licenses/
71
+ # ****************************************************************************
72
+
73
+ # Keep OLD division semantics for Python 2 compatibility, such that
74
+ # lazy imports support old and true division.
75
+
76
+ cimport cython
77
+ from cpython.object cimport PyObject_RichCompare
78
+ from cpython.number cimport PyNumber_TrueDivide, PyNumber_Power, PyNumber_Index
79
+
80
+ cdef extern from *:
81
+ int likely(int) nogil # Defined by Cython
82
+
83
+ import os
84
+ import pickle
85
+ from warnings import warn
86
+ import inspect
87
+ from sage.misc import sageinspect
88
+
89
+
90
+ # LazyImport.__repr__ uses try... except FeatureNotPresentError.
91
+ # This is defined in sage.features, provided by the distribution sagemath-environment.
92
+ try:
93
+ from sage.features import FeatureNotPresentError
94
+ except ImportError:
95
+ # If sage.features cannot be imported, then FeatureNotPresentError cannot
96
+ # be raised. In this case, use the empty tuple as the exception specification.
97
+ FeatureNotPresentError = ()
98
+
99
+
100
+ cdef inline obj(x):
101
+ if type(x) is LazyImport:
102
+ return (<LazyImport>x).get_object()
103
+ else:
104
+ return x
105
+
106
+
107
+ # boolean to determine whether Sage is still starting up
108
+ cdef bint startup_guard = False
109
+
110
+ cdef bint finish_startup_called = False
111
+
112
+
113
+ cpdef finish_startup():
114
+ """
115
+ Finish the startup phase.
116
+
117
+ This function must be called exactly once at the end of the Sage
118
+ import process (:mod:`~sage.all`).
119
+
120
+ TESTS::
121
+
122
+ sage: from sage.misc.lazy_import import finish_startup
123
+ sage: finish_startup()
124
+ Traceback (most recent call last):
125
+ ...
126
+ AssertionError: finish_startup() must be called exactly once
127
+ """
128
+ global startup_guard, finish_startup_called
129
+ assert startup_guard, 'finish_startup() must be called exactly once'
130
+ startup_guard = False
131
+ finish_startup_called = True
132
+
133
+
134
+ cpdef commence_startup():
135
+ """
136
+ Begin the startup phase.
137
+
138
+ This should only be called once, and only during the monolithic startup (:mod:`~sage.all`).
139
+ """
140
+ global startup_guard
141
+ assert not startup_guard and not finish_startup_called, 'commence_startup() can only be called once, and not after finish_startup()'
142
+ startup_guard = True
143
+
144
+
145
+ cpdef ensure_startup_finished():
146
+ """
147
+ Make sure that the startup phase is finished.
148
+
149
+ In contrast to :func:`finish_startup`, this function can
150
+ be called repeatedly.
151
+
152
+ TESTS::
153
+
154
+ sage: from sage.misc.lazy_import import ensure_startup_finished
155
+ sage: ensure_startup_finished()
156
+ """
157
+ global startup_guard
158
+ startup_guard = False
159
+
160
+
161
+ cpdef bint is_during_startup() noexcept:
162
+ """
163
+ Return whether Sage is currently starting up.
164
+
165
+ OUTPUT: boolean
166
+
167
+ TESTS::
168
+
169
+ sage: from sage.misc.lazy_import import is_during_startup
170
+ sage: is_during_startup()
171
+ False
172
+ """
173
+ global startup_guard
174
+ return startup_guard
175
+
176
+
177
+ cpdef test_fake_startup():
178
+ """
179
+ For testing purposes only.
180
+
181
+ Switch the startup lazy import guard back on.
182
+
183
+ EXAMPLES::
184
+
185
+ sage: sage.misc.lazy_import.test_fake_startup()
186
+ sage: lazy_import('sage.rings.integer_ring', 'ZZ', 'my_ZZ')
187
+ sage: my_ZZ(123)
188
+ doctest:warning...
189
+ UserWarning: Resolving lazy import ZZ during startup
190
+ 123
191
+ sage: sage.misc.lazy_import.finish_startup()
192
+ """
193
+ global startup_guard, finish_startup_called
194
+ startup_guard = True
195
+ finish_startup_called = False
196
+
197
+
198
+ @cython.final
199
+ cdef class LazyImport():
200
+ """
201
+ EXAMPLES::
202
+
203
+ sage: from sage.misc.lazy_import import LazyImport
204
+ sage: my_integer = LazyImport('sage.rings.integer', 'Integer')
205
+ sage: my_integer(4)
206
+ 4
207
+ sage: my_integer('101', base=2)
208
+ 5
209
+ sage: my_integer(3/2)
210
+ Traceback (most recent call last):
211
+ ...
212
+ TypeError: no conversion of this rational to integer
213
+ """
214
+ def __init__(self, module, name, as_name=None, at_startup=False, namespace=None,
215
+ deprecation=None, feature=None):
216
+ """
217
+ EXAMPLES::
218
+
219
+ sage: from sage.misc.lazy_import import LazyImport
220
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
221
+ sage: type(lazy_ZZ)
222
+ <class 'sage.misc.lazy_import.LazyImport'>
223
+ sage: lazy_ZZ._get_object() is ZZ
224
+ True
225
+ sage: type(lazy_ZZ)
226
+ <class 'sage.misc.lazy_import.LazyImport'>
227
+ """
228
+ self._object = None
229
+ self._module = module
230
+ self._name = name
231
+ self._as_name = name if as_name is None else as_name
232
+ self._namespace = namespace
233
+ self._at_startup = at_startup
234
+ self._deprecation = deprecation
235
+ self._feature = feature
236
+
237
+ cdef inline get_object(self):
238
+ """
239
+ Faster, Cython-only partially-inlined version of ``_get_object``.
240
+ """
241
+ if likely(self._object is not None):
242
+ return self._object
243
+ return self._get_object()
244
+
245
+ cpdef _get_object(self):
246
+ """
247
+ Return the wrapped object, importing it if necessary.
248
+
249
+ OUTPUT: the wrapped object
250
+
251
+ EXAMPLES::
252
+
253
+ sage: from sage.misc.lazy_import import LazyImport
254
+ sage: my_integer_ring = LazyImport('sage.rings.integer_ring', 'ZZ')
255
+ sage: my_integer_ring._object is None
256
+ True
257
+ sage: my_integer_ring._get_object()
258
+ Integer Ring
259
+ sage: my_integer_ring._object is None
260
+ False
261
+ sage: my_rats = LazyImport('sage.rings.rational_field', 'QQ', at_startup=True)
262
+ sage: my_rats
263
+ doctest:warning...
264
+ UserWarning: Option ``at_startup=True`` for lazy import QQ not needed anymore
265
+ Rational Field
266
+ """
267
+ if self._object is not None:
268
+ return self._object
269
+
270
+ if startup_guard and not self._at_startup:
271
+ warn(f"Resolving lazy import {self._name} during startup")
272
+ elif self._at_startup and not startup_guard:
273
+ if finish_startup_called:
274
+ warn(f"Option ``at_startup=True`` for lazy import {self._name} not needed anymore")
275
+
276
+ feature = self._feature
277
+ try:
278
+ self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
279
+ except ImportError as e:
280
+ if feature:
281
+ # Avoid warnings from static type checkers by explicitly importing FeatureNotPresentError.
282
+ from sage.features import FeatureNotPresentError
283
+ raise FeatureNotPresentError(feature, reason=f'Importing {self._name} failed: {e}')
284
+ raise
285
+
286
+ if feature:
287
+ # for the case that the feature is hidden
288
+ feature.require()
289
+
290
+ if self._deprecation is not None:
291
+ from sage.misc.superseded import deprecation_cython as deprecation
292
+ try:
293
+ issue_number, message = self._deprecation
294
+ except TypeError:
295
+ issue_number = self._deprecation
296
+ import_command = f'from {self._module} import {self._name}'
297
+ if self._as_name != self._name:
298
+ import_command += f' as {self._as_name}'
299
+ message = f'\nImporting {self._as_name} from here is deprecated; please use "{import_command}" instead.'
300
+ deprecation(issue_number, message)
301
+ # Replace the lazy import in the namespace by the actual object
302
+ name = self._as_name
303
+ if self._namespace is not None:
304
+ if self._namespace.get(name) is self:
305
+ self._namespace[name] = self._object
306
+ return self._object
307
+
308
+ def _get_deprecation_issue(self):
309
+ """
310
+ Return the issue number of the deprecation, or 0 if this lazy
311
+ import is not deprecated.
312
+
313
+ EXAMPLES::
314
+
315
+ sage: from sage.misc.lazy_import import LazyImport
316
+ sage: H = LazyImport('sage.categories.homsets', 'Homsets')
317
+ sage: H._get_deprecation_issue()
318
+ 0
319
+ sage: H = LazyImport('sage.categories.homsets', 'Homsets', deprecation=10668)
320
+ sage: H._get_deprecation_issue()
321
+ 10668
322
+ sage: H = LazyImport('sage.categories.homsets', 'Homsets', deprecation=(10668, "this is deprecated"))
323
+ sage: H._get_deprecation_issue()
324
+ 10668
325
+ """
326
+ if self._deprecation is None:
327
+ return 0
328
+ try:
329
+ return self._deprecation[0]
330
+ except TypeError:
331
+ return self._deprecation
332
+
333
+ def _instancedoc_(self):
334
+ """
335
+ Return the docstring of the wrapped object for introspection.
336
+
337
+ EXAMPLES::
338
+
339
+ sage: from sage.misc.lazy_import import LazyImport
340
+ sage: my_isprime = LazyImport('sage.arith.misc', 'is_prime')
341
+ sage: my_isprime.__doc__ is is_prime.__doc__
342
+ True
343
+
344
+ TESTS:
345
+
346
+ Check that :issue:`19475` is fixed::
347
+
348
+ sage: 'A subset of the real line' in RealSet.__doc__
349
+ True
350
+ """
351
+ return sageinspect.sage_getdoc_original(self.get_object())
352
+
353
+ def _sage_src_(self):
354
+ """
355
+ Return the source of the wrapped object for introspection.
356
+
357
+ EXAMPLES::
358
+
359
+ sage: from sage.misc.lazy_import import LazyImport
360
+ sage: my_isprime = LazyImport('sage.arith.misc', 'is_prime')
361
+ sage: 'def is_prime(' in my_isprime._sage_src_()
362
+ True
363
+ """
364
+ return sageinspect.sage_getsource(self.get_object())
365
+
366
+ def _sage_argspec_(self):
367
+ """
368
+ Return the argspec of the wrapped object for introspection.
369
+
370
+ EXAMPLES::
371
+
372
+ sage: from sage.misc.lazy_import import LazyImport
373
+ sage: rm = LazyImport('sage.matrix.special', 'random_matrix')
374
+ sage: rm._sage_argspec_() # needs sage.modules
375
+ FullArgSpec(args=['ring', 'nrows', 'ncols', 'algorithm', 'implementation'],
376
+ varargs='args', varkw='kwds', defaults=(None, 'randomize', None),
377
+ kwonlyargs=[], kwonlydefaults=None, annotations={})
378
+ """
379
+ return sageinspect.sage_getargspec(self.get_object())
380
+
381
+ def __getattr__(self, attr):
382
+ """
383
+ Attribute lookup on ``self`` defers to attribute lookup on the
384
+ wrapped object.
385
+
386
+ EXAMPLES::
387
+
388
+ sage: from sage.misc.lazy_import import LazyImport
389
+ sage: my_integer = LazyImport('sage.rings.integer', 'Integer')
390
+ sage: my_integer.sqrt is Integer.sqrt
391
+ True
392
+ """
393
+ return getattr(self.get_object(), attr)
394
+
395
+ # We need to wrap all the slot methods, as they are not forwarded
396
+ # via getattr.
397
+
398
+ def __dir__(self):
399
+ """
400
+ Tab completion on ``self`` defers to completion on the wrapped
401
+ object.
402
+
403
+ EXAMPLES::
404
+
405
+ sage: from sage.misc.lazy_import import LazyImport
406
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
407
+ sage: dir(lazy_ZZ) == dir(ZZ)
408
+ True
409
+ """
410
+ return dir(self.get_object())
411
+
412
+ def __call__(self, *args, **kwds):
413
+ """
414
+ Calling ``self`` calls the wrapped object.
415
+
416
+ EXAMPLES::
417
+
418
+ sage: from sage.misc.lazy_import import LazyImport
419
+ sage: my_isprime = LazyImport('sage.arith.misc', 'is_prime')
420
+ sage: is_prime(12) == my_isprime(12)
421
+ True
422
+ sage: is_prime(13) == my_isprime(13)
423
+ True
424
+ """
425
+ return self.get_object()(*args, **kwds)
426
+
427
+ def __repr__(self):
428
+ """
429
+ TESTS::
430
+
431
+ sage: from sage.misc.lazy_import import LazyImport
432
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
433
+ sage: repr(lazy_ZZ) == repr(ZZ)
434
+ True
435
+ """
436
+ try:
437
+ obj = self.get_object()
438
+ return repr(obj)
439
+ except FeatureNotPresentError as e:
440
+ return "Failed lazy import:\n" + str(e)
441
+
442
+ def __str__(self):
443
+ """
444
+ TESTS::
445
+
446
+ sage: from sage.misc.lazy_import import LazyImport
447
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
448
+ sage: str(lazy_ZZ) == str(ZZ)
449
+ True
450
+ """
451
+ return str(self.get_object())
452
+
453
+ def __bool__(self):
454
+ """
455
+ TESTS::
456
+
457
+ sage: from sage.misc.lazy_import import LazyImport
458
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
459
+ sage: bool(lazy_ZZ) == bool(ZZ)
460
+ True
461
+ """
462
+ return bool(self.get_object())
463
+
464
+ def __hash__(self):
465
+ """
466
+ TESTS::
467
+
468
+ sage: from sage.misc.lazy_import import LazyImport
469
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
470
+ sage: hash(lazy_ZZ) == hash(ZZ)
471
+ True
472
+ """
473
+ return hash(self.get_object())
474
+
475
+ def __richcmp__(left, right, int op):
476
+ """
477
+ TESTS::
478
+
479
+ sage: from sage.misc.lazy_import import LazyImport
480
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
481
+ sage: lazy_ZZ == ZZ
482
+ True
483
+ sage: lazy_ZZ == RR
484
+ False
485
+ """
486
+ return PyObject_RichCompare(obj(left), obj(right), op)
487
+
488
+ def __len__(self):
489
+ """
490
+ TESTS::
491
+
492
+ sage: lazy_import('sys', 'version_info')
493
+ sage: type(version_info)
494
+ <class 'sage.misc.lazy_import.LazyImport'>
495
+ sage: len(version_info)
496
+ 5
497
+ """
498
+ return len(self.get_object())
499
+
500
+ def __get__(self, instance, owner):
501
+ """
502
+ EXAMPLES:
503
+
504
+ Here we show how to take a function in a module, and lazy
505
+ import it as a method of a class. For the sake of this
506
+ example, we add manually a function in :mod:`sage.all__sagemath_objects`::
507
+
508
+ sage: def my_method(self): return self
509
+ sage: import sage.all__sagemath_objects
510
+ sage: sage.all__sagemath_objects.my_method = my_method
511
+
512
+ Now we lazy import it as a method of a new class ``Foo``::
513
+
514
+ sage: from sage.misc.lazy_import import LazyImport
515
+ sage: class Foo():
516
+ ....: my_method = LazyImport('sage.all__sagemath_objects', 'my_method')
517
+
518
+ Now we can use it as a usual method::
519
+
520
+ sage: Foo().my_method()
521
+ <__main__.Foo object at ...>
522
+ sage: Foo.my_method
523
+ <function my_method at 0x...>
524
+ sage: Foo().my_method
525
+ <bound method my_method of <__main__.Foo object at ...>>
526
+
527
+ When a :class:`LazyImport` method is a method (or attribute)
528
+ of a class, then extra work must be done to replace this
529
+ :class:`LazyImport` object with the actual object. See the
530
+ documentation of :meth:`_get_object` for an explanation of
531
+ this.
532
+
533
+ .. NOTE::
534
+
535
+ For a :class:`LazyImport` object that appears in a class
536
+ namespace, we need to do something special. Indeed, the
537
+ class namespace dictionary at the time of the class
538
+ definition is not the one that actually gets used. Thus,
539
+ ``__get__`` needs to manually modify the class dict::
540
+
541
+ sage: class Foo():
542
+ ....: lazy_import('sage.plot.plot', 'plot')
543
+ sage: class Bar(Foo):
544
+ ....: pass
545
+ sage: type(Foo.__dict__['plot'])
546
+ <class 'sage.misc.lazy_import.LazyImport'>
547
+
548
+ We access the ``plot`` method::
549
+
550
+ sage: Bar.plot # needs sage.plot
551
+ <function plot at 0x...>
552
+
553
+ Now ``plot`` has been replaced in the dictionary of ``Foo``::
554
+
555
+ sage: type(Foo.__dict__['plot']) # needs sage.plot
556
+ <... 'function'>
557
+ """
558
+ # Don't use the namespace of the class definition
559
+ self._namespace = None
560
+ obj = self.get_object()
561
+
562
+ name = self._as_name
563
+ for cls in inspect.getmro(owner):
564
+ if cls.__dict__.get(name) is self:
565
+ setattr(cls, name, obj)
566
+ break
567
+
568
+ # Check whether the imported object is itself a descriptor
569
+ try:
570
+ get = obj.__get__
571
+ except AttributeError:
572
+ return obj
573
+ else:
574
+ return get(instance, owner)
575
+
576
+ def __getitem__(self, key):
577
+ """
578
+ TESTS::
579
+
580
+ sage: import sys
581
+ sage: py_version = sys.version_info[0]
582
+ sage: lazy_import('sys', 'version_info')
583
+ sage: version_info[0] == py_version
584
+ True
585
+ """
586
+ return self.get_object()[key]
587
+
588
+ def __setitem__(self, key, value):
589
+ """
590
+ TESTS::
591
+
592
+ sage: from sage.misc.lazy_import import LazyImport
593
+ sage: import sage.all__sagemath_objects
594
+ sage: sage.all__sagemath_objects.foo = list(range(10))
595
+ sage: lazy_foo = LazyImport('sage.all__sagemath_objects', 'foo')
596
+ sage: lazy_foo[1] = 100
597
+ sage: print(lazy_foo)
598
+ [0, 100, 2, 3, 4, 5, 6, 7, 8, 9]
599
+ sage: sage.all__sagemath_objects.foo
600
+ [0, 100, 2, 3, 4, 5, 6, 7, 8, 9]
601
+ """
602
+ self.get_object()[key] = value
603
+
604
+ def __delitem__(self, key):
605
+ """
606
+ TESTS::
607
+
608
+ sage: from sage.misc.lazy_import import LazyImport
609
+ sage: import sage.all__sagemath_objects
610
+ sage: sage.all__sagemath_objects.foo = list(range(10))
611
+ sage: lazy_foo = LazyImport('sage.all__sagemath_objects', 'foo')
612
+ sage: del lazy_foo[1]
613
+ sage: print(lazy_foo)
614
+ [0, 2, 3, 4, 5, 6, 7, 8, 9]
615
+ sage: print(sage.all__sagemath_objects.foo)
616
+ [0, 2, 3, 4, 5, 6, 7, 8, 9]
617
+ """
618
+ del self.get_object()[key]
619
+
620
+ def __iter__(self):
621
+ """
622
+ TESTS::
623
+
624
+ sage: lazy_import('sys', 'version_info')
625
+ sage: iter(version_info)
626
+ <...iterator object at ...>
627
+ """
628
+ return iter(self.get_object())
629
+
630
+ def __contains__(self, item):
631
+ """
632
+ TESTS::
633
+
634
+ sage: import sys
635
+ sage: py_version = sys.version_info[0]
636
+ sage: lazy_import('sys', 'version_info')
637
+ sage: py_version in version_info
638
+ True
639
+
640
+ sage: lazy_import('sys', 'version_info')
641
+ sage: 2000 not in version_info
642
+ True
643
+ """
644
+ return item in self.get_object()
645
+
646
+ def __add__(left, right):
647
+ """
648
+ TESTS::
649
+
650
+ sage: import sage.all__sagemath_objects
651
+ sage: sage.all__sagemath_objects.foo = 10
652
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
653
+ sage: foo + 1
654
+ 11
655
+ """
656
+ return obj(left) + obj(right)
657
+
658
+ def __sub__(left, right):
659
+ """
660
+ TESTS::
661
+
662
+ sage: import sage.all__sagemath_objects
663
+ sage: sage.all__sagemath_objects.foo = 10
664
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
665
+ sage: foo - 1
666
+ 9
667
+ """
668
+ return obj(left) - obj(right)
669
+
670
+ def __mul__(left, right):
671
+ """
672
+ TESTS::
673
+
674
+ sage: import sage.all__sagemath_objects
675
+ sage: sage.all__sagemath_objects.foo = 10
676
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
677
+ sage: foo * 2
678
+ 20
679
+ """
680
+ return obj(left) * obj(right)
681
+
682
+ def __matmul__(left, right):
683
+ """
684
+ TESTS::
685
+
686
+ sage: # needs sympy
687
+ sage: from sympy import Matrix
688
+ sage: import sage.all__sagemath_objects
689
+ sage: sage.all__sagemath_objects.foo = Matrix([[1,1], [0,1]])
690
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
691
+ sage: foo.__matmul__(foo)
692
+ Matrix([
693
+ [1, 2],
694
+ [0, 1]])
695
+ """
696
+ return obj(left) @ obj(right)
697
+
698
+ def __floordiv__(left, right):
699
+ """
700
+ TESTS::
701
+
702
+ sage: import sage.all__sagemath_objects
703
+ sage: sage.all__sagemath_objects.foo = 10
704
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
705
+ sage: foo // 3
706
+ 3
707
+ """
708
+ return obj(left) // obj(right)
709
+
710
+ def __truediv__(left, right):
711
+ """
712
+ TESTS::
713
+
714
+ sage: import sage.all__sagemath_objects
715
+ sage: sage.all__sagemath_objects.foo = 10
716
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
717
+ sage: operator.truediv(foo, 3)
718
+ 10/3
719
+ """
720
+ return PyNumber_TrueDivide(obj(left), obj(right))
721
+
722
+ def __pow__(left, right, mod):
723
+ """
724
+ TESTS::
725
+
726
+ sage: import sage.all__sagemath_objects
727
+ sage: sage.all__sagemath_objects.foo = 10
728
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
729
+ sage: foo ** 2
730
+ 100
731
+ """
732
+ return PyNumber_Power(obj(left), obj(right), obj(mod))
733
+
734
+ def __mod__(left, right):
735
+ """
736
+ TESTS::
737
+
738
+ sage: import sage.all__sagemath_objects
739
+ sage: sage.all__sagemath_objects.foo = 10
740
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
741
+ sage: foo % 7
742
+ 3
743
+ """
744
+ return obj(left) % obj(right)
745
+
746
+ def __lshift__(left, right):
747
+ """
748
+ TESTS::
749
+
750
+ sage: import sage.all__sagemath_objects
751
+ sage: sage.all__sagemath_objects.foo = 10
752
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
753
+ sage: foo << 3
754
+ 80
755
+ """
756
+ return obj(left) << obj(right)
757
+
758
+ def __rshift__(left, right):
759
+ """
760
+ TESTS::
761
+
762
+ sage: import sage.all__sagemath_objects
763
+ sage: sage.all__sagemath_objects.foo = 10
764
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
765
+ sage: foo >> 2
766
+ 2
767
+ """
768
+ return obj(left) >> obj(right)
769
+
770
+ def __and__(left, right):
771
+ """
772
+ TESTS::
773
+
774
+ sage: import sage.all__sagemath_objects
775
+ sage: sage.all__sagemath_objects.foo = 10
776
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
777
+ sage: foo & 7
778
+ 2
779
+ """
780
+ return obj(left) & obj(right)
781
+
782
+ def __or__(left, right):
783
+ """
784
+ TESTS::
785
+
786
+ sage: import sage.all__sagemath_objects
787
+ sage: sage.all__sagemath_objects.foo = 10
788
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
789
+ sage: foo | 7
790
+ 15
791
+ """
792
+ return obj(left) | obj(right)
793
+
794
+ def __xor__(left, right):
795
+ """
796
+ TESTS::
797
+
798
+ sage: import sage.all__sagemath_objects
799
+ sage: sage.all__sagemath_objects.foo = 10
800
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
801
+ sage: foo ^^ 7
802
+ 13
803
+ """
804
+ return obj(left) ^ obj(right)
805
+
806
+ def __neg__(self):
807
+ """
808
+ TESTS::
809
+
810
+ sage: import sage.all__sagemath_objects
811
+ sage: sage.all__sagemath_objects.foo = 10
812
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
813
+ sage: -foo
814
+ -10
815
+ """
816
+ return -self.get_object()
817
+
818
+ def __pos__(self):
819
+ """
820
+ TESTS::
821
+
822
+ sage: import sage.all__sagemath_objects
823
+ sage: sage.all__sagemath_objects.foo = 10
824
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
825
+ sage: +foo
826
+ 10
827
+ """
828
+ return +self.get_object()
829
+
830
+ def __abs__(self):
831
+ """
832
+ TESTS::
833
+
834
+ sage: import sage.all__sagemath_objects
835
+ sage: sage.all__sagemath_objects.foo = -1000
836
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
837
+ sage: abs(foo)
838
+ 1000
839
+ """
840
+ return abs(self.get_object())
841
+
842
+ def __invert__(self):
843
+ """
844
+ TESTS::
845
+
846
+ sage: import sage.all__sagemath_objects
847
+ sage: sage.all__sagemath_objects.foo = 10
848
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
849
+ sage: ~foo
850
+ 1/10
851
+ """
852
+ return ~self.get_object()
853
+
854
+ def __complex__(self):
855
+ """
856
+ TESTS::
857
+
858
+ sage: import sage.all__sagemath_objects
859
+ sage: sage.all__sagemath_objects.foo = 10
860
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
861
+ sage: complex(foo)
862
+ (10+0j)
863
+ """
864
+ return complex(self.get_object())
865
+
866
+ def __int__(self):
867
+ """
868
+ TESTS::
869
+
870
+ sage: import sage.all__sagemath_objects
871
+ sage: sage.all__sagemath_objects.foo = 10
872
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
873
+ sage: int(foo)
874
+ 10
875
+ """
876
+ return int(self.get_object())
877
+
878
+ def __float__(self):
879
+ """
880
+ TESTS::
881
+
882
+ sage: import sage.all__sagemath_objects
883
+ sage: sage.all__sagemath_objects.foo = 10
884
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
885
+ sage: float(foo)
886
+ 10.0
887
+ """
888
+ return float(self.get_object())
889
+
890
+ def __oct__(self):
891
+ """
892
+ TESTS::
893
+
894
+ sage: import sage.all__sagemath_objects
895
+ sage: sage.all__sagemath_objects.foo = 10
896
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
897
+ sage: oct(foo)
898
+ '0o12'
899
+ """
900
+ return self.get_object().__oct__()
901
+
902
+ def __hex__(self):
903
+ """
904
+ TESTS::
905
+
906
+ sage: import sage.all__sagemath_objects
907
+ sage: sage.all__sagemath_objects.foo = 10
908
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
909
+ sage: hex(foo)
910
+ '0xa'
911
+ """
912
+ return self.get_object().__hex__()
913
+
914
+ def __index__(self):
915
+ """
916
+ TESTS::
917
+
918
+ sage: import sage.all__sagemath_objects
919
+ sage: sage.all__sagemath_objects.foo = 10
920
+ sage: lazy_import('sage.all__sagemath_objects', 'foo')
921
+ sage: list(range(100))[foo]
922
+ 10
923
+ """
924
+ return PyNumber_Index(self.get_object())
925
+
926
+ def __copy__(self):
927
+ """
928
+ Support ``copy()``.
929
+
930
+ TESTS::
931
+
932
+ sage: from sage.misc.lazy_import import LazyImport
933
+ sage: import sage.all__sagemath_objects
934
+ sage: sage.all__sagemath_objects.foo = [[1,2], 3]
935
+ sage: lazy_foo = LazyImport('sage.all__sagemath_objects', 'foo')
936
+ sage: a = copy(lazy_foo)
937
+ sage: a is sage.all__sagemath_objects.foo # copy
938
+ False
939
+ sage: a[0] is sage.all__sagemath_objects.foo[0] # copy but not deep
940
+ True
941
+ sage: type(lazy_foo) is LazyImport
942
+ True
943
+ """
944
+ import copy
945
+ return copy.copy(self.get_object())
946
+
947
+ def __deepcopy__(self, memo=None):
948
+ """
949
+ Support ``copy()``.
950
+
951
+ TESTS::
952
+
953
+ sage: from sage.misc.lazy_import import LazyImport
954
+ sage: import sage.all__sagemath_objects
955
+ sage: sage.all__sagemath_objects.foo = [[1,2], 3]
956
+ sage: lazy_foo = LazyImport('sage.all__sagemath_objects', 'foo')
957
+ sage: a = deepcopy(lazy_foo)
958
+ sage: a is sage.all__sagemath_objects.foo # copy
959
+ False
960
+ sage: a[0] is sage.all__sagemath_objects.foo[0] # deep copy
961
+ False
962
+ sage: type(lazy_foo) is LazyImport
963
+ True
964
+ """
965
+ import copy
966
+ return copy.deepcopy(self.get_object())
967
+
968
+ def __instancecheck__(self, x):
969
+ """
970
+ Support ``isinstance()``.
971
+
972
+ EXAMPLES::
973
+
974
+ sage: lazy_import('sage.rings.rational_field', 'RationalField')
975
+ sage: isinstance(QQ, RationalField)
976
+ True
977
+
978
+ No object is an instance of a class that cannot be imported::
979
+
980
+ sage: lazy_import('sage.xxxxx_does_not_exist', 'DoesNotExist')
981
+ sage: isinstance(QQ, DoesNotExist)
982
+ False
983
+ """
984
+ try:
985
+ return isinstance(x, self.get_object())
986
+ except ImportError:
987
+ return False
988
+
989
+ def __subclasscheck__(self, x):
990
+ """
991
+ Support ``issubclass()``.
992
+
993
+ EXAMPLES::
994
+
995
+ sage: lazy_import('sage.structure.parent', 'Parent')
996
+ sage: issubclass(RationalField, Parent)
997
+ True
998
+
999
+ No class is a subclass of a class that cannot be imported::
1000
+
1001
+ sage: lazy_import('sage.xxxxx_does_not_exist', 'DoesNotExist')
1002
+ sage: issubclass(RationalField, DoesNotExist)
1003
+ False
1004
+ """
1005
+ try:
1006
+ return issubclass(x, self.get_object())
1007
+ except ImportError:
1008
+ return False
1009
+
1010
+
1011
+ def lazy_import(module, names, as_=None, *,
1012
+ at_startup=False, namespace=None,
1013
+ deprecation=None, feature=None):
1014
+ """
1015
+ Create a lazy import object and inject it into the caller's global
1016
+ namespace. For the purposes of introspection and calling, this is
1017
+ like performing a lazy "from module import name" where the import
1018
+ is delayed until the object actually is used or inspected.
1019
+
1020
+ INPUT:
1021
+
1022
+ - ``module`` -- string representing the module to import
1023
+
1024
+ - ``names`` -- string or list of strings representing the names to
1025
+ import from module
1026
+
1027
+ - ``as_`` -- (optional) a string or list of strings representing the
1028
+ names of the objects in the importing module. This is analogous to
1029
+ ``from ... import ... as ...``.
1030
+
1031
+ - ``at_startup`` -- boolean (default: ``False``);
1032
+ whether the lazy import is supposed to be resolved at startup time
1033
+
1034
+ - ``namespace`` -- the namespace where importing the names; by default,
1035
+ import the names to current namespace
1036
+
1037
+ - ``deprecation`` -- (optional) if not ``None``, a deprecation warning
1038
+ will be issued when the object is actually imported;
1039
+ ``deprecation`` should be either a trac number (integer) or a
1040
+ pair ``(issue_number, message)``
1041
+
1042
+ - ``feature`` -- a python module (optional), if it cannot be imported
1043
+ an appropriate error is raised
1044
+
1045
+ .. SEEALSO:: :mod:`sage.misc.lazy_import`, :class:`LazyImport`
1046
+
1047
+ EXAMPLES::
1048
+
1049
+ sage: lazy_import('sage.rings.integer_ring', 'ZZ')
1050
+ sage: type(ZZ)
1051
+ <class 'sage.misc.lazy_import.LazyImport'>
1052
+ sage: ZZ(4.0)
1053
+ 4
1054
+ sage: lazy_import('sage.rings.real_double', 'RDF', 'my_RDF')
1055
+ sage: my_RDF._get_object() is RDF
1056
+ True
1057
+ sage: my_RDF(1/2)
1058
+ 0.5
1059
+
1060
+ sage: lazy_import('sage.rings.rational_field', ['QQ', 'frac'], ['my_QQ', 'my_frac'])
1061
+ sage: my_QQ._get_object() is QQ
1062
+ True
1063
+ sage: my_frac._get_object() is sage.rings.rational_field.frac
1064
+ True
1065
+
1066
+ Upon the first use, the object is injected directly into
1067
+ the calling namespace::
1068
+
1069
+ sage: lazy_import('sage.rings.integer_ring', 'ZZ', 'my_ZZ')
1070
+ sage: my_ZZ is ZZ
1071
+ False
1072
+ sage: my_ZZ(37)
1073
+ 37
1074
+ sage: my_ZZ is ZZ
1075
+ True
1076
+
1077
+ We check that :func:`lazy_import` also works for methods::
1078
+
1079
+ sage: class Foo():
1080
+ ....: lazy_import('sage.plot.plot', 'plot')
1081
+ sage: class Bar(Foo):
1082
+ ....: pass
1083
+ sage: type(Foo.__dict__['plot'])
1084
+ <class 'sage.misc.lazy_import.LazyImport'>
1085
+ sage: 'EXAMPLES' in Bar.plot.__doc__ # needs sage.plot
1086
+ True
1087
+ sage: type(Foo.__dict__['plot']) # needs sage.plot
1088
+ <... 'function'>
1089
+
1090
+ If deprecated then a deprecation warning is issued::
1091
+
1092
+ sage: lazy_import('sage.rings.padics.factory', 'Qp', 'my_Qp',
1093
+ ....: deprecation=14275)
1094
+ sage: my_Qp(5) # needs sage.rings.padics
1095
+ doctest:...: DeprecationWarning:
1096
+ Importing my_Qp from here is deprecated;
1097
+ please use "from sage.rings.padics.factory import Qp as my_Qp" instead.
1098
+ See https://github.com/sagemath/sage/issues/14275 for details.
1099
+ 5-adic Field with capped relative precision 20
1100
+
1101
+ An example of deprecation with a message::
1102
+
1103
+ sage: lazy_import('sage.rings.padics.factory', 'Qp', 'my_Qp_msg',
1104
+ ....: deprecation=(14275, "This is an example."))
1105
+ sage: my_Qp_msg(5) # needs sage.rings.padics
1106
+ doctest:...: DeprecationWarning: This is an example.
1107
+ See https://github.com/sagemath/sage/issues/14275 for details.
1108
+ 5-adic Field with capped relative precision 20
1109
+
1110
+ An example of an import relying on a feature::
1111
+
1112
+ sage: from sage.features import PythonModule
1113
+ sage: lazy_import('ppl', 'equation',
1114
+ ....: feature=PythonModule('ppl', spkg='pplpy', type='standard'))
1115
+ sage: equation # needs pplpy
1116
+ <cyfunction equation at ...>
1117
+ sage: lazy_import('PyNormaliz', 'NmzListConeProperties',
1118
+ ....: feature=PythonModule('PyNormaliz', spkg='pynormaliz'))
1119
+ sage: NmzListConeProperties # optional - pynormaliz
1120
+ <built-in function NmzListConeProperties>
1121
+ sage: lazy_import('foo', 'not_there',
1122
+ ....: feature=PythonModule('foo', spkg='non-existing-package'))
1123
+ sage: not_there
1124
+ Failed lazy import:
1125
+ foo is not available.
1126
+ Importing not_there failed: No module named 'foo'...
1127
+ No equivalent system packages for ... are known to Sage...
1128
+ """
1129
+ if as_ is None:
1130
+ as_ = names
1131
+ if isinstance(names, str):
1132
+ names = [names]
1133
+ as_ = [as_]
1134
+ else:
1135
+ names = list(names)
1136
+ as_ = list(as_)
1137
+ if namespace is None:
1138
+ namespace = inspect.currentframe().f_locals
1139
+ if "*" in names:
1140
+ from sage.misc.superseded import deprecation_cython
1141
+
1142
+ deprecation_cython(37433,
1143
+ 'lazy_import of * is deprecated; provide the names to be imported explicitly')
1144
+
1145
+ ix = names.index("*")
1146
+ all = get_star_imports(module)
1147
+ names[ix:ix+1] = all
1148
+ as_[ix:ix+1] = all
1149
+ for name, alias in zip(names, as_):
1150
+ namespace[alias] = LazyImport(module, name, alias, at_startup, namespace, deprecation, feature)
1151
+
1152
+
1153
+ star_imports = None
1154
+
1155
+
1156
+ def save_cache_file():
1157
+ """
1158
+ Used to save the cached * import names.
1159
+
1160
+ TESTS::
1161
+
1162
+ sage: import sage.misc.lazy_import
1163
+ sage: sage.misc.lazy_import.save_cache_file()
1164
+ """
1165
+ from sage.misc.temporary_file import atomic_write
1166
+ from sage.misc.lazy_import_cache import get_cache_file
1167
+
1168
+ global star_imports
1169
+ if star_imports is None:
1170
+ star_imports = {}
1171
+ cache_file = get_cache_file()
1172
+ cache_dir = os.path.dirname(cache_file)
1173
+
1174
+ os.makedirs(cache_dir, exist_ok=True)
1175
+ with atomic_write(cache_file, binary=True) as f:
1176
+ pickle.dump(star_imports, f)
1177
+
1178
+
1179
+ def get_star_imports(module_name):
1180
+ """
1181
+ Lookup the list of names in a module that would be imported with "import \\*"
1182
+ either via a cache or actually importing.
1183
+
1184
+ EXAMPLES::
1185
+
1186
+ sage: from sage.misc.lazy_import import get_star_imports
1187
+ sage: 'get_star_imports' in get_star_imports('sage.misc.lazy_import')
1188
+ True
1189
+ sage: 'EllipticCurve' in get_star_imports('sage.schemes.all') # needs sage.schemes
1190
+ True
1191
+
1192
+ TESTS::
1193
+
1194
+ sage: import os, tempfile
1195
+ sage: fd, cache_file = tempfile.mkstemp()
1196
+ sage: os.write(fd, b'invalid')
1197
+ 7
1198
+ sage: os.close(fd)
1199
+ sage: import sage.misc.lazy_import as lazy
1200
+ sage: import sage.misc.lazy_import_cache as cache
1201
+ sage: cache.get_cache_file = (lambda: cache_file)
1202
+ sage: lazy.star_imports = None
1203
+ sage: lazy.get_star_imports('sage.schemes.all') # needs sage.schemes
1204
+ doctest:...: UserWarning: star_imports cache is corrupted
1205
+ [...]
1206
+ sage: os.remove(cache_file)
1207
+ """
1208
+ global star_imports
1209
+ if star_imports is None:
1210
+ from sage.misc.lazy_import_cache import get_cache_file
1211
+ star_imports = {}
1212
+ try:
1213
+ with open(get_cache_file(), "rb") as cache_file:
1214
+ star_imports = pickle.load(cache_file)
1215
+ except IOError: # file does not exist
1216
+ pass
1217
+ except Exception: # unpickling failed
1218
+ import warnings
1219
+ warnings.warn('star_imports cache is corrupted')
1220
+ try:
1221
+ return star_imports[module_name]
1222
+ except KeyError:
1223
+ module = __import__(module_name, {}, {}, ["*"])
1224
+ if hasattr(module, "__all__"):
1225
+ all = module.__all__
1226
+ else:
1227
+ all = [key for key in dir(module) if key[0] != "_"]
1228
+ star_imports[module_name] = all
1229
+ return all
1230
+
1231
+
1232
+ def attributes(a):
1233
+ """
1234
+ Return the private attributes of a :class:`LazyImport` object in a dictionary.
1235
+
1236
+ This is for debugging and doctesting purposes only.
1237
+
1238
+ EXAMPLES::
1239
+
1240
+ sage: from sage.misc.lazy_import import attributes
1241
+ sage: lazy_import("sage.structure.unique_representation", "foo")
1242
+ sage: attributes(foo)['_namespace'] is globals()
1243
+ True
1244
+ sage: D = attributes(foo)
1245
+ sage: del D['_namespace']
1246
+ sage: D
1247
+ {'_as_name': 'foo',
1248
+ '_at_startup': False,
1249
+ '_deprecation': None,
1250
+ '_module': 'sage.structure.unique_representation',
1251
+ '_name': 'foo',
1252
+ '_object': None}
1253
+ """
1254
+ cdef LazyImport b
1255
+ b = a
1256
+ return {"_object": b._object,
1257
+ "_module": b._module,
1258
+ "_name": b._name,
1259
+ "_as_name": b._as_name,
1260
+ "_namespace": b._namespace,
1261
+ "_at_startup": b._at_startup,
1262
+ "_deprecation": b._deprecation}
1263
+
1264
+
1265
+ def clean_namespace(namespace=None):
1266
+ """
1267
+ Adjust :class:`LazyImport` bindings in given namespace to refer to this actual namespace.
1268
+
1269
+ When :class:`LazyImport` objects are imported into other namespaces via normal ``import``
1270
+ instructions, the data stored on a :class:`LazyImport` object that helps it to adjust the
1271
+ binding in the namespace to the actual imported object upon access is not adjusted.
1272
+ This routine fixes that.
1273
+
1274
+ INPUT:
1275
+
1276
+ - ``namespace`` -- the namespace where importing the names; by default,
1277
+ import the names to current namespace
1278
+
1279
+ EXAMPLES::
1280
+
1281
+ sage: # needs sage.symbolic
1282
+ sage: from sage.misc.lazy_import import attributes, clean_namespace
1283
+ sage: from sage.calculus.calculus import maxima as C
1284
+ sage: attributes(C)['_as_name']
1285
+ 'maxima'
1286
+ sage: attributes(C)['_namespace'] is sage.calculus.calculus.__dict__
1287
+ True
1288
+ sage: clean_namespace(globals())
1289
+ sage: attributes(C)['_as_name']
1290
+ 'C'
1291
+ sage: attributes(C)['_namespace'] is globals()
1292
+ True
1293
+ """
1294
+ cdef LazyImport w
1295
+ if namespace is None:
1296
+ namespace = inspect.currentframe().f_locals
1297
+ for k, v in namespace.items():
1298
+ if type(v) is LazyImport:
1299
+ w = v
1300
+ if w._namespace is not None and (w._namespace is not namespace or w._as_name != k):
1301
+ namespace[k] = LazyImport(w._module, w._name, as_name=k, at_startup=w._at_startup,
1302
+ namespace=namespace, deprecation=w._deprecation)
1303
+
1304
+
1305
+ # Add support for _instancedoc_
1306
+ from sage.misc.instancedoc import instancedoc
1307
+ instancedoc(LazyImport)