diff -up src/sage/repl/attach.py.orig src/sage/repl/attach.py --- src/sage/repl/attach.py.orig 2016-08-18 13:12:59.071122164 -0400 +++ src/sage/repl/attach.py 2016-08-18 13:13:01.904122272 -0400 @@ -13,7 +13,7 @@ Check that no file clutter is produced:: sage: dir = tmp_dir() sage: src = os.path.join(dir, 'foobar.sage') sage: with open(src, 'w') as f: - ....: f.write('print("")\n') + ....: f.write('print ""\n') sage: attach(src) sage: os.listdir(dir) @@ -67,13 +67,11 @@ character-by-character:: # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import print_function import os import six import time from sage.repl.load import load, load_wrap -import sage.repl.inputhook import sage.env # The attached files as a dict of {filename:mtime} @@ -165,7 +163,7 @@ def load_attach_path(path=None, replace= ['.'] sage: t_dir = tmp_dir() sage: fullpath = os.path.join(t_dir, 'test.py') - sage: open(fullpath, 'w').write("print(37 * 3)") + sage: open(fullpath, 'w').write("print 37 * 3") sage: attach('test.py') Traceback (most recent call last): ... @@ -266,13 +264,6 @@ def attach(*files): Attach a file or files to a running instance of Sage and also load that file. - .. NOTE:: - - Attaching files uses the Python inputhook, which will conflict - with other inputhook users. This generally includes GUI main loop - integrations, for example tkinter. So you can only use tkinter or - attach, but not both at the same time. - INPUT: - ``files`` -- a list of filenames (strings) to attach. @@ -313,9 +304,9 @@ def attach(*files): sage: sage.repl.attach.reset() sage: t1 = tmp_filename(ext='.py') - sage: open(t1,'w').write("print('hello world')") + sage: open(t1,'w').write("print 'hello world'") sage: t2 = tmp_filename(ext='.py') - sage: open(t2,'w').write("print('hi there xxx')") + sage: open(t2,'w').write("print 'hi there xxx'") sage: attach(t1, t2) hello world hi there xxx @@ -371,7 +362,6 @@ def add_attached_file(filename): sage: af.attached_files() [] """ - sage.repl.inputhook.install() fpath = os.path.abspath(filename) attached[fpath] = os.path.getmtime(fpath) @@ -389,7 +379,7 @@ def attached_files(): sage: sage.repl.attach.reset() sage: t = tmp_filename(ext='.py') - sage: open(t,'w').write("print('hello world')") + sage: open(t,'w').write("print 'hello world'") sage: attach(t) hello world sage: attached_files() @@ -415,7 +405,7 @@ def detach(filename): sage: sage.repl.attach.reset() sage: t = tmp_filename(ext='.py') - sage: open(t,'w').write("print('hello world')") + sage: open(t,'w').write("print 'hello world'") sage: attach(t) hello world sage: attached_files() == [t] @@ -429,7 +419,7 @@ def detach(filename): ['.'] sage: t_dir = tmp_dir() sage: fullpath = os.path.join(t_dir, 'test.py') - sage: open(fullpath, 'w').write("print(37 * 3)") + sage: open(fullpath, 'w').write("print 37 * 3") sage: load_attach_path(t_dir) sage: attach('test.py') 111 @@ -441,7 +431,7 @@ def detach(filename): sage: attach('test.py') 111 sage: fullpath = os.path.join(t_dir, 'test2.py') - sage: open(fullpath, 'w').write("print(3)") + sage: open(fullpath, 'w').write("print 3") sage: attach('test2.py') 3 sage: detach(attached_files()) @@ -474,8 +464,6 @@ def detach(filename): attached.pop(fpath) else: raise ValueError("file '{0}' is not attached, see attached_files()".format(filename)) - if not attached: - sage.repl.inputhook.uninstall() def reset(): """ @@ -485,7 +473,7 @@ def reset(): sage: sage.repl.attach.reset() sage: t = tmp_filename(ext='.py') - sage: open(t,'w').write("print('hello world')") + sage: open(t,'w').write("print 'hello world'") sage: attach(t) hello world sage: attached_files() == [t] diff -up src/sage/repl/display/fancy_repr.py.orig src/sage/repl/display/fancy_repr.py --- src/sage/repl/display/fancy_repr.py.orig 2016-08-18 13:12:59.078122164 -0400 +++ src/sage/repl/display/fancy_repr.py 2016-08-18 13:13:01.906122272 -0400 @@ -119,7 +119,8 @@ class SomeIPythonRepr(ObjectReprABC): .. automethod:: __call__ """ type_repr = _type_pprinters.copy() - del type_repr[type] + del type_repr[types.TypeType] + del type_repr[types.ClassType] del type_repr[types.BuiltinFunctionType] del type_repr[types.FunctionType] del type_repr[str] @@ -250,7 +251,7 @@ class PlainPythonRepr(ObjectReprABC): a custom representer. Note that it is undesirable to have a trailing newline, and if we don't display it you can't fix it:: - + sage: class Newline(object): ....: def __repr__(self): ....: return 'newline\n' @@ -316,37 +317,12 @@ class TallListRepr(ObjectReprABC): sage: format_list = TallListRepr().format_string sage: format_list([1, 2, identity_matrix(2)]) '[\n [1 0]\n1, 2, [0 1]\n]' - - Check that :trac:`18743` is fixed:: - - sage: class Foo(object): - ....: def __repr__(self): - ....: return '''BBB AA RRR - ....: B B A A R R - ....: BBB AAAA RRR - ....: B B A A R R - ....: BBB A A R R''' - ....: def _repr_option(self, key): - ....: return key == 'ascii_art' - sage: F = Foo() - sage: [F, F] - [ - BBB AA RRR BBB AA RRR - B B A A R R B B A A R R - BBB AAAA RRR BBB AAAA RRR - B B A A R R B B A A R R - BBB A A R R, BBB A A R R - ] """ if not (isinstance(obj, (tuple, list)) and len(obj) > 0): return False ascii_art_repr = False for o in obj: try: - ascii_art_repr = ascii_art_repr or o._repr_option('ascii_art') - except (AttributeError, TypeError): - pass - try: ascii_art_repr = ascii_art_repr or o.parent()._repr_option('element_ascii_art') except (AttributeError, TypeError): pass diff -up src/sage/repl/display/formatter.py.orig src/sage/repl/display/formatter.py --- src/sage/repl/display/formatter.py.orig 2016-08-18 13:12:59.083122164 -0400 +++ src/sage/repl/display/formatter.py 2016-08-18 13:13:01.907122273 -0400 @@ -97,7 +97,7 @@ class SageDisplayFormatter(DisplayFormat self.dm.check_backend_class(BackendIPython) def format(self, obj, include=None, exclude=None): - r""" + """ Use the Sage rich output instead of IPython INPUT/OUTPUT: @@ -124,44 +124,9 @@ class SageDisplayFormatter(DisplayFormat 10*x + 9*x + 8*x + 7*x + 6*x + 5*x + 4*x + 3*x + 2*x + x sage: shell.run_cell('%display default') sage: shell.quit() - - TESTS:: - - sage: import os - sage: from sage.env import SAGE_EXTCODE - sage: example_png = os.path.join(SAGE_EXTCODE, 'doctest', 'rich_output', 'example.png') - sage: from sage.repl.rich_output.backend_ipython import BackendIPython - sage: backend = BackendIPython() - sage: shell = get_test_shell() - sage: backend.install(shell=shell) - sage: shell.run_cell('get_ipython().display_formatter') - - sage: shell.run_cell('from IPython.display import Image') - sage: shell.run_cell('ipython_image = Image("{0}")'.format(example_png)) - sage: shell.run_cell('ipython_image') - - sage: shell.run_cell('get_ipython().display_formatter.format(ipython_image)') - ({u'image/png': '\x89PNG...', - u'text/plain': u''}, - {}) """ - # First, use Sage rich output if there is any - PLAIN_TEXT = u'text/plain' - sage_format, sage_metadata = self.dm.displayhook(obj) - assert PLAIN_TEXT in sage_format, 'plain text is always present' - if sage_format.keys() != [PLAIN_TEXT]: - return sage_format, sage_metadata - # Second, try IPython widgets (obj._ipython_display_ and type registry) - if self.ipython_display_formatter(obj): - return {}, {} - # Finally, try IPython rich representation (obj._repr_foo_ methods) - if exclude is not None: - exclude = list(exclude) + [PLAIN_TEXT] - ipy_format, ipy_metadata = super(SageDisplayFormatter, self).format( - obj, include=include, exclude=exclude) - ipy_format.update(sage_format) - ipy_metadata.update(sage_metadata) - return ipy_format, ipy_metadata + return self.dm.displayhook(obj) + class SagePlainTextFormatter(PlainTextFormatter): @@ -190,7 +155,7 @@ class SagePlainTextFormatter(PlainTextFo sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.display_formatter.formatters['text/plain'] - + sage: shell.quit() """ super(SagePlainTextFormatter, self).__init__(*args, **kwds) diff -up src/sage/repl/display/jsmol_iframe.py.orig src/sage/repl/display/jsmol_iframe.py --- src/sage/repl/display/jsmol_iframe.py.orig 2016-08-18 13:12:59.088122165 -0400 +++ src/sage/repl/display/jsmol_iframe.py 2016-08-18 13:13:01.908122273 -0400 @@ -249,7 +249,7 @@ class JSMolHtml(SageObject): String. EXAMPLES:: - + sage: from sage.repl.display.jsmol_iframe import JSMolHtml sage: from sage.repl.rich_output.output_graphics3d import OutputSceneJmol sage: jmol = JSMolHtml(OutputSceneJmol.example()) @@ -276,7 +276,7 @@ class JSMolHtml(SageObject): String EXAMPLES:: - + sage: from sage.repl.display.jsmol_iframe import JSMolHtml sage: from sage.repl.rich_output.output_graphics3d import OutputSceneJmol sage: jmol = JSMolHtml(OutputSceneJmol.example(), width=500, height=300) diff -up src/sage/repl/display/pretty_print.py.orig src/sage/repl/display/pretty_print.py --- src/sage/repl/display/pretty_print.py.orig 2016-08-18 13:12:59.093122165 -0400 +++ src/sage/repl/display/pretty_print.py 2016-08-18 13:13:01.909122273 -0400 @@ -74,12 +74,12 @@ class SagePrettyPrinter(PrettyPrinter): See IPython documentation. EXAMPLES:: - + sage: 123 123 IPython pretty printers:: - + sage: set({1, 2, 3}) {1, 2, 3} sage: dict(zzz=123, aaa=99, xab=10) # sorted by keys @@ -88,16 +88,20 @@ class SagePrettyPrinter(PrettyPrinter): These are overridden in IPython in a way that we feel is somewhat confusing, and we prefer to print them like plain Python which is more informative. See :trac:`14466` :: - + sage: 'this is a string' 'this is a string' sage: type(123) sage: type + sage: [type, type] + [, ] sage: import types - sage: type('name', (), {}) - + sage: types.ClassType('name', (), {}) + + sage: types.TypeType + sage: types.BuiltinFunctionType diff -up src/sage/repl/display/util.py.orig src/sage/repl/display/util.py --- src/sage/repl/display/util.py.orig 2016-08-18 13:12:59.099122165 -0400 +++ src/sage/repl/display/util.py 2016-08-18 13:13:01.909122273 -0400 @@ -14,7 +14,6 @@ methods elsewhere. # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import print_function class TallListFormatter(object): @@ -75,8 +74,8 @@ class TallListFormatter(object): TESTS:: sage: from sage.repl.display.util import format_list - sage: print(format_list.try_format( - ....: [matrix([[1, 2, 3, 4], [5, 6, 7, 8]]) for i in xrange(7)])) + sage: print format_list.try_format( + ....: [matrix([[1, 2, 3, 4], [5, 6, 7, 8]]) for i in xrange(7)]) [ [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8], diff -up src/sage/repl/image.py.orig src/sage/repl/image.py --- src/sage/repl/image.py.orig 2016-08-18 13:12:59.104122165 -0400 +++ src/sage/repl/image.py 2016-08-18 13:13:01.910122273 -0400 @@ -14,9 +14,8 @@ EXAMPLES:: sage: from sage.repl.image import Image sage: img = Image('RGB', (256, 256), 'white') sage: pixels = img.pixels() - sage: for x in range(img.width()): - ....: for y in range(img.height()): - ....: pixels[x, y] = (x, y, 100) + sage: for x, y in CartesianProduct(range(img.width()), range(img.height())): + ....: pixels[x, y] = (x, y, 100) sage: img 256x256px 24-bit RGB image sage: type(img) @@ -39,7 +38,7 @@ from sage.structure.sage_object import S class Image(SageObject): - def __init__(self, mode, size, color='white'): + def __init__(self, mode, size, color=0): """ Creates a new image with the given mode and size. @@ -76,12 +75,13 @@ class Image(SageObject): - ``size`` -- 2-tuple, containing (width, height) in pixels. - - ``color`` -- string or tuple of numeric. What colour to use - for the image. Default is black. If given, this should be a - a tuple with one value per band. When creating RGB images, - you can also use colour strings as supported by the - ImageColor module. If the colour is None, the image is not - initialised. + - ``color`` -- string or numeric. What colour to use for the + image. Default is black. If given, this should be a single + integer or floating point value for single-band modes, and a + tuple for multi-band modes (one value per band). When + creating RGB images, you can also use colour strings as + supported by the ImageColor module. If the colour is None, + the image is not initialised. OUTPUT: @@ -90,7 +90,7 @@ class Image(SageObject): EXAMPLES:: sage: from sage.repl.image import Image - sage: Image('P', (16, 16), (13,)) + sage: Image('P', (16, 16), 13) 16x16px 8-bit Color image """ self._pil = PIL.Image.new(mode, size, color) @@ -232,7 +232,7 @@ class Image(SageObject): EXAMPLES:: sage: from sage.repl.image import Image - sage: img = Image('P', (12, 34), (13,)) + sage: img = Image('P', (12, 34), 13) sage: filename = tmp_filename(ext='.png') sage: img.save(filename) sage: open(filename).read().startswith('\x89PNG') diff -up src/sage/repl/interpreter.py.orig src/sage/repl/interpreter.py --- src/sage/repl/interpreter.py.orig 2016-08-18 13:12:59.109122165 -0400 +++ src/sage/repl/interpreter.py 2016-08-18 13:13:01.911122273 -0400 @@ -76,18 +76,14 @@ Check that Cython source code appears in sage: shell = get_test_shell() sage: shell.run_cell('1/0') --------------------------------------------------------------------------- - ZeroDivisionError Traceback (most recent call last) - in () - ----> 1 Integer(1)/Integer(0) + .../sage/rings/integer_ring.pyx in sage.rings.integer_ring.IntegerRing_class._div (.../cythonized/sage/rings/integer_ring.c:...)() + ... cdef rational.Rational x = rational.Rational.__new__(rational.Rational) + ... if mpz_sgn(right.value) == 0: + ... raise ZeroDivisionError('Rational division by zero') + ... mpz_set(mpq_numref(x.value), left.value) + ... mpz_set(mpq_denref(x.value), right.value) - .../src/sage/rings/integer.pyx in sage.rings.integer.Integer.__div__ (.../cythonized/sage/rings/integer.c:...)() - ... if type(left) is type(right): - ... if mpz_sgn((right).value) == 0: - -> ... raise ZeroDivisionError("rational division by zero") - ... x = Rational.__new__(Rational) - ... mpq_div_zz(x.value, (left).value, (right).value) - - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero sage: shell.quit() """ @@ -108,8 +104,8 @@ import re import sys from sage.repl.preparse import preparse -from traitlets.config.loader import Config -from traitlets import Bool, Type +from IPython import Config +from IPython.utils.traitlets import Bool, Type from sage.env import SAGE_LOCAL @@ -184,6 +180,10 @@ class SageShellOverride(object): """ Run a system command. + If the command is not a sage-specific binary, adjust the library + paths before calling system commands. See :trac:`975` for a + discussion of running system commands. + This is equivalent to the sage-native-execute shell script. EXAMPLES:: @@ -196,12 +196,22 @@ class SageShellOverride(object): sage: shell.system_raw('true') sage: shell.user_ns['_exit_code'] 0 + sage: shell.system_raw('env | grep "^LD_LIBRARY_PATH=" | grep $SAGE_LOCAL') + sage: shell.user_ns['_exit_code'] + 1 sage: shell.system_raw('R --version') R version ... sage: shell.user_ns['_exit_code'] 0 sage: shell.quit() """ + path = os.path.join(SAGE_LOCAL, 'bin', + re.split(r'[\s|;&]', cmd)[0]) + if not os.access(path, os.X_OK): + libraries = 'LD_LIBRARY_PATH="$SAGE_ORIG_LD_LIBRARY_PATH";export LD_LIBRARY_PATH;' + if os.uname()[0]=='Darwin': + libraries += 'DYLD_LIBRARY_PATH="$SAGE_ORIG_DYLD_LIBRARY_PATH";export DYLD_LIBRARY_PATH;' + cmd = libraries+cmd return super(SageShellOverride, self).system_raw(cmd) @@ -362,7 +372,7 @@ class SageTestShell(SageShellOverride, T --------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero sage: rc is None True sage: shell.quit() @@ -680,6 +690,10 @@ def get_test_shell(): app.shell._restart() except AttributeError: pass + # overwrite the default (console + graphics) formatter with the plain text one + import sage.repl.display.formatter as formatter + app.shell.display_formatter.formatters['text/plain'] = ( + formatter.SagePlainTextFormatter(config=app.shell.config)) # No quit noise app.shell.verbose_quit = False return app.shell @@ -721,10 +735,10 @@ class SageTerminalApp(TerminalIPythonApp name = u'Sage' crash_handler_class = SageCrashHandler - test_shell = Bool(False, help='Whether the shell is a test shell') - test_shell.tag(config=True) - shell_class = Type(InteractiveShell, help='Type of the shell') - shell_class.tag(config=True) + test_shell = Bool(False, config=True, + help='Whether the shell is a test shell') + shell_class = Type(InteractiveShell, config=True, + help='Type of the shell') def load_config_file(self, *args, **kwds): r""" @@ -741,7 +755,7 @@ class SageTerminalApp(TerminalIPythonApp sage: from sage.misc.temporary_file import tmp_dir sage: from sage.repl.interpreter import SageTerminalApp sage: d = tmp_dir() - sage: from IPython.paths import get_ipython_dir + sage: from IPython.utils.path import get_ipython_dir sage: IPYTHONDIR = get_ipython_dir() sage: os.environ['IPYTHONDIR'] = d sage: SageTerminalApp().load_config_file() diff -up src/sage/repl/ipython_extension.py.orig src/sage/repl/ipython_extension.py --- src/sage/repl/ipython_extension.py.orig 2016-08-18 13:12:59.114122166 -0400 +++ src/sage/repl/ipython_extension.py 2016-08-18 13:13:01.912122273 -0400 @@ -15,8 +15,6 @@ A Sage extension which adds sage-specifi - ``%mode`` (like ``%maxima``, etc.) - - ``%%cython`` - * preparsing of input * loading Sage library @@ -57,13 +55,12 @@ In contrast, input to the ``%time`` magi 2 * 3^3 * 11 sage: shell.quit() """ -from __future__ import absolute_import -from IPython.core.magic import Magics, magics_class, line_magic, cell_magic +from IPython.core.magic import Magics, magics_class, line_magic from sage.repl.load import load_wrap + from sage.env import SAGE_IMPORTALL, SAGE_STARTUP_FILE -from sage.misc.lazy_import import LazyImport @magics_class class SageMagics(Magics): @@ -324,38 +321,6 @@ class SageMagics(Magics): except ValueError as err: print(err) # do not show traceback - @cell_magic - def cython(self, line, cell): - """ - Cython cell magic - - This is syntactic sugar on the - :func:`~sage.misc.cython_c.cython` function. - - INPUT:: - - - ``line`` -- ignored. - - - ``cell`` -- string. The Cython source code to process. - - OUTPUT: - - None. The Cython code is compiled and loaded. - - EXAMPLES:: - - sage: from sage.repl.interpreter import get_test_shell - sage: shell = get_test_shell() - sage: shell.run_cell(''' - ....: %%cython - ....: def f(): - ....: print('test') - ....: ''') - ....: shell.run_cell('f()') - """ - from sage.misc.cython_c import cython_compile - return cython_compile(cell) - class SageCustomizations(object): @@ -368,12 +333,19 @@ class SageCustomizations(object): self.auto_magics = SageMagics(shell) self.shell.register_magics(self.auto_magics) + import sage.repl.display.formatter as formatter + self.shell.display_formatter.formatters['text/plain'] = ( + formatter.SagePlainTextFormatter(config=shell.config)) + import sage.misc.edit_module as edit_module self.shell.set_hook('editor', edit_module.edit_devel) self.init_inspector() self.init_line_transforms() + import inputhook + inputhook.install() + import sage.all # until sage's import hell is fixed self.shell.verbose_quit = True @@ -384,12 +356,31 @@ class SageCustomizations(object): if SAGE_IMPORTALL == 'yes': self.init_environment() + def register_interface_magics(self): """ Register magics for each of the Sage interfaces """ - from sage.repl.interface_magic import InterfaceMagic - InterfaceMagic.register_all(self.shell) + from sage.misc.superseded import deprecation + import sage.interfaces.all + interfaces = [(name, obj) + for name, obj in sage.interfaces.all.__dict__.items() + if isinstance(obj, sage.interfaces.interface.Interface)] + + for real_name, obj in interfaces: + def tmp(line, name=real_name): + self.shell.run_cell('%s.interact()' % name) + tmp.__doc__ = "Interact with %s" % real_name + self.shell.register_magic_function(tmp, magic_name=real_name) + + obj_name = obj.name() + if real_name != obj_name: + def tmp_deprecated(line, name=real_name, badname=obj_name): + deprecation(6288, 'Use %%%s instead of %%%s.' % (name, + badname)) + self.shell.run_cell('%s.interact()' % name) + tmp_deprecated.__doc__ = "Interact with %s" % real_name + self.shell.register_magic_function(tmp_deprecated, magic_name=obj_name) def set_quit_hook(self): """ @@ -426,17 +417,19 @@ class SageCustomizations(object): # that we could override; however, IPython looks them up in # the global :class:`IPython.core.oinspect` module namespace. # Thus, we have to monkey-patch. + import sage.misc.sagedoc as sagedoc + import sage.misc.sageinspect as sageinspect import IPython.core.oinspect - IPython.core.oinspect.getdoc = LazyImport("sage.misc.sageinspect", "sage_getdoc") - IPython.core.oinspect.getsource = LazyImport("sage.misc.sagedoc", "my_getsource") - IPython.core.oinspect.find_file = LazyImport("sage.misc.sageinspect", "sage_getfile") - IPython.core.oinspect.getargspec = LazyImport("sage.misc.sageinspect", "sage_getargspec") + IPython.core.oinspect.getdoc = sageinspect.sage_getdoc + IPython.core.oinspect.getsource = sagedoc.my_getsource + IPython.core.oinspect.find_file = sageinspect.sage_getfile + IPython.core.oinspect.getargspec = sageinspect.sage_getargspec def init_line_transforms(self): """ Set up transforms (like the preparser). """ - from .interpreter import (SagePreparseTransformer, + from interpreter import (SagePreparseTransformer, SagePromptTransformer) for s in (self.shell.input_splitter, self.shell.input_transformer_manager): diff -up src/sage/repl/ipython_kernel/install.py.orig src/sage/repl/ipython_kernel/install.py --- src/sage/repl/ipython_kernel/install.py.orig 2016-08-18 13:12:59.119122166 -0400 +++ src/sage/repl/ipython_kernel/install.py 2016-08-18 13:13:01.912122273 -0400 @@ -1,38 +1,41 @@ """ -Installing the SageMath Jupyter Kernel and extensions +Installing the Sage IPython Kernel -Kernels have to register themselves with Jupyter so that they appear -in the Jupyter notebook's kernel drop-down. This is done by +Kernels have to register themselves with IPython so that they appear +in the IPython notebook's kernel drop-down. This is done by :class:`SageKernelSpec`. """ import os import errno +import copy + +from IPython.kernel.kernelspec import ( + get_kernel_spec, install_kernel_spec, NoSuchKernel) +from IPython.utils.path import get_ipython_dir from sage.env import ( SAGE_ROOT, SAGE_DOC, SAGE_LOCAL, SAGE_EXTCODE, SAGE_VERSION ) -from jupyter_core.paths import ENV_JUPYTER_PATH -JUPYTER_PATH = ENV_JUPYTER_PATH[0] +from sage.misc.temporary_file import tmp_dir class SageKernelSpec(object): def __init__(self): """ - Utility to manage SageMath kernels and extensions + Utility to manage Sage kernels EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec() sage: spec._display_name # random output - 'SageMath 6.9' + 'Sage 6.6.beta2' """ - self._display_name = 'SageMath {0}'.format(SAGE_VERSION) - self.nbextensions_dir = os.path.join(JUPYTER_PATH, "nbextensions") - self.kernel_dir = os.path.join(JUPYTER_PATH, "kernels", self.identifier()) + self._display_name = 'Sage {0}'.format(SAGE_VERSION) + self._ipython_dir = get_ipython_dir() self._mkdirs() def _mkdirs(self): @@ -44,33 +47,40 @@ class SageKernelSpec(object): sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec() sage: spec._mkdirs() - sage: os.path.isdir(spec.nbextensions_dir) + sage: nbextensions = os.path.join(spec._ipython_dir, 'nbextensions') + sage: os.path.exists(nbextensions) True """ - def mkdir_p(path): + def mkdir_p(*path_components): + path = os.path.join(*path_components) try: os.makedirs(path) - except OSError: - if not os.path.isdir(path): + except OSError as err: + if err.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise - mkdir_p(self.nbextensions_dir) - mkdir_p(self.kernel_dir) + mkdir_p(self._ipython_dir, 'nbextensions') @classmethod - def identifier(cls): + def identifier(self): """ - Internal identifier for the SageMath kernel + Internal identifier for the Sage kernel + + OUTPUT: - OUTPUT: the string ``"sagemath"``. + String. EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec - sage: SageKernelSpec.identifier() - 'sagemath' + sage: SageKernelSpec.identifier() # random output + 'sage_6_6_beta3' + sage: SageKernelSpec.identifier().startswith('sage_') + True """ - return 'sagemath' - + return 'Sage {0}'.format(SAGE_VERSION).lower().replace(' ', '_').replace('.', '_') + def symlink(self, src, dst): """ Symlink ``src`` to ``dst`` @@ -95,48 +105,38 @@ class SageKernelSpec(object): if err.errno == errno.EEXIST: return os.symlink(src, dst) - + def use_local_mathjax(self): """ - Symlink SageMath's Mathjax install to the Jupyter notebook. + Symlink Sage's Mathjax Install to the IPython notebook. EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec + sage: from IPython.utils.path import get_ipython_dir sage: spec = SageKernelSpec() sage: spec.use_local_mathjax() - sage: mathjax = os.path.join(spec.nbextensions_dir, 'mathjax') - sage: os.path.isdir(mathjax) + sage: ipython_dir = get_ipython_dir() + sage: mathjax = os.path.join(ipython_dir, 'nbextensions', 'mathjax') + sage: os.path.exists(mathjax) True """ src = os.path.join(SAGE_LOCAL, 'share', 'mathjax') - dst = os.path.join(self.nbextensions_dir, 'mathjax') + dst = os.path.join(self._ipython_dir, 'nbextensions', 'mathjax') self.symlink(src, dst) def use_local_jsmol(self): - """ - Symlink jsmol to the Jupyter notebook. - - EXAMPLES:: - - sage: from sage.repl.ipython_kernel.install import SageKernelSpec - sage: spec = SageKernelSpec() - sage: spec.use_local_jsmol() - sage: jsmol = os.path.join(spec.nbextensions_dir, 'jsmol') - sage: os.path.isdir(jsmol) - True - """ src = os.path.join(SAGE_LOCAL, 'share', 'jsmol') - dst = os.path.join(self.nbextensions_dir, 'jsmol') + dst = os.path.join(self._ipython_dir, 'nbextensions', 'jsmol') self.symlink(src, dst) def _kernel_cmd(self): """ - Helper to construct the SageMath kernel command. - + Helper to construct the Sage kernel command. + OUTPUT: - List of strings. The command to start a new SageMath kernel. + List of strings. The command to start a new Sage kernel. EXAMPLES:: @@ -144,7 +144,7 @@ class SageKernelSpec(object): sage: spec = SageKernelSpec() sage: spec._kernel_cmd() ['/.../sage', - '--python', + '-python', '-m', 'sage.repl.ipython_kernel', '-f', @@ -152,34 +152,40 @@ class SageKernelSpec(object): """ return [ os.path.join(SAGE_ROOT, 'sage'), - '--python', + '-python', '-m', 'sage.repl.ipython_kernel', '-f', '{connection_file}', ] - + def kernel_spec(self): """ Return the kernel spec as Python dictionary OUTPUT: - A dictionary. See the Jupyter documentation for details. + A dictionary. See the IPython documentation for details. EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec() sage: spec.kernel_spec() - {'argv': ..., 'display_name': 'SageMath ...'} + {'argv': ..., 'display_name': 'Sage ...'} """ return dict( argv=self._kernel_cmd(), display_name=self._display_name, ) - + def _install_spec(self): """ - Install the SageMath Jupyter kernel + Install the Sage IPython kernel + + It is safe to call this method multiple times, only one Sage + kernel spec is ever installed for any given Sage + version. However, it resets the IPython kernel spec directory + so additional resources symlinked there are lost. See + :meth:`symlink_resources`. EXAMPLES:: @@ -187,17 +193,21 @@ class SageKernelSpec(object): sage: spec = SageKernelSpec() sage: spec._install_spec() # not tested """ - jsonfile = os.path.join(self.kernel_dir, "kernel.json") import json - with open(jsonfile, 'w') as f: + temp = tmp_dir() + kernel_spec = os.path.join(temp, 'kernel.json') + with open(kernel_spec, 'w') as f: json.dump(self.kernel_spec(), f) + identifier = self.identifier() + install_kernel_spec(temp, identifier, user=True, replace=True) + self._spec = get_kernel_spec(identifier) def _symlink_resources(self): """ Symlink miscellaneous resources - This method symlinks additional resources (like the SageMath - documentation) into the SageMath kernel directory. This is + This method symlinks additional resources (like the Sage + documentation) into the Sage kernel directory. This is necessary to make the help links in the notebook work. EXAMPLES:: @@ -207,23 +217,25 @@ class SageKernelSpec(object): sage: spec._install_spec() # not tested sage: spec._symlink_resources() # not tested """ + assert self._spec, 'call _install_spec() first' + spec_dir = self._spec.resource_dir path = os.path.join(SAGE_EXTCODE, 'notebook-ipython') for filename in os.listdir(path): self.symlink( os.path.join(path, filename), - os.path.join(self.kernel_dir, filename) + os.path.join(spec_dir, filename) ) self.symlink( - os.path.join(SAGE_DOC, 'html', 'en'), - os.path.join(self.kernel_dir, 'doc') + os.path.join(SAGE_DOC, 'output', 'html', 'en'), + os.path.join(spec_dir, 'doc') ) - + @classmethod def update(cls): """ - Configure the Jupyter notebook for the SageMath kernel - - This method does everything necessary to use the SageMath kernel, + Configure the IPython notebook for the Sage kernel + + This method does everything necessary to use the Sage kernel, you should never need to call any of the other methods directly. @@ -231,7 +243,7 @@ class SageKernelSpec(object): sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec() - sage: spec.update() # not tested + sage: spec.update() """ instance = cls() instance.use_local_mathjax() @@ -239,18 +251,13 @@ class SageKernelSpec(object): instance._install_spec() instance._symlink_resources() - -def have_prerequisites(debug=True): + +def have_prerequisites(): """ - Check that we have all prerequisites to run the Jupyter notebook. + Check that we have all prerequisites to run the IPython notebook. - In particular, the Jupyter notebook requires OpenSSL whether or - not you are using https. See :trac:`17318`. - - INPUT: - - ``debug`` -- boolean (default: ``True``). Whether to print debug - information in case that prerequisites are missing. + In particular, the IPython notebook requires OpenSSL whether or + not you are using https. See trac:`17318`. OUTPUT: @@ -259,14 +266,15 @@ def have_prerequisites(debug=True): EXAMPLES:: sage: from sage.repl.ipython_kernel.install import have_prerequisites - sage: have_prerequisites(debug=False) in [True, False] + sage: have_prerequisites() in [True, False] True """ try: - from notebook.notebookapp import NotebookApp + from IPython.html.notebookapp import NotebookApp return True - except ImportError: - if debug: - import traceback - traceback.print_exc() + except ImportError as err: return False + + + + diff -up src/sage/repl/ipython_kernel/kernel.py.orig src/sage/repl/ipython_kernel/kernel.py --- src/sage/repl/ipython_kernel/kernel.py.orig 2016-08-18 13:12:59.125122166 -0400 +++ src/sage/repl/ipython_kernel/kernel.py 2016-08-18 13:13:01.913122273 -0400 @@ -1,8 +1,8 @@ """ The Sage ZMQ Kernel -Version of the Jupyter kernel when running Sage inside the Jupyter -notebook or remote Jupyter sessions. +Version of the IPython kernel when running Sage inside the IPython +notebook or remote IPython sessions. """ #***************************************************************************** @@ -15,9 +15,9 @@ notebook or remote Jupyter sessions. #***************************************************************************** import sys -from ipykernel.ipkernel import IPythonKernel -from ipykernel.zmqshell import ZMQInteractiveShell -from traitlets import Type +from IPython.kernel.zmq.ipkernel import IPythonKernel +from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell +from IPython.utils.traitlets import Type from sage.env import SAGE_VERSION, SAGE_EXTCODE, SAGE_DOC from sage.repl.interpreter import SageNotebookInteractiveShell @@ -27,7 +27,7 @@ class SageZMQInteractiveShell(SageNotebo pass -class SageKernel(IPythonKernel): +class SageKernel(IPythonKernel): implementation = 'sage' implementation_version = SAGE_VERSION @@ -35,11 +35,11 @@ class SageKernel(IPythonKernel): def __init__(self, **kwds): """ - The Sage Jupyter Kernel + The Sage IPython Kernel INPUT: - See the Jupyter documentation + See the IPython documentation EXAMPLES:: @@ -54,8 +54,8 @@ class SageKernel(IPythonKernel): def banner(self): r""" The Sage Banner - - The value of this property is displayed in the Jupyter + + The value of this property is displayed in the IPython notebook. OUTPUT: @@ -67,7 +67,7 @@ class SageKernel(IPythonKernel): sage: from sage.repl.ipython_kernel.kernel import SageKernel sage: sk = SageKernel.__new__(SageKernel) sage: sk.banner - '...SageMath version...' + '\xe2\x94\x8c\xe2...SageMath Version...' """ from sage.misc.banner import banner_text return banner_text() @@ -75,16 +75,11 @@ class SageKernel(IPythonKernel): @property def help_links(self): r""" - Help in the Jupyter Notebook - + Help in the IPython Notebook + OUTPUT: - See the Jupyter documentation. - - .. NOTE:: - - Urls starting with "kernelspecs" are prepended by the - browser with the appropriate path. + See the IPython documentation. EXAMPLES:: @@ -92,16 +87,16 @@ class SageKernel(IPythonKernel): sage: sk = SageKernel.__new__(SageKernel) sage: sk.help_links [{'text': 'Sage Documentation', - 'url': 'kernelspecs/sagemath/doc/index.html'}, + 'url': '/kernelspecs/sage_.../doc/index.html'}, ...] """ from sage.repl.ipython_kernel.install import SageKernelSpec identifier = SageKernelSpec.identifier() - kernel_url = lambda x: 'kernelspecs/{0}/{1}'.format(identifier, x) + kernel_url = lambda x: '/kernelspecs/{0}/{1}'.format(identifier, x) return [ { 'text': 'Sage Documentation', - 'url': kernel_url('doc/index.html'), + 'url': kernel_url('doc/index.html') }, { 'text': 'Sage Tutorial', @@ -124,7 +119,7 @@ class SageKernel(IPythonKernel): 'url': kernel_url('doc/reference/index.html'), }, { - 'text': "Developer's Guide", + 'text': 'Developers Guide', 'url': kernel_url('doc/developer/index.html'), }, { @@ -164,7 +159,3 @@ class SageKernel(IPythonKernel): 'url': "http://help.github.com/articles/github-flavored-markdown", }, ] - - def pre_handler_hook(self): - from cysignals import init_cysignals - self.saved_sigint_handler = init_cysignals() diff -up src/sage/repl/ipython_kernel/__main__.py.orig src/sage/repl/ipython_kernel/__main__.py --- src/sage/repl/ipython_kernel/__main__.py.orig 2016-08-18 13:12:59.131122166 -0400 +++ src/sage/repl/ipython_kernel/__main__.py 2016-08-18 13:13:01.913122273 -0400 @@ -1,3 +1,3 @@ -from ipykernel.kernelapp import IPKernelApp +from IPython.kernel.zmq.kernelapp import IPKernelApp from sage.repl.ipython_kernel.kernel import SageKernel IPKernelApp.launch_instance(kernel_class=SageKernel) diff -up src/sage/repl/preparse.py.orig src/sage/repl/preparse.py --- src/sage/repl/preparse.py.orig 2016-08-18 13:12:59.137122166 -0400 +++ src/sage/repl/preparse.py 2016-08-18 13:13:01.914122273 -0400 @@ -216,7 +216,7 @@ Behind the scenes what happens is the fo # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import print_function + import os import re @@ -321,9 +321,9 @@ def strip_string_literals(code, state=No '[%(L1)s, %(L2)s, %(L3)s, %(L4)s]' sage: literals {'L1': "'a'", 'L2': '"b"', 'L3': "'c'", 'L4': '"d\\""'} - sage: print(s % literals) + sage: print s % literals ['a', "b", 'c', "d\""] - sage: print(strip_string_literals(r'-"\\\""-"\\"-')[0]) + sage: print strip_string_literals(r'-"\\\""-"\\"-')[0] -%(L1)s-%(L2)s- Triple-quotes are handled as well:: @@ -331,7 +331,7 @@ def strip_string_literals(code, state=No sage: s, literals, state = strip_string_literals("[a, '''b''', c, '']") sage: s '[a, %(L1)s, c, %(L2)s]' - sage: print(s % literals) + sage: print s % literals [a, '''b''', c, ''] Comments are substitute too:: @@ -449,9 +449,8 @@ def containing_block(code, ix, delimiter sage: s = "factor(next_prime(L[5]+1))" sage: s[22] '+' - sage: start, end = containing_block(s, 22) - sage: start, end - (17, 25) + sage: start, end = containing_block(s, 22); print start, end + 17 25 sage: s[start:end] '(L[5]+1)' sage: s[20] @@ -524,9 +523,9 @@ def parse_ellipsis(code, preparse_step=T sage: [1.0..2.0] [1.00000000000000, 2.00000000000000] - TESTS: + TESTS: - Check that nested ellipsis is processed correctly (:trac:`17378`):: + Check that nested ellipsis is processed correctly (:trac:`17378`):: sage: preparse('[1,..,2,..,len([1..3])]') '(ellipsis_range(Integer(1),Ellipsis,Integer(2),Ellipsis,len((ellipsis_range(Integer(1),Ellipsis,Integer(3))))))' @@ -586,9 +585,9 @@ def extract_numeric_literals(code): sage: from sage.repl.preparse import extract_numeric_literals sage: code, nums = extract_numeric_literals("1.2 + 5") - sage: print(code) + sage: print code _sage_const_1p2 + _sage_const_5 - sage: print(nums) + sage: print nums {'_sage_const_1p2': "RealNumber('1.2')", '_sage_const_5': 'Integer(5)'} sage: extract_numeric_literals("[1, 1.1, 1e1, -1e-1, 1.]")[0] @@ -662,9 +661,9 @@ def preparse_numeric_literals(code, extr sage: preparse_numeric_literals("0x10.sqrt()") 'Integer(0x10).sqrt()' sage: preparse_numeric_literals('0o100') - 'Integer(0o100)' + "Integer('100', 8)" sage: preparse_numeric_literals('0b111001') - 'Integer(0b111001)' + "Integer('111001', 2)" sage: preparse_numeric_literals('0xe') 'Integer(0xe)' sage: preparse_numeric_literals('0xEAR') @@ -721,18 +720,25 @@ def preparse_numeric_literals(code, extr end += 1 num += '.' - num_name = numeric_literal_prefix + num.replace('.', 'p').replace('-', 'n').replace('+', '') - if 'J' in postfix: - num_make = "ComplexNumber(0, '%s')" % num - num_name += 'j' - elif len(num) < 2 or num[1] in 'oObBxX': - num_make = "Integer(%s)" % num - elif '.' in num or 'e' in num or 'E' in num: - num_make = "RealNumber('%s')" % num - elif num[0] == "0": - num_make = "Integer('%s')" % num + if len(num)>2 and num[1] in 'oObBxX': + # Py3 oct and bin support + num_name = numeric_literal_prefix + num + if num[1] in 'bB': + num_make = "Integer('%s', 2)" % num[2:] + elif num[1] in 'oO': + num_make = "Integer('%s', 8)" % num[2:] + else: + num_make = "Integer(%s)" % num + elif '.' in num or 'e' in num or 'E' in num or 'J' in postfix: + num_name = numeric_literal_prefix + num.replace('.', 'p').replace('-', 'n').replace('+', '') + if 'J' in postfix: + num_make = "ComplexNumber(0, '%s')" % num + num_name += 'j' + else: + num_make = "RealNumber('%s')" % num else: + num_name = numeric_literal_prefix + num num_make = "Integer(%s)" % num literals[num_name] = num_make @@ -1100,7 +1106,7 @@ def preparse(line, reset=True, do_time=F 'a * BackslashOperator() * b \\' sage: preparse("time R. = ZZ[]", do_time=True) - '__time__=misc.cputime(); __wall__=misc.walltime(); R = ZZ[\'x\']; print("Time: CPU %.2f s, Wall: %.2f s"%(misc.cputime(__time__), misc.walltime(__wall__))); (x,) = R._first_ngens(1)' + '__time__=misc.cputime(); __wall__=misc.walltime(); R = ZZ[\'x\']; print "Time: CPU %.2f s, Wall: %.2f s"%(misc.cputime(__time__), misc.walltime(__wall__)); (x,) = R._first_ngens(1)' """ global quote_state if reset: @@ -1171,8 +1177,8 @@ def preparse(line, reset=True, do_time=F if do_time: # Time keyword L = re.sub(r';time;(\s*)(\S[^;]*)', - r';\1__time__=misc.cputime(); __wall__=misc.walltime(); \2; print(' + - '"Time: CPU %%.2f s, Wall: %%.2f s"%%(misc.cputime(__time__), misc.walltime(__wall__)))', + r';\1__time__=misc.cputime(); __wall__=misc.walltime(); \2; print ' + + '"Time: CPU %%.2f s, Wall: %%.2f s"%%(misc.cputime(__time__), misc.walltime(__wall__))', L) # Remove extra ;'s @@ -1216,7 +1222,7 @@ def preparse_file(contents, globals=None sage: from sage.repl.preparse import preparse_file sage: lots_of_numbers = "[%s]" % ", ".join(str(i) for i in range(3000)) sage: _ = preparse_file(lots_of_numbers) - sage: print(preparse_file("type(100r), type(100)")) + sage: print preparse_file("type(100r), type(100)") _sage_const_100 = Integer(100) type(100 ), type(_sage_const_100 ) """ @@ -1424,10 +1430,10 @@ def handle_encoding_declaration(contents Two hash marks are okay; this shows up in SageTeX-generated scripts:: - sage: contents = '## -*- coding: utf-8 -*-\nimport os, sys\nprint(x)' + sage: contents = '## -*- coding: utf-8 -*-\nimport os, sys\nprint x' sage: handle_encoding_declaration(contents, sys.stdout) ## -*- coding: utf-8 -*- - 'import os, sys\nprint(x)' + 'import os, sys\nprint x' When the encoding declaration doesn't match the specification, we spit out a default UTF-8 encoding. @@ -1454,24 +1460,24 @@ def handle_encoding_declaration(contents '#!/usr/local/bin/python\nimport os, sys' - NOTES: + NOTES:: - - PEP 263: http://www.python.org/dev/peps/pep-0263/ + PEP 263: http://www.python.org/dev/peps/pep-0263/ - - PEP 263 says that Python will interpret a UTF-8 byte order mark - as a declaration of UTF-8 encoding, but I don't think we do - that; this function only sees a Python string so it can't - account for a BOM. + PEP 263 says that Python will interpret a UTF-8 byte order mark + as a declaration of UTF-8 encoding, but I don't think we do + that; this function only sees a Python string so it can't + account for a BOM. - - We default to UTF-8 encoding even though PEP 263 says that - Python files should default to ASCII. + We default to UTF-8 encoding even though PEP 263 says that + Python files should default to ASCII. - - Also see http://docs.python.org/ref/encodings.html. + Also see http://docs.python.org/ref/encodings.html. - AUTHORS: + AUTHORS:: - - Lars Fischer - - Dan Drake (2010-12-08, rewrite for :trac:`10440`) + - Lars Fischer + - Dan Drake (2010-12-08, rewrite for ticket #10440) """ lines = contents.splitlines() for num, line in enumerate(lines[:2]): diff -up src/sage/repl/rich_output/backend_base.py.orig src/sage/repl/rich_output/backend_base.py --- src/sage/repl/rich_output/backend_base.py.orig 2016-08-18 13:12:59.143122167 -0400 +++ src/sage/repl/rich_output/backend_base.py 2016-08-18 13:14:03.167124618 -0400 @@ -47,7 +47,6 @@ EXAMPLES:: # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import from sage.structure.sage_object import SageObject @@ -187,27 +186,6 @@ class BackendBase(SageObject): """ raise NotImplementedError('derived classes must implement this method') - def is_in_terminal(self): - """ - Test whether the UI is meant to run in a terminal - - See - :meth:`sage.repl.rich_output.display_manager.DisplayManager.is_in_terminal` - for details. - - OUTPUT: - - Defaults to ``False``. - - EXAMPLES:: - - sage: from sage.repl.rich_output.backend_base import BackendBase - sage: backend = BackendBase() - sage: backend.is_in_terminal() - False - """ - return False - def max_width(self): """ Return the number of characters that fit into one output line @@ -510,8 +488,8 @@ class BackendBase(SageObject): sage: _ # indirect doctest 'foo' """ - from six.moves import builtins - builtins._ = obj + import __builtin__ + __builtin__._ = obj def displayhook(self, plain_text, rich_output): """ diff -up src/sage/repl/rich_output/backend_doctest.py.orig src/sage/repl/rich_output/backend_doctest.py --- src/sage/repl/rich_output/backend_doctest.py.orig 2016-08-18 13:12:59.148122167 -0400 +++ src/sage/repl/rich_output/backend_doctest.py 2016-08-18 13:13:39.071123696 -0400 @@ -86,7 +86,7 @@ class BackendDoctest(BackendBase): backend. EXAMPLES:: - + sage: from sage.repl.rich_output.backend_doctest import BackendDoctest sage: backend = BackendDoctest() sage: backend.install() @@ -104,7 +104,7 @@ class BackendDoctest(BackendBase): should never call it by hand. EXAMPLES:: - + sage: from sage.repl.rich_output.backend_doctest import BackendDoctest sage: backend = BackendDoctest() sage: backend.install() @@ -137,9 +137,6 @@ class BackendDoctest(BackendBase): OutputImagePng, OutputImageGif, OutputImageJpg, OutputImageSvg, OutputImagePdf, OutputImageDvi, OutputSceneJmol, OutputSceneCanvas3d, OutputSceneWavefront, - OutputVideoOgg, OutputVideoWebM, OutputVideoMp4, - OutputVideoFlash, OutputVideoMatroska, OutputVideoAvi, - OutputVideoWmv, OutputVideoQuicktime, ]) def displayhook(self, plain_text, rich_output): @@ -249,14 +246,6 @@ class BackendDoctest(BackendBase): sage: backend.validate(dm.types.OutputSceneJmol.example()) sage: backend.validate(dm.types.OutputSceneWavefront.example()) sage: backend.validate(dm.types.OutputSceneCanvas3d.example()) - sage: backend.validate(dm.types.OutputVideoOgg.example()) - sage: backend.validate(dm.types.OutputVideoWebM.example()) - sage: backend.validate(dm.types.OutputVideoMp4.example()) - sage: backend.validate(dm.types.OutputVideoFlash.example()) - sage: backend.validate(dm.types.OutputVideoMatroska.example()) - sage: backend.validate(dm.types.OutputVideoAvi.example()) - sage: backend.validate(dm.types.OutputVideoWmv.example()) - sage: backend.validate(dm.types.OutputVideoQuicktime.example()) """ if isinstance(rich_output, OutputPlainText): pass @@ -286,34 +275,5 @@ class BackendDoctest(BackendBase): assert rich_output.mtl.get().startswith('newmtl ') elif isinstance(rich_output, OutputSceneCanvas3d): assert rich_output.canvas3d.get().startswith('[{vertices:') - elif isinstance(rich_output, OutputVideoOgg): - assert rich_output.video.get().startswith('OggS') - elif isinstance(rich_output, OutputVideoWebM): - data = rich_output.video.get() - assert data.startswith('\x1a\x45\xdf\xa3') - assert '\x42\x82\x84webm' in data - elif isinstance(rich_output, OutputVideoMp4): - data = rich_output.video.get() - assert data[4:8] == 'ftyp' - assert data.startswith('\0\0\0') - # See http://www.ftyps.com/ - ftyps = [data[i:i+4] for i in range(8, ord(data[3]), 4)] - del ftyps[1] # version number, not an ftyp - expected = ['avc1', 'iso2', 'mp41', 'mp42'] - assert any(i in ftyps for i in expected) - elif isinstance(rich_output, OutputVideoFlash): - assert rich_output.video.get().startswith('FLV\x01') - elif isinstance(rich_output, OutputVideoMatroska): - data = rich_output.video.get() - assert data.startswith('\x1a\x45\xdf\xa3') - assert '\x42\x82\x88matroska' in data - elif isinstance(rich_output, OutputVideoAvi): - data = rich_output.video.get() - assert data[:4] == 'RIFF' and data[8:12] == 'AVI ' - elif isinstance(rich_output, OutputVideoWmv): - assert rich_output.video.get().startswith('\x30\x26\xb2\x75') - elif isinstance(rich_output, OutputVideoQuicktime): - data = rich_output.video.get() - assert data[4:12] == 'ftypqt ' or data[4:8] == 'moov' else: raise TypeError('rich_output type not supported') diff -up src/sage/repl/rich_output/backend_ipython.py.orig src/sage/repl/rich_output/backend_ipython.py --- src/sage/repl/rich_output/backend_ipython.py.orig 2016-08-18 13:12:59.154122167 -0400 +++ src/sage/repl/rich_output/backend_ipython.py 2016-08-18 13:14:14.599125056 -0400 @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- encoding: utf-8 -*- """ IPython Backend for the Sage Rich Output System @@ -108,7 +108,6 @@ class BackendIPython(BackendBase): if not formatted: return publish_display_data(data=formatted, metadata=metadata) - class BackendIPythonCommandline(BackendIPython): """ @@ -371,26 +370,38 @@ class BackendIPythonCommandline(BackendI .format(jmol_cmd, launch_script)) return 'Launched jmol viewer for {0}'.format(plain_text) - def is_in_terminal(self): + def launch_sage3d(self, output_wavefront, plain_text): """ - Test whether the UI is meant to run in a terminal + Launch the stand-alone java3d viewer - See - :meth:`sage.repl.rich_output.display_manager.DisplayManager.is_in_terminal` - for details. + INPUT: + + - ``output_wavefront`` -- + :class:`~sage.repl.rich_output.output_graphics3d.OutputSceneWavefront`. The + scene to launch Java3d with. + + - ``plain_text`` -- string. The plain text representation. OUTPUT: - ``True`` for the IPython commandline. + String. Human-readable message indicating that the viewer was launched. EXAMPLES:: sage: from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline sage: backend = BackendIPythonCommandline() - sage: backend.is_in_terminal() - True + sage: from sage.repl.rich_output.output_graphics3d import OutputSceneWavefront + sage: backend.launch_sage3d(OutputSceneWavefront.example(), 'Graphics3d object') + 'Launched Java 3D viewer for Graphics3d object' """ - return True + from sage.env import SAGE_LOCAL + sage3d = os.path.join(SAGE_LOCAL, 'bin', 'sage3d') + obj = output_wavefront.obj_filename() + from sage.doctest import DOCTEST_MODE + if not DOCTEST_MODE: + os.system('{0} {1} 2>/dev/null 1>/dev/null &' + .format(sage3d, obj)) + return 'Launched Java 3D viewer for {0}'.format(plain_text) class BackendIPythonNotebook(BackendIPython): """ @@ -450,8 +461,8 @@ class BackendIPythonNotebook(BackendIPyt False """ return set([ - OutputPlainText, OutputAsciiArt, OutputUnicodeArt, OutputLatex, OutputHtml, + OutputPlainText, OutputAsciiArt, OutputUnicodeArt, OutputLatex, OutputImagePng, OutputImageJpg, OutputImageSvg, OutputImagePdf, OutputSceneJmol, diff -up src/sage/repl/rich_output/backend_sagenb.py.orig src/sage/repl/rich_output/backend_sagenb.py --- src/sage/repl/rich_output/backend_sagenb.py.orig 2016-08-18 13:12:59.160122167 -0400 +++ src/sage/repl/rich_output/backend_sagenb.py 2016-08-18 13:14:20.303125275 -0400 @@ -38,21 +38,6 @@ filenames:: sage: os.path.exists('sage0.png') True sage: os.remove('sage0.png') - -Tables are typeset as html in SageNB:: - - sage: table([1, 2, 3]) -
- - - - - - - - -
-
""" #***************************************************************************** @@ -67,12 +52,10 @@ Tables are typeset as html in SageNB:: import os import stat from sage.misc.cachefunc import cached_method -from sage.misc.html import html from sage.misc.temporary_file import graphics_filename from sage.doctest import DOCTEST_MODE from sage.repl.rich_output.backend_base import BackendBase from sage.repl.rich_output.output_catalog import * -from sage.repl.rich_output.output_video import OutputVideoBase def world_readable(filename): @@ -320,13 +303,12 @@ class BackendSageNB(BackendBase): True """ return set([ - OutputPlainText, OutputAsciiArt, OutputLatex, OutputHtml, + OutputPlainText, OutputAsciiArt, OutputLatex, OutputImagePng, OutputImageGif, OutputImageJpg, OutputImagePdf, OutputImageSvg, SageNbOutputSceneJmol, OutputSceneCanvas3d, - OutputVideoOgg, OutputVideoWebM, OutputVideoMp4, ]) def display_immediately(self, plain_text, rich_output): @@ -382,8 +364,6 @@ class BackendSageNB(BackendBase): rich_output.embed() elif isinstance(rich_output, OutputSceneCanvas3d): self.embed_image(rich_output.canvas3d, '.canvas3d') - elif isinstance(rich_output, OutputVideoBase): - self.embed_video(rich_output) else: raise TypeError('rich_output type not supported, got {0}'.format(rich_output)) @@ -423,11 +403,4 @@ class BackendSageNB(BackendBase): output_buffer.save_as(filename) world_readable(filename) - def embed_video(self, video_output): - filename = graphics_filename(ext=video_output.ext) - video_output.video.save_as(filename) - world_readable(filename) - html(video_output.html_fragment( - url='cell://' + filename, - link_attrs='class="file_link"', - )) + diff -up src/sage/repl/rich_output/display_manager.py.orig src/sage/repl/rich_output/display_manager.py --- src/sage/repl/rich_output/display_manager.py.orig 2016-08-18 13:12:59.166122168 -0400 +++ src/sage/repl/rich_output/display_manager.py 2016-08-18 13:13:01.918122273 -0400 @@ -343,26 +343,6 @@ class DisplayManager(SageObject): """ return self._preferences - def is_in_terminal(self): - """ - Test whether the UI is meant to run in a terminal - - When this method returns ``True``, you can assume that it is - possible to use ``raw_input`` or launch external programs that - take over the input. - - Otherwise, you should assume that the backend runs remotely or - in a pty controlled by another program. Then you should not - launch external programs with a (text or graphical) UI. - - This is used to enable/disable interpreter consoles. - - OUTPUT: - - Boolean. - """ - return self._backend.is_in_terminal() - def check_backend_class(self, backend_class): """ Check that the current backend is an instance of diff -up src/sage/repl/rich_output/output_catalog.py.orig src/sage/repl/rich_output/output_catalog.py --- src/sage/repl/rich_output/output_catalog.py.orig 2016-08-18 13:12:59.172122168 -0400 +++ src/sage/repl/rich_output/output_catalog.py 2016-08-18 13:14:45.136126226 -0400 @@ -40,14 +40,3 @@ from .output_graphics3d import ( OutputSceneWavefront, OutputSceneCanvas3d, ) - -from .output_video import ( - OutputVideoOgg, - OutputVideoWebM, - OutputVideoMp4, - OutputVideoFlash, - OutputVideoMatroska, - OutputVideoAvi, - OutputVideoWmv, - OutputVideoQuicktime, -) diff -up src/sage/repl/rich_output/pretty_print.py.orig src/sage/repl/rich_output/pretty_print.py --- src/sage/repl/rich_output/pretty_print.py.orig 2016-08-18 13:12:59.177122168 -0400 +++ src/sage/repl/rich_output/pretty_print.py 2016-08-18 13:13:01.919122273 -0400 @@ -210,20 +210,23 @@ def pretty_print(*args, **kwds): sage: pretty_print(LatexExpr(r"\frac{x^2 + 1}{x - 2}")) + Iterators and generators are unwrapped:: + + sage: iterator = iter(range(3)); iterator + + sage: pretty_print(iterator) + + TESTS:: sage: plt = plot(sin) sage: pretty_print(plt) # graphics output - sage: pretty_print(ZZ, 123, plt) # optional - latex - + sage: pretty_print(ZZ, 123, plt) # latex output + sage: pretty_print(plt, plt) # graphics output """ - # Support deprecation trac #18292 - if len(args) == 1: - import sage.misc.html - if sage.misc.html.WarnIfNotPrinted.skip_pretty_print(args[0]): - return - + if len(args) == 1 and isinstance(args[0], (types.GeneratorType, collections.Iterator)): + args = tuple(args[0]) dm = get_display_manager() old_preferences_text = dm.preferences.text try: