Beispiel #1
0
    def _install_spec(self):
        """
        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::

            sage: from sage.repl.ipython_kernel.install import SageKernelSpec
            sage: spec = SageKernelSpec()
            sage: spec._install_spec()    # not tested
        """
        import json

        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 launch_script_filename(self):
        """
        Return a launch script suitable to display the scene.

        This method saves the scene to disk and creates a launch
        script. The latter contains an absolute path to the scene
        file. The launch script is often necessary to make jmol
        render the 3d scene.

        OUTPUT:

        String. The file name of a suitable launch script.

        EXAMPLES::

            sage: from sage.repl.rich_output.output_catalog import OutputSceneJmol
            sage: rich_output = OutputSceneJmol.example();  rich_output
            OutputSceneJmol container
            sage: filename = rich_output.launch_script_filename();  filename
            '/.../scene.spt'
            sage: with open(filename) as fobj:
            ....:     print(fobj.read())
            set defaultdirectory "/.../scene.spt.zip"
            script SCRIPT
        """
        from sage.misc.temporary_file import tmp_dir
        basedir = tmp_dir()
        scene_filename = os.path.join(basedir, 'scene.spt.zip')
        script_filename = os.path.join(basedir, 'scene.spt')
        self.scene_zip.save_as(scene_filename)
        with open(script_filename, 'w') as f:
            f.write('set defaultdirectory "{0}"\n'.format(scene_filename))
            f.write('script SCRIPT\n')
        return script_filename
Beispiel #3
0
    def launch_script_filename(self):
        """
        Return a launch script suitable to display the scene.

        This method saves the scene to disk and creates a launch
        script. The latter contains an absolute path to the scene
        file. The launch script is often necessary to make jmol
        render the 3d scene.

        OUTPUT:

        String. The file name of a suitable launch script.

        EXAMPLES::

            sage: from sage.repl.rich_output.output_catalog import OutputSceneJmol
            sage: rich_output = OutputSceneJmol.example();  rich_output
            OutputSceneJmol container
            sage: filename = rich_output.launch_script_filename();  filename
            '/.../scene.spt'
            sage: print(open(filename).read())
            set defaultdirectory "/.../scene.spt.zip"
            script SCRIPT
        """
        from sage.misc.temporary_file import tmp_dir
        basedir = tmp_dir()
        scene_filename = os.path.join(basedir, 'scene.spt.zip')
        script_filename = os.path.join(basedir, 'scene.spt')
        self.scene_zip.save_as(scene_filename)
        with open(script_filename, 'w') as f:
            f.write('set defaultdirectory "{0}"\n'.format(scene_filename))
            f.write('script SCRIPT\n')
        return script_filename
Beispiel #4
0
 def __init__(self, n, time):
     self._n = n
     if time:
         cmd = 'time QuadraticSieve'
     else:
         cmd = 'QuadraticSieve'
     env = os.environ.copy()
     env['TMPDIR'] = tmp_dir('qsieve')
     self._p = SageSpawn(cmd, env=env)
     cleaner.cleaner(self._p.pid, 'QuadraticSieve')
     self._p.sendline(str(self._n) + '\n\n\n')
     self._done = False
     self._out = ''
     self._time = ''
     self._do_time = time
Beispiel #5
0
    def obj_filename(self):
        """
        Return the file name of the ``.obj`` file

        This method saves the object and texture to separate files in
        a temporary directory and returns the object file name. This
        is often used to launch a 3d viewer.

        OUTPUT:

        String. The file name (absolute path) of the saved obj file.

        EXAMPLES::

            sage: from sage.repl.rich_output.output_catalog import OutputSceneWavefront
            sage: rich_output = OutputSceneWavefront.example();  rich_output
            OutputSceneWavefront container
            sage: obj = rich_output.obj_filename();  obj
            '/.../scene.obj'
            sage: with open(obj) as fobj:
            ....:     print(fobj.read())
            mtllib scene.mtl
            g obj_1
            ...
            f 3 2 6 8

            sage: path = os.path.dirname(obj)
            sage: mtl = os.path.join(path, 'scene.mtl');  mtl
            '/.../scene.mtl'
            sage: os.path.exists(mtl)
            True
            sage: os.path.dirname(obj) == os.path.dirname(mtl)
            True
            sage: with open(mtl) as fobj:
            ....:     print(fobj.read())
            newmtl texture177
            Ka 0.2 0.2 0.5
            ...
            d 1
        """
        from sage.misc.temporary_file import tmp_dir
        basedir = tmp_dir()
        obj_filename = os.path.join(basedir, 'scene.obj')
        mtl_filename = os.path.join(basedir, self.mtllib())
        self.obj.save_as(obj_filename)
        self.mtl.save_as(mtl_filename)
        return os.path.abspath(obj_filename)
    def obj_filename(self):
        """
        Return the file name of the ``.obj`` file

        This method saves the object and texture to separate files in
        a temporary directory and returns the object file name. This
        is often used to launch a 3d viewer.

        OUTPUT:

        String. The file name (absolute path) of the saved obj file.

        EXAMPLES::

            sage: from sage.repl.rich_output.output_catalog import OutputSceneWavefront
            sage: rich_output = OutputSceneWavefront.example();  rich_output
            OutputSceneWavefront container
            sage: obj = rich_output.obj_filename();  obj
            '/.../scene.obj'
            sage: with open(obj) as fobj:
            ....:     print(fobj.read())
            mtllib scene.mtl
            g obj_1
            ...
            f 3 2 6 8

            sage: path = os.path.dirname(obj)
            sage: mtl = os.path.join(path, 'scene.mtl');  mtl
            '/.../scene.mtl'
            sage: os.path.exists(mtl)
            True
            sage: os.path.dirname(obj) == os.path.dirname(mtl)
            True
            sage: with open(mtl) as fobj:
            ....:     print(fobj.read())
            newmtl texture177
            Ka 0.2 0.2 0.5
            ...
            d 1
        """
        from sage.misc.temporary_file import tmp_dir
        basedir = tmp_dir()
        obj_filename = os.path.join(basedir, 'scene.obj')
        mtl_filename = os.path.join(basedir, self.mtllib())
        self.obj.save_as(obj_filename)
        self.mtl.save_as(mtl_filename)
        return os.path.abspath(obj_filename)
Beispiel #7
0
    def directory(self):
        r"""
        Return the directory where the input files for 4ti2 are
        written by Sage and where 4ti2 is run.

        EXAMPLES::

            sage: from sage.interfaces.four_ti_2 import FourTi2
            sage: f = FourTi2("/tmp/")
            sage: f.directory()
            '/tmp/'
        """
        from sage.misc.temporary_file import tmp_dir
        if self._directory is None:
            # we have to put this here rather than in the __init__
            # method since apparently importing sage.misc.misc does not
            # work until Sage is done starting up.
            self._directory = tmp_dir()
        return self._directory
Beispiel #8
0
    def directory(self):
        r"""
        Return the directory where the input files for 4ti2 are
        written by Sage and where 4ti2 is run.

        EXAMPLES::

            sage: from sage.interfaces.four_ti_2 import FourTi2
            sage: f = FourTi2("/tmp/")
            sage: f.directory()
            '/tmp/'
        """
        from sage.misc.temporary_file import tmp_dir
        if self._directory is None:
            # we have to put this here rather than in the __init__
            # method since apparently importing sage.misc.misc does not
            # work until Sage is done starting up.
            self._directory = tmp_dir()
        return self._directory
Beispiel #9
0
    def png(self, dir=None):
        r"""
        Render PNG images of the frames in this animation, saving them
        in ``dir``.  Return the absolute path to that directory.  If
        the frames have been previously rendered and ``dir`` is
        ``None``, just return the directory in which they are stored.

        When ``dir`` is other than ``None``, force re-rendering of
        frames.

        INPUT:

        - ``dir`` -- Directory in which to store frames.  Default
          ``None``; in this case, a temporary directory will be
          created for storing the frames.

        EXAMPLES::

            sage: a = animate([plot(x^2 + n) for n in range(4)])
            sage: d = a.png()
            sage: v = os.listdir(d); v.sort(); v
            ['00000000.png', '00000001.png', '00000002.png', '00000003.png']
        """
        if dir is None:
            try:
                return self._png_dir
            except AttributeError:
                pass
            d = tmp_dir()
        else:
            d = dir
        G = self._frames
        for i, frame in enumerate(self._frames):
            filename = '%s/%s'%(d,sage.misc.misc.pad_zeros(i,8))
            try:
                frame.save_image(filename + '.png', **self._kwds)
            except AttributeError:
                self.make_image(frame, filename + '.png', **self._kwds)
        self._png_dir = d
        return d
Beispiel #10
0
    def png(self, dir=None):
        r"""
        Render PNG images of the frames in this animation, saving them
        in ``dir``.  Return the absolute path to that directory.  If
        the frames have been previously rendered and ``dir`` is
        ``None``, just return the directory in which they are stored.

        When ``dir`` is other than ``None``, force re-rendering of
        frames.

        INPUT:

        - ``dir`` -- Directory in which to store frames.  Default
          ``None``; in this case, a temporary directory will be
          created for storing the frames.

        EXAMPLES::

            sage: a = animate([plot(x^2 + n) for n in range(4)])
            sage: d = a.png()
            sage: v = os.listdir(d); v.sort(); v
            ['00000000.png', '00000001.png', '00000002.png', '00000003.png']
        """
        if dir is None:
            try:
                return self._png_dir
            except AttributeError:
                pass
            d = tmp_dir()
        else:
            d = dir
        G = self._frames
        for i, frame in enumerate(self._frames):
            filename = '%s/%s'%(d,sage.misc.misc.pad_zeros(i,8))
            try:
                frame.save_image(filename + '.png', **self._kwds)
            except AttributeError:
                self.make_image(frame, filename + '.png', **self._kwds)
        self._png_dir = d
        return d
Beispiel #11
0
    def png(self, dir=None):
        """
        Return the absolute path to a temp directory that contains the
        rendered PNG's of all the images in this animation.

        EXAMPLES::

            sage: a = animate([plot(x^2 + n) for n in range(4)])
            sage: d = a.png()
            sage: v = os.listdir(d); v.sort(); v
            ['00000000.png', '00000001.png', '00000002.png', '00000003.png']
        """
        try:
            return self._png_dir
        except AttributeError:
            pass
        d = tmp_dir()
        G = self._frames
        for i, frame in enumerate(self._frames):
            filename = '%s/%s'%(d,sage.misc.misc.pad_zeros(i,8))
            frame.save(filename + '.png', **self._kwds)
        self._png_dir = d
        return d
Beispiel #12
0
    def png(self, dir=None):
        """
        Return the absolute path to a temp directory that contains the
        rendered PNG's of all the images in this animation.

        EXAMPLES::

            sage: a = animate([plot(x^2 + n) for n in range(4)])
            sage: d = a.png()
            sage: v = os.listdir(d); v.sort(); v
            ['00000000.png', '00000001.png', '00000002.png', '00000003.png']
        """
        try:
            return self._png_dir
        except AttributeError:
            pass
        d = tmp_dir()
        G = self._frames
        for i, frame in enumerate(self._frames):
            filename = '%s/%s' % (d, sage.misc.misc.pad_zeros(i, 8))
            frame.save(filename + '.png', **self._kwds)
        self._png_dir = d
        return d
Beispiel #13
0
def qsieve_block(n, time, verbose=False):
    """
    Compute the factorization of n using Hart's quadratic Sieve
    blocking until complete.
    """

    cmd = ['QuadraticSieve']
    if time:
        cmd = ['time'] + cmd

    env = os.environ.copy()
    env['TMPDIR'] = tmp_dir('qsieve')
    p = sp.Popen(cmd,
                 env=env,
                 stdout=sp.PIPE,
                 stderr=sp.STDOUT,
                 stdin=sp.PIPE,
                 encoding='latin1')
    out, err = p.communicate(str(n))
    z = data_to_list(out, n, time=time)
    if verbose:
        print(z[-1])
    return z[:2]
Beispiel #14
0
    def _install_spec(self):
        """
        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::

            sage: from sage.repl.ipython_kernel.install import SageKernelSpec
            sage: spec = SageKernelSpec()
            sage: spec._install_spec()    # not tested
        """
        import json
        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)
Beispiel #15
0
    def eval(self, x, globals=None, locals=None):
        """
        EXAMPLES::
        
            sage: from sage.misc.inline_fortran import InlineFortran, _example
            sage: fortran = InlineFortran(globals())
            sage: fortran(_example)
            sage: import numpy
            sage: n = numpy.array(range(10),dtype=float)
            sage: fib(n,int(10))
            sage: n
            array([  0.,   1.,   1.,   2.,   3.,   5.,   8.,  13.,  21.,  34.])

        TESTS::

            sage: os.chdir(SAGE_ROOT)
            sage: fortran.eval("SYNTAX ERROR !@#$")
            Traceback (most recent call last):
            ...
            RuntimeError: failed to compile Fortran code:...
            sage: os.getcwd() == SAGE_ROOT
            True
        """
        if len(x.splitlines()) == 1 and os.path.exists(x):
            filename = x
            x = open(x).read()
            if filename.lower().endswith('.f90'):
                x = '!f90\n' + x

        from numpy import f2py

        # Create everything in a temporary directory
        mytmpdir = tmp_dir()

        try:
            old_cwd = os.getcwd()
            os.chdir(mytmpdir)

            old_import_path = os.sys.path
            os.sys.path.append(mytmpdir)
    
            name = "fortran_module"  # Python module name
            # if the first line has !f90 as a comment, gfortran will
            # treat it as Fortran 90 code
            if x.startswith('!f90'):
                fortran_file = name + '.f90'
            else:
                fortran_file = name + '.f'
    
            s_lib_path = ""
            s_lib = ""
            for s in self.library_paths:
                s_lib_path = s_lib_path + "-L%s "
    
            for s in self.libraries:
                s_lib = s_lib + "-l%s "%s
    
            log = name + ".log"
            extra_args = '--quiet --f77exec=sage-inline-fortran --f90exec=sage-inline-fortran %s %s >"%s" 2>&1'%(
                s_lib_path, s_lib, log)
    
            f2py.compile(x, name, extra_args = extra_args, source_fn=fortran_file)
            log_string = open(log).read()
    
            # f2py.compile() doesn't raise any exception if it fails.
            # So we manually check whether the compiled file exists.
            # NOTE: the .so extension is used, even on OS X where .dylib
            # might be expected.
            soname = name + '.so'
            if not os.path.isfile(soname):
                raise RuntimeError("failed to compile Fortran code:\n" + log_string)
    
            if self.verbose:
                print log_string
            
            m = __builtin__.__import__(name)
        finally:
            os.sys.path = old_import_path
            os.chdir(old_cwd)
            try:
                import shutil
                shutil.rmtree(mytmpdir)
            except OSError:
                # This can fail for example over NFS
                pass
        
        for k, x in m.__dict__.iteritems():
            if k[0] != '_':
                self.globals[k] = x
Beispiel #16
0
    def eval(self, x, globals=None, locals=None):
        """
        Compile fortran code ``x`` and adds the functions in it to
        ``globals``.

        INPUT:

        - ``x`` -- Fortran code

        - ``globals`` -- a dict to which to add the functions from the
          fortran module

        - ``locals`` -- ignored

        EXAMPLES::

            sage: code = '''
            ....: C FILE: FIB1.F
            ....:       SUBROUTINE FIB(A,N)
            ....: C
            ....: C     CALCULATE FIRST N FIBONACCI NUMBERS
            ....: C
            ....:       INTEGER N
            ....:       REAL*8 A(N)
            ....:       DO I=1,N
            ....:          IF (I.EQ.1) THEN
            ....:             A(I) = 0.0D0
            ....:          ELSEIF (I.EQ.2) THEN
            ....:             A(I) = 1.0D0
            ....:          ELSE
            ....:             A(I) = A(I-1) + A(I-2)
            ....:          ENDIF
            ....:       ENDDO
            ....:       END
            ....: C END FILE FIB1.F
            ....: '''
            sage: fortran(code, globals())
            sage: import numpy
            sage: a = numpy.array(range(10), dtype=float)
            sage: fib(a, 10)
            sage: a
            array([  0.,   1.,   1.,   2.,   3.,   5.,   8.,  13.,  21.,  34.])

        TESTS::

            sage: os.chdir(SAGE_ROOT)
            sage: fortran.eval("SYNTAX ERROR !@#$")
            Traceback (most recent call last):
            ...
            RuntimeError: failed to compile Fortran code:...
            sage: os.getcwd() == SAGE_ROOT
            True
        """
        if len(x.splitlines()) == 1 and os.path.exists(x):
            from sage.misc.superseded import deprecation
            deprecation(
                2891,
                "Calling fortran() with a filename is deprecated, use fortran(open(f).read) instead"
            )
            filename = x
            x = open(x).read()
            if filename.lower().endswith('.f90'):
                x = '!f90\n' + x

        if globals is None:
            globals = self.globs

        from numpy import f2py

        # Create everything in a temporary directory
        mytmpdir = tmp_dir()

        try:
            old_cwd = os.getcwd()
            os.chdir(mytmpdir)

            name = "fortran_module"  # Python module name
            # if the first line has !f90 as a comment, gfortran will
            # treat it as Fortran 90 code
            if x.startswith('!f90'):
                fortran_file = name + '.f90'
            else:
                fortran_file = name + '.f'

            s_lib_path = ""
            s_lib = ""
            for s in self.library_paths:
                s_lib_path = s_lib_path + "-L%s "

            for s in self.libraries:
                s_lib = s_lib + "-l%s " % s

            log = name + ".log"
            extra_args = '--quiet --f77exec=sage-inline-fortran --f90exec=sage-inline-fortran %s %s >"%s" 2>&1' % (
                s_lib_path, s_lib, log)

            f2py.compile(x,
                         name,
                         extra_args=extra_args,
                         source_fn=fortran_file)
            log_string = open(log).read()

            # Note that f2py() doesn't raise an exception if it fails.
            # In that case, the import below will fail.
            try:
                file, pathname, description = imp.find_module(name, [mytmpdir])
            except ImportError:
                raise RuntimeError("failed to compile Fortran code:\n" +
                                   log_string)
            try:
                m = imp.load_module(name, file, pathname, description)
            finally:
                file.close()

            if self.verbose:
                print(log_string)
        finally:
            os.chdir(old_cwd)
            try:
                shutil.rmtree(mytmpdir)
            except OSError:
                # This can fail for example over NFS
                pass

        for k, x in m.__dict__.iteritems():
            if k[0] != '_':
                globals[k] = x
Beispiel #17
0
    def eval(self, x, globals=None, locals=None):
        """
        Compile fortran code ``x`` and adds the functions in it to
        ``globals``.

        INPUT:

        - ``x`` -- Fortran code

        - ``globals`` -- a dict to which to add the functions from the
          fortran module

        - ``locals`` -- ignored

        EXAMPLES::

            sage: code = '''
            ....: C FILE: FIB1.F
            ....:       SUBROUTINE FIB(A,N)
            ....: C
            ....: C     CALCULATE FIRST N FIBONACCI NUMBERS
            ....: C
            ....:       INTEGER N
            ....:       REAL*8 A(N)
            ....:       DO I=1,N
            ....:          IF (I.EQ.1) THEN
            ....:             A(I) = 0.0D0
            ....:          ELSEIF (I.EQ.2) THEN
            ....:             A(I) = 1.0D0
            ....:          ELSE
            ....:             A(I) = A(I-1) + A(I-2)
            ....:          ENDIF
            ....:       ENDDO
            ....:       END
            ....: C END FILE FIB1.F
            ....: '''
            sage: fortran(code, globals())
            sage: import numpy
            sage: a = numpy.array(range(10), dtype=float)
            sage: fib(a, 10)
            sage: a
            array([  0.,   1.,   1.,   2.,   3.,   5.,   8.,  13.,  21.,  34.])

        TESTS::

            sage: os.chdir(SAGE_ROOT)
            sage: fortran.eval("SYNTAX ERROR !@#$")
            Traceback (most recent call last):
            ...
            RuntimeError: failed to compile Fortran code:...
            sage: os.getcwd() == SAGE_ROOT
            True
        """
        if len(x.splitlines()) == 1 and os.path.exists(x):
            from sage.misc.superseded import deprecation
            deprecation(2891, "Calling fortran() with a filename is deprecated, use fortran(open(f).read) instead")
            filename = x
            x = open(x).read()
            if filename.lower().endswith('.f90'):
                x = '!f90\n' + x

        if globals is None:
            globals = self.globs

        from numpy import f2py

        # Create everything in a temporary directory
        mytmpdir = tmp_dir()

        try:
            old_cwd = os.getcwd()
            os.chdir(mytmpdir)

            name = "fortran_module"  # Python module name
            # if the first line has !f90 as a comment, gfortran will
            # treat it as Fortran 90 code
            if x.startswith('!f90'):
                fortran_file = name + '.f90'
            else:
                fortran_file = name + '.f'

            s_lib_path = ""
            s_lib = ""
            for s in self.library_paths:
                s_lib_path = s_lib_path + "-L%s "

            for s in self.libraries:
                s_lib = s_lib + "-l%s "%s

            log = name + ".log"
            extra_args = '--quiet --f77exec=sage-inline-fortran --f90exec=sage-inline-fortran %s %s >"%s" 2>&1'%(
                s_lib_path, s_lib, log)

            f2py.compile(x, name, extra_args = extra_args, source_fn=fortran_file)
            log_string = open(log).read()

            # Note that f2py() doesn't raise an exception if it fails.
            # In that case, the import below will fail.
            try:
                file, pathname, description = imp.find_module(name, [mytmpdir])
            except ImportError:
                raise RuntimeError("failed to compile Fortran code:\n" + log_string)
            try:
                m = imp.load_module(name, file, pathname, description)
            finally:
                file.close()

            if self.verbose:
                print(log_string)
        finally:
            os.chdir(old_cwd)
            try:
                shutil.rmtree(mytmpdir)
            except OSError:
                # This can fail for example over NFS
                pass

        for k, x in m.__dict__.iteritems():
            if k[0] != '_':
                globals[k] = x
Beispiel #18
0
    def run_val_gdb(self, testing=False):
        """
        Spawns a subprocess to run tests under the control of gdb or valgrind.

        INPUT:

        - ``testing`` -- boolean; if True then the command to be run
          will be printed rather than a subprocess started.

        EXAMPLES:

        Note that the command lines include unexpanded environment
        variables. It is safer to let the shell expand them than to
        expand them here and risk insufficient quoting. ::

            sage: from sage.doctest.control import DocTestDefaults, DocTestController
            sage: DD = DocTestDefaults(gdb=True)
            sage: DC = DocTestController(DD, ["hello_world.py"])
            sage: DC.run_val_gdb(testing=True)
            exec gdb -x "...sage-gdb-commands" --args sage-runtests --serial --timeout=0 hello_world.py

        ::

            sage: DD = DocTestDefaults(valgrind=True, optional="all", timeout=172800)
            sage: DC = DocTestController(DD, ["hello_world.py"])
            sage: DC.run_val_gdb(testing=True)
            exec valgrind --tool=memcheck --leak-resolution=high --leak-check=full --num-callers=25 --suppressions="...valgrind/pyalloc.supp" --suppressions="...valgrind/sage.supp" --suppressions="...valgrind/sage-additional.supp"  --log-file=".../valgrind/sage-memcheck.%p" sage-runtests --serial --timeout=172800 --optional=all hello_world.py
        """
        try:
            sage_cmd = self._assemble_cmd()
        except ValueError:
            self.log(sys.exc_info()[1])
            return 2
        opt = self.options
        if opt.gdb:
            cmd = '''exec gdb -x "%s" --args ''' % (os.path.join(
                SAGE_VENV, "bin", "sage-gdb-commands"))
            flags = ""
            if opt.logfile:
                sage_cmd += " --logfile %s" % (opt.logfile)
        else:
            if opt.logfile is None:
                default_log = os.path.join(DOT_SAGE, "valgrind")
                if os.path.exists(default_log):
                    if not os.path.isdir(default_log):
                        self.log("%s must be a directory" % default_log)
                        return 2
                else:
                    os.makedirs(default_log)
                logfile = os.path.join(default_log, "sage-%s")
            else:
                logfile = opt.logfile
            if opt.valgrind:
                toolname = "memcheck"
                flags = os.getenv("SAGE_MEMCHECK_FLAGS")
                if flags is None:
                    flags = "--leak-resolution=high --leak-check=full --num-callers=25 "
                    flags += '''--suppressions="%s" ''' % (os.path.join(
                        SAGE_EXTCODE, "valgrind", "pyalloc.supp"))
                    flags += '''--suppressions="%s" ''' % (os.path.join(
                        SAGE_EXTCODE, "valgrind", "sage.supp"))
                    flags += '''--suppressions="%s" ''' % (os.path.join(
                        SAGE_EXTCODE, "valgrind", "sage-additional.supp"))
            elif opt.massif:
                toolname = "massif"
                flags = os.getenv("SAGE_MASSIF_FLAGS", "--depth=6 ")
            elif opt.cachegrind:
                toolname = "cachegrind"
                flags = os.getenv("SAGE_CACHEGRIND_FLAGS", "")
            elif opt.omega:
                toolname = "exp-omega"
                flags = os.getenv("SAGE_OMEGA_FLAGS", "")
            cmd = "exec valgrind --tool=%s " % (toolname)
            flags += ''' --log-file="%s" ''' % logfile
            if opt.omega:
                toolname = "omega"
            if "%s" in flags:
                flags %= toolname + ".%p"  # replace %s with toolname
        cmd += flags + sage_cmd

        sys.stdout.flush()
        sys.stderr.flush()
        self.log(cmd)

        if testing:
            return

        # Setup signal handlers.
        # Save crash logs in temporary directory.
        os.putenv('CYSIGNALS_CRASH_LOGS', tmp_dir("crash_logs_"))
        init_cysignals()

        import signal
        import subprocess
        p = subprocess.Popen(cmd, shell=True)
        if opt.timeout > 0:
            signal.alarm(opt.timeout)
        try:
            return p.wait()
        except AlarmInterrupt:
            self.log("    Timed out")
            return 4
        except KeyboardInterrupt:
            self.log("    Interrupted")
            return 128
        finally:
            signal.alarm(0)
            if p.returncode is None:
                p.terminate()
Beispiel #19
0
    def eval(self, x, globals=None, locals=None):
        """
        Compile fortran code ``x`` and adds the functions in it to
        ``globals``.

        INPUT:

        - ``x`` -- Fortran code

        - ``globals`` -- a dict to which to add the functions from the
          fortran module

        - ``locals`` -- ignored

        EXAMPLES::

            sage: code = '''
            ....: C FILE: FIB1.F
            ....:       SUBROUTINE FIB(A,N)
            ....: C
            ....: C     CALCULATE FIRST N FIBONACCI NUMBERS
            ....: C
            ....:       INTEGER N
            ....:       REAL*8 A(N)
            ....:       DO I=1,N
            ....:          IF (I.EQ.1) THEN
            ....:             A(I) = 0.0D0
            ....:          ELSEIF (I.EQ.2) THEN
            ....:             A(I) = 1.0D0
            ....:          ELSE
            ....:             A(I) = A(I-1) + A(I-2)
            ....:          ENDIF
            ....:       ENDDO
            ....:       END
            ....: C END FILE FIB1.F
            ....: '''
            sage: fortran(code, globals())
            sage: import numpy
            sage: a = numpy.array(range(10), dtype=float)
            sage: fib(a, 10)
            sage: a
            array([  0.,   1.,   1.,   2.,   3.,   5.,   8.,  13.,  21.,  34.])

        TESTS::

            sage: os.chdir(SAGE_ROOT)
            sage: fortran.eval("SYNTAX ERROR !@#$")
            Traceback (most recent call last):
            ...
            RuntimeError: failed to compile Fortran code:...
            sage: os.getcwd() == SAGE_ROOT
            True
        """
        if globals is None:
            globals = self.globs
            if globals is None:
                from sage.repl.user_globals import get_globals
                globals = get_globals()

        from numpy import f2py

        # Create everything in a temporary directory
        mytmpdir = tmp_dir()

        try:
            old_cwd = os.getcwd()
            os.chdir(mytmpdir)

            name = "fortran_module"  # Python module name
            # if the first line has !f90 as a comment, gfortran will
            # treat it as Fortran 90 code
            if x.startswith('!f90'):
                fortran_file = name + '.f90'
            else:
                fortran_file = name + '.f'

            s_lib_path = ""
            s_lib = ""
            for s in self.library_paths:
                s_lib_path = s_lib_path + "-L%s "

            for s in self.libraries:
                s_lib = s_lib + "-l%s "%s

            log = name + ".log"
            extra_args = ('--quiet --f77exec=sage-inline-fortran '
                          '--f90exec=sage-inline-fortran {lib_path} {lib} '
                          '> {log} 2>&1'.format(lib_path=s_lib_path,
                                                lib=s_lib, log=log))

            f2py.compile(x, name, extra_args=extra_args,
                         source_fn=fortran_file)

            with open(log) as fobj:
                log_string = fobj.read()

            # Note that f2py() doesn't raise an exception if it fails.
            # In that case, the import below will fail.
            try:
                mod = _import_module_from_path(name, [mytmpdir])
            except ImportError:
                raise RuntimeError("failed to compile Fortran code:\n" +
                                   log_string)

            if self.verbose:
                print(log_string)
        finally:
            os.chdir(old_cwd)

            if sys.platform != 'cygwin':
                # Do not delete temporary DLLs on Cygwin; this will cause
                # future forks of this process to fail.  Instead temporary DLLs
                # will be cleaned up upon process exit
                try:
                    shutil.rmtree(mytmpdir)
                except OSError:
                    # This can fail for example over NFS
                    pass

        for k, x in iteritems(mod.__dict__):
            if k[0] != '_':
                globals[k] = x
Beispiel #20
0
import csv
import os
from IPython.display import display, Image
from sage.matrix.constructor import Matrix
from sage.misc.temporary_file import tmp_dir, tmp_filename


dirname = tmp_dir()


def nb_show(graphics_object, ext='.png'):
    name = os.path.join(dirname, tmp_filename(ext=ext))
    graphics_object.save(name)
    display(Image(name))


def matrix_of_csv(fname):
    with open(fname, 'rb') as csvfile:
        mreader = csv.reader(csvfile, delimiter=',', quotechar="'")
        return Matrix([[int(x) for x in row] for row in mreader])
Beispiel #21
0
    def __call__(self, f, inputs):
        """
        Parallel iterator using ``fork()``.

        INPUT:

        - ``f`` -- a function (or more general, any callable)

        - ``inputs`` -- a list of pairs ``(args, kwds)`` to be used as
          arguments to ``f``, where ``args`` is a tuple and ``kwds`` is
          a dictionary.

        OUTPUT:

        EXAMPLES::

            sage: F = sage.parallel.use_fork.p_iter_fork(2,3)
            sage: sorted(list( F( (lambda x: x^2), [([10],{}), ([20],{})])))
            [(([10], {}), 100), (([20], {}), 400)]
            sage: sorted(list( F( (lambda x, y: x^2+y), [([10],{'y':1}), ([20],{'y':2})])))
            [(([10], {'y': 1}), 101), (([20], {'y': 2}), 402)]

        TESTS:

        The output of functions decorated with :func:`parallel` is read
        as a pickle by the parent process. We intentionally break the
        unpickling and demonstrate that this failure is handled
        gracefully (the exception is put in the list instead of the
        answer)::

            sage: Polygen = parallel(polygen)
            sage: list(Polygen([QQ]))
            [(((Rational Field,), {}), x)]
            sage: from sage.misc.persist import unpickle_override, register_unpickle_override
            sage: register_unpickle_override('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint', Integer)
            sage: L = list(Polygen([QQ]))
            sage: L
            [(((Rational Field,), {}),
              'INVALID DATA __init__() takes at most 2 positional arguments (4 given)')]

        Fix the unpickling::

            sage: del unpickle_override[('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')]
            sage: list(Polygen([QQ,QQ]))
            [(((Rational Field,), {}), x), (((Rational Field,), {}), x)]
        """
        n = self.ncpus
        v = list(inputs)
        import os
        import sys
        import signal
        from sage.misc.persist import loads
        from sage.misc.temporary_file import tmp_dir
        dir = tmp_dir()
        timeout = self.timeout

        workers = {}
        try:
            while v or workers:
                # Spawn up to n subprocesses
                while v and len(workers) < n:
                    v0 = v.pop(0)  # Input value for the next subprocess
                    with ContainChildren():
                        pid = os.fork()
                        # The way fork works is that pid returns the
                        # nonzero pid of the subprocess for the master
                        # process and returns 0 for the subprocess.
                        if not pid:
                            # This is the subprocess.
                            self._subprocess(f, dir, *v0)

                    workers[pid] = WorkerData(v0)

                if len(workers) > 0:
                    # Now wait for one subprocess to finish and report the result.
                    # However, wait at most the time since the oldest process started.
                    T = walltime()
                    if timeout:
                        oldest = min(W.starttime for W in workers.values())
                        alarm(max(timeout - (T - oldest), 0.1))

                    try:
                        pid = os.wait()[0]
                        cancel_alarm()
                        W = workers.pop(pid)
                    except AlarmInterrupt:
                        # Kill workers that are too old
                        for pid, W in workers.items():
                            if T - W.starttime > timeout:
                                if self.verbose:
                                    print(
                                        "Killing subprocess %s with input %s which took too long"
                                        % (pid, W.input))
                                os.kill(pid, signal.SIGKILL)
                                W.failure = " (timed out)"
                    except KeyError:
                        # Some other process exited, not our problem...
                        pass
                    else:
                        # collect data from process that successfully terminated
                        sobj = os.path.join(dir, '%s.sobj' % pid)
                        try:
                            with open(sobj, "rb") as file:
                                data = file.read()
                        except IOError:
                            answer = "NO DATA" + W.failure
                        else:
                            os.unlink(sobj)
                            try:
                                answer = loads(data, compress=False)
                            except Exception as E:
                                answer = "INVALID DATA {}".format(E)

                        out = os.path.join(dir, '%s.out' % pid)
                        try:
                            with open(out) as file:
                                sys.stdout.write(file.read())
                            os.unlink(out)
                        except IOError:
                            pass

                        yield (W.input, answer)
        finally:
            # Send SIGKILL signal to workers that are left.
            if workers:
                if self.verbose:
                    print("Killing any remaining workers...")
                sys.stdout.flush()
                for pid in workers:
                    try:
                        os.kill(pid, signal.SIGKILL)
                    except OSError:
                        # If kill() failed, it is most likely because
                        # the process already exited.
                        pass
                    else:
                        try:
                            os.waitpid(pid, 0)
                        except OSError as msg:
                            if self.verbose:
                                print(msg)

            # Clean up all temporary files.
            rmtree(dir)
Beispiel #22
0
    def eval(self, x, globals=None, locals=None):
        """
        EXAMPLES::

            sage: from sage.misc.inline_fortran import InlineFortran, _example
            sage: fortran = InlineFortran(globals())
            sage: fortran(_example)
            sage: import numpy
            sage: n = numpy.array(range(10),dtype=float)
            sage: fib(n,int(10))
            sage: n
            array([  0.,   1.,   1.,   2.,   3.,   5.,   8.,  13.,  21.,  34.])

        TESTS::

            sage: os.chdir(SAGE_ROOT)
            sage: fortran.eval("SYNTAX ERROR !@#$")
            Traceback (most recent call last):
            ...
            RuntimeError: failed to compile Fortran code:...
            sage: os.getcwd() == SAGE_ROOT
            True
        """
        if len(x.splitlines()) == 1 and os.path.exists(x):
            filename = x
            x = open(x).read()
            if filename.lower().endswith('.f90'):
                x = '!f90\n' + x

        from numpy import f2py

        # Create everything in a temporary directory
        mytmpdir = tmp_dir()

        try:
            old_cwd = os.getcwd()
            os.chdir(mytmpdir)

            old_import_path = os.sys.path
            os.sys.path.append(mytmpdir)

            name = "fortran_module"  # Python module name
            # if the first line has !f90 as a comment, gfortran will
            # treat it as Fortran 90 code
            if x.startswith('!f90'):
                fortran_file = name + '.f90'
            else:
                fortran_file = name + '.f'

            s_lib_path = ""
            s_lib = ""
            for s in self.library_paths:
                s_lib_path = s_lib_path + "-L%s "

            for s in self.libraries:
                s_lib = s_lib + "-l%s " % s

            log = name + ".log"
            extra_args = '--quiet --f77exec=sage-inline-fortran --f90exec=sage-inline-fortran %s %s >"%s" 2>&1' % (
                s_lib_path, s_lib, log)

            f2py.compile(x,
                         name,
                         extra_args=extra_args,
                         source_fn=fortran_file)
            log_string = open(log).read()

            # f2py.compile() doesn't raise any exception if it fails.
            # So we manually check whether the compiled file exists.
            # NOTE: the .so extension is used expect on Cygwin,
            # that is even on OS X where .dylib might be expected.
            soname = name
            uname = os.uname()[0].lower()
            if uname[:6] == "cygwin":
                soname += '.dll'
            else:
                soname += '.so'
            if not os.path.isfile(soname):
                raise RuntimeError("failed to compile Fortran code:\n" +
                                   log_string)

            if self.verbose:
                print(log_string)

            m = __builtin__.__import__(name)
        finally:
            os.sys.path = old_import_path
            os.chdir(old_cwd)
            try:
                import shutil
                shutil.rmtree(mytmpdir)
            except OSError:
                # This can fail for example over NFS
                pass

        for k, x in m.__dict__.iteritems():
            if k[0] != '_':
                self.globals[k] = x
Beispiel #23
0
    def eval(self, x, globals=None, locals=None):
        """
        Compile fortran code ``x`` and adds the functions in it to
        ``globals``.

        INPUT:

        - ``x`` -- Fortran code

        - ``globals`` -- a dict to which to add the functions from the
          fortran module

        - ``locals`` -- ignored

        EXAMPLES::

            sage: code = '''
            ....: C FILE: FIB1.F
            ....:       SUBROUTINE FIB(A,N)
            ....: C
            ....: C     CALCULATE FIRST N FIBONACCI NUMBERS
            ....: C
            ....:       INTEGER N
            ....:       REAL*8 A(N)
            ....:       DO I=1,N
            ....:          IF (I.EQ.1) THEN
            ....:             A(I) = 0.0D0
            ....:          ELSEIF (I.EQ.2) THEN
            ....:             A(I) = 1.0D0
            ....:          ELSE
            ....:             A(I) = A(I-1) + A(I-2)
            ....:          ENDIF
            ....:       ENDDO
            ....:       END
            ....: C END FILE FIB1.F
            ....: '''
            sage: fortran(code, globals())
            sage: import numpy
            sage: a = numpy.array(range(10), dtype=float)
            sage: fib(a, 10)
            sage: a
            array([  0.,   1.,   1.,   2.,   3.,   5.,   8.,  13.,  21.,  34.])

        TESTS::

            sage: os.chdir(DOT_SAGE)
            sage: fortran.eval("SYNTAX ERROR !@#$")
            Traceback (most recent call last):
            ...
            RuntimeError: failed to compile Fortran code:...
            sage: os.getcwd() == os.path.realpath(DOT_SAGE)
            True
        """
        if globals is None:
            globals = self.globs
            if globals is None:
                from sage.repl.user_globals import get_globals
                globals = get_globals()

        # Create everything in a temporary directory
        mytmpdir = tmp_dir()

        try:
            old_cwd = os.getcwd()
            os.chdir(mytmpdir)

            name = "fortran_module"  # Python module name
            # if the first line has !f90 as a comment, gfortran will
            # treat it as Fortran 90 code
            if x.startswith('!f90'):
                fortran_file = name + '.f90'
            else:
                fortran_file = name + '.f'

            s_lib_path = ['-L' + p for p in self.library_paths]
            s_lib = ['-l' + l for l in self.libraries]

            with open(fortran_file, 'w') as fobj:
                fobj.write(x)

            # This is basically the same as what f2py.compile() does, but we
            # do it manually here in order to customize running the subprocess
            # a bit more (in particular to capture stderr)
            cmd = [
                sys.executable, '-c', 'import numpy.f2py; numpy.f2py.main()'
            ]

            # What follows are the arguments to f2py itself (appended later
            # just for logical separation)
            cmd += [
                '-c', '-m', name, fortran_file, '--quiet',
                '--f77exec=sage-inline-fortran',
                '--f90exec=sage-inline-fortran'
            ] + s_lib_path + s_lib

            try:
                out = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
            except subprocess.CalledProcessError as exc:
                raise RuntimeError(
                    "failed to compile Fortran code:\n{}".format(exc.output))

            # Note that f2py() doesn't raise an exception if it fails.
            # In that case, the import below will fail.
            try:
                mod = _import_module_from_path(name, [mytmpdir])
            except ImportError as exc:
                # Failed to import the module; include any output from building
                # the module (even though it was ostensibly successful) in case
                # it might help
                msg = "failed to load compiled Fortran code: {}".format(exc)
                if out:
                    msg += '\n' + out
                raise RuntimeError(msg)

            if self.verbose:
                print(out)
        finally:
            os.chdir(old_cwd)

            if sys.platform != 'cygwin':
                # Do not delete temporary DLLs on Cygwin; this will cause
                # future forks of this process to fail.  Instead temporary DLLs
                # will be cleaned up upon process exit
                try:
                    shutil.rmtree(mytmpdir)
                except OSError:
                    # This can fail for example over NFS
                    pass

        for k, x in mod.__dict__.items():
            if k[0] != '_':
                globals[k] = x
Beispiel #24
0
    def run_val_gdb(self, testing=False):
        """
        Spawns a subprocess to run tests under the control of gdb or valgrind.

        INPUT:

        - ``testing`` -- boolean; if True then the command to be run
          will be printed rather than a subprocess started.

        EXAMPLES:

        Note that the command lines include unexpanded environment
        variables. It is safer to let the shell expand them than to
        expand them here and risk insufficient quoting. ::

            sage: from sage.doctest.control import DocTestDefaults, DocTestController
            sage: DD = DocTestDefaults(gdb=True)
            sage: DC = DocTestController(DD, ["hello_world.py"])
            sage: DC.run_val_gdb(testing=True)
            exec gdb -x "$SAGE_LOCAL/bin/sage-gdb-commands" --args python "$SAGE_LOCAL/bin/sage-runtests" --serial --timeout=0 hello_world.py

        ::

            sage: DD = DocTestDefaults(valgrind=True, optional="all", timeout=172800)
            sage: DC = DocTestController(DD, ["hello_world.py"])
            sage: DC.run_val_gdb(testing=True)
            exec valgrind --tool=memcheck --leak-resolution=high --leak-check=full --num-callers=25 --suppressions="$SAGE_EXTCODE/valgrind/pyalloc.supp" --suppressions="$SAGE_EXTCODE/valgrind/sage.supp" --suppressions="$SAGE_EXTCODE/valgrind/sage-additional.supp"  --log-file=".../valgrind/sage-memcheck.%p" python "$SAGE_LOCAL/bin/sage-runtests" --serial --timeout=172800 --optional=all hello_world.py
        """
        try:
            sage_cmd = self._assemble_cmd()
        except ValueError:
            self.log(sys.exc_info()[1])
            return 2
        opt = self.options
        if opt.gdb:
            cmd = '''exec gdb -x "$SAGE_LOCAL/bin/sage-gdb-commands" --args '''
            flags = ""
            if opt.logfile:
                sage_cmd += " --logfile %s"%(opt.logfile)
        else:
            if opt.logfile is None:
                default_log = os.path.join(DOT_SAGE, "valgrind")
                if os.path.exists(default_log):
                    if not os.path.isdir(default_log):
                        self.log("%s must be a directory"%default_log)
                        return 2
                else:
                    os.makedirs(default_log)
                logfile = os.path.join(default_log, "sage-%s")
            else:
                logfile = opt.logfile
            if opt.valgrind:
                toolname = "memcheck"
                flags = os.getenv("SAGE_MEMCHECK_FLAGS")
                if flags is None:
                    flags = "--leak-resolution=high --leak-check=full --num-callers=25 "
                    flags += '''--suppressions="%s" '''%(os.path.join("$SAGE_EXTCODE","valgrind","pyalloc.supp"))
                    flags += '''--suppressions="%s" '''%(os.path.join("$SAGE_EXTCODE","valgrind","sage.supp"))
                    flags += '''--suppressions="%s" '''%(os.path.join("$SAGE_EXTCODE","valgrind","sage-additional.supp"))
            elif opt.massif:
                toolname = "massif"
                flags = os.getenv("SAGE_MASSIF_FLAGS", "--depth=6 ")
            elif opt.cachegrind:
                toolname = "cachegrind"
                flags = os.getenv("SAGE_CACHEGRIND_FLAGS", "")
            elif opt.omega:
                toolname = "exp-omega"
                flags = os.getenv("SAGE_OMEGA_FLAGS", "")
            cmd = "exec valgrind --tool=%s "%(toolname)
            flags += ''' --log-file="%s" ''' % logfile
            if opt.omega:
                toolname = "omega"
            if "%s" in flags:
                flags %= toolname + ".%p" # replace %s with toolname
        cmd += flags + sage_cmd

        sys.stdout.flush()
        sys.stderr.flush()
        self.log(cmd)

        if testing:
            return

        # Setup signal handlers.
        # Save crash logs in temporary directory.
        os.putenv('CYSIGNALS_CRASH_LOGS', tmp_dir("crash_logs_"))
        init_cysignals()

        import signal, subprocess
        p = subprocess.Popen(cmd, shell=True)
        if opt.timeout > 0:
            signal.alarm(opt.timeout)
        try:
            return p.wait()
        except AlarmInterrupt:
            self.log("    Timed out")
            return 4
        except KeyboardInterrupt:
            self.log("    Interrupted")
            return 128
        finally:
            signal.alarm(0)
            if p.returncode is None:
                p.terminate()
Beispiel #25
0
    def __call__(self, f, inputs):
        """
        Parallel iterator using ``fork()``.

        INPUT:

        - ``f`` -- a function (or more general, any callable)

        - ``inputs`` -- a list of pairs ``(args, kwds)`` to be used as
          arguments to ``f``, where ``args`` is a tuple and ``kwds`` is
          a dictionary.

        OUTPUT:

        EXAMPLES::

            sage: F = sage.parallel.use_fork.p_iter_fork(2,3)
            sage: sorted(list( F( (lambda x: x^2), [([10],{}), ([20],{})])))
            [(([10], {}), 100), (([20], {}), 400)]
            sage: sorted(list( F( (lambda x, y: x^2+y), [([10],{'y':1}), ([20],{'y':2})])))
            [(([10], {'y': 1}), 101), (([20], {'y': 2}), 402)]

        TESTS:

        The output of functions decorated with :func:`parallel` is read
        as a pickle by the parent process. We intentionally break the
        unpickling and demonstrate that this failure is handled
        gracefully (the exception is put in the list instead of the
        answer)::

            sage: Polygen = parallel(polygen)
            sage: list(Polygen([QQ]))
            [(((Rational Field,), {}), x)]
            sage: from sage.structure.sage_object import unpickle_override, register_unpickle_override
            sage: register_unpickle_override('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint', Integer)
            sage: L = list(Polygen([QQ]))
            sage: L
            [(((Rational Field,), {}),
              'INVALID DATA __init__() takes at most 2 positional arguments (4 given)')]

        Fix the unpickling::

            sage: del unpickle_override[('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')]
            sage: list(Polygen([QQ,QQ]))
            [(((Rational Field,), {}), x), (((Rational Field,), {}), x)]
        """
        n = self.ncpus
        v = list(inputs)
        import os, sys, signal
        from sage.structure.sage_object import loads
        from sage.misc.temporary_file import tmp_dir
        dir = tmp_dir()
        timeout = self.timeout

        workers = {}
        try:
            while len(v) > 0 or len(workers) > 0:
                # Spawn up to n subprocesses
                while len(v) > 0 and len(workers) < n:
                    v0 = v.pop(0)  # Input value for the next subprocess
                    with ContainChildren():
                        pid = os.fork()
                        # The way fork works is that pid returns the
                        # nonzero pid of the subprocess for the master
                        # process and returns 0 for the subprocess.
                        if not pid:
                            # This is the subprocess.
                            self._subprocess(f, dir, *v0)

                    workers[pid] = WorkerData(v0)

                if len(workers) > 0:
                    # Now wait for one subprocess to finish and report the result.
                    # However, wait at most the time since the oldest process started.
                    T = walltime()
                    if timeout:
                        oldest = min(W.starttime for W in workers.values())
                        alarm(max(timeout - (T - oldest), 0.1))

                    try:
                        pid = os.wait()[0]
                        cancel_alarm()
                        W = workers.pop(pid)
                    except AlarmInterrupt:
                        # Kill workers that are too old
                        for pid, W in workers.items():
                            if T - W.starttime > timeout:
                                if self.verbose:
                                    print(
                                        "Killing subprocess %s with input %s which took too long"
                                         % (pid, W.input) )
                                os.kill(pid, signal.SIGKILL)
                                W.failure = " (timed out)"
                    except KeyError:
                        # Some other process exited, not our problem...
                        pass
                    else:
                        # collect data from process that successfully terminated
                        sobj = os.path.join(dir, '%s.sobj'%pid)
                        try:
                            with open(sobj) as file:
                                data = file.read()
                        except IOError:
                            answer = "NO DATA" + W.failure
                        else:
                            os.unlink(sobj)
                            try:
                                answer = loads(data, compress=False)
                            except Exception as E:
                                answer = "INVALID DATA {}".format(E)

                        out = os.path.join(dir, '%s.out'%pid)
                        try:
                            with open(out) as file:
                                sys.stdout.write(file.read())
                            os.unlink(out)
                        except IOError:
                            pass

                        yield (W.input, answer)
        finally:
            # Send SIGKILL signal to workers that are left.
            if workers:
                if self.verbose:
                    print("Killing any remaining workers...")
                sys.stdout.flush()
                for pid in workers:
                    try:
                        os.kill(pid, signal.SIGKILL)
                    except OSError:
                        # If kill() failed, it is most likely because
                        # the process already exited.
                        pass
                    else:
                        try:
                            os.waitpid(pid, 0)
                        except OSError as msg:
                            if self.verbose:
                                print(msg)

            # Clean up all temporary files.
            rmtree(dir)