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
@@ -0,0 +1,153 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
"""
|
3
|
+
The Sage pretty printer
|
4
|
+
|
5
|
+
Any transformation to a string goes through here. In other words, the
|
6
|
+
:class:`~sage.repl.displayhook.formatter.SagePlainTextFormatter` is
|
7
|
+
entirely implemented via :class:`SagePrettyPrinter`. Other formatters
|
8
|
+
may or may not use :class:`SagePrettyPrinter` to generate text output.
|
9
|
+
|
10
|
+
AUTHORS:
|
11
|
+
|
12
|
+
- Bill Cauchois (2009): initial version
|
13
|
+
- Jean-Baptiste Priez <jbp@kerios.fr> (2013): ASCII art
|
14
|
+
- Volker Braun (2013): refactored into DisplayHookBase
|
15
|
+
"""
|
16
|
+
|
17
|
+
# ****************************************************************************
|
18
|
+
# Copyright (C) 2014 Volker Braun <vbraun.name@gmail.com>
|
19
|
+
#
|
20
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
21
|
+
# as published by the Free Software Foundation; either version 2 of
|
22
|
+
# the License, or (at your option) any later version.
|
23
|
+
# https://www.gnu.org/licenses/
|
24
|
+
# ****************************************************************************
|
25
|
+
|
26
|
+
|
27
|
+
from IPython.lib.pretty import PrettyPrinter
|
28
|
+
|
29
|
+
from sage.repl.display.fancy_repr import (TallListRepr, PlainPythonRepr,
|
30
|
+
LargeMatrixHelpRepr,
|
31
|
+
SomeIPythonRepr)
|
32
|
+
|
33
|
+
|
34
|
+
class SagePrettyPrinter(PrettyPrinter):
|
35
|
+
|
36
|
+
DEBUG = False
|
37
|
+
|
38
|
+
# These object representers will be tried, in this order, until
|
39
|
+
# one is found that is able to deal with the object.
|
40
|
+
pretty_repr = (
|
41
|
+
TallListRepr(),
|
42
|
+
LargeMatrixHelpRepr(),
|
43
|
+
SomeIPythonRepr(),
|
44
|
+
PlainPythonRepr(),
|
45
|
+
)
|
46
|
+
|
47
|
+
def toplevel(self):
|
48
|
+
r"""
|
49
|
+
Return whether we are currently at the top level.
|
50
|
+
|
51
|
+
OUTPUT:
|
52
|
+
|
53
|
+
boolean; whether we are currently pretty-printing an object at
|
54
|
+
the outermost level (``True``), or whether the object is
|
55
|
+
inside a container (``False``).
|
56
|
+
|
57
|
+
EXAMPLES::
|
58
|
+
|
59
|
+
sage: from sage.repl.display.pretty_print import SagePrettyPrinter
|
60
|
+
sage: from io import StringIO
|
61
|
+
sage: stream = StringIO()
|
62
|
+
sage: spp = SagePrettyPrinter(stream, 78, '\n')
|
63
|
+
sage: spp.toplevel()
|
64
|
+
True
|
65
|
+
"""
|
66
|
+
return len(self.stack) <= 1 # only the object currently being represented
|
67
|
+
|
68
|
+
def __init__(self, output, max_width, newline, max_seq_length=None):
|
69
|
+
"""
|
70
|
+
Pretty print Sage objects for the commandline.
|
71
|
+
|
72
|
+
INPUT:
|
73
|
+
|
74
|
+
See IPython documentation.
|
75
|
+
|
76
|
+
EXAMPLES::
|
77
|
+
|
78
|
+
sage: 123
|
79
|
+
123
|
80
|
+
|
81
|
+
IPython pretty printers::
|
82
|
+
|
83
|
+
sage: set({1, 2, 3})
|
84
|
+
{1, 2, 3}
|
85
|
+
sage: dict(zzz=123, aaa=99, xab=10) # sorted by keys
|
86
|
+
{'aaa': 99, 'xab': 10, 'zzz': 123}
|
87
|
+
|
88
|
+
These are overridden in IPython in a way that we feel is somewhat
|
89
|
+
confusing, and we prefer to print them like plain Python which is
|
90
|
+
more informative. See :issue:`14466` ::
|
91
|
+
|
92
|
+
sage: 'this is a string'
|
93
|
+
'this is a string'
|
94
|
+
sage: type(123)
|
95
|
+
<class 'sage.rings.integer.Integer'>
|
96
|
+
sage: type
|
97
|
+
<... 'type'>
|
98
|
+
sage: import types
|
99
|
+
sage: type('name', (), {})
|
100
|
+
<class '__main__.name'>
|
101
|
+
sage: types.BuiltinFunctionType
|
102
|
+
<class 'builtin_function_or_method'>
|
103
|
+
|
104
|
+
sage: def foo(): pass
|
105
|
+
sage: foo
|
106
|
+
<function foo at 0x...>
|
107
|
+
"""
|
108
|
+
super().__init__(output, max_width, newline,
|
109
|
+
max_seq_length=max_seq_length)
|
110
|
+
self.stack = []
|
111
|
+
|
112
|
+
def pretty(self, obj):
|
113
|
+
r"""
|
114
|
+
Pretty print ``obj``.
|
115
|
+
|
116
|
+
This is the only method that outside code should invoke.
|
117
|
+
|
118
|
+
INPUT:
|
119
|
+
|
120
|
+
- ``obj`` -- anything
|
121
|
+
|
122
|
+
OUTPUT: string representation for object
|
123
|
+
|
124
|
+
EXAMPLES::
|
125
|
+
|
126
|
+
sage: from sage.repl.display.pretty_print import SagePrettyPrinter
|
127
|
+
sage: from io import StringIO
|
128
|
+
sage: stream = StringIO()
|
129
|
+
sage: SagePrettyPrinter(stream, 78, '\n').pretty([type, 123, 'foo'])
|
130
|
+
sage: stream.getvalue()
|
131
|
+
"[<... 'type'>,"
|
132
|
+
"""
|
133
|
+
obj_id = id(obj)
|
134
|
+
cycle = obj_id in self.stack
|
135
|
+
self.stack.append(obj_id)
|
136
|
+
self.begin_group()
|
137
|
+
try:
|
138
|
+
ok = False
|
139
|
+
for representation in self.pretty_repr:
|
140
|
+
if self.DEBUG:
|
141
|
+
print('Trying {0}'.format(representation))
|
142
|
+
ok = representation(obj, self, cycle)
|
143
|
+
if self.DEBUG:
|
144
|
+
print('ok = {0}'.format(ok))
|
145
|
+
if ok not in [True, False]:
|
146
|
+
raise RuntimeError('printer failed to return boolean')
|
147
|
+
if ok:
|
148
|
+
break
|
149
|
+
if not ok:
|
150
|
+
raise RuntimeError('no printer registered for object')
|
151
|
+
finally:
|
152
|
+
self.end_group()
|
153
|
+
self.stack.pop()
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
"""
|
3
|
+
Utility functions for pretty-printing
|
4
|
+
|
5
|
+
These utility functions are used in the implementations of ``_repr_``
|
6
|
+
methods elsewhere.
|
7
|
+
"""
|
8
|
+
|
9
|
+
# ****************************************************************************
|
10
|
+
# Copyright (C) 2014 Volker Braun <vbraun.name@gmail.com>
|
11
|
+
#
|
12
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
13
|
+
# as published by the Free Software Foundation; either version 2 of
|
14
|
+
# the License, or (at your option) any later version.
|
15
|
+
# https://www.gnu.org/licenses/
|
16
|
+
# ****************************************************************************
|
17
|
+
|
18
|
+
|
19
|
+
class TallListFormatter:
|
20
|
+
"""
|
21
|
+
Special representation for lists with tall entries (e.g. matrices).
|
22
|
+
|
23
|
+
.. automethod:: __call__
|
24
|
+
"""
|
25
|
+
|
26
|
+
# This is used to wrap lines when printing "tall" lists.
|
27
|
+
MAX_COLUMN = 70
|
28
|
+
|
29
|
+
def _tall_list_row(self, running_lines, last_row=False):
|
30
|
+
"""
|
31
|
+
Helper for :meth:`_check_tall_list_and_format`.
|
32
|
+
|
33
|
+
This helper function processes and outputs the contents of the
|
34
|
+
running_lines array.
|
35
|
+
|
36
|
+
TESTS::
|
37
|
+
|
38
|
+
sage: from sage.repl.display.util import format_list
|
39
|
+
sage: format_list._tall_list_row(['a b', 'b c', 'c'])
|
40
|
+
['a b', 'b c', 'c,', '']
|
41
|
+
"""
|
42
|
+
s = []
|
43
|
+
for i, line in enumerate(running_lines):
|
44
|
+
if i + 1 != len(running_lines):
|
45
|
+
sep, tail = ' ', ''
|
46
|
+
else:
|
47
|
+
# The commas go on the bottom line of this row.
|
48
|
+
sep, tail = ', ', '' if last_row else ','
|
49
|
+
s.append(sep.join(line) + tail)
|
50
|
+
# Separate rows with a newline to make them stand out.
|
51
|
+
if not last_row:
|
52
|
+
s.append("")
|
53
|
+
return s
|
54
|
+
|
55
|
+
def try_format(self, the_list):
|
56
|
+
"""
|
57
|
+
First check whether a list is "tall" -- whether the reprs of the
|
58
|
+
elements of the list will span multiple lines and cause the list
|
59
|
+
to be printed awkwardly. If not, this function returns ``None`` and
|
60
|
+
does nothing; you should revert back to the normal method for
|
61
|
+
printing an object (its repr). If so, return the string in the
|
62
|
+
special format. Note that the special format isn't just for
|
63
|
+
matrices. Any object with a multiline repr will be formatted.
|
64
|
+
|
65
|
+
INPUT:
|
66
|
+
|
67
|
+
- ``the_list`` -- the list (or a tuple)
|
68
|
+
|
69
|
+
OUTPUT:
|
70
|
+
|
71
|
+
String or ``None``. The latter is returned if the list is not
|
72
|
+
deemed to be tall enough and another formatter should be used.
|
73
|
+
|
74
|
+
TESTS::
|
75
|
+
|
76
|
+
sage: from sage.repl.display.util import format_list
|
77
|
+
sage: print(format_list.try_format( # needs sage.modules
|
78
|
+
....: [matrix([[1, 2, 3, 4], [5, 6, 7, 8]]) for i in range(7)]))
|
79
|
+
[
|
80
|
+
[1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4]
|
81
|
+
[5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8],
|
82
|
+
<BLANKLINE>
|
83
|
+
[1 2 3 4]
|
84
|
+
[5 6 7 8]
|
85
|
+
]
|
86
|
+
|
87
|
+
sage: format_list.try_format(['not', 'tall']) is None
|
88
|
+
True
|
89
|
+
"""
|
90
|
+
# For every object to be printed, split its repr on newlines and store the
|
91
|
+
# result in this list.
|
92
|
+
split_reprs = []
|
93
|
+
tall = False
|
94
|
+
for elem in the_list:
|
95
|
+
split_reprs.append(repr(elem).split('\n'))
|
96
|
+
if len(split_reprs[-1]) > 1:
|
97
|
+
# Meanwhile, check to make sure the list is actually "tall".
|
98
|
+
tall = True
|
99
|
+
if not tall:
|
100
|
+
return None
|
101
|
+
# Figure out which type of parenthesis to use, based on the type of the_list.
|
102
|
+
if isinstance(the_list, tuple):
|
103
|
+
parens = '()'
|
104
|
+
elif isinstance(the_list, list):
|
105
|
+
parens = '[]'
|
106
|
+
else:
|
107
|
+
raise TypeError('expected list or tuple')
|
108
|
+
|
109
|
+
# running_lines is a list of lines, which are stored as lists of strings
|
110
|
+
# to be joined later. For each split repr, we add its lines to the
|
111
|
+
# running_lines array. When current_column exceeds MAX_COLUMN, process
|
112
|
+
# and output running_lines using _print_tall_list_row.
|
113
|
+
running_lines = [[]]
|
114
|
+
current_column = 0
|
115
|
+
s = [parens[0]]
|
116
|
+
for split_repr in split_reprs:
|
117
|
+
width = max(len(x) for x in split_repr)
|
118
|
+
if current_column + width > self.MAX_COLUMN and not (width > self.MAX_COLUMN):
|
119
|
+
s.extend(self._tall_list_row(running_lines))
|
120
|
+
running_lines = [[]]
|
121
|
+
current_column = 0
|
122
|
+
current_column += width + 2
|
123
|
+
# Add the lines from split_repr to the running_lines array. It may
|
124
|
+
# be necessary to add or remove lines from either one so that the
|
125
|
+
# number of lines matches up.
|
126
|
+
for i in range(len(running_lines), len(split_repr)):
|
127
|
+
running_lines.insert(0, [' ' * len(x) for x in running_lines[-1]])
|
128
|
+
line_diff = len(running_lines) - len(split_repr)
|
129
|
+
for i, x in enumerate(split_repr):
|
130
|
+
running_lines[i + line_diff].append(x.ljust(width))
|
131
|
+
for i in range(line_diff):
|
132
|
+
running_lines[i].append(' ' * width)
|
133
|
+
# Output any remaining entries.
|
134
|
+
if len(running_lines[0]) > 0:
|
135
|
+
s.extend(self._tall_list_row(running_lines, True))
|
136
|
+
s.append(parens[1])
|
137
|
+
return "\n".join(s)
|
138
|
+
|
139
|
+
def __call__(self, the_list):
|
140
|
+
"""
|
141
|
+
Return "tall list" string representation.
|
142
|
+
|
143
|
+
See also :meth:`try_format`.
|
144
|
+
|
145
|
+
INPUT:
|
146
|
+
|
147
|
+
- ``the_list`` -- list or tuple
|
148
|
+
|
149
|
+
OUTPUT: string
|
150
|
+
|
151
|
+
EXAMPLES::
|
152
|
+
|
153
|
+
sage: from sage.repl.display.util import format_list
|
154
|
+
sage: format_list(['not', 'tall'])
|
155
|
+
"['not', 'tall']"
|
156
|
+
"""
|
157
|
+
output = self.try_format(the_list)
|
158
|
+
if output is None:
|
159
|
+
output = repr(the_list)
|
160
|
+
return output
|
161
|
+
|
162
|
+
|
163
|
+
format_list = TallListFormatter()
|
sage/repl/image.py
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
# sage.doctest: needs pillow
|
3
|
+
"""
|
4
|
+
Sage Wrapper for Bitmap Images
|
5
|
+
|
6
|
+
Some computations in Sage return bitmap images, for example matrices
|
7
|
+
can be turned into bitmaps directly. Note that this is different from
|
8
|
+
all plotting functionality, the latter can equally produce vector
|
9
|
+
graphics. This module is about bitmaps only, and a shallow wrapper
|
10
|
+
around ``PIL.Image``. The only difference is that :class:`Image`
|
11
|
+
is displayed as graphics by the Sage if the UI can.
|
12
|
+
|
13
|
+
EXAMPLES::
|
14
|
+
|
15
|
+
sage: from sage.repl.image import Image
|
16
|
+
sage: img = Image('RGB', (256, 256), 'white')
|
17
|
+
sage: pixels = img.pixels()
|
18
|
+
sage: for x in range(img.width()):
|
19
|
+
....: for y in range(img.height()):
|
20
|
+
....: pixels[x, y] = (x, y, 100)
|
21
|
+
sage: img
|
22
|
+
256x256px 24-bit RGB image
|
23
|
+
sage: type(img)
|
24
|
+
<class 'sage.repl.image.Image'>
|
25
|
+
"""
|
26
|
+
|
27
|
+
# ****************************************************************************
|
28
|
+
# Copyright (C) 2015 Volker Braun <vbraun.name@gmail.com>
|
29
|
+
#
|
30
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
31
|
+
# as published by the Free Software Foundation; either version 2 of
|
32
|
+
# the License, or (at your option) any later version.
|
33
|
+
# https://www.gnu.org/licenses/
|
34
|
+
# ****************************************************************************
|
35
|
+
|
36
|
+
import io
|
37
|
+
|
38
|
+
import PIL.Image
|
39
|
+
from sage.structure.sage_object import SageObject
|
40
|
+
|
41
|
+
|
42
|
+
class Image(SageObject):
|
43
|
+
|
44
|
+
def __init__(self, mode, size, color='white'):
|
45
|
+
"""
|
46
|
+
Create a new image with the given mode and size.
|
47
|
+
|
48
|
+
INPUT:
|
49
|
+
|
50
|
+
- ``mode`` -- string. The mode to use for the new image. Valid
|
51
|
+
options are:
|
52
|
+
|
53
|
+
* ``'1'`` (1-bit pixels, black and white, stored with
|
54
|
+
one pixel per byte)
|
55
|
+
|
56
|
+
* ``'L'`` (8-bit pixels, black and white)
|
57
|
+
|
58
|
+
* ``'P'`` (8-bit pixels, mapped to any other mode using
|
59
|
+
a color palette)
|
60
|
+
|
61
|
+
* ``'RGB'`` (3x8-bit pixels, true color)
|
62
|
+
|
63
|
+
* ``'RGBA'`` (4x8-bit pixels, true color with
|
64
|
+
transparency mask)
|
65
|
+
|
66
|
+
* ``'CMYK'`` (4x8-bit pixels, color separation)
|
67
|
+
|
68
|
+
* ``'YCbCr'`` (3x8-bit pixels, color video format)
|
69
|
+
|
70
|
+
* ``'LAB'`` (3x8-bit pixels, the L*a*b color space)
|
71
|
+
|
72
|
+
* ``'HSV'`` (3x8-bit pixels, Hue, Saturation, Value
|
73
|
+
color space)
|
74
|
+
|
75
|
+
* ``'I'`` (32-bit signed integer pixels)
|
76
|
+
|
77
|
+
* ``'F'`` (32-bit floating point pixels)
|
78
|
+
|
79
|
+
- ``size`` -- 2-tuple, containing (width, height) in pixels
|
80
|
+
|
81
|
+
- ``color`` -- string, numeric or tuple of numeric. What colour to use
|
82
|
+
for the image. Default is black. If given, this should be a
|
83
|
+
a tuple with one value per band. When creating RGB images,
|
84
|
+
you can also use colour strings as supported by the
|
85
|
+
ImageColor module. If the colour is None, the image is not
|
86
|
+
initialised.
|
87
|
+
|
88
|
+
OUTPUT: a new :class:`Image` object
|
89
|
+
|
90
|
+
EXAMPLES::
|
91
|
+
|
92
|
+
sage: from sage.repl.image import Image
|
93
|
+
sage: Image('P', (16, 16), 13)
|
94
|
+
16x16px 8-bit Color image
|
95
|
+
"""
|
96
|
+
# pillow does not support Sage integers as color
|
97
|
+
from sage.rings.integer import Integer
|
98
|
+
if isinstance(color, Integer):
|
99
|
+
color = int(color)
|
100
|
+
elif isinstance(color, tuple):
|
101
|
+
color = tuple(int(i) if isinstance(i, Integer) else i for i in color)
|
102
|
+
self._pil = PIL.Image.new(mode, size, color)
|
103
|
+
|
104
|
+
@property
|
105
|
+
def pil(self):
|
106
|
+
"""
|
107
|
+
Access the wrapped PIL(low) Image.
|
108
|
+
|
109
|
+
OUTPUT: the underlying ``PIL.Image.Image object``
|
110
|
+
|
111
|
+
EXAMPLES::
|
112
|
+
|
113
|
+
sage: from sage.repl.image import Image
|
114
|
+
sage: img = Image('RGB', (16, 16), 'white')
|
115
|
+
sage: img.pil
|
116
|
+
<PIL.Image.Image image mode=RGB size=16x16 at 0x...>
|
117
|
+
"""
|
118
|
+
return self._pil
|
119
|
+
|
120
|
+
def pixels(self):
|
121
|
+
"""
|
122
|
+
Return the pixel map.
|
123
|
+
|
124
|
+
OUTPUT:
|
125
|
+
|
126
|
+
The PIL PixelAccess object that allows you to get/set the
|
127
|
+
pixel data.
|
128
|
+
|
129
|
+
EXAMPLES::
|
130
|
+
|
131
|
+
sage: from sage.repl.image import Image
|
132
|
+
sage: img = Image('RGB', (16, 16), 'white')
|
133
|
+
sage: img.pixels()
|
134
|
+
<PixelAccess object at 0x...>
|
135
|
+
"""
|
136
|
+
return self._pil.load()
|
137
|
+
|
138
|
+
def _repr_(self) -> str:
|
139
|
+
"""
|
140
|
+
Return string representation.
|
141
|
+
|
142
|
+
OUTPUT: string
|
143
|
+
|
144
|
+
EXAMPLES::
|
145
|
+
|
146
|
+
sage: from sage.repl.image import Image
|
147
|
+
sage: Image('RGB', (16, 16), 'white') # indirect doctest
|
148
|
+
16x16px 24-bit RGB image
|
149
|
+
"""
|
150
|
+
modestr = {
|
151
|
+
'1': '{0}x{1}px BW image',
|
152
|
+
'L': '{0}x{1}px 8-bit BW image',
|
153
|
+
'P': '{0}x{1}px 8-bit Color image',
|
154
|
+
'RGB': '{0}x{1}px 24-bit RGB image',
|
155
|
+
'RGBA': '{0}x{1}px 32-bit RGBA image',
|
156
|
+
'CMYK': '{0}x{1}px 24-bit CMYK image',
|
157
|
+
'YCbCr': '{0}x{1}px 24-bit YCbCr mage',
|
158
|
+
'LAB': '{0}x{1}px 24-bit LAB image',
|
159
|
+
'HSV': '{0}x{1}px 24-bit HSV image',
|
160
|
+
'I': '{0}x{1}px 32-bit signed integer image',
|
161
|
+
'F': '{0}x{1}px 32-bit float image',
|
162
|
+
}
|
163
|
+
try:
|
164
|
+
mode = modestr[self.pil.mode]
|
165
|
+
except AttributeError:
|
166
|
+
mode = 'Unknown mode'
|
167
|
+
width, height = self.pil.size
|
168
|
+
return mode.format(width, height)
|
169
|
+
|
170
|
+
def mode(self):
|
171
|
+
"""
|
172
|
+
Return the color mode.
|
173
|
+
|
174
|
+
OUTPUT: string; as given when constructing the image
|
175
|
+
|
176
|
+
EXAMPLES::
|
177
|
+
|
178
|
+
sage: from sage.repl.image import Image
|
179
|
+
sage: img = Image('YCbCr', (16, 16), 'white')
|
180
|
+
sage: img.mode()
|
181
|
+
'YCbCr'
|
182
|
+
"""
|
183
|
+
return self.pil.mode
|
184
|
+
|
185
|
+
def width(self):
|
186
|
+
"""
|
187
|
+
Return the horizontal dimension in pixels.
|
188
|
+
|
189
|
+
OUTPUT: integer
|
190
|
+
|
191
|
+
EXAMPLES::
|
192
|
+
|
193
|
+
sage: from sage.repl.image import Image
|
194
|
+
sage: img = Image('1', (12, 34), 'white')
|
195
|
+
sage: img.width()
|
196
|
+
12
|
197
|
+
sage: img.height()
|
198
|
+
34
|
199
|
+
"""
|
200
|
+
return self.pil.size[0]
|
201
|
+
|
202
|
+
def height(self):
|
203
|
+
"""
|
204
|
+
Return the vertical dimension in pixels.
|
205
|
+
|
206
|
+
OUTPUT: integer
|
207
|
+
|
208
|
+
EXAMPLES::
|
209
|
+
|
210
|
+
sage: from sage.repl.image import Image
|
211
|
+
sage: img = Image('1', (12, 34), 'white')
|
212
|
+
sage: img.width()
|
213
|
+
12
|
214
|
+
sage: img.height()
|
215
|
+
34
|
216
|
+
"""
|
217
|
+
return self.pil.size[1]
|
218
|
+
|
219
|
+
def save(self, filename):
|
220
|
+
r"""
|
221
|
+
Save the bitmap image.
|
222
|
+
|
223
|
+
INPUT:
|
224
|
+
|
225
|
+
- ``filename`` -- string; the filename to save as. The given
|
226
|
+
extension automatically determines the image file type
|
227
|
+
|
228
|
+
EXAMPLES::
|
229
|
+
|
230
|
+
sage: from sage.repl.image import Image
|
231
|
+
sage: img = Image('P', (12, 34), 13)
|
232
|
+
sage: filename = tmp_filename(ext='.png')
|
233
|
+
sage: img.save(filename)
|
234
|
+
sage: with open(filename, 'rb') as f:
|
235
|
+
....: f.read(4) == b'\x89PNG'
|
236
|
+
True
|
237
|
+
"""
|
238
|
+
self.pil.save(filename)
|
239
|
+
|
240
|
+
def show(self):
|
241
|
+
r"""
|
242
|
+
Show this image immediately.
|
243
|
+
|
244
|
+
This method attempts to display the graphics immediately,
|
245
|
+
without waiting for the currently running code (if any) to
|
246
|
+
return to the command line. Be careful, calling it from within
|
247
|
+
a loop will potentially launch a large number of external
|
248
|
+
viewer programs.
|
249
|
+
|
250
|
+
OUTPUT:
|
251
|
+
|
252
|
+
This method does not return anything. Use :meth:`save` if you
|
253
|
+
want to save the figure as an image.
|
254
|
+
|
255
|
+
EXAMPLES::
|
256
|
+
|
257
|
+
sage: from sage.repl.image import Image
|
258
|
+
sage: img = Image('1', (12, 34), 'white')
|
259
|
+
sage: img.show()
|
260
|
+
"""
|
261
|
+
from sage.repl.rich_output import get_display_manager
|
262
|
+
dm = get_display_manager()
|
263
|
+
dm.display_immediately(self)
|
264
|
+
|
265
|
+
def _rich_repr_(self, display_manager, **kwds):
|
266
|
+
"""
|
267
|
+
Rich Output Magic Method.
|
268
|
+
|
269
|
+
See :mod:`sage.repl.rich_output` for details.
|
270
|
+
|
271
|
+
EXAMPLES::
|
272
|
+
|
273
|
+
sage: from sage.repl.image import Image
|
274
|
+
sage: img = Image('1', (16, 16), 'white')
|
275
|
+
sage: from sage.repl.rich_output import get_display_manager
|
276
|
+
sage: dm = get_display_manager()
|
277
|
+
sage: img._rich_repr_(dm)
|
278
|
+
OutputImagePng container
|
279
|
+
|
280
|
+
sage: img = Image('F', (16, 16), 'white') # not supported in PNG
|
281
|
+
sage: img._rich_repr_(dm)
|
282
|
+
OutputImageGif container
|
283
|
+
"""
|
284
|
+
if display_manager.preferences.graphics == 'disable':
|
285
|
+
return
|
286
|
+
types = display_manager.types
|
287
|
+
preferred = (
|
288
|
+
('PNG', types.OutputImagePng),
|
289
|
+
('JPEG', types.OutputImageJpg),
|
290
|
+
('GIF', types.OutputImageGif),
|
291
|
+
)
|
292
|
+
from sage.repl.rich_output.buffer import OutputBuffer
|
293
|
+
for format, output_container in preferred:
|
294
|
+
if output_container in display_manager.supported_output():
|
295
|
+
stream = io.BytesIO()
|
296
|
+
try:
|
297
|
+
self.pil.save(stream, format=format)
|
298
|
+
except OSError:
|
299
|
+
# not all formats support all modes, e.g. no alpha support in gif
|
300
|
+
continue
|
301
|
+
buf = OutputBuffer(stream.getvalue())
|
302
|
+
return output_container(buf)
|
sage/repl/inputhook.py
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
"""
|
3
|
+
The Sage Input Hook
|
4
|
+
|
5
|
+
This lets us perform actions while IPython is sitting at the terminal input
|
6
|
+
prompt. We use it to reload attached files if they have changed.
|
7
|
+
"""
|
8
|
+
|
9
|
+
###########################################################################
|
10
|
+
# Copyright (C) 2016 Volker Braun <vbraun.name@gmail.com>
|
11
|
+
#
|
12
|
+
# This program is free software: you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU General Public License as published by
|
14
|
+
# the Free Software Foundation, either version 2 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
# https://www.gnu.org/licenses/
|
17
|
+
###########################################################################
|
18
|
+
|
19
|
+
import select
|
20
|
+
import errno
|
21
|
+
import contextlib
|
22
|
+
import io
|
23
|
+
|
24
|
+
from IPython.core.getipython import get_ipython
|
25
|
+
from IPython.terminal.pt_inputhooks import register
|
26
|
+
|
27
|
+
import sage.repl.attach
|
28
|
+
|
29
|
+
|
30
|
+
TIMEOUT = 0.25 # seconds
|
31
|
+
|
32
|
+
|
33
|
+
def sage_inputhook(context):
|
34
|
+
f = context.fileno()
|
35
|
+
while True:
|
36
|
+
sage.repl.attach.reload_attached_files_if_modified()
|
37
|
+
try:
|
38
|
+
r, _, _ = select.select([f], [], [], TIMEOUT)
|
39
|
+
if f in r:
|
40
|
+
return # IPython signalled us to stop
|
41
|
+
except OSError as e:
|
42
|
+
if e[0] != errno.EINTR:
|
43
|
+
raise
|
44
|
+
|
45
|
+
|
46
|
+
register('sage', sage_inputhook)
|
47
|
+
|
48
|
+
|
49
|
+
def install():
|
50
|
+
"""
|
51
|
+
Install the Sage input hook.
|
52
|
+
|
53
|
+
EXAMPLES:
|
54
|
+
|
55
|
+
Make sure ipython is running so we really test this function::
|
56
|
+
|
57
|
+
sage: from sage.repl.interpreter import get_test_shell
|
58
|
+
sage: get_test_shell()
|
59
|
+
<sage.repl.interpreter.SageTestShell object at ...>
|
60
|
+
|
61
|
+
Run the function twice, to check it is idempotent (see :issue:`35235`)::
|
62
|
+
|
63
|
+
sage: from sage.repl.inputhook import install
|
64
|
+
sage: install()
|
65
|
+
sage: install()
|
66
|
+
"""
|
67
|
+
ip = get_ipython()
|
68
|
+
if not ip:
|
69
|
+
return # Not running in ipython, e.g. doctests
|
70
|
+
if ip._inputhook != sage_inputhook:
|
71
|
+
# silence `ip.enable_gui()` useless output
|
72
|
+
with contextlib.redirect_stdout(io.StringIO()):
|
73
|
+
ip.enable_gui('sage')
|
74
|
+
|
75
|
+
|
76
|
+
def uninstall():
|
77
|
+
"""
|
78
|
+
Uninstall the Sage input hook.
|
79
|
+
|
80
|
+
EXAMPLES::
|
81
|
+
|
82
|
+
sage: from sage.repl.inputhook import uninstall
|
83
|
+
sage: uninstall()
|
84
|
+
"""
|
85
|
+
ip = get_ipython()
|
86
|
+
if not ip:
|
87
|
+
return
|
88
|
+
if ip._inputhook == sage_inputhook:
|
89
|
+
# silence `ip.enable_gui()` useless output
|
90
|
+
with contextlib.redirect_stdout(io.StringIO()):
|
91
|
+
ip.enable_gui(None)
|