ASKSAGE: Sage Q&A Forum - RSS feedhttps://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Mon, 08 Jun 2020 21:15:11 +0200importing .sage fileshttps://ask.sagemath.org/question/7867/importing-sage-files/What's the recommended approach for importing .sage scripts as a module, i.e. into their own namespace? I have a file with ~10k functions and it'd be much nicer to keep them filed tidily away.
I've written a hack sage_import wrapper which seems to work for my use case, but hopefully there's a better way. Thu, 13 Jan 2011 10:19:28 +0100https://ask.sagemath.org/question/7867/importing-sage-files/Comment by kcrisman for <p>What's the recommended approach for importing .sage scripts as a module, i.e. into their own namespace? I have a file with ~10k functions and it'd be much nicer to keep them filed tidily away.</p>
<p>I've written a hack sage_import wrapper which seems to work for my use case, but hopefully there's a better way. </p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22289#post-id-22289Maybe you can post your hack as an edit to your post?Thu, 13 Jan 2011 10:39:12 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22289#post-id-22289Answer by Hilder Vitor Lima Pereira for <p>What's the recommended approach for importing .sage scripts as a module, i.e. into their own namespace? I have a file with ~10k functions and it'd be much nicer to keep them filed tidily away.</p>
<p>I've written a hack sage_import wrapper which seems to work for my use case, but hopefully there's a better way. </p>
https://ask.sagemath.org/question/7867/importing-sage-files/?answer=48909#post-id-48909Just to make @niles' answer more explicit: You can add the following function to the beginning of your main sage script.
## Hack to import my own sage scripts
def my_import(module_name, func_name='*'):
import os
os.system('sage --preparse ' + module_name + '.sage')
os.system('mv ' + module_name + '.sage.py ' + module_name + '.py')
from sage.misc.python import Python
python = Python()
python.eval('from ' + module_name + ' import ' + func_name, globals())
Then, to import all functions from my_lib.sage, you can do
my_import("my_lib") # from my_lib import *
To import a particular function, say my_func, you can do
my_import("my_lib", "my_func") # from my_lib import my_func
(I created this function using [this solution](https://nadiah.org/2015/07/22/import-self-made-sage-modules-and-functions-into-sage-script/))Wed, 27 Nov 2019 16:34:18 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?answer=48909#post-id-48909Comment by Iguananaut for <p>Just to make <a href="/users/33/niles/">@niles</a>' answer more explicit: You can add the following function to the beginning of your main sage script. </p>
<pre><code>## Hack to import my own sage scripts
def my_import(module_name, func_name='*'):
import os
os.system('sage --preparse ' + module_name + '.sage')
os.system('mv ' + module_name + '.sage.py ' + module_name + '.py')
from sage.misc.python import Python
python = Python()
python.eval('from ' + module_name + ' import ' + func_name, globals())
</code></pre>
<p>Then, to import all functions from my_lib.sage, you can do</p>
<pre><code>my_import("my_lib") # from my_lib import *
</code></pre>
<p>To import a particular function, say my_func, you can do</p>
<pre><code>my_import("my_lib", "my_func") # from my_lib import my_func
</code></pre>
<p>(I created this function using <a href="https://nadiah.org/2015/07/22/import-self-made-sage-modules-and-functions-into-sage-script/">this solution</a>)</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=48945#post-id-48945You can access the Sage preparser as a function call--no need to use `os.system` for any of this. I'll post an answer with a simplified solution.Thu, 05 Dec 2019 12:12:41 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=48945#post-id-48945Answer by Iguananaut for <p>What's the recommended approach for importing .sage scripts as a module, i.e. into their own namespace? I have a file with ~10k functions and it'd be much nicer to keep them filed tidily away.</p>
<p>I've written a hack sage_import wrapper which seems to work for my use case, but hopefully there's a better way. </p>
https://ask.sagemath.org/question/7867/importing-sage-files/?answer=48947#post-id-48947Here's a rough sketch of a `sage_import` that works similarly to the Python import statement on `.sage` files, including searching `sys.path` for the file (which by default includes your current working directory), but this part is optional I suppose.
# sage_import.py
import imp
import inspect
import os
import sys
import sage.all
def sage_import(modname, fromlist=None, namespace=None):
"""
Import a .sage module from the filename <modname>.sage
Returns the resulting Python module. If ``fromlist`` is given, returns
just those members of the module into the global namespace where the
function was called, or the given namespace.
"""
filename = modname + '.sage'
for path in sys.path:
modpath = os.path.join(path, filename)
if os.path.isfile(modpath):
break
else:
raise ImportError('no file {} on sys.path'.format(filename))
with open(modpath) as fobj:
code = sage.all.preparse(fobj.read())
mod = imp.new_module(modname)
mod.__file__ = modpath
# Fill with all the default Sage globals
# We could just do a dict.update but we want to exclude dunder
# and private attributes I guess
for k, v in sage.all.__dict__.items():
if not k.startswith('_'):
mod.__dict__[k] = v
exec code in mod.__dict__
if namespace is None:
namespace = inspect.currentframe().f_back.f_globals
if fromlist is not None:
# First check that each name in fromlist exists before adding
# any of them to the given namespace.
for name in fromlist:
if name not in mod.__dict__:
raise ImportError('cannot import name {!r} from {}'.format(
name, filename))
for name in fromlist:
namespace[name] = mod.__dict__[name]
else:
namespace[modname] = mod
Given a file in my current directory named `a.sage` containing:
# a.sage
a = 1 / 2
I can use this either in Sage or in a standard Python interpreter like
>>> from sage_import import sage_import
>>> sage_import('a', fromlist=['a'])
>>> a
1/2
>>> type(a)
<type 'sage.rings.rational.Rational'>
This version works for Python 2. It can be adapted to Python 3 with some small tweaks.
There is an [open issue](https://trac.sagemath.org/ticket/27074) to build this functionality directly into Sage so that you can use the standard `import` statement to import .sage modules. This can be done but it requires a bit of care. I think a prototype was started at one point but it still hasn't been submitted.
Thu, 05 Dec 2019 12:45:44 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?answer=48947#post-id-48947Comment by Emmanuel Charpentier for <p>Here's a rough sketch of a <code>sage_import</code> that works similarly to the Python import statement on <code>.sage</code> files, including searching <code>sys.path</code> for the file (which by default includes your current working directory), but this part is optional I suppose.</p>
<pre><code># sage_import.py
import imp
import inspect
import os
import sys
import sage.all
def sage_import(modname, fromlist=None, namespace=None):
"""
Import a .sage module from the filename <modname>.sage
Returns the resulting Python module. If ``fromlist`` is given, returns
just those members of the module into the global namespace where the
function was called, or the given namespace.
"""
filename = modname + '.sage'
for path in sys.path:
modpath = os.path.join(path, filename)
if os.path.isfile(modpath):
break
else:
raise ImportError('no file {} on sys.path'.format(filename))
with open(modpath) as fobj:
code = sage.all.preparse(fobj.read())
mod = imp.new_module(modname)
mod.__file__ = modpath
# Fill with all the default Sage globals
# We could just do a dict.update but we want to exclude dunder
# and private attributes I guess
for k, v in sage.all.__dict__.items():
if not k.startswith('_'):
mod.__dict__[k] = v
exec code in mod.__dict__
if namespace is None:
namespace = inspect.currentframe().f_back.f_globals
if fromlist is not None:
# First check that each name in fromlist exists before adding
# any of them to the given namespace.
for name in fromlist:
if name not in mod.__dict__:
raise ImportError('cannot import name {!r} from {}'.format(
name, filename))
for name in fromlist:
namespace[name] = mod.__dict__[name]
else:
namespace[modname] = mod
</code></pre>
<p>Given a file in my current directory named <code>a.sage</code> containing:</p>
<pre><code># a.sage
a = 1 / 2
</code></pre>
<p>I can use this either in Sage or in a standard Python interpreter like</p>
<pre><code>>>> from sage_import import sage_import
>>> sage_import('a', fromlist=['a'])
>>> a
1/2
>>> type(a)
<type 'sage.rings.rational.Rational'>
</code></pre>
<p>This version works for Python 2. It can be adapted to Python 3 with some small tweaks. </p>
<p>There is an <a href="https://trac.sagemath.org/ticket/27074">open issue</a> to build this functionality directly into Sage so that you can use the standard <code>import</code> statement to import .sage modules. This can be done but it requires a bit of care. I think a prototype was started at one point but it still hasn't been submitted.</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=48951#post-id-48951See a somewhat related [comment](https://trac.sagemath.org/ticket/27074#comment:11) in the [ticket](https://trac.sagemath.org/ticket/27074).Thu, 05 Dec 2019 17:23:15 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=48951#post-id-48951Answer by niles for <p>What's the recommended approach for importing .sage scripts as a module, i.e. into their own namespace? I have a file with ~10k functions and it'd be much nicer to keep them filed tidily away.</p>
<p>I've written a hack sage_import wrapper which seems to work for my use case, but hopefully there's a better way. </p>
https://ask.sagemath.org/question/7867/importing-sage-files/?answer=11922#post-id-11922You could instead apply the [sage preparser](http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing), resulting in a `.py` file which you can then import with no trouble.
If you call "`sage filename.sage`", sage will preparse and store `filename.py` in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that
"`sage --preparse filename.sage`"
will do just the preparsing :)
NilesThu, 13 Jan 2011 11:25:32 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?answer=11922#post-id-11922Comment by kcrisman for <p>You could instead apply the <a href="http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing">sage preparser</a>, resulting in a <code>.py</code> file which you can then import with no trouble. </p>
<p>If you call "<code>sage filename.sage</code>", sage will preparse and store <code>filename.py</code> in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that </p>
<p>"<code>sage --preparse filename.sage</code>" </p>
<p>will do just the preparsing :)</p>
<p>Niles</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22286#post-id-22286I like this, though I don't know if it is answering DSM's question. It would be nice to have something like `attach('foo.sage',global_namespace=False)` available for those who use it from the command line - if that's what DSM is asking.Thu, 13 Jan 2011 13:34:08 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22286#post-id-22286Comment by Ivan Andrus for <p>You could instead apply the <a href="http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing">sage preparser</a>, resulting in a <code>.py</code> file which you can then import with no trouble. </p>
<p>If you call "<code>sage filename.sage</code>", sage will preparse and store <code>filename.py</code> in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that </p>
<p>"<code>sage --preparse filename.sage</code>" </p>
<p>will do just the preparsing :)</p>
<p>Niles</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22280#post-id-22280I haven't seen any problems with just running `sage --preparse FILE.sage`. What problems do you have?Sat, 15 Jan 2011 09:03:57 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22280#post-id-22280Comment by niles for <p>You could instead apply the <a href="http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing">sage preparser</a>, resulting in a <code>.py</code> file which you can then import with no trouble. </p>
<p>If you call "<code>sage filename.sage</code>", sage will preparse and store <code>filename.py</code> in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that </p>
<p>"<code>sage --preparse filename.sage</code>" </p>
<p>will do just the preparsing :)</p>
<p>Niles</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22279#post-id-22279Ah *that's* the command I was looking for! `sage-preparse` is a separate executable which needs to be called in the right way, which I couldn't figure out; passing the `--preparse` option to sage seems to do the trick. Thanks!Sat, 15 Jan 2011 10:27:47 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22279#post-id-22279Comment by dsejas for <p>You could instead apply the <a href="http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing">sage preparser</a>, resulting in a <code>.py</code> file which you can then import with no trouble. </p>
<p>If you call "<code>sage filename.sage</code>", sage will preparse and store <code>filename.py</code> in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that </p>
<p>"<code>sage --preparse filename.sage</code>" </p>
<p>will do just the preparsing :)</p>
<p>Niles</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=48911#post-id-48911Hello, I have created a library with pure *.sage files. From the point of view of Python, this is not a valid library, but from Sage's point of view it is correct. I was just about to ask this same question on the forum because of this.
While I am developing the library, it would be really annoying to have to go though the `sage --preparse` process over and over again, every time I add a new function, in order to test and debug. Also I think this process is error-prone. Maybe there is a special syntax like `import <module_name>` for sage?Wed, 27 Nov 2019 22:26:28 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=48911#post-id-48911Comment by niles for <p>You could instead apply the <a href="http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing">sage preparser</a>, resulting in a <code>.py</code> file which you can then import with no trouble. </p>
<p>If you call "<code>sage filename.sage</code>", sage will preparse and store <code>filename.py</code> in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that </p>
<p>"<code>sage --preparse filename.sage</code>" </p>
<p>will do just the preparsing :)</p>
<p>Niles</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22277#post-id-22277ah; that is annoyingSat, 15 Jan 2011 11:22:58 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22277#post-id-22277Comment by DSM for <p>You could instead apply the <a href="http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing">sage preparser</a>, resulting in a <code>.py</code> file which you can then import with no trouble. </p>
<p>If you call "<code>sage filename.sage</code>", sage will preparse and store <code>filename.py</code> in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that </p>
<p>"<code>sage --preparse filename.sage</code>" </p>
<p>will do just the preparsing :)</p>
<p>Niles</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22278#post-id-22278Well, invoking the functions in sage.misc.preparser is what my hack currently does. One problem with preparser approaches -- mine included, at least so far -- is that the resulting code shows up in a mymodule.somefunc?? call in its postprocessed form, which is often hard to read. (Enough __sage_const_ bits floating around and even simple formulae look confusing.) This gives writing Sage code _in Sage code_ a weirdly second-class status. I'm leaning towards modifying the .func_code.co_* data so that I can see what I actually wrote [possibly putting the post-processed version below it]; this is a little tricky, though.Sat, 15 Jan 2011 11:13:59 +0100https://ask.sagemath.org/question/7867/importing-sage-files/?comment=22278#post-id-22278Comment by Giles Gardam for <p>You could instead apply the <a href="http://www.sagemath.org/doc/developer/coding_in_python.html#sage-preparsing">sage preparser</a>, resulting in a <code>.py</code> file which you can then import with no trouble. </p>
<p>If you call "<code>sage filename.sage</code>", sage will preparse and store <code>filename.py</code> in the same directory (as well as carrying out all the commands in the file, which will be problematic in some cases). @ivan-andrus points out that </p>
<p>"<code>sage --preparse filename.sage</code>" </p>
<p>will do just the preparsing :)</p>
<p>Niles</p>
https://ask.sagemath.org/question/7867/importing-sage-files/?comment=51841#post-id-51841Preparsing `filename.sage` creates `filename.sage.py` rather than `filename.py` (perhaps behaviour changed since 2011?) necessitating a `mv filename.sage.py filename.py` before it can be imported, as per the solution below by @"Hilder VĂtor Lima Pereira".Mon, 08 Jun 2020 21:15:11 +0200https://ask.sagemath.org/question/7867/importing-sage-files/?comment=51841#post-id-51841