passagemath-repl 10.4.62__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.
- passagemath_repl-10.4.62.data/scripts/sage-cachegrind +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-callgrind +16 -0
- passagemath_repl-10.4.62.data/scripts/sage-cleaner +230 -0
- passagemath_repl-10.4.62.data/scripts/sage-coverage +327 -0
- passagemath_repl-10.4.62.data/scripts/sage-eval +14 -0
- passagemath_repl-10.4.62.data/scripts/sage-fixdoctests +708 -0
- passagemath_repl-10.4.62.data/scripts/sage-inline-fortran +12 -0
- passagemath_repl-10.4.62.data/scripts/sage-ipynb2rst +50 -0
- passagemath_repl-10.4.62.data/scripts/sage-ipython +16 -0
- passagemath_repl-10.4.62.data/scripts/sage-massif +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-notebook +267 -0
- passagemath_repl-10.4.62.data/scripts/sage-omega +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-preparse +302 -0
- passagemath_repl-10.4.62.data/scripts/sage-run +27 -0
- passagemath_repl-10.4.62.data/scripts/sage-run-cython +10 -0
- passagemath_repl-10.4.62.data/scripts/sage-runtests +9 -0
- passagemath_repl-10.4.62.data/scripts/sage-startuptime.py +163 -0
- passagemath_repl-10.4.62.data/scripts/sage-valgrind +34 -0
- passagemath_repl-10.4.62.dist-info/METADATA +77 -0
- passagemath_repl-10.4.62.dist-info/RECORD +162 -0
- passagemath_repl-10.4.62.dist-info/WHEEL +5 -0
- passagemath_repl-10.4.62.dist-info/top_level.txt +1 -0
- sage/all__sagemath_repl.py +119 -0
- sage/doctest/__init__.py +4 -0
- sage/doctest/__main__.py +236 -0
- sage/doctest/all.py +4 -0
- sage/doctest/check_tolerance.py +261 -0
- sage/doctest/control.py +1727 -0
- sage/doctest/external.py +534 -0
- sage/doctest/fixtures.py +383 -0
- sage/doctest/forker.py +2665 -0
- sage/doctest/marked_output.py +102 -0
- sage/doctest/parsing.py +1708 -0
- sage/doctest/parsing_test.py +79 -0
- sage/doctest/reporting.py +733 -0
- sage/doctest/rif_tol.py +124 -0
- sage/doctest/sources.py +1657 -0
- sage/doctest/test.py +584 -0
- sage/doctest/tests/1second.rst +4 -0
- sage/doctest/tests/99seconds.rst +4 -0
- sage/doctest/tests/abort.rst +5 -0
- sage/doctest/tests/atexit.rst +7 -0
- sage/doctest/tests/fail_and_die.rst +6 -0
- sage/doctest/tests/initial.rst +15 -0
- sage/doctest/tests/interrupt.rst +7 -0
- sage/doctest/tests/interrupt_diehard.rst +14 -0
- sage/doctest/tests/keyboardinterrupt.rst +11 -0
- sage/doctest/tests/longtime.rst +5 -0
- sage/doctest/tests/nodoctest +5 -0
- sage/doctest/tests/random_seed.rst +4 -0
- sage/doctest/tests/show_skipped.rst +18 -0
- sage/doctest/tests/sig_on.rst +9 -0
- sage/doctest/tests/simple_failure.rst +8 -0
- sage/doctest/tests/sleep_and_raise.rst +106 -0
- sage/doctest/tests/tolerance.rst +31 -0
- sage/doctest/util.py +750 -0
- sage/interfaces/cleaner.py +48 -0
- sage/interfaces/quit.py +163 -0
- sage/misc/all__sagemath_repl.py +51 -0
- sage/misc/banner.py +235 -0
- sage/misc/benchmark.py +221 -0
- sage/misc/classgraph.py +131 -0
- sage/misc/copying.py +22 -0
- sage/misc/cython.py +694 -0
- sage/misc/dev_tools.py +745 -0
- sage/misc/edit_module.py +304 -0
- sage/misc/explain_pickle.py +3079 -0
- sage/misc/gperftools.py +361 -0
- sage/misc/inline_fortran.py +212 -0
- sage/misc/messaging.py +86 -0
- sage/misc/pager.py +21 -0
- sage/misc/profiler.py +179 -0
- sage/misc/python.py +70 -0
- sage/misc/remote_file.py +53 -0
- sage/misc/sage_eval.py +246 -0
- sage/misc/sage_input.py +3621 -0
- sage/misc/sagedoc.py +1742 -0
- sage/misc/sh.py +38 -0
- sage/misc/trace.py +90 -0
- sage/repl/__init__.py +16 -0
- sage/repl/all.py +15 -0
- sage/repl/attach.py +625 -0
- sage/repl/configuration.py +186 -0
- sage/repl/display/__init__.py +1 -0
- sage/repl/display/fancy_repr.py +354 -0
- sage/repl/display/formatter.py +318 -0
- sage/repl/display/jsmol_iframe.py +290 -0
- sage/repl/display/pretty_print.py +153 -0
- sage/repl/display/util.py +163 -0
- sage/repl/image.py +302 -0
- sage/repl/inputhook.py +91 -0
- sage/repl/interface_magic.py +298 -0
- sage/repl/interpreter.py +854 -0
- sage/repl/ipython_extension.py +593 -0
- sage/repl/ipython_kernel/__init__.py +1 -0
- sage/repl/ipython_kernel/__main__.py +4 -0
- sage/repl/ipython_kernel/all_jupyter.py +10 -0
- sage/repl/ipython_kernel/install.py +301 -0
- sage/repl/ipython_kernel/interact.py +278 -0
- sage/repl/ipython_kernel/kernel.py +217 -0
- sage/repl/ipython_kernel/widgets.py +466 -0
- sage/repl/ipython_kernel/widgets_sagenb.py +587 -0
- sage/repl/ipython_tests.py +163 -0
- sage/repl/load.py +326 -0
- sage/repl/preparse.py +2218 -0
- sage/repl/prompts.py +90 -0
- sage/repl/rich_output/__init__.py +4 -0
- sage/repl/rich_output/backend_base.py +648 -0
- sage/repl/rich_output/backend_doctest.py +316 -0
- sage/repl/rich_output/backend_emacs.py +151 -0
- sage/repl/rich_output/backend_ipython.py +596 -0
- sage/repl/rich_output/buffer.py +311 -0
- sage/repl/rich_output/display_manager.py +829 -0
- sage/repl/rich_output/example.avi +0 -0
- sage/repl/rich_output/example.canvas3d +1 -0
- sage/repl/rich_output/example.dvi +0 -0
- sage/repl/rich_output/example.flv +0 -0
- sage/repl/rich_output/example.gif +0 -0
- sage/repl/rich_output/example.jpg +0 -0
- sage/repl/rich_output/example.mkv +0 -0
- sage/repl/rich_output/example.mov +0 -0
- sage/repl/rich_output/example.mp4 +0 -0
- sage/repl/rich_output/example.ogv +0 -0
- sage/repl/rich_output/example.pdf +0 -0
- sage/repl/rich_output/example.png +0 -0
- sage/repl/rich_output/example.svg +54 -0
- sage/repl/rich_output/example.webm +0 -0
- sage/repl/rich_output/example.wmv +0 -0
- sage/repl/rich_output/example_jmol.spt.zip +0 -0
- sage/repl/rich_output/example_wavefront_scene.mtl +7 -0
- sage/repl/rich_output/example_wavefront_scene.obj +17 -0
- sage/repl/rich_output/output_basic.py +391 -0
- sage/repl/rich_output/output_browser.py +103 -0
- sage/repl/rich_output/output_catalog.py +54 -0
- sage/repl/rich_output/output_graphics.py +320 -0
- sage/repl/rich_output/output_graphics3d.py +345 -0
- sage/repl/rich_output/output_video.py +231 -0
- sage/repl/rich_output/preferences.py +432 -0
- sage/repl/rich_output/pretty_print.py +339 -0
- sage/repl/rich_output/test_backend.py +201 -0
- sage/repl/user_globals.py +214 -0
- sage/tests/__init__.py +1 -0
- sage/tests/all.py +3 -0
- sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +630 -0
- sage/tests/arxiv_0812_2725.py +351 -0
- sage/tests/benchmark.py +1923 -0
- sage/tests/book_schilling_zabrocki_kschur_primer.py +795 -0
- sage/tests/book_stein_ent.py +651 -0
- sage/tests/book_stein_modform.py +558 -0
- sage/tests/cmdline.py +790 -0
- sage/tests/combinatorial_hopf_algebras.py +52 -0
- sage/tests/finite_poset.py +623 -0
- sage/tests/functools_partial_src.py +27 -0
- sage/tests/gosper-sum.py +218 -0
- sage/tests/lazy_imports.py +28 -0
- sage/tests/modular_group_cohomology.py +80 -0
- sage/tests/numpy.py +21 -0
- sage/tests/parigp.py +76 -0
- sage/tests/startup.py +27 -0
- sage/tests/symbolic-series.py +76 -0
- sage/tests/sympy.py +16 -0
- 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))
|