def push(self, line): """ EXAMPLES:: sage: from sage.misc.interpreter import SagePreparseTransformer sage: spt = SagePreparseTransformer() sage: spt.push('1+1r+2.3^2.3r') "Integer(1)+1+RealNumber('2.3')**2.3" sage: preparser(False) sage: spt.push('2.3^2') '2.3^2' TESTS: Check that syntax errors in the preparser do not crash IPython, see :trac:`14961`. :: sage: bad_syntax = "R.<t> = QQ{]" sage: preparse(bad_syntax) Traceback (most recent call last): ... SyntaxError: Mismatched ']' sage: from sage.misc.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell(bad_syntax) Traceback (most recent call last): ... SyntaxError: Mismatched ']' """ if line is None: self.reset() elif do_preparse and not line.startswith('%'): return preparse(line) else: return line
def preparse_imports_from_sage(interface, line, locals={}): """ The input line is being fed to the given interface. This function extracts any "sage(zzz)"'s, parses them, and replaces them by appropriate objects in the interface. This is used for moving objects from Sage back into the interface. """ import sage_eval i = line.find('%s('%interface_name) n = len(interface_name) if i == -1: i = line.find('sage(') n = 4 if i == -1: return line j = i + line[i:].find(')') expr = line[i+n+1:j] expr = preparser.preparse(expr) s = 'import sage.misc.preparser_ipython; \ sage.misc.preparser_ipython._v_ = sage.misc.preparser_ipython.interface(%s)'%expr #print s __IPYTHON__.runsource(s) #print _v_ line = line[:i] + _v_.name() + line[j+2:] return line
def __call__(self, line, line_number): """ Transform ``line``. INPUT: - ``line`` -- string. The line to be transformed. OUTPUT: A string, the transformed line. EXAMPLES:: sage: from sage.misc.interpreter import SagePreparseTransformer sage: spt = SagePreparseTransformer() sage: spt('2', 0) 'Integer(2)' sage: preparser(False) sage: spt('2', 0) '2' sage: preparser(True) """ if do_preparse and not line.startswith('%'): # we use preparse_file instead of just preparse because preparse_file # automatically prepends attached files return preparse(line, reset=(line_number==0)) else: return line
def preparse_imports_from_sage(self, line): """ Finds occurrences of strings such as ``sage(object)`` in *line*, converts ``object`` to :attr:`shell.interface`, and replaces those strings with their identifier in the new system. This also works with strings such as ``maxima(object`` if :attr:`shell.interface` is ``maxima``. :param line: the line to transform :type line: string .. warning:: This does not parse nested parentheses correctly. Thus, lines like ``sage(a.foo())`` will not work correctly. This can't be done in generality with regular expressions. EXAMPLES:: sage: from sage.misc.interpreter import interface_shell_embed, InterfaceShellTransformer sage: shell = interface_shell_embed(maxima) sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, prefilter_manager=shell.prefilter_manager) sage: ift.shell.ex('a = 3') sage: ift.preparse_imports_from_sage('2 + sage(a)') '2 + sage0 ' sage: maxima.eval('sage0') '3' sage: ift.preparse_imports_from_sage('2 + maxima(a)') '2 + sage1 ' sage: ift.preparse_imports_from_sage('2 + gap(a)') '2 + gap(a)' """ from sage_eval import sage_eval for sage_code in self._sage_import_re.findall(line): expr = preparse(sage_code) result = self.shell.interface(sage_eval(expr, self.shell.user_ns)) self.temporary_objects.append(result) line = self._sage_import_re.sub(' ' + result.name() + ' ', line, 1) return line
def preparse_ipython(line, reset=True): """ TESTS: Make sure #10933 is fixed :: sage: sage.misc.preparser_ipython.preparse_ipython("def foo(str):\n time gp(str)\n\nprint gp('1')") 'def foo(str):\n __time__=misc.cputime(); __wall__=misc.walltime(); gp(str); print "Time: CPU %.2f s, Wall: %.2f s"%(misc.cputime(__time__), misc.walltime(__wall__))\n\nprint gp(\'1\')' """ global num_lines global q_lines L = line.lstrip() if L.startswith('%'): # This should be installed as an Ipython magic command, # but I don't know how yet... L = L[1:].strip() import sage.interfaces.all if L.lower() in sage.interfaces.all.interfaces: switch_interface(L.lower()) return "''" else: # only preparse non-magic lines return line if interface is None: #We could remove do_time=True if #10933 get's fixed upstream return preparser.preparse(line, reset=reset, do_time=True) if L.startswith('?') or L.endswith('?'): L = L.strip('?') interface.help(L) return '' line = preparse_imports_from_sage(interface, line) line = line.rstrip() ends_in_backslash = line.endswith('\\') if ends_in_backslash: line = line.rstrip('\\') num_lines += 1 else: if interface_name in ['gap', 'magma', 'kash', 'singular']: if not line.endswith(';'): line += ';' elif interface_name == 'mathematica': line = 'InputForm[%s]'%line if ends_in_backslash: q_lines.append(line) else: if len(q_lines) > 0: line = ''.join(q_lines) + line q_lines = [] # TODO: do sage substitutions here #t = interface._eval_line(line) t = interface.eval(line) import sage.misc.interpreter if ends_in_backslash: sage.misc.interpreter.set_sage_prompt('.'*len(interface_name)) else: sage.misc.interpreter.set_sage_prompt('%s'%interface_name) #print t #__IPYTHON__.output_hist[len(__IPYTHON__.input_hist_raw)] = t # TODO: this is a very lazy temporary bug fix. # Nobody uses this logging stuff anymore, anyways, because # of the Sage notebook. try: return """logstr(%r)"""%t except UnboundLocalError: return 'logstr("")'
def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, precision=3, seconds=False): """ Accurately measure the wall time required to execute ``stmt``. INPUT: - ``stmt`` -- a text string. - ``globals_dict`` -- a dictionary or ``None`` (default). Evaluate ``stmt`` in the context of the globals dictionary. If not set, the current ``globals()`` dictionary is used. - ``preparse`` -- (default: use globals preparser default) if ``True`` preparse ``stmt`` using the Sage preparser. - ``number`` -- integer, (optional, default: 0), number of loops. - ``repeat`` -- integer, (optional, default: 3), number of repetition. - ``precision`` -- integer, (optional, default: 3), precision of output time. - ``seconds`` -- boolean (default: ``False``). Whether to just return time in seconds. OUTPUT: An instance of ``SageTimeitResult`` unless the optional parameter ``seconds=True`` is passed. In that case, the elapsed time in seconds is returned as a floating-point number. EXAMPLES:: sage: from sage.misc.sage_timeit import sage_timeit sage: sage_timeit('3^100000', globals(), preparse=True, number=50) # random output '50 loops, best of 3: 1.97 ms per loop' sage: sage_timeit('3^100000', globals(), preparse=False, number=50) # random output '50 loops, best of 3: 67.1 ns per loop' sage: a = 10 sage: sage_timeit('a^2', globals(), number=50) # random output '50 loops, best of 3: 4.26 us per loop' If you only want to see the timing and not have access to additional information, just use the ``timeit`` object:: sage: timeit('10^2', number=50) 50 loops, best of 3: ... per loop Using sage_timeit gives you more information though:: sage: s = sage_timeit('10^2', globals(), repeat=1000) sage: len(s.series) 1000 sage: mean(s.series) # random output 3.1298141479492283e-07 sage: min(s.series) # random output 2.9258728027343752e-07 sage: t = stats.TimeSeries(s.series) sage: t.scale(10^6).plot_histogram(bins=20,figsize=[12,6], ymax=2) The input expression can contain newlines (but doctests cannot, so we use ``os.linesep`` here):: sage: from sage.misc.sage_timeit import sage_timeit sage: from os import linesep as CR sage: # sage_timeit(r'a = 2\\nb=131\\nfactor(a^b-1)') sage: sage_timeit('a = 2' + CR + 'b=131' + CR + 'factor(a^b-1)', ... globals(), number=10) 10 loops, best of 3: ... per loop Test to make sure that ``timeit`` behaves well with output:: sage: timeit("print 'Hi'", number=50) 50 loops, best of 3: ... per loop If you want a machine-readable output, use the ``seconds=True`` option:: sage: timeit("print 'Hi'", seconds=True) # random output 1.42555236816e-06 sage: t = timeit("print 'Hi'", seconds=True) sage: t #r random output 3.6010742187499999e-07 TESTS: Make sure that garbage collection is re-enabled after an exception occurs in timeit:: sage: def f(): raise ValueError sage: import gc sage: gc.isenabled() True sage: timeit("f()") Traceback (most recent call last): ... ValueError sage: gc.isenabled() True """ import timeit as timeit_, time, math, preparser, interpreter number=int(number) repeat=int(repeat) precision=int(precision) if preparse is None: preparse = interpreter.do_preparse if preparse: stmt = preparser.preparse(stmt) if stmt == "": return '' units = ["s", "ms", "\xc2\xb5s", "ns"] scaling = [1, 1e3, 1e6, 1e9] timer = timeit_.Timer() # this code has tight coupling to the inner workings of timeit.Timer, # but is there a better way to achieve that the code stmt has access # to the shell namespace? src = timeit_.template % {'stmt': timeit_.reindent(stmt, 8), 'setup': "pass"} code = compile(src, "<magic-timeit>", "exec") ns = {} if not globals_dict: globals_dict = globals() exec code in globals_dict, ns timer.inner = ns["inner"] try: import sys f = sys.stdout sys.stdout = open('/dev/null', 'w') if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 for i in range(1, 5): number *= 5 if timer.timeit(number) >= 0.2: break series = [s/number for s in timer.repeat(repeat, number)] best = min(series) finally: sys.stdout.close() sys.stdout = f import gc gc.enable() if seconds: return best if best > 0.0: order = min(-int(math.floor(math.log10(best)) // 3), 3) else: order = 3 stats = (number, repeat, precision, best * scaling[order], units[order]) return SageTimeitResult(stats,series=series)
def sage_eval(source, locals=None, cmds='', preparse=True): r""" Obtain a Sage object from the input string by evaluating it using Sage. This means calling eval after preparsing and with globals equal to everything included in the scope of ``from sage.all import *``.). INPUT: - ``source`` - a string or object with a _sage_ method - ``locals`` - evaluate in namespace of sage.all plus the locals dictionary - ``cmds`` - string; sequence of commands to be run before source is evaluated. - ``preparse`` - (default: True) if True, preparse the string expression. EXAMPLES: This example illustrates that preparsing is applied. :: sage: eval('2^3') 1 sage: sage_eval('2^3') 8 However, preparsing can be turned off. :: sage: sage_eval('2^3', preparse=False) 1 Note that you can explicitly define variables and pass them as the second option:: sage: x = PolynomialRing(RationalField(),"x").gen() sage: sage_eval('x^2+1', locals={'x':x}) x^2 + 1 This example illustrates that evaluation occurs in the context of ``from sage.all import *``. Even though bernoulli has been redefined in the local scope, when calling ``sage_eval`` the default value meaning of bernoulli is used. Likewise for QQ below. :: sage: bernoulli = lambda x : x^2 sage: bernoulli(6) 36 sage: eval('bernoulli(6)') 36 sage: sage_eval('bernoulli(6)') 1/42 :: sage: QQ = lambda x : x^2 sage: QQ(2) 4 sage: sage_eval('QQ(2)') 2 sage: parent(sage_eval('QQ(2)')) Rational Field This example illustrates setting a variable for use in evaluation. :: sage: x = 5 sage: eval('4/3 + x', {'x':25}) 26 sage: sage_eval('4/3 + x', locals={'x':25}) 79/3 You can also specify a sequence of commands to be run before the expression is evaluated:: sage: sage_eval('p', cmds='K.<x> = QQ[]\np = x^2 + 1') x^2 + 1 If you give commands to execute and a dictionary of variables, then the dictionary will be modified by assignments in the commands:: sage: vars = {} sage: sage_eval('None', cmds='y = 3', locals=vars) sage: vars['y'], parent(vars['y']) (3, Integer Ring) You can also specify the object to evaluate as a tuple. A 2-tuple is assumed to be a pair of a command sequence and an expression; a 3-tuple is assumed to be a triple of a command sequence, an expression, and a dictionary holding local variables. (In this case, the given dictionary will not be modified by assignments in the commands.) :: sage: sage_eval(('f(x) = x^2', 'f(3)')) 9 sage: vars = {'rt2': sqrt(2.0)} sage: sage_eval(('rt2 += 1', 'rt2', vars)) 2.41421356237309 sage: vars['rt2'] 1.41421356237310 This example illustrates how ``sage_eval`` can be useful when evaluating the output of other computer algebra systems. :: sage: R.<x> = PolynomialRing(RationalField()) sage: gap.eval('R:=PolynomialRing(Rationals,["x"]);') 'Rationals[x]' sage: ff = gap.eval('x:=IndeterminatesOfPolynomialRing(R);; f:=x^2+1;'); ff 'x^2+1' sage: sage_eval(ff, locals={'x':x}) x^2 + 1 sage: eval(ff) Traceback (most recent call last): ... RuntimeError: Use ** for exponentiation, not '^', which means xor in Python, and has the wrong precedence. Here you can see eval simply will not work but ``sage_eval`` will. TESTS: We get a nice minimal error message for syntax errors, that still points to the location of the error (in the input string):: sage: sage_eval('RR(22/7]') Traceback (most recent call last): ... File "<string>", line 1 RR(Integer(22)/Integer(7)] ^ SyntaxError: unexpected EOF while parsing :: sage: sage_eval('None', cmds='$x = $y[3] # Does Perl syntax work?') Traceback (most recent call last): ... File "<string>", line 1 $x = $y[Integer(3)] # Does Perl syntax work? ^ SyntaxError: invalid syntax """ if isinstance(source, (list, tuple)): cmds = source[0] if len(source) > 2: locals = copy(source[2]) source = source[1] if not isinstance(source, basestring): raise TypeError, "source must be a string." if locals is None: locals = {} import sage.all if len(cmds): cmd_seq = cmds + '\n_sage_eval_returnval_ = ' + source if preparse: cmd_seq = preparser.preparse_file(cmd_seq) else: if preparse: source = preparser.preparse(source) if len(cmds): exec cmd_seq in sage.all.__dict__, locals return locals['_sage_eval_returnval_'] else: return eval(source, sage.all.__dict__, locals)
def trace(code, preparse=True): r""" Evaluate Sage code using the interactive tracer and return the result. The string ``code`` must be a valid expression enclosed in quotes (no assignments - the result of the expression is returned). In the Sage notebook this just raises a NotImplementedException. INPUT: - ``code`` - str - ``preparse`` - bool (default: True); if True, run expression through the Sage preparser. REMARKS: This function is extremely powerful! For example, if you want to step through each line of execution of, e.g., ``factor(100)``, type :: sage: trace("factor(100)") # not tested then at the (Pdb) prompt type ``s`` (or ``step``), then press return over and over to step through every line of Python that is called in the course of the above computation. Type ``?`` at any time for help on how to use the debugger (e.g., ``l`` lists 11 lines around the current line; ``bt`` gives a back trace, etc.). Setting a break point: If you have some code in a file and would like to drop into the debugger at a given point, put the following code at that point in the file: ``import pdb; pdb.set_trace()`` For an article on how to use the Python debugger, see http://www.onlamp.com/pub/a/python/2005/09/01/debugger.html TESTS: The only real way to test this is via pexpect spawning a sage subprocess that uses IPython. :: sage: import pexpect sage: s = pexpect.spawn('sage') sage: _ = s.sendline("trace('print factor(10)'); print 3+97") sage: _ = s.sendline("s"); _ = s.sendline("c"); sage: _ = s.expect('100', timeout=90) Seeing the ipdb prompt and the 2 \* 5 in the output below is a strong indication that the trace command worked correctly. :: sage: print s.before[s.before.find('-'):] ---... ipdb> c 2 * 5 We test what happens in notebook embedded mode:: sage: sage.plot.plot.EMBEDDED_MODE = True sage: trace('print factor(10)') Traceback (most recent call last): ... NotImplementedError: the trace command is not implemented in the Sage notebook; you must use the command line. """ from sage.plot.plot import EMBEDDED_MODE if EMBEDDED_MODE: raise NotImplementedError, "the trace command is not implemented in the Sage notebook; you must use the command line." from IPython.core.debugger import Pdb pdb = Pdb() try: ipython = get_ipython() except NameError: raise NotImplementedError("the trace command can only be run from the Sage command-line") import preparser code = preparser.preparse(code) return pdb.run(code, ipython.user_ns)
def reset(self): preparse('', reset=True)
def preparse_ipython(line, reset=True): global num_lines global q_lines L = line.lstrip() if L.startswith('%'): # This should be installed as an Ipython magic command, # but I don't know how yet... L = L[1:].strip() import sage.interfaces.all if L.lower() in sage.interfaces.all.interfaces: switch_interface(L.lower()) return "''" else: # only preparse non-magic lines return line if interface is None: return preparser.preparse(line, reset=reset) if L.startswith('?') or L.endswith('?'): L = L.strip('?') interface.help(L) return '' line = preparse_imports_from_sage(interface, line) line = line.rstrip() ends_in_backslash = line.endswith('\\') if ends_in_backslash: line = line.rstrip('\\') num_lines += 1 else: if interface_name in ['gap', 'magma', 'kash', 'singular']: if not line.endswith(';'): line += ';' if magma_colon_equals and interface_name == 'magma': line = line.replace(':=','=').replace('=',':=') elif interface_name == 'mathematica': line = 'InputForm[%s]'%line if ends_in_backslash: q_lines.append(line) else: if len(q_lines) > 0: line = ''.join(q_lines) + line q_lines = [] # TODO: do sage substitutions here #t = interface._eval_line(line) t = interface.eval(line) import sage.misc.interpreter if ends_in_backslash: sage.misc.interpreter.set_sage_prompt('.'*len(interface_name)) else: sage.misc.interpreter.set_sage_prompt('%s'%interface_name) #print t #__IPYTHON__.output_hist[len(__IPYTHON__.input_hist_raw)] = t # TODO: this is a very lazy temporary bug fix. # Nobody uses this logging stuff anymore, anyways, because # of the SAGE notebook. try: return """logstr(%r)"""%t except UnboundLocalError: return 'logstr("")'
def trace(code, preparse=True): r""" Evaluate Sage code using the interactive tracer and return the result. The string ``code`` must be a valid expression enclosed in quotes (no assignments - the result of the expression is returned). In the Sage notebook this just raises a NotImplementedException. INPUT: - ``code`` - str - ``preparse`` - bool (default: True); if True, run expression through the Sage preparser. REMARKS: This function is extremely powerful! For example, if you want to step through each line of execution of, e.g., ``factor(100)``, type :: sage: trace("factor(100)") # not tested then at the (Pdb) prompt type ``s`` (or ``step``), then press return over and over to step through every line of Python that is called in the course of the above computation. Type ``?`` at any time for help on how to use the debugger (e.g., ``l`` lists 11 lines around the current line; ``bt`` gives a back trace, etc.). Setting a break point: If you have some code in a file and would like to drop into the debugger at a given point, put the following code at that point in the file: ``import pdb; pdb.set_trace()`` For an article on how to use the Python debuger, see http://www.onlamp.com/pub/a/python/2005/09/01/debugger.html TESTS: The only real way to test this is via pexpect spawning a sage subprocess that uses IPython. :: sage: import pexpect sage: s = pexpect.spawn('sage') sage: _ = s.sendline("trace('print factor(10)'); print 3+97") sage: _ = s.sendline("s"); _ = s.sendline("c"); sage: _ = s.expect('100') Seeing the ipdb prompt and the 2 \* 5 in the output below is a strong indication that the trace command worked correctly. :: sage: print s.before[s.before.find('-'):] ---... ipdb> c 2 * 5 We test what happens in notebook embedded mode:: sage: sage.plot.plot.EMBEDDED_MODE = True sage: trace('print factor(10)') Traceback (most recent call last): ... NotImplementedError: the trace command is not implemented in the Sage notebook; you must use the command line. """ from sage.plot.plot import EMBEDDED_MODE if EMBEDDED_MODE: raise NotImplementedError, "the trace command is not implemented in the Sage notebook; you must use the command line." import IPython.Debugger pdb = IPython.Debugger.Pdb() import IPython.ipapi _ip = IPython.ipapi.get() import preparser code = preparser.preparse(code) return pdb.run(code, _ip.user_ns)
def sage_timeit(stmt, globals, preparse=None, number = 0, repeat = 3, precision = 3): """ INPUT: stmt -- a text string which may globals -- evaluate stmt in the context of the globals dictionary preparse -- (default: use global preparser default) if True preparse stmt using the Sage preparser. EXAMPLES: sage: from sage.misc.sage_timeit import sage_timeit sage: sage_timeit('3^100000', globals(), preparse=True, number=50) # random output '50 loops, best of 3: 1.97 ms per loop' sage: sage_timeit('3^100000', globals(), preparse=False, number=50) # random output '50 loops, best of 3: 67.1 ns per loop' sage: a = 10 sage: sage_timeit('a^2', globals(), number=50) # random output '50 loops, best of 3: 4.26 us per loop' It's usually better to use the timeit object, usually: sage: timeit('10^2', number=50) 50 loops, best of 3: ... per loop The input expression can contain newlines: sage: from sage.misc.sage_timeit import sage_timeit sage: sage_timeit("a = 2\nb=131\nfactor(a^b-1)", globals(), number=10) 10 loops, best of 3: ... per loop Test to make sure that timeit behaves well with output: sage: timeit("print 'Hi'", number=50) 50 loops, best of 3: ... per loop Make sure that garbage collection is renabled after an exception occurs in timeit. TESTS: sage: def f(): raise ValueError sage: import gc sage: gc.isenabled() True sage: timeit("f()") Traceback (most recent call last): ... ValueError sage: gc.isenabled() True """ number=int(number) repeat=int(repeat) precision=int(precision) if preparse is None: preparse = interpreter.do_preparse if preparse: stmt = preparser.preparse(stmt) if stmt == "": return '' units = ["s", "ms", "\xc2\xb5s", "ns"] scaling = [1, 1e3, 1e6, 1e9] timer = timeit_.Timer() # this code has tight coupling to the inner workings of timeit.Timer, # but is there a better way to achieve that the code stmt has access # to the shell namespace? src = timeit_.template % {'stmt': timeit_.reindent(stmt, 8), 'setup': "pass"} code = compile(src, "<magic-timeit>", "exec") ns = {} exec code in globals, ns timer.inner = ns["inner"] try: import sys f = sys.stdout sys.stdout = open('/dev/null', 'w') if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 for i in range(1, 5): number *= 5 if timer.timeit(number) >= 0.2: break best = min(timer.repeat(repeat, number)) / number finally: sys.stdout.close() sys.stdout = f import gc gc.enable() if best > 0.0: order = min(-int(math.floor(math.log10(best)) // 3), 3) else: order = 3 stats = (number, repeat, precision, best * scaling[order], units[order]) return SageTimeitResult(stats)