passagemath-repl 10.5.1__py3-none-any.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 (162) hide show
  1. passagemath_repl-10.5.1.data/scripts/sage-cachegrind +25 -0
  2. passagemath_repl-10.5.1.data/scripts/sage-callgrind +16 -0
  3. passagemath_repl-10.5.1.data/scripts/sage-cleaner +230 -0
  4. passagemath_repl-10.5.1.data/scripts/sage-coverage +327 -0
  5. passagemath_repl-10.5.1.data/scripts/sage-eval +14 -0
  6. passagemath_repl-10.5.1.data/scripts/sage-fixdoctests +710 -0
  7. passagemath_repl-10.5.1.data/scripts/sage-inline-fortran +12 -0
  8. passagemath_repl-10.5.1.data/scripts/sage-ipynb2rst +50 -0
  9. passagemath_repl-10.5.1.data/scripts/sage-ipython +16 -0
  10. passagemath_repl-10.5.1.data/scripts/sage-massif +25 -0
  11. passagemath_repl-10.5.1.data/scripts/sage-notebook +267 -0
  12. passagemath_repl-10.5.1.data/scripts/sage-omega +25 -0
  13. passagemath_repl-10.5.1.data/scripts/sage-preparse +302 -0
  14. passagemath_repl-10.5.1.data/scripts/sage-run +27 -0
  15. passagemath_repl-10.5.1.data/scripts/sage-run-cython +10 -0
  16. passagemath_repl-10.5.1.data/scripts/sage-runtests +9 -0
  17. passagemath_repl-10.5.1.data/scripts/sage-startuptime.py +163 -0
  18. passagemath_repl-10.5.1.data/scripts/sage-valgrind +34 -0
  19. passagemath_repl-10.5.1.dist-info/METADATA +77 -0
  20. passagemath_repl-10.5.1.dist-info/RECORD +162 -0
  21. passagemath_repl-10.5.1.dist-info/WHEEL +5 -0
  22. passagemath_repl-10.5.1.dist-info/top_level.txt +1 -0
  23. sage/all__sagemath_repl.py +119 -0
  24. sage/doctest/__init__.py +4 -0
  25. sage/doctest/__main__.py +236 -0
  26. sage/doctest/all.py +4 -0
  27. sage/doctest/check_tolerance.py +261 -0
  28. sage/doctest/control.py +1727 -0
  29. sage/doctest/external.py +534 -0
  30. sage/doctest/fixtures.py +383 -0
  31. sage/doctest/forker.py +2665 -0
  32. sage/doctest/marked_output.py +102 -0
  33. sage/doctest/parsing.py +1708 -0
  34. sage/doctest/parsing_test.py +79 -0
  35. sage/doctest/reporting.py +733 -0
  36. sage/doctest/rif_tol.py +124 -0
  37. sage/doctest/sources.py +1657 -0
  38. sage/doctest/test.py +584 -0
  39. sage/doctest/tests/1second.rst +4 -0
  40. sage/doctest/tests/99seconds.rst +4 -0
  41. sage/doctest/tests/abort.rst +5 -0
  42. sage/doctest/tests/atexit.rst +7 -0
  43. sage/doctest/tests/fail_and_die.rst +6 -0
  44. sage/doctest/tests/initial.rst +15 -0
  45. sage/doctest/tests/interrupt.rst +7 -0
  46. sage/doctest/tests/interrupt_diehard.rst +14 -0
  47. sage/doctest/tests/keyboardinterrupt.rst +11 -0
  48. sage/doctest/tests/longtime.rst +5 -0
  49. sage/doctest/tests/nodoctest +5 -0
  50. sage/doctest/tests/random_seed.rst +4 -0
  51. sage/doctest/tests/show_skipped.rst +18 -0
  52. sage/doctest/tests/sig_on.rst +9 -0
  53. sage/doctest/tests/simple_failure.rst +8 -0
  54. sage/doctest/tests/sleep_and_raise.rst +106 -0
  55. sage/doctest/tests/tolerance.rst +31 -0
  56. sage/doctest/util.py +750 -0
  57. sage/interfaces/cleaner.py +48 -0
  58. sage/interfaces/quit.py +163 -0
  59. sage/misc/all__sagemath_repl.py +51 -0
  60. sage/misc/banner.py +235 -0
  61. sage/misc/benchmark.py +221 -0
  62. sage/misc/classgraph.py +134 -0
  63. sage/misc/copying.py +22 -0
  64. sage/misc/cython.py +694 -0
  65. sage/misc/dev_tools.py +745 -0
  66. sage/misc/edit_module.py +304 -0
  67. sage/misc/explain_pickle.py +3079 -0
  68. sage/misc/gperftools.py +361 -0
  69. sage/misc/inline_fortran.py +212 -0
  70. sage/misc/messaging.py +86 -0
  71. sage/misc/pager.py +21 -0
  72. sage/misc/profiler.py +179 -0
  73. sage/misc/python.py +70 -0
  74. sage/misc/remote_file.py +53 -0
  75. sage/misc/sage_eval.py +249 -0
  76. sage/misc/sage_input.py +3621 -0
  77. sage/misc/sagedoc.py +1742 -0
  78. sage/misc/sh.py +38 -0
  79. sage/misc/trace.py +90 -0
  80. sage/repl/__init__.py +16 -0
  81. sage/repl/all.py +15 -0
  82. sage/repl/attach.py +625 -0
  83. sage/repl/configuration.py +186 -0
  84. sage/repl/display/__init__.py +1 -0
  85. sage/repl/display/fancy_repr.py +354 -0
  86. sage/repl/display/formatter.py +318 -0
  87. sage/repl/display/jsmol_iframe.py +290 -0
  88. sage/repl/display/pretty_print.py +153 -0
  89. sage/repl/display/util.py +163 -0
  90. sage/repl/image.py +302 -0
  91. sage/repl/inputhook.py +91 -0
  92. sage/repl/interface_magic.py +298 -0
  93. sage/repl/interpreter.py +854 -0
  94. sage/repl/ipython_extension.py +593 -0
  95. sage/repl/ipython_kernel/__init__.py +1 -0
  96. sage/repl/ipython_kernel/__main__.py +4 -0
  97. sage/repl/ipython_kernel/all_jupyter.py +10 -0
  98. sage/repl/ipython_kernel/install.py +301 -0
  99. sage/repl/ipython_kernel/interact.py +278 -0
  100. sage/repl/ipython_kernel/kernel.py +217 -0
  101. sage/repl/ipython_kernel/widgets.py +466 -0
  102. sage/repl/ipython_kernel/widgets_sagenb.py +587 -0
  103. sage/repl/ipython_tests.py +163 -0
  104. sage/repl/load.py +326 -0
  105. sage/repl/preparse.py +2218 -0
  106. sage/repl/prompts.py +90 -0
  107. sage/repl/rich_output/__init__.py +4 -0
  108. sage/repl/rich_output/backend_base.py +648 -0
  109. sage/repl/rich_output/backend_doctest.py +316 -0
  110. sage/repl/rich_output/backend_emacs.py +151 -0
  111. sage/repl/rich_output/backend_ipython.py +596 -0
  112. sage/repl/rich_output/buffer.py +311 -0
  113. sage/repl/rich_output/display_manager.py +829 -0
  114. sage/repl/rich_output/example.avi +0 -0
  115. sage/repl/rich_output/example.canvas3d +1 -0
  116. sage/repl/rich_output/example.dvi +0 -0
  117. sage/repl/rich_output/example.flv +0 -0
  118. sage/repl/rich_output/example.gif +0 -0
  119. sage/repl/rich_output/example.jpg +0 -0
  120. sage/repl/rich_output/example.mkv +0 -0
  121. sage/repl/rich_output/example.mov +0 -0
  122. sage/repl/rich_output/example.mp4 +0 -0
  123. sage/repl/rich_output/example.ogv +0 -0
  124. sage/repl/rich_output/example.pdf +0 -0
  125. sage/repl/rich_output/example.png +0 -0
  126. sage/repl/rich_output/example.svg +54 -0
  127. sage/repl/rich_output/example.webm +0 -0
  128. sage/repl/rich_output/example.wmv +0 -0
  129. sage/repl/rich_output/example_jmol.spt.zip +0 -0
  130. sage/repl/rich_output/example_wavefront_scene.mtl +7 -0
  131. sage/repl/rich_output/example_wavefront_scene.obj +17 -0
  132. sage/repl/rich_output/output_basic.py +391 -0
  133. sage/repl/rich_output/output_browser.py +103 -0
  134. sage/repl/rich_output/output_catalog.py +54 -0
  135. sage/repl/rich_output/output_graphics.py +320 -0
  136. sage/repl/rich_output/output_graphics3d.py +345 -0
  137. sage/repl/rich_output/output_video.py +231 -0
  138. sage/repl/rich_output/preferences.py +432 -0
  139. sage/repl/rich_output/pretty_print.py +339 -0
  140. sage/repl/rich_output/test_backend.py +201 -0
  141. sage/repl/user_globals.py +214 -0
  142. sage/tests/all.py +0 -0
  143. sage/tests/all__sagemath_repl.py +3 -0
  144. sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +630 -0
  145. sage/tests/arxiv_0812_2725.py +351 -0
  146. sage/tests/benchmark.py +1925 -0
  147. sage/tests/book_schilling_zabrocki_kschur_primer.py +795 -0
  148. sage/tests/book_stein_ent.py +651 -0
  149. sage/tests/book_stein_modform.py +558 -0
  150. sage/tests/cmdline.py +796 -0
  151. sage/tests/combinatorial_hopf_algebras.py +52 -0
  152. sage/tests/finite_poset.py +623 -0
  153. sage/tests/functools_partial_src.py +27 -0
  154. sage/tests/gosper-sum.py +218 -0
  155. sage/tests/lazy_imports.py +28 -0
  156. sage/tests/modular_group_cohomology.py +80 -0
  157. sage/tests/numpy.py +21 -0
  158. sage/tests/parigp.py +76 -0
  159. sage/tests/startup.py +27 -0
  160. sage/tests/symbolic-series.py +76 -0
  161. sage/tests/sympy.py +16 -0
  162. sage/tests/test_deprecation.py +31 -0
sage/misc/dev_tools.py ADDED
@@ -0,0 +1,745 @@
1
+ # sage_setup: distribution = sagemath-repl
2
+ r"""
3
+ Some tools for developers
4
+
5
+ AUTHORS:
6
+
7
+ - Nicolas M. Thiery: initial version
8
+
9
+ - Vincent Delecroix (2012 and 2013): improve import_statements
10
+ """
11
+ # ****************************************************************************
12
+ # Copyright (C) 2011 Nicolas M. Thiery <nthiery at users.sf.net>
13
+ #
14
+ # Distributed under the terms of the GNU General Public License (GPL)
15
+ # https://www.gnu.org/licenses/
16
+ # *****************************************************************************
17
+
18
+ import os
19
+ import re
20
+ import sys
21
+
22
+ from collections import defaultdict
23
+
24
+
25
+ def runsnake(command):
26
+ """
27
+ Graphical profiling with ``runsnake``.
28
+
29
+ INPUT:
30
+
31
+ - ``command`` -- the command to be run as a string
32
+
33
+ EXAMPLES::
34
+
35
+ sage: from sage.misc.dev_tools import runsnake
36
+ sage: runsnake("list(SymmetricGroup(3))") # optional - runsnake
37
+
38
+ ``command`` is first preparsed (see :func:`preparse`)::
39
+
40
+ sage: runsnake('for x in range(1,4): print(x^2)') # optional - runsnake
41
+ 1
42
+ 4
43
+ 9
44
+
45
+ :func:`runsnake` requires the program ``runsnake``. Due to non
46
+ trivial dependencies (python-wxgtk, ...), installing it within the
47
+ Sage distribution is unpractical. Hence, we recommend installing
48
+ it with the system wide Python. On Ubuntu 10.10, this can be done
49
+ with::
50
+
51
+ > sudo apt-get install python-profiler python-wxgtk2.8 python-setuptools
52
+ > sudo easy_install RunSnakeRun
53
+
54
+ See the ``runsnake`` website for instructions for other platforms.
55
+
56
+ :func:`runsnake` further assumes that the system wide Python is
57
+ installed in ``/usr/bin/python``.
58
+
59
+ .. SEEALSO::
60
+
61
+ - `The runsnake website <http://www.vrplumber.com/programming/runsnakerun/>`_
62
+ - ``%prun``
63
+ - :class:`Profiler`
64
+ """
65
+ import cProfile
66
+ from sage.misc.temporary_file import tmp_filename
67
+ from sage.misc.misc import get_main_globals
68
+ from sage.repl.preparse import preparse
69
+ tmpfile = tmp_filename()
70
+ cProfile.runctx(preparse(command.lstrip().rstrip()), get_main_globals(),
71
+ locals(), filename=tmpfile)
72
+ os.system("/usr/bin/python -E `which runsnake` %s &" % tmpfile)
73
+
74
+
75
+ def import_statement_string(module, names, lazy):
76
+ r"""
77
+ Return a (lazy) import statement for ``names`` from ``module``.
78
+
79
+ INPUT:
80
+
81
+ - ``module`` -- the name of a module
82
+
83
+ - ``names`` -- list of 2-tuples containing names and alias to
84
+ import
85
+
86
+ - ``lazy`` -- boolean; whether to return a lazy import statement
87
+
88
+ EXAMPLES::
89
+
90
+ sage: import sage.misc.dev_tools as dt
91
+ sage: modname = 'sage.misc.dev_tools'
92
+ sage: names_and_aliases = [('import_statement_string', 'iss')]
93
+ sage: dt.import_statement_string(modname, names_and_aliases, False)
94
+ 'from sage.misc.dev_tools import import_statement_string as iss'
95
+ sage: dt.import_statement_string(modname, names_and_aliases, True)
96
+ "lazy_import('sage.misc.dev_tools', 'import_statement_string', 'iss')"
97
+ sage: dt.import_statement_string(modname, [('a','b'),('c','c'),('d','e')], False)
98
+ 'from sage.misc.dev_tools import a as b, c, d as e'
99
+ sage: dt.import_statement_string(modname, [(None,None)], False)
100
+ 'import sage.misc.dev_tools'
101
+ """
102
+ if lazy:
103
+ if len(names) == 1:
104
+ name, alias = names[0]
105
+ if name == alias:
106
+ if name is None:
107
+ raise ValueError("cannot lazy import modules")
108
+ return "lazy_import('%s', '%s')" % (module, name)
109
+ else:
110
+ return "lazy_import('%s', '%s', '%s')" % (module, name, alias)
111
+ obj_names = "[" + ", ".join("'" + name[0] + "'" for name in names) + "]"
112
+ obj_aliases = "[" + ", ".join("'" + name[1] + "'" for name in names) + "]"
113
+ return "lazy_import('%s', %s, %s)" % (module, obj_names, obj_aliases)
114
+ else:
115
+ import_module = False
116
+ name_list = []
117
+ for name, alias in names:
118
+ if name == alias:
119
+ if name is None:
120
+ import_module = True
121
+ continue
122
+ name_list.append(name)
123
+ else:
124
+ name_list.append("%s as %s" % (name, alias))
125
+ res = []
126
+ if import_module:
127
+ res.append("import %s" % module)
128
+ if name_list:
129
+ res.append("from %s import %s" % (module, ', '.join(name_list)))
130
+ return "\n".join(res)
131
+
132
+
133
+ def load_submodules(module=None, exclude_pattern=None):
134
+ r"""
135
+ Load all submodules of a given modules.
136
+
137
+ This method is intended to be used by developers and especially the one
138
+ who uses :func:`import_statements`. By default it load the sage library and
139
+ it takes around a minute.
140
+
141
+ INPUT:
142
+
143
+ - ``module`` -- an optional module
144
+
145
+ - ``exclude_pattern`` -- an optional regular expression pattern of module
146
+ names that have to be excluded
147
+
148
+ EXAMPLES::
149
+
150
+ sage: sage.misc.dev_tools.load_submodules(sage.combinat)
151
+ load sage.combinat.SJT... succeeded
152
+ load sage.combinat.affine_permutation... succeeded
153
+ load sage.combinat.algebraic_combinatorics... succeeded
154
+ ...
155
+ load sage.combinat.words.suffix_trees... succeeded
156
+
157
+ Calling a second time has no effect (since the function does not import
158
+ modules already imported)::
159
+
160
+ sage: sage.misc.dev_tools.load_submodules(sage.combinat)
161
+
162
+ The second argument allows to exclude a pattern::
163
+
164
+ sage: sage.misc.dev_tools.load_submodules(sage.geometry, "database$|lattice")
165
+ load sage.geometry.cone... succeeded
166
+ load sage.geometry.cone_catalog... succeeded
167
+ load sage.geometry.fan_isomorphism... succeeded
168
+ ...
169
+ load sage.geometry.riemannian_manifolds.surface3d_generators... succeeded
170
+
171
+ sage: sage.misc.dev_tools.load_submodules(sage.geometry)
172
+ load sage.geometry.lattice_polytope... succeeded
173
+ load sage.geometry.polyhedron.lattice_euclidean_group_element... succeeded
174
+ load sage.geometry.polyhedron.palp_database... succeeded
175
+ load sage.geometry.polyhedron.ppl_lattice_polygon... succeeded
176
+ """
177
+ from .package_dir import walk_packages
178
+ import importlib.util
179
+
180
+ if module is None:
181
+ import sage
182
+ module = sage
183
+ exclude_pattern = r"^sage\.libs|^sage\.tests|tests$|^sage\.all_|all$|sage\.interacts$|^sage\.misc\.benchmark$"
184
+
185
+ if exclude_pattern:
186
+ exclude = re.compile(exclude_pattern)
187
+ else:
188
+ exclude = None
189
+
190
+ for importer, module_name, ispkg in walk_packages(module.__path__, module.__name__ + '.'):
191
+ if ispkg or module_name in sys.modules:
192
+ continue
193
+
194
+ # we exclude several sage components because loading them is much of a
195
+ # problem...
196
+ if exclude and exclude.search(module_name):
197
+ continue
198
+
199
+ try:
200
+ sys.stdout.write("load %s..." % module_name)
201
+ sys.stdout.flush()
202
+ # see
203
+ # https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
204
+ spec = importer.find_spec(module_name)
205
+ module = importlib.util.module_from_spec(spec)
206
+ sys.modules[module_name] = module
207
+ spec.loader.exec_module(module)
208
+ sys.stdout.write(" succeeded\n")
209
+ except (ValueError, AttributeError, TypeError, ImportError):
210
+ # we might get error because of cython code that has been
211
+ # compiled but with source removed
212
+ sys.stdout.write("failed\n")
213
+
214
+
215
+ def find_objects_from_name(name, module_name=None, include_lazy_imports=False):
216
+ r"""
217
+ Return the list of objects from ``module_name`` whose name is ``name``.
218
+
219
+ INPUT:
220
+
221
+ - ``name`` -- string
222
+
223
+ - ``module_name`` -- string or ``None``:
224
+
225
+ - If ``module_name`` is ``None``, the function runs through all
226
+ loaded modules and returns the list of objects whose name matches ``name``.
227
+
228
+ - If ``module_name`` is a string, then search only in submodules of
229
+ ``module_name``.
230
+
231
+ - ``include_lazy_imports`` -- boolean (default: ``False``); whether to
232
+ include unresolved lazy imports (i.e., :class:`~sage.misc.lazy_import.LazyImport`
233
+ objects) in the output.
234
+
235
+ In order to search through more modules you might use the function
236
+ :func:`load_submodules`.
237
+
238
+ EXAMPLES::
239
+
240
+ sage: import sage.misc.dev_tools as dt
241
+ sage: dt.find_objects_from_name('FareySymbol') # needs sage.modular
242
+ [<class 'sage.modular.arithgroup.farey_symbol.Farey'>]
243
+
244
+ sage: # needs sympy
245
+ sage: import sympy
246
+ sage: dt.find_objects_from_name('RR')
247
+ [Real Field with 53 bits of precision, RR]
248
+ sage: dt.find_objects_from_name('RR', 'sage')
249
+ [Real Field with 53 bits of precision]
250
+ sage: dt.find_objects_from_name('RR', 'sympy')
251
+ [RR]
252
+
253
+ Examples that do not belong to the global namespace but in a loaded module::
254
+
255
+ sage: 'find_objects_from_name' in globals()
256
+ False
257
+ sage: objs = dt.find_objects_from_name('find_objects_from_name')
258
+ sage: len(objs)
259
+ 1
260
+ sage: dt.find_objects_from_name is dt.find_objects_from_name
261
+ True
262
+
263
+ When ``include_lazy_imports=True`` is used, several
264
+ :class:`~sage.misc.lazy_import.LazyImport` objects that are resolving to the
265
+ same object may be included in the output::
266
+
267
+ sage: dt.find_objects_from_name('RR', include_lazy_imports=True) # needs sage.rings.real_mpfr
268
+ [Real Field with 53 bits of precision,
269
+ ...
270
+ Real Field with 53 bits of precision,
271
+ RR]
272
+
273
+ .. NOTE::
274
+
275
+ It might be a good idea to move this function into
276
+ :mod:`sage.misc.sageinspect`.
277
+ """
278
+ from sage.misc.lazy_import import LazyImport
279
+
280
+ obj = []
281
+ for smodule_name, smodule in sys.modules.items():
282
+ if module_name and not smodule_name.startswith(module_name):
283
+ continue
284
+ if smodule_name.rpartition('.')[2].startswith('all__sagemath_'):
285
+ continue
286
+ if hasattr(smodule, '__dict__') and name in smodule.__dict__:
287
+ u = smodule.__dict__[name]
288
+ if (not isinstance(u, LazyImport) or include_lazy_imports) and all(v is not u for v in obj):
289
+ obj.append(u)
290
+
291
+ return obj
292
+
293
+
294
+ def find_object_modules(obj):
295
+ r"""
296
+ Return a dictionary whose keys are the names of the modules where ``obj``
297
+ appear and the value at a given module name is the list of names that
298
+ ``obj`` have in that module.
299
+
300
+ It is very unlikely that the output dictionary has several keys except when
301
+ ``obj`` is an instance of a class.
302
+
303
+ EXAMPLES::
304
+
305
+ sage: from sage.misc.dev_tools import find_object_modules
306
+ sage: find_object_modules(RR) # needs sage.rings.real_mpfr
307
+ {'sage.rings.real_mpfr': ['RR']}
308
+ sage: find_object_modules(ZZ)
309
+ {'sage.rings.integer_ring': ['Z', 'ZZ']}
310
+
311
+ .. NOTE::
312
+
313
+ It might be a good idea to move this function in
314
+ :mod:`sage.misc.sageinspect`.
315
+ """
316
+ from sage.misc import sageinspect
317
+
318
+ # see if the object is defined in its own module
319
+ # might be wrong for class instances as the instantiation might appear
320
+ # outside of the module !!
321
+ module_name = None
322
+ if sageinspect.isclassinstance(obj):
323
+ module_name = obj.__class__.__module__
324
+ elif hasattr(obj, '__module__') and obj.__module__:
325
+ module_name = obj.__module__
326
+
327
+ if module_name:
328
+ if module_name not in sys.modules:
329
+ raise ValueError("this should never happen")
330
+ d = sys.modules[module_name].__dict__
331
+ matching = sorted(key for key in d if d[key] is obj)
332
+ if matching:
333
+ return {module_name: matching}
334
+
335
+ # otherwise, we parse all (already loaded) modules and hope to find
336
+ # something
337
+ module_to_obj = {}
338
+ for module_name, module in sys.modules.items():
339
+ if module_name != '__main__' and hasattr(module, '__dict__'):
340
+ d = module.__dict__
341
+ names = [key for key in d if d[key] is obj]
342
+ if names:
343
+ module_to_obj[module_name] = names
344
+
345
+ # if the object is an instance, we try to guess where it is defined
346
+ if sageinspect.isclassinstance(obj):
347
+ dec_pattern = re.compile(r"^(\w[\w0-9\_]*)\s*=", re.MULTILINE)
348
+ module_to_obj2 = {}
349
+ for module_name, obj_names in module_to_obj.items():
350
+ module_to_obj2[module_name] = []
351
+ try:
352
+ src = sageinspect.sage_getsource(sys.modules[module_name])
353
+ except TypeError:
354
+ pass
355
+ else:
356
+ m = dec_pattern.search(src)
357
+ while m:
358
+ if m.group(1) in obj_names:
359
+ module_to_obj2[module_name].append(m.group(1))
360
+ m = dec_pattern.search(src, m.end())
361
+ if not module_to_obj2[module_name]:
362
+ del module_to_obj2[module_name]
363
+
364
+ if module_to_obj2:
365
+ return module_to_obj2
366
+
367
+ return module_to_obj
368
+
369
+
370
+ def import_statements(*objects, **kwds):
371
+ r"""
372
+ Print import statements for the given objects.
373
+
374
+ INPUT:
375
+
376
+ - ``*objects`` -- a sequence of objects or comma-separated strings of names
377
+
378
+ - ``lazy`` -- boolean (default: ``False``); whether to print a lazy import
379
+ statement
380
+
381
+ - ``verbose`` -- boolean (default: ``True``); whether to print information
382
+ in case of ambiguity
383
+
384
+ - ``answer_as_str`` -- boolean (default: ``False``); if ``True`` return a
385
+ string instead of printing the statement
386
+
387
+ EXAMPLES::
388
+
389
+ sage: import_statements(WeylGroup, lazy_attribute) # needs sage.libs.gap
390
+ from sage.combinat.root_system.weyl_group import WeylGroup
391
+ from sage.misc.lazy_attribute import lazy_attribute
392
+
393
+ sage: import_statements(IntegerRing)
394
+ from sage.rings.integer_ring import IntegerRing
395
+
396
+ If ``lazy`` is True, then :func:`lazy_import` statements are
397
+ displayed instead::
398
+
399
+ sage: import_statements(WeylGroup, lazy_attribute, lazy=True) # needs sage.libs.gap
400
+ from sage.misc.lazy_import import lazy_import
401
+ lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup')
402
+ lazy_import('sage.misc.lazy_attribute', 'lazy_attribute')
403
+
404
+ In principle, the function should also work on object which are instances.
405
+ In case of ambiguity, one or two warning lines are printed::
406
+
407
+ sage: import_statements(RDF)
408
+ from sage.rings.real_double import RDF
409
+
410
+ sage: import_statements(ZZ)
411
+ # ** Warning **: several names for that object: Z, ZZ
412
+ from sage.rings.integer_ring import Z
413
+
414
+ sage: import_statements(euler_phi)
415
+ from sage.arith.misc import euler_phi
416
+
417
+ sage: import_statements(x) # needs sage.symbolic
418
+ from sage.calculus.predefined import x
419
+
420
+ If you don't like the warning you can disable them with the option ``verbose``::
421
+
422
+ sage: import_statements(ZZ, verbose=False)
423
+ from sage.rings.integer_ring import Z
424
+
425
+ sage: import_statements(x, verbose=False) # needs sage.symbolic
426
+ from sage.calculus.predefined import x
427
+
428
+ If the object has several names, an other way to get the import
429
+ statement you expect is to use a string instead of the object::
430
+
431
+ sage: import_statements(matrix) # needs sage.modules
432
+ # ** Warning **: several names for that object: Matrix, matrix
433
+ from sage.matrix.constructor import Matrix
434
+
435
+ sage: import_statements('cached_function')
436
+ from sage.misc.cachefunc import cached_function
437
+ sage: import_statements('Z')
438
+ # **Warning**: distinct objects with name 'Z' in:
439
+ # - sage.calculus.predefined
440
+ # - sage.rings.integer_ring
441
+ from sage.rings.integer_ring import Z
442
+
443
+ The strings are allowed to be comma-separated names, and parenthesis
444
+ are stripped for convenience::
445
+
446
+ sage: import_statements('(floor, ceil)') # needs sage.symbolic
447
+ from sage.functions.other import floor, ceil
448
+
449
+ Specifying a string is also useful for objects that are not
450
+ imported in the Sage interpreter namespace by default. In this
451
+ case, an object with that name is looked up in all the modules
452
+ that have been imported in this session::
453
+
454
+ sage: import_statement_string
455
+ Traceback (most recent call last):
456
+ ...
457
+ NameError: name 'import_statement_string' is not defined
458
+
459
+ sage: import_statements("import_statement_string")
460
+ from sage.misc.dev_tools import import_statement_string
461
+
462
+ Sometimes objects are imported as an alias (from XXX import YYY as ZZZ) or
463
+ are affected (XXX = YYY) and the function might detect it::
464
+
465
+ sage: import_statements('FareySymbol')
466
+ from sage.modular.arithgroup.farey_symbol import Farey as FareySymbol
467
+
468
+ sage: import_statements('power')
469
+ from sage.arith.power import generic_power as power
470
+
471
+ In order to be able to detect functions that belong to a non-loaded module,
472
+ you might call the helper :func:`load_submodules` as in the following::
473
+
474
+ sage: import_statements('HeckeMonoid')
475
+ Traceback (most recent call last):
476
+ ...
477
+ LookupError: no object named 'HeckeMonoid'
478
+ sage: from sage.misc.dev_tools import load_submodules
479
+ sage: load_submodules(sage.monoids)
480
+ load sage.monoids.automatic_semigroup... succeeded
481
+ load sage.monoids.hecke_monoid... succeeded
482
+ load sage.monoids.indexed_free_monoid... succeeded
483
+ sage: import_statements('HeckeMonoid')
484
+ from sage.monoids.hecke_monoid import HeckeMonoid
485
+
486
+ We test different objects which have no appropriate answer::
487
+
488
+ sage: import_statements('my_tailor_is_rich')
489
+ Traceback (most recent call last):
490
+ ...
491
+ LookupError: no object named 'my_tailor_is_rich'
492
+ sage: import_statements(5)
493
+ Traceback (most recent call last):
494
+ ...
495
+ ValueError: no import statement found for '5'.
496
+
497
+ We test that it behaves well with lazy imported objects (:issue:`14767`)::
498
+
499
+ sage: import_statements(NN)
500
+ from sage.rings.semirings.non_negative_integer_semiring import NN
501
+ sage: import_statements('NN')
502
+ from sage.rings.semirings.non_negative_integer_semiring import NN
503
+
504
+ Deprecated lazy imports are ignored (see :issue:`17458`)::
505
+
506
+ sage: lazy_import('sage.all', 'RR', 'deprecated_RR', namespace=sage.__dict__, deprecation=17458)
507
+ sage: import_statements('deprecated_RR')
508
+ Traceback (most recent call last):
509
+ ...
510
+ LookupError: object named 'deprecated_RR' is deprecated (see Issue #17458)
511
+ sage: lazy_import('sage.all', 'RR', namespace=sage.__dict__, deprecation=17458)
512
+ sage: import_statements('RR')
513
+ from sage.rings.real_mpfr import RR
514
+
515
+ The following were fixed with :issue:`15351`::
516
+
517
+ sage: import_statements('Rationals')
518
+ from sage.rings.rational_field import RationalField as Rationals
519
+ sage: from sage.combinat.partition_algebra import SetPartitionsAk
520
+ sage: import_statements(SetPartitionsAk)
521
+ from sage.combinat.partition_algebra import SetPartitionsAk
522
+ sage: import_statements(CIF)
523
+ from sage.rings.cif import CIF
524
+ sage: import_statements(NaN) # needs sage.symbolic
525
+ from sage.symbolic.constants import NaN
526
+ sage: import_statements(pi) # needs sage.symbolic
527
+ from sage.symbolic.constants import pi
528
+ sage: import_statements('SAGE_ENV')
529
+ from sage.env import SAGE_ENV
530
+ sage: import_statements('graph_decompositions')
531
+ import sage.graphs.graph_decompositions
532
+
533
+ Check that a name from the global namespace is properly found (see
534
+ :issue:`23779`)::
535
+
536
+ sage: import_statements('log')
537
+ from sage.misc.functional import log
538
+
539
+ .. NOTE::
540
+
541
+ The programmers try to made this function as smart as possible.
542
+ Nevertheless it is far from being perfect (for example it does not
543
+ detect deprecated stuff). So, if you use it, double check the answer and
544
+ report weird behaviors.
545
+ """
546
+ import itertools
547
+ import inspect
548
+ from sage.misc.lazy_import import LazyImport
549
+
550
+ answer = defaultdict(list)
551
+ module_name = None
552
+ # a dictionary module -> [(name1,alias1), (name2,alias2) ...]
553
+ # where "nameX" is an object in "module" that has to be
554
+ # imported with the alias "aliasX"
555
+
556
+ lazy = kwds.pop("lazy", False)
557
+ verbose = kwds.pop("verbose", True)
558
+ answer_as_str = kwds.pop("answer_as_str", False)
559
+
560
+ if kwds:
561
+ raise TypeError("Unexpected '{}' argument".format(next(iter(kwds))))
562
+
563
+ def expand_comma_separated_names(obj):
564
+ if isinstance(obj, str):
565
+ for w in obj.strip('()').split(','):
566
+ yield w.strip()
567
+ else:
568
+ yield obj
569
+
570
+ for obj in itertools.chain.from_iterable(expand_comma_separated_names(object)
571
+ for object in objects):
572
+ name = None # the name of the object
573
+
574
+ # 1. if obj is a string, we look for an object that has that name
575
+ if isinstance(obj, str):
576
+ from sage.all import sage_globals
577
+ G = sage_globals()
578
+ name = obj
579
+ if name in G:
580
+ # 1.a. object in the sage namespace
581
+ obj = [G[name]]
582
+ else:
583
+ # 1.b. object inside a submodule of sage
584
+ obj = find_objects_from_name(name, 'sage', include_lazy_imports=True)
585
+ if not obj:
586
+ # 1.c. object from something already imported
587
+ obj = find_objects_from_name(name, include_lazy_imports=True)
588
+
589
+ # remove lazy imported objects from list obj
590
+ i = 0
591
+ deprecation = None
592
+ while i < len(obj):
593
+ if isinstance(obj[i], LazyImport):
594
+ tmp = obj.pop(i)
595
+ # Ignore deprecated lazy imports
596
+ tmp_deprecation = tmp._get_deprecation_issue()
597
+ if tmp_deprecation:
598
+ deprecation = tmp_deprecation
599
+ else:
600
+ tmp = tmp._get_object()
601
+ if all(u is not tmp for u in obj):
602
+ obj.append(tmp)
603
+ else:
604
+ i += 1
605
+
606
+ if verbose and len(obj) > 1:
607
+ modules = set()
608
+ for o in obj:
609
+ modules.update(find_object_modules(o))
610
+ print("# **Warning**: distinct objects with name '{}' "
611
+ "in:".format(name))
612
+ for mod in sorted(modules):
613
+ print("# - {}".format(mod))
614
+
615
+ # choose a random object among the potentially enormous list of
616
+ # objects we get from "name"
617
+ try:
618
+ obj = obj[0]
619
+ except IndexError:
620
+ if deprecation:
621
+ raise LookupError(
622
+ "object named {!r} is deprecated (see Issue #"
623
+ "{})".format(name, deprecation))
624
+ else:
625
+ raise LookupError("no object named {!r}".format(name))
626
+
627
+ # 1'. if obj is a LazyImport we recover the real object
628
+ if isinstance(obj, LazyImport):
629
+ obj = obj._get_object()
630
+
631
+ # 2. Find out in which modules obj lives
632
+ # and update answer with a couple of strings "(name,alias)" where "name" is
633
+ # the name of the object in the module and "alias" is the name of the
634
+ # object
635
+
636
+ # easy case: the object is itself a module
637
+ if inspect.ismodule(obj):
638
+ module_name = obj.__name__
639
+ answer[module_name].append((None, None))
640
+ continue
641
+
642
+ modules = find_object_modules(obj)
643
+ if '__main__' in modules:
644
+ del modules['__main__']
645
+ if '__mp_main__' in modules:
646
+ del modules['__mp_main__']
647
+
648
+ if not modules:
649
+ raise ValueError("no import statement found for '{}'.".format(obj))
650
+
651
+ if name is None:
652
+ # if the object is available under both ascii and unicode names,
653
+ # prefer the ascii version.
654
+ def is_ascii(s):
655
+ """
656
+ Equivalent of `str.isascii` in Python >= 3.7
657
+ """
658
+ return all(ord(c) < 128 for c in s)
659
+ if any(is_ascii(s)
660
+ for (module_name, obj_names) in modules.items()
661
+ for s in obj_names):
662
+ for module_name, obj_names in list(modules.items()):
663
+ if any(not is_ascii(s) for s in obj_names):
664
+ obj_names = [name for name in obj_names if is_ascii(name)]
665
+ if not obj_names:
666
+ del modules[module_name]
667
+ else:
668
+ modules[module_name] = obj_names
669
+
670
+ if len(modules) == 1: # the module is well defined
671
+ (module_name, obj_names), = modules.items()
672
+ if name is None:
673
+ if verbose and len(obj_names) > 1:
674
+ print("# ** Warning **: several names for that object: "
675
+ "{}".format(', '.join(sorted(obj_names))))
676
+ name = alias = obj_names[0]
677
+ elif name in modules[module_name]:
678
+ alias = name
679
+ else:
680
+ alias = name
681
+ name = obj_names[0]
682
+
683
+ answer[module_name].append((name, alias))
684
+ continue
685
+
686
+ # here modules contain several answers and we first try to see if there
687
+ # is a best one (i.e. the object "obj" is contained in the module and
688
+ # has name "name")
689
+ if name is not None:
690
+ good_modules = [mod for mod in modules if name in modules[mod]]
691
+
692
+ if len(good_modules) == 1:
693
+ answer[good_modules[0]].append((name, name))
694
+ continue
695
+
696
+ # if the object is a class instance, it is likely that it is defined in
697
+ # some XYZ.all module
698
+ from .sageinspect import isclassinstance
699
+ if isclassinstance(obj):
700
+ module_name = type(obj).__module__
701
+ i = module_name.rfind('.')
702
+ all_module_name = module_name[:i] + '.all'
703
+ if all_module_name in modules:
704
+ module_name = all_module_name
705
+ modules[module_name][0]
706
+ else:
707
+ module_name = None
708
+
709
+ if module_name is None:
710
+ # here, either "obj" is a class instance but there is no natural
711
+ # candidate for its module or "obj" is not a class instance.
712
+ all_re = re.compile(r'.+\.all(?:_\w+)?$')
713
+ not_all_modules = [mod for mod in modules
714
+ if not all_re.match(mod)]
715
+ if not not_all_modules:
716
+ print("# ** Warning **: the object {} is only defined in "
717
+ ".all modules".format(obj))
718
+ module_name = next(iter(modules))
719
+ else:
720
+ if len(not_all_modules) > 1:
721
+ print("# ** Warning **: several modules for the object "
722
+ "{}: {}".format(obj, ', '.join(sorted(modules))))
723
+ module_name = not_all_modules[0]
724
+
725
+ # 3. Now that we found the module, we fix the problem of the alias
726
+ if name is None:
727
+ alias = name = modules[module_name][0]
728
+ else:
729
+ alias = name
730
+ name = modules[module_name][0]
731
+
732
+ answer[module_name].append((name, alias))
733
+
734
+ res = []
735
+
736
+ if lazy:
737
+ res.append("from sage.misc.lazy_import import lazy_import")
738
+
739
+ res.extend(import_statement_string(module_name, answer[module_name], lazy)
740
+ for module_name in sorted(answer))
741
+
742
+ if answer_as_str:
743
+ return '\n'.join(res)
744
+ else:
745
+ print('\n'.join(res))