コード例 #1
0
ファイル: test-paper.py プロジェクト: WeilerWebServices/SymPy
def main():
    if sympy.__version__ != "1.0":
        sys.exit(
            "The doctests must be run against SymPy 1.0. Please install SymPy 1.0 and run them again."
        )
    full_text = ""

    for file in files:
        with open(file, 'r') as f:
            s = f.read()
            st = s.find(begin)
            while st != -1:
                if not (st >= len(skip)) or s[st - len(skip):st] != skip:
                    full_text += s[st + len(begin):s.find(end, st)]
                st = s.find(begin, st + len(begin))

    full_text = full_text.replace(r'\end{verbatim}', '')

    with open(output_file, "w") as f:
        f.write("'''\n %s \n'''" % full_text)

    # force pprint to be in ascii mode in doctests
    pprint_use_unicode(False)

    # hook our nice, hash-stable strprinter
    init_printing(pretty_print=False)

    import test_full_paper

    # find the doctest
    module = pdoctest._normalize_module(test_full_paper)
    tests = SymPyDocTestFinder().find(module)
    test = tests[0]

    runner = SymPyDocTestRunner(optionflags=pdoctest.ELLIPSIS
                                | pdoctest.NORMALIZE_WHITESPACE
                                | pdoctest.IGNORE_EXCEPTION_DETAIL)
    runner._checker = SymPyOutputChecker()

    old = sys.stdout
    new = StringIO()
    sys.stdout = new

    future_flags = __future__.division.compiler_flag | __future__.print_function.compiler_flag

    try:
        f, t = runner.run(test,
                          compileflags=future_flags,
                          out=new.write,
                          clear_globs=False)
    except KeyboardInterrupt:
        raise
    finally:
        sys.stdout = old

    if f > 0:
        print(new.getvalue())
        return 1
    else:
        return 0
コード例 #2
0
ファイル: test-paper.py プロジェクト: mattcurry/sympy-paper
def main():
    if sympy.__version__ != "1.0":
        sys.exit("The doctests must be run against SymPy 1.0. Please install SymPy 1.0 and run them again.")
    full_text = ""

    for file in files:
        with open(file, 'r') as f:
            s = f.read()
            st = s.find(begin)
            while st != -1:
                if not (st >= len(skip)) or s[st - len(skip) : st] != skip:
                    full_text += s[st + len(begin) : s.find(end, st)]
                st = s.find(begin, st+ len(begin))

    full_text = full_text.replace(r'\end{verbatim}', '')

    with open(output_file, "w") as f:
        f.write("'''\n %s \n'''" % full_text)

    # force pprint to be in ascii mode in doctests
    pprint_use_unicode(False)

    # hook our nice, hash-stable strprinter
    init_printing(pretty_print=False)

    import test_full_paper

    # find the doctest
    module = pdoctest._normalize_module(test_full_paper)
    tests = SymPyDocTestFinder().find(module)
    test = tests[0]

    runner = SymPyDocTestRunner(optionflags=pdoctest.ELLIPSIS |
            pdoctest.NORMALIZE_WHITESPACE |
            pdoctest.IGNORE_EXCEPTION_DETAIL)
    runner._checker = SymPyOutputChecker()

    old = sys.stdout
    new = StringIO()
    sys.stdout = new

    future_flags = __future__.division.compiler_flag | __future__.print_function.compiler_flag

    try:
        f, t = runner.run(test, compileflags=future_flags,
                          out=new.write, clear_globs=False)
    except KeyboardInterrupt:
        raise
    finally:
        sys.stdout = old

    if f > 0:
        print(new.getvalue())
        return 1
    else:
        return 0
コード例 #3
0
def test_debug():
    from sympy.core.compatibility import StringIO
    file = StringIO()
    rl = debug(posdec, file)
    rl(5)
    log = file.getvalue()
    file.close()

    assert get_function_name(posdec) in log
    assert '5' in log
    assert '4' in log
コード例 #4
0
ファイル: test_core.py プロジェクト: AdrianPotter/sympy
def test_debug():
    from sympy.core.compatibility import StringIO
    file = StringIO()
    rl = debug(posdec, file)
    rl(5)
    log = file.getvalue()
    file.close()

    assert get_function_name(posdec) in log
    assert '5' in log
    assert '4' in log
コード例 #5
0
def test_m_code_argument_order():
    expr = x + y
    routine = make_routine("test",
                           expr,
                           argument_sequence=[z, x, y],
                           language="octave")
    code_gen = OctaveCodeGen()
    output = StringIO()
    code_gen.dump_m([routine], output, "test", header=False, empty=False)
    source = output.getvalue()
    expected = ("function out1 = test(z, x, y)\n" "  out1 = x + y;\n" "end\n")
    assert source == expected
コード例 #6
0
def get_string(dump_fn, routines, prefix="file", header=False, empty=False):
    """Wrapper for dump_fn. dump_fn writes its results to a stream object and
       this wrapper returns the contents of that stream as a string. This
       auxiliary function is used by many tests below.

       The header and the empty lines are not generated to facilitate the
       testing of the output.
    """
    output = StringIO()
    dump_fn(routines, output, prefix, header, empty)
    source = output.getvalue()
    output.close()
    return source
コード例 #7
0
def get_string(dump_fn, routines, prefix="file", header=False, empty=False):
    """Wrapper for dump_fn. dump_fn writes its results to a stream object and
       this wrapper returns the contents of that stream as a string. This
       auxiliary function is used by many tests below.

       The header and the empty lines are not generator to facilitate the
       testing of the output.
    """
    output = StringIO()
    dump_fn(routines, output, prefix, header, empty)
    source = output.getvalue()
    output.close()
    return source
コード例 #8
0
def test_m_code_argument_order():
    expr = x + y
    routine = make_routine("test", expr, argument_sequence=[z, x, y], language="octave")
    code_gen = OctaveCodeGen()
    output = StringIO()
    code_gen.dump_m([routine], output, "test", header=False, empty=False)
    source = output.getvalue()
    expected = (
        "function out1 = test(z, x, y)\n"
        "  out1 = x + y;\n"
        "end\n"
    )
    assert source == expected
コード例 #9
0
def test_jl_code_argument_order():
    expr = x + y
    routine = make_routine("test", expr, argument_sequence=[z, x, y], language="julia")
    code_gen = JuliaCodeGen()
    output = StringIO()
    code_gen.dump_jl([routine], output, "test", header=False, empty=False)
    source = output.getvalue()
    expected = (
        "function test(z, x, y)\n"
        "    out1 = x + y\n"
        "    return out1\n"
        "end\n"
    )
    assert source == expected
コード例 #10
0
ファイル: test_codegen_rust.py プロジェクト: baoqchau/sympy
def test_argument_order():
    expr = x + y
    routine = make_routine("test", expr, argument_sequence=[z, x, y], language="rust")
    code_gen = RustCodeGen()
    output = StringIO()
    code_gen.dump_rs([routine], output, "test", header=False, empty=False)
    source = output.getvalue()
    expected = (
        "fn test(z: f64, x: f64, y: f64) -> f64 {\n"
        "    let out1 = x + y;\n"
        "    out1\n"
        "}\n"
    )
    assert source == expected
コード例 #11
0
def test_jl_code_argument_order():
    expr = x + y
    routine = make_routine("test", expr, argument_sequence=[z, x, y], language="julia")
    code_gen = JuliaCodeGen()
    output = StringIO()
    code_gen.dump_jl([routine], output, "test", header=False, empty=False)
    source = output.getvalue()
    expected = (
        "function test(z, x, y)\n"
        "    out1 = x + y\n"
        "    return out1\n"
        "end\n"
    )
    assert source == expected
コード例 #12
0
def test_argument_order():
    expr = x + y
    routine = make_routine("test", expr, argument_sequence=[z, x, y], language="rust")
    code_gen = RustCodeGen()
    output = StringIO()
    code_gen.dump_rs([routine], output, "test", header=False, empty=False)
    source = output.getvalue()
    expected = (
        "fn test(z: f64, x: f64, y: f64) -> f64 {\n"
        "    let out1 = x + y;\n"
        "    out1\n"
        "}\n"
    )
    assert source == expected
コード例 #13
0
ファイル: pkgdata.py プロジェクト: twobitlogic/sympy
def get_resource(identifier, pkgname=__name__):
    """
    Acquire a readable object for a given package name and identifier.
    An IOError will be raised if the resource can not be found.

    For example::

        mydata = get_esource('mypkgdata.jpg').read()

    Note that the package name must be fully qualified, if given, such
    that it would be found in sys.modules.

    In some cases, getResource will return a real file object.  In that
    case, it may be useful to use its name attribute to get the path
    rather than use it as a file-like object.  For example, you may
    be handing data off to a C API.
    """

    mod = sys.modules[pkgname]
    fn = getattr(mod, '__file__', None)
    if fn is None:
        raise IOError("%r has no __file__!")
    path = os.path.join(os.path.dirname(fn), identifier)
    loader = getattr(mod, '__loader__', None)
    if loader is not None:
        try:
            data = loader.get_data(path)
        except (IOError,AttributeError):
            pass
        else:
            return StringIO(data)
    return file(os.path.normpath(path), 'rb')
コード例 #14
0
ファイル: codegen.py プロジェクト: Soroche/sympy
    def write(self, routines, prefix, to_files=False, header=True, empty=True):
        """Writes all the source code files for the given routines.

        The generated source is returned as a list of (filename, contents)
        tuples, or is written to files (see below).  Each filename consists
        of the given prefix, appended with an appropriate extension.

        Parameters
        ==========

        routines : list
            A list of Routine instances to be written

        prefix : string
            The prefix for the output files

        to_files : bool, optional
            When True, the output is written to files.  Otherwise, a list
            of (filename, contents) tuples is returned.  [default: False]

        header : bool, optional
            When True, a header comment is included on top of each source
            file. [default: True]

        empty : bool, optional
            When True, empty lines are included to structure the source
            files. [default: True]

        """
        if to_files:
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                with open(filename, "w") as f:
                    dump_fn(self, routines, f, prefix, header, empty)
        else:
            result = []
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                contents = StringIO()
                dump_fn(self, routines, contents, prefix, header, empty)
                result.append((filename, contents.getvalue()))
            return result
コード例 #15
0
    def write(self, routines, prefix, to_files=False, header=True, empty=True):
        """Writes all the source code files for the given routines.

        The generated source is returned as a list of (filename, contents)
        tuples, or is written to files (see below).  Each filename consists
        of the given prefix, appended with an appropriate extension.

        Parameters
        ==========

        routines : list
            A list of Routine instances to be written

        prefix : string
            The prefix for the output files

        to_files : bool, optional
            When True, the output is written to files.  Otherwise, a list
            of (filename, contents) tuples is returned.  [default: False]

        header : bool, optional
            When True, a header comment is included on top of each source
            file. [default: True]

        empty : bool, optional
            When True, empty lines are included to structure the source
            files. [default: True]

        """
        if to_files:
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                with open(filename, "w") as f:
                    dump_fn(self, routines, f, prefix, header, empty)
        else:
            result = []
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                contents = StringIO()
                dump_fn(self, routines, contents, prefix, header, empty)
                result.append((filename, contents.getvalue()))
            return result
コード例 #16
0
 def redirect(ipy=False):
     GA_LatexPrinter.ipy = ipy
     GA_LatexPrinter.latex_flg = True
     GA_LatexPrinter.Basic__str__ = Basic.__str__
     GA_LatexPrinter.Matrix__str__ = Matrix.__str__
     Basic.__str__ = lambda self: GA_LatexPrinter().doprint(self)
     Matrix.__str__ = lambda self: GA_LatexPrinter().doprint(self)
     if not ipy:
         GA_LatexPrinter.stdout = sys.stdout
         sys.stdout = StringIO()
     return
コード例 #17
0
ファイル: session.py プロジェクト: Daaofer/sympyTest
def int_to_Integer(s):
    """
    Wrap integer literals with Integer.

    This is based on the decistmt example from
    http://docs.python.org/library/tokenize.html.

    Only integer literals are converted.  Float literals are left alone.

    Examples
    ========

    >>> from __future__ import division
    >>> from sympy.interactive.session import int_to_Integer
    >>> from sympy import Integer
    >>> s = '1.2 + 1/2 - 0x12 + a1'
    >>> int_to_Integer(s)
    '1.2 +Integer (1 )/Integer (2 )-Integer (0x12 )+a1 '
    >>> s = 'print (1/2)'
    >>> int_to_Integer(s)
    'print (Integer (1 )/Integer (2 ))'
    >>> exec(s)
    0.5
    >>> exec(int_to_Integer(s))
    1/2
    """
    from tokenize import generate_tokens, untokenize, NUMBER, NAME, OP
    from sympy.core.compatibility import StringIO

    def _is_int(num):
        """
        Returns true if string value num (with token NUMBER) represents an integer.
        """
        # XXX: Is there something in the standard library that will do this?
        if '.' in num or 'j' in num.lower() or 'e' in num.lower():
            return False
        return True

    result = []
    g = generate_tokens(StringIO(s).readline)   # tokenize the string
    for toknum, tokval, _, _, _ in g:
        if toknum == NUMBER and _is_int(tokval):  # replace NUMBER tokens
            result.extend([
                (NAME, 'Integer'),
                (OP, '('),
                (NUMBER, tokval),
                (OP, ')')
            ])
        else:
            result.append((toknum, tokval))
    return untokenize(result)
コード例 #18
0
ファイル: codegen.py プロジェクト: Eskatrem/sympy
    def write(self, routines, prefix, to_files=False, header=True, empty=True):
        """Writes all the source code files for the given routines.

            The generate source is returned as a list of (filename, contents)
            tuples, or is written to files (see options). Each filename consists
            of the given prefix, appended with an appropriate extension.

            ``routines``
                A list of Routine instances to be written
            ``prefix``
                The prefix for the output files
            ``to_files``
                When True, the output is effectively written to files.
                [DEFAULT=False] Otherwise, a list of (filename, contents)
                tuples is returned.
            ``header``
                When True, a header comment is included on top of each source
                file. [DEFAULT=True]
            ``empty``
                When True, empty lines are included to structure the source
                files. [DEFAULT=True]

        """
        if to_files:
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                with open(filename, "w") as f:
                    dump_fn(self, routines, f, prefix, header, empty)
        else:
            result = []
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                contents = StringIO()
                dump_fn(self, routines, contents, prefix, header, empty)
                result.append((filename, contents.getvalue()))
            return result
コード例 #19
0
    def write(self, routines, prefix, to_files=False, header=True, empty=True):
        """Writes all the source code files for the given routines.

            The generate source is returned as a list of (filename, contents)
            tuples, or is written to files (see options). Each filename consists
            of the given prefix, appended with an appropriate extension.

            ``routines``
                A list of Routine instances to be written
            ``prefix``
                The prefix for the output files
            ``to_files``
                When True, the output is effectively written to files.
                [DEFAULT=False] Otherwise, a list of (filename, contents)
                tuples is returned.
            ``header``
                When True, a header comment is included on top of each source
                file. [DEFAULT=True]
            ``empty``
                When True, empty lines are included to structure the source
                files. [DEFAULT=True]

        """
        if to_files:
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                with open(filename, "w") as f:
                    dump_fn(self, routines, f, prefix, header, empty)
        else:
            result = []
            for dump_fn in self.dump_fns:
                filename = "%s.%s" % (prefix, dump_fn.extension)
                contents = StringIO()
                dump_fn(self, routines, contents, prefix, header, empty)
                result.append((filename, contents.getvalue()))
            return result
コード例 #20
0
def stringify_expr(s, local_dict, global_dict, transformations):
    """
    Converts the string ``s`` to Python code, in ``local_dict``

    Generally, ``parse_expr`` should be used.
    """

    tokens = []
    input_code = StringIO(s.strip())
    for toknum, tokval, _, _, _ in generate_tokens(input_code.readline):
        tokens.append((toknum, tokval))

    for transform in transformations:
        tokens = transform(tokens, local_dict, global_dict)

    return untokenize(tokens)
コード例 #21
0
def test_empty_m_code():
    code_gen = OctaveCodeGen()
    output = StringIO()
    code_gen.dump_m([], output, "file", header=False, empty=False)
    source = output.getvalue()
    assert source == ""
コード例 #22
0
def test_empty_jl_code():
    code_gen = JuliaCodeGen()
    output = StringIO()
    code_gen.dump_jl([], output, "file", header=False, empty=False)
    source = output.getvalue()
    assert source == ""
コード例 #23
0
def preview(expr,
            output='png',
            viewer=None,
            euler=True,
            packages=(),
            filename=None,
            outputbuffer=None,
            preamble=None,
            dvioptions=None,
            outputTexFile=None,
            **latex_settings):
    r"""
    View expression or LaTeX markup in PNG, DVI, PostScript or PDF form.

    If the expr argument is an expression, it will be exported to LaTeX and
    then compiled using the available TeX distribution.  The first argument,
    'expr', may also be a LaTeX string.  The function will then run the
    appropriate viewer for the given output format or use the user defined
    one. By default png output is generated.

    By default pretty Euler fonts are used for typesetting (they were used to
    typeset the well known "Concrete Mathematics" book). For that to work, you
    need the 'eulervm.sty' LaTeX style (in Debian/Ubuntu, install the
    texlive-fonts-extra package). If you prefer default AMS fonts or your
    system lacks 'eulervm' LaTeX package then unset the 'euler' keyword
    argument.

    To use viewer auto-detection, lets say for 'png' output, issue

    >>> from sympy import symbols, preview, Symbol
    >>> x, y = symbols("x,y")

    >>> preview(x + y, output='png')

    This will choose 'pyglet' by default. To select a different one, do

    >>> preview(x + y, output='png', viewer='gimp')

    The 'png' format is considered special. For all other formats the rules
    are slightly different. As an example we will take 'dvi' output format. If
    you would run

    >>> preview(x + y, output='dvi')

    then 'view' will look for available 'dvi' viewers on your system
    (predefined in the function, so it will try evince, first, then kdvi and
    xdvi). If nothing is found you will need to set the viewer explicitly.

    >>> preview(x + y, output='dvi', viewer='superior-dvi-viewer')

    This will skip auto-detection and will run user specified
    'superior-dvi-viewer'. If 'view' fails to find it on your system it will
    gracefully raise an exception.

    You may also enter 'file' for the viewer argument. Doing so will cause
    this function to return a file object in read-only mode, if 'filename'
    is unset. However, if it was set, then 'preview' writes the genereted
    file to this filename instead.

    There is also support for writing to a StringIO like object, which needs
    to be passed to the 'outputbuffer' argument.

    >>> from StringIO import StringIO
    >>> obj = StringIO()
    >>> preview(x + y, output='png', viewer='StringIO',
    ...         outputbuffer=obj)

    The LaTeX preamble can be customized by setting the 'preamble' keyword
    argument. This can be used, e.g., to set a different font size, use a
    custom documentclass or import certain set of LaTeX packages.

    >>> preamble = "\\documentclass[10pt]{article}\n" \
    ...            "\\usepackage{amsmath,amsfonts}\\begin{document}"
    >>> preview(x + y, output='png', preamble=preamble)

    If the value of 'output' is different from 'dvi' then command line
    options can be set ('dvioptions' argument) for the execution of the
    'dvi'+output conversion tool. These options have to be in the form of a
    list of strings (see subprocess.Popen).

    Additional keyword args will be passed to the latex call, e.g., the
    symbol_names flag.

    >>> phidd = Symbol('phidd')
    >>> preview(phidd, symbol_names={phidd:r'\ddot{\varphi}'})

    For post-processing the generated TeX File can be written to a file by
    passing the desired filename to the 'outputTexFile' keyword
    argument. To write the TeX code to a file named
    "sample.tex" and run the default png viewer to display the resulting
    bitmap, do

    >>> preview(x + y, outputTexFile="sample.tex")


    """
    special = ['pyglet']

    if viewer is None:
        if output == "png":
            viewer = "pyglet"
        else:
            # sorted in order from most pretty to most ugly
            # very discussable, but indeed 'gv' looks awful :)
            # TODO add candidates for windows to list
            candidates = {
                "dvi": ["evince", "okular", "kdvi", "xdvi"],
                "ps": ["evince", "okular", "gsview", "gv"],
                "pdf": ["evince", "okular", "kpdf", "acroread", "xpdf", "gv"],
            }

            try:
                for candidate in candidates[output]:
                    path = find_executable(candidate)
                    if path is not None:
                        viewer = path
                        break
                else:
                    raise SystemError(
                        "No viewers found for '%s' output format." % output)
            except KeyError:
                raise SystemError("Invalid output format: %s" % output)
    else:
        if viewer == "file":
            if filename is None:
                SymPyDeprecationWarning(
                    feature="Using viewer=\"file\" without a "
                    "specified filename",
                    deprecated_since_version="0.7.3",
                    useinstead="viewer=\"file\" and filename=\"desiredname\"",
                    issue=3919).warn()
        elif viewer == "StringIO":
            if outputbuffer is None:
                raise ValueError("outputbuffer has to be a StringIO "
                                 "compatible object if viewer=\"StringIO\"")
        elif viewer not in special and not find_executable(viewer):
            raise SystemError("Unrecognized viewer: %s" % viewer)

    if preamble is None:
        actual_packages = packages + ("amsmath", "amsfonts")
        if euler:
            actual_packages += ("euler", )
        package_includes = "\n" + "\n".join(
            ["\\usepackage{%s}" % p for p in actual_packages])

        preamble = r"""\documentclass[12pt]{article}
\pagestyle{empty}
%s

\begin{document}
""" % (package_includes)
    else:
        if len(packages) > 0:
            raise ValueError("The \"packages\" keyword must not be set if a "
                             "custom LaTeX preamble was specified")
    latex_main = preamble + '\n%s\n\n' + r"\end{document}"

    if isinstance(expr, str):
        latex_string = expr
    else:
        latex_string = latex(expr, mode='inline', **latex_settings)

    try:
        workdir = tempfile.mkdtemp()

        with open(join(workdir, 'texput.tex'), 'w') as fh:
            fh.write(latex_main % latex_string)

        if outputTexFile is not None:
            shutil.copyfile(join(workdir, 'texput.tex'), outputTexFile)

        if not find_executable('latex'):
            raise RuntimeError("latex program is not installed")

        try:
            check_output([
                'latex', '-halt-on-error', '-interaction=nonstopmode',
                'texput.tex'
            ],
                         cwd=workdir,
                         stderr=STDOUT)
        except CalledProcessError as e:
            raise RuntimeError(
                "'latex' exited abnormally with the following output:\n%s" %
                e.output)

        if output != "dvi":
            defaultoptions = {
                "ps": [],
                "pdf": [],
                "png": ["-T", "tight", "-z", "9", "--truecolor"]
            }

            commandend = {
                "ps": ["-o", "texput.ps", "texput.dvi"],
                "pdf": ["texput.dvi", "texput.pdf"],
                "png": ["-o", "texput.png", "texput.dvi"]
            }

            cmd = ["dvi" + output]
            if not find_executable(cmd[0]):
                raise RuntimeError("%s is not installed" % cmd[0])
            try:
                if dvioptions is not None:
                    cmd.extend(dvioptions)
                else:
                    cmd.extend(defaultoptions[output])
                cmd.extend(commandend[output])
            except KeyError:
                raise SystemError("Invalid output format: %s" % output)

            try:
                check_output(cmd, cwd=workdir, stderr=STDOUT)
            except CalledProcessError as e:
                raise RuntimeError(
                    "'%s' exited abnormally with the following output:\n%s" %
                    (' '.join(cmd), e.output))

        src = "texput.%s" % (output)

        if viewer == "file":
            if filename is None:
                buffer = StringIO()
                with open(join(workdir, src), 'rb') as fh:
                    buffer.write(fh.read())
                return buffer
            else:
                shutil.move(join(workdir, src), filename)
        elif viewer == "StringIO":
            with open(join(workdir, src), 'rb') as fh:
                outputbuffer.write(fh.read())
        elif viewer == "pyglet":
            try:
                from pyglet import window, image, gl
                from pyglet.window import key
            except ImportError:
                raise ImportError(
                    "pyglet is required for preview.\n visit http://www.pyglet.org/"
                )

            if output == "png":
                from pyglet.image.codecs.png import PNGImageDecoder
                img = image.load(join(workdir, src), decoder=PNGImageDecoder())
            else:
                raise SystemError("pyglet preview works only for 'png' files.")

            offset = 25

            win = window.Window(width=img.width + 2 * offset,
                                height=img.height + 2 * offset,
                                caption="sympy",
                                resizable=False)

            win.set_vsync(False)

            try:

                def on_close():
                    win.has_exit = True

                win.on_close = on_close

                def on_key_press(symbol, modifiers):
                    if symbol in [key.Q, key.ESCAPE]:
                        on_close()

                win.on_key_press = on_key_press

                def on_expose():
                    gl.glClearColor(1.0, 1.0, 1.0, 1.0)
                    gl.glClear(gl.GL_COLOR_BUFFER_BIT)

                    img.blit((win.width - img.width) / 2,
                             (win.height - img.height) / 2)

                win.on_expose = on_expose

                while not win.has_exit:
                    win.dispatch_events()
                    win.flip()
            except KeyboardInterrupt:
                pass

            win.close()
        else:
            try:
                check_output([viewer, src], cwd=workdir, stderr=STDOUT)
            except CalledProcessError as e:
                raise RuntimeError(
                    "'%s %s' exited abnormally with the following output:\n%s"
                    % (viewer, src, e.output))
    finally:
        try:
            shutil.rmtree(workdir)  # delete directory
        except OSError as e:
            if e.errno != 2:  # code 2 - no such file or directory
                raise