Python-level error messages don't give the source file name

43 views
Skip to first unread message

Jonathan Thornburg

unread,
Jan 8, 2022, 9:56:30 PM1/8/22
to sage-...@googlegroups.com
I've noticed that some (many) Python-level error messages (e.g., syntax
errors) from Sage 9.5.beta8 fail to give the name of the source file
in which the error occured. For example, a few minutes ago I got this
error message from a Sage code I'm working on:

> Traceback (most recent call last):
>
> File "/usr/local/sage/sage-9.5.beta8/local/var/lib/sage/venv-python3.7/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3441, in run_code
> exec(code_obj, self.user_global_ns, self.user_ns)
>
> File "<ipython-input-2-6e41d69a86f4>", line 1, in <module>
> load('setup.sage')
>
> File "sage/misc/persist.pyx", line 173, in sage.misc.persist.load (build/cythonized/sage/misc/persist.c:2578)
> sage.repl.load.load(filename, globals())
>
> File "/usr/local/sage/sage-9.5.beta8/local/var/lib/sage/venv-python3.7/lib/python3.7/site-packages/sage/repl/load.py", line 272, in load
> exec(preparse_file(f.read()) + "\n", globals)
>
> File "<string>", line 8, in <module>
>
> File "sage/misc/persist.pyx", line 173, in sage.misc.persist.load (build/cythonized/sage/misc/persist.c:2578)
> sage.repl.load.load(filename, globals())
>
> File "/usr/local/sage/sage-9.5.beta8/local/var/lib/sage/venv-python3.7/lib/python3.7/site-packages/sage/repl/load.py", line 272, in load
> exec(preparse_file(f.read()) + "\n", globals)
>
> File "<string>", line 66
> P_xx[a,b] = simplify_expression(
> ^
> IndentationError: expected an indented block
>
> sage:

Notice that the traceback entries mentioning Sage internal files all
include the file name and line number, but the traceback errors for my
own code just say 'File "<string>"', with no useful information about
which of my source-code files the error occured in.

I'm not sure how much of this is Python's fault and how much is Sage's,
but the user experience is not good.

To reproduce this problem, create the following 2 files:
% head error*
==> error1.sage <==
load('error2.sage')
print bad_function(2, 3)

==> error2.sage <==
def bad_function(x,y)
"""
Note the missing ':' at the end of the first line of this file.
This will produce a Sage/python syntax error when this file
is loaded.
"""
return x+y
%
and type
load('error1.sage')
at the sage command prompt.

stay safe and COVID-free,
--
-- "Jonathan Thornburg [remove color- to reply]" <jthor...@pink-gmail.com>
on the west coast of Canada, eh?
"There was of course no way of knowing whether you were being watched
at any given moment. How often, or on what system, the Thought Police
plugged in on any individual wire was guesswork. It was even conceivable
that they watched everybody all the time." -- George Orwell, "1984"

Michael Orlitzky

unread,
Jan 8, 2022, 10:24:10 PM1/8/22
to sage-...@googlegroups.com
On 2022-01-08 18:56:21, Jonathan Thornburg wrote:
> I've noticed that some (many) Python-level error messages (e.g., syntax
> errors) from Sage 9.5.beta8 fail to give the name of the source file
> in which the error occured. For example, a few minutes ago I got this
> error message from a Sage code I'm working on:
>

I think the load() method has been superseded by whatever magic ipython
offers. I'm not an expert, but I think

sage: %run <file>

will give you a better error message.

Jonathan Thornburg

unread,
Jan 9, 2022, 2:27:51 AM1/9/22
to sage-...@googlegroups.com
I wrote:
> I've noticed that some (many) Python-level error messages (e.g., syntax
> errors) from Sage 9.5.beta8 fail to give the name of the source file
> in which the error occured. [[...]]

On Sat, Jan 08, 2022 at 10:24:07PM -0500, Michael Orlitzky replied:
> I think the load() method has been superseded by whatever magic ipython
> offers. I'm not an expert, but I think
>
> sage: %run <file>
>
> will give you a better error message.

Thanks for the suggestion. A bit of poking around shows that the sage
input
sage: run 'file-name'
will work nicely. (There's no initial '%' sign -- the sage preparser
adds that back on.)

Alas, this is ONLY valid at the top-level ipython/sage REPL. Inside
a 'run-ed' file, the run command doesn't work (it's a syntax error
regardless of whether it's spelled 'run' or '%run').


More generally, suppose I have a bunch of Sage assignments-to-globals
and function definitions in several files, say
foo.sage
bar.sage
baz.sage
what's the idiomatic way for some other piece of Sage source code to
execute the contents of all of those files? What I've been doing is
to create another file (say 'setup.sage') which contains the lines
load('foo.sage')
load('bar.sage')
load('baz.sage')
so that
load('setup.sage')
(either at the interactive Sage prompt or in another source file) loads
all the individual files. This works fine apart from the un-helpful
error messages when (not if, *when*) I have bugs in my code. Is there
a more idiomatic way?

Michael Orlitzky

unread,
Jan 10, 2022, 4:05:28 PM1/10/22
to sage-...@googlegroups.com
On Sat, 2022-01-08 at 23:27 -0800, Jonathan Thornburg wrote:
> what's the idiomatic way for some other piece of Sage source code to
> execute the contents of all of those files? What I've been doing is
> to create another file (say 'setup.sage') which contains the lines
> load('foo.sage')
> load('bar.sage')
> load('baz.sage')
> so that
> load('setup.sage')
> (either at the interactive Sage prompt or in another source file) loads
> all the individual files. This works fine apart from the un-helpful
> error messages when (not if, *when*) I have bugs in my code. Is there
> a more idiomatic way?
>
>

Since you haven't received a better reply... as soon as my own code
starts to span multiple files, I stop thinking of it as a series of
commands to be fed to the sage interpreter, and instead start thinking
of it as a python program/library.

Globals are always tricky, but in your example I might define a
function

def initialize_globals():
...

in foo.py so that whatever you consider to be the "main program" can
run e.g.

from sage.all import *
from foo import initialize_globals
from baz import compute_stuff

initialize_globals()
result = compute_stuff()
print(result)

Beware that you won't get preparsing this way, but otherwise, this more
or less allows you to write a well-structured python library using all
of the features of sage.


Reply all
Reply to author
Forward
0 new messages