# sympy/galgebra/printing.py
"""
printing.py implements GA_Printer and GA_LatexPrinter classes for
multivectors by derivation from the SymPy Printer and LatexPrinter
classes. Where we wish to change the behavior of printing for
existing SymPy types the required function have been rewritten
and included in GA_Printer and GA_LatexPrinter. For example
we have rewritten:
_print_Derivative
_print_Function
_print_Matrix
_print_Pow
_print_Symbol
for GA_LatexPrinter and
_print_Derivative
_print_Function
for GA_Printer.
There is also and enhanced_print class that allows multivectors,
multivector functions, and multivector derivatives to print out
in different colors on ansi terminals.
"""
from __future__ import print_function
import os
import sys
from sympy.core.compatibility import StringIO
from sympy.core.decorators import deprecated
from sympy import C, S, Basic, Symbol, Matrix
from sympy.printing.str import StrPrinter
from sympy.printing.latex import LatexPrinter
from sympy.printing.conventions import split_super_sub
SYS_CMD = {'linux2': {'rm': 'rm', 'evince': 'evince', 'null': ' > /dev/null', '&': '&'},
'win32': {'rm': 'del', 'evince': '', 'null': ' > NUL', '&': ''},
'darwin': {'rm': 'rm', 'evince': 'open', 'null': ' > /dev/null', '&': '&'}}
ColorCode = {
'black': '0;30', 'bright gray': '0;37',
'blue': '0;34', 'white': '1;37',
'green': '0;32', 'bright blue': '1;34',
'cyan': '0;36', 'bright green': '1;32',
'red': '0;31', 'bright cyan': '1;36',
'purple': '0;35', 'bright red': '1;31',
'yellow': '0;33', 'bright purple': '1;35',
'dark gray': '1;30', 'bright yellow': '1;33',
'normal': '0'
}
InvColorCode = dict(zip(ColorCode.values(), ColorCode.keys()))
accepted_latex_functions = ['arcsin', 'arccos', 'arctan', 'sin', 'cos', 'tan',
'theta', 'beta', 'alpha', 'gamma', 'sinh', 'cosh', 'tanh', 'sqrt',
'ln', 'log', 'sec', 'csc', 'cot', 'coth', 're', 'im', 'frac', 'root',
'arg', 'zeta']
[docs]def find_executable(executable, path=None):
"""
Try to find 'executable' in the directories listed in 'path' (a
string listing directories separated by 'os.pathsep'; defaults to
os.environ['PATH']). Returns the complete filename or None if not
found
"""
if path is None:
path = os.environ['PATH']
paths = path.split(os.pathsep)
extlist = ['']
if os.name == 'os2':
(base, ext) = os.path.splitext(executable)
# executable files on OS/2 can have an arbitrary extension, but
# .exe is automatically appended if no dot is present in the name
if not ext:
executable = executable + ".exe"
elif sys.platform == 'win32':
pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
(base, ext) = os.path.splitext(executable)
if ext.lower() not in pathext:
extlist = pathext
for ext in extlist:
execname = executable + ext
if os.path.isfile(execname):
return execname
else:
for p in paths:
f = os.path.join(p, execname)
if os.path.isfile(f):
return f
else:
return None
[docs]class enhance_print:
"""
A class for color coding the string printing going to a terminal.
"""
normal = ''
base = ''
fct = ''
deriv = ''
bold = ''
def __init__(self, base=None, fct=None, deriv=None, on=True, keys=False):
if on:
if 'win' in sys.platform:
if base is None:
enhance_print.base = ColorCode['blue']
else:
enhance_print.base = ColorCode[base]
if fct is None:
enhance_print.fct = ColorCode['red']
else:
enhance_print.fct = ColorCode[fct]
if deriv is None:
enhance_print.deriv = ColorCode['cyan']
else:
enhance_print.deriv = ColorCode[deriv]
enhance_print.normal = '\033[0m'
else:
if base is None:
enhance_print.base = ColorCode['dark gray']
else:
enhance_print.base = ColorCode[base]
if fct is None:
enhance_print.fct = ColorCode['red']
else:
enhance_print.fct = ColorCode[fct]
if deriv is None:
enhance_print.deriv = ColorCode['cyan']
else:
enhance_print.deriv = ColorCode[deriv]
enhance_print.normal = '\033[0m'
if keys:
print('Enhanced Printing is on:')
print('Base/Blade color is ' + InvColorCode[enhance_print.base])
print('Function color is ' + InvColorCode[enhance_print.fct])
print('Derivative color is ' + InvColorCode[enhance_print.deriv] + '\n')
enhance_print.base = '\033[' + enhance_print.base + 'm'
enhance_print.fct = '\033[' + enhance_print.fct + 'm'
enhance_print.deriv = '\033[' + enhance_print.deriv + 'm'
@staticmethod
def enhance_base(s):
return enhance_print.base + s + enhance_print.normal
@staticmethod
def enhance_fct(s):
return enhance_print.fct + s + enhance_print.normal
@staticmethod
def enhance_deriv(s):
return enhance_print.deriv + s + enhance_print.normal
@staticmethod
def strip_base(s):
new_s = s.replace(enhance_print.base, '')
new_s = new_s.replace(enhance_print.normal, '')
return new_s
[docs]class GA_Printer(StrPrinter):
"""
An enhanced string printer that is galgebra-aware.
"""
function_names = ('acos', 'acosh', 'acot', 'acoth', 'arg', 'asin', 'asinh',
'atan', 'atan2', 'atanh', 'ceiling', 'conjugate', 'cos',
'cosh', 'cot', 'coth', 'exp', 'floor', 'im', 'log', 're',
'root', 'sin', 'sinh', 'sqrt', 'sign', 'tan', 'tanh')
def _print_Function(self, expr):
name = expr.func.__name__
if expr.func.nargs is not None:
if name in GA_Printer.function_names:
return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ")
return enhance_print.enhance_fct("%s" % (name, ))
def _print_Derivative(self, expr):
diff_args = list(map(self._print, expr.args))
return enhance_print.enhance_deriv('D{%s}' % (diff_args[1], )) + '%s' % (diff_args[0], )
def _print_MV(self, expr):
if expr.obj.is_zero:
return '0'
else:
if expr.print_blades:
expr.base_to_blade()
ostr = expr.get_normal_order_str()
return ostr
def _print_Vector(self, expr):
if expr.obj.is_zero:
return '0'
else:
ostr = GA_Printer().doprint(expr.obj)
ostr = ostr.replace(' ', '')
return ostr
@staticmethod
def _on():
GA_Printer.Basic__str__ = Basic.__str__
Basic.__str__ = lambda self: GA_Printer().doprint(self)
return
@staticmethod
def _off():
Basic.__str__ = GA_Printer.Basic__str__
return
def __enter__ (self):
GA_Printer._on()
return self
def __exit__ (self, type, value, traceback):
GA_Printer._off()
@staticmethod
@deprecated(useinstead="with GA_Printer()", issue=4042, deprecated_since_version="0.7.4")
def on():
GA_Printer._on()
@staticmethod
@deprecated(useinstead="with GA_Printer()", issue=4042, deprecated_since_version="0.7.4")
def off():
GA_Printer._off()
[docs]class GA_LatexPrinter(LatexPrinter):
r"""
An enhanced LaTeX printer that is galgebra-aware.
The latex printer is turned on with the function (in ga.py) -
Format(Fmode=True,Dmode=True,ipy=False)
where Fmode is the function printing mode that surpresses printing arguments,
Dmode is the derivative printing mode that does not use fractions, and
ipy=True is the Ipython notebook mode that does not redirect the print output.
The latex output is post processed and displayed with the function (in GAPrint.py) -
xdvi(filename='tmplatex.tex',debug=False)
where filename is the name of the tex file one would keep for future
inclusion in documents and debug=True would display the tex file
immediately.
There are three options for printing multivectors in latex. They are
acessed with the multivector member function -
A.Fmt(self,fmt=1,title=None)
where fmt=1, 2, or 3 determines whether the entire multivector A is
printed entirely on one line, or one grade is printed per line, or
one base is printed per line. If title is not None then the latex
string generated is of the form -
title+' = '+str(A)
where it is assumed that title is a latex math mode string. If title
contains '%' it is treated as a pure latex math mode string. If it
does not contain '%' then the following character mappings are applied -
- 'grad' replaced by '\\bm{\\nabla} '
- '*' replaced by ''
- '^' replaced by '\\W '
- '|' replaced by '\\cdot '
- '>' replaced by '\\lfloor '
- '<' replaced by '\\rfloor '
In the case of a print statement of the form -
print(title,A)
everthing in the title processing still applies except that the multivector
formatting is one multivector per line.
For print statements of the form -
print(title)
where no program variables are printed if title contains '#' then title
is printed as regular latex line. If title does not contain '#' then
title is printed in equation mode. '%' has the same effect in title as
in the Fmt() member function.
"""
preamble = \
"""
\\pagestyle{empty}
\\usepackage[latin1]{inputenc}
\\usepackage{amsmath}
\\usepackage{bm}
\\usepackage{amsfonts}
\\usepackage{amssymb}
\\usepackage{amsbsy}
\\usepackage{tensor}
\\usepackage{listings}
\\usepackage{color}
\\definecolor{gray}{rgb}{0.95,0.95,0.95}
\\setlength{\\parindent}{0pt}
\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}
\\newcommand{\\lp}{\\left (}
\\newcommand{\\rp}{\\right )}
\\newcommand{\\half}{\\frac{1}{2}}
\\newcommand{\\llt}{\\left <}
\\newcommand{\\rgt}{\\right >}
\\newcommand{\\abs}[1]{\\left |{#1}\\right | }
\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}
\\newcommand{\\lbrc}{\\left \\{}
\\newcommand{\\rbrc}{\\right \\}}
\\newcommand{\\W}{\\wedge}
\\newcommand{\\prm}[1]{{#1}'}
\\newcommand{\\ddt}[1]{\\bfrac{d{#1}}{dt}}
\\newcommand{\\R}{\\dagger}
\\newcommand{\\deriv}[3]{\\bfrac{d^{#3}#1}{d{#2}^{#3}}}
\\newcommand{\\grade}[1]{\\left < {#1} \\right >}
\\newcommand{\\f}[2]{{#1}\\lp{#2}\\rp}
\\newcommand{\\eval}[2]{\\left . {#1} \\right |_{#2}}
\\usepackage{float}
\\floatstyle{plain} % optionally change the style of the new float
\\newfloat{Code}{H}{myc}
\\lstloadlanguages{Python}
\\begin{document}
"""
postscript = '\\end{document}\n'
Dmode = False # True - Print derivative contracted
Fmode = False # True - Print function contracted
latex_flg = False
@staticmethod
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
@staticmethod
def restore():
GA_LatexPrinter.latex_flg = False
if not GA_LatexPrinter.ipy:
sys.stdout = GA_LatexPrinter.stdout
Basic.__str__ = GA_LatexPrinter.Basic__str__
Matrix.__str__ = GA_LatexPrinter.Matrix__str__
return
def _print_Pow(self, expr):
base = self._print(expr.base)
if ('_' in base or '^' in base) and 'cdot' not in base:
mode = True
else:
mode = False
# Treat x**Rational(1,n) as special case
if expr.exp.is_Rational and abs(expr.exp.p) == 1 and expr.exp.q != 1:
expq = expr.exp.q
if expq == 2:
tex = r"\sqrt{%s}" % base
elif self._settings['itex']:
tex = r"\root{%d}{%s}" % (expq, base)
else:
tex = r"\sqrt[%d]{%s}" % (expq, base)
if expr.exp.is_negative:
return r"\frac{1}{%s}" % tex
else:
return tex
elif self._settings['fold_frac_powers'] \
and expr.exp.is_Rational \
and expr.exp.q != 1:
base, p, q = self._print(expr.base), expr.exp.p, expr.exp.q
if mode:
return r"{\lp %s \rp}^{%s/%s}" % (base, p, q)
else:
return r"%s^{%s/%s}" % (base, p, q)
elif expr.exp.is_Rational and expr.exp.is_negative and expr.base.is_Function:
# Things like 1/x
return r"\frac{%s}{%s}" % \
(1, self._print(C.Pow(expr.base, -expr.exp)))
else:
if expr.base.is_Function:
return self._print(expr.base, self._print(expr.exp))
else:
if expr.is_commutative and expr.exp == -1:
"""
solves issue 1030
As Mul always simplify 1/x to x**-1
The objective is achieved with this hack
first we get the latex for -1 * expr,
which is a Mul expression
"""
tex = self._print(S.NegativeOne * expr).strip()
# the result comes with a minus and a space, so we remove
if tex[:1] == "-":
return tex[1:].strip()
if self._needs_brackets(expr.base):
tex = r"\left(%s\right)^{%s}"
else:
if mode:
tex = r"{\lp %s \rp}^{%s}"
else:
tex = r"%s^{%s}"
return tex % (self._print(expr.base),
self._print(expr.exp))
def _print_Symbol(self, expr):
def str_symbol(name_str):
(name, supers, subs) = split_super_sub(name_str)
# translate name, supers and subs to tex keywords
greek = set(['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta',
'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu',
'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon',
'phi', 'chi', 'psi', 'omega'])
greek_translated = {'lamda': 'lambda', 'Lamda': 'Lambda'}
other = set(['aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth',
'hbar', 'hslash', 'mho'])
def translate(s):
tmp = s.lower()
if tmp in greek or tmp in other:
return "\\" + s
if s in greek_translated:
return "\\" + greek_translated[s]
else:
return s
name = translate(name)
if supers != []:
supers = list(map(translate, supers))
if subs != []:
subs = list(map(translate, subs))
# glue all items together:
if len(supers) > 0:
name += "^{%s}" % " ".join(supers)
if len(subs) > 0:
name += "_{%s}" % " ".join(subs)
return name
if expr in self._settings['symbol_names']:
return self._settings['symbol_names'][expr]
name_str = expr.name
if '.' in name_str and name_str[0] == '(' and name_str[-1] == ')':
name_str = name_str[1:-1]
name_lst = name_str.split('.')
name_str = r'\lp ' + str_symbol(name_lst[0]) + r'\cdot ' + str_symbol(name_lst[1]) + r'\rp '
return name_str
return str_symbol(expr.name)
def _print_Function(self, expr, exp=None):
func = expr.func.__name__
name = func
if hasattr(self, '_print_' + func):
return getattr(self, '_print_' + func)(expr, exp)
else:
args = [str(self._print(arg)) for arg in expr.args]
# How inverse trig functions should be displayed, formats are:
# abbreviated: asin, full: arcsin, power: sin^-1
inv_trig_style = self._settings['inv_trig_style']
# If we are dealing with a power-style inverse trig function
inv_trig_power_case = False
# If it is applicable to fold the argument brackets
can_fold_brackets = self._settings['fold_func_brackets'] and \
len(args) == 1 and \
not self._needs_function_brackets(expr.args[0])
inv_trig_table = ["asin", "acos", "atan", "acot"]
# If the function is an inverse trig function, handle the style
if func in inv_trig_table:
if inv_trig_style == "abbreviated":
func = func
elif inv_trig_style == "full":
func = "arc" + func[1:]
elif inv_trig_style == "power":
func = func[1:]
inv_trig_power_case = True
# Can never fold brackets if we're raised to a power
if exp is not None:
can_fold_brackets = False
if inv_trig_power_case:
if func in accepted_latex_functions:
name = r"\%s^{-1}" % func
else:
name = r"\operatorname{%s}^{-1}" % func
elif exp is not None:
if func in accepted_latex_functions:
name = r"\%s^{%s}" % (func, exp)
else:
name = latex(Symbol(func))
if '_' in func or '^' in func:
name = r'{\lp ' + name + r'\rp }^{' + exp + '}'
else:
name += '^{' + exp + '}'
else:
if func in accepted_latex_functions:
name = r"\%s" % func
else:
name = latex(Symbol(func))
if exp is not None:
if '_' in name or '^' in name:
name = r'\lp ' + name + r'\rp^{' + exp + '}'
else:
name += '^{' + exp + '}'
if can_fold_brackets:
if func in accepted_latex_functions:
# Wrap argument safely to avoid parse-time conflicts
# with the function name itself
name += r" {%s}"
else:
if not GA_LatexPrinter.Fmode:
name += r"%s"
else:
if func in accepted_latex_functions or not GA_LatexPrinter.Fmode:
name += r"{\left (%s \right )}"
if inv_trig_power_case and exp is not None:
name += r"^{%s}" % exp
if func in accepted_latex_functions or not GA_LatexPrinter.Fmode:
if len(args) == 1:
return name % args[0]
else:
return name % ",".join(args)
else:
return name
def _print_Derivative(self, expr):
dim = len(expr.variables)
imax = 1
if dim == 1:
if GA_LatexPrinter.Dmode:
tex = r"\partial_{%s}" % self._print(expr.variables[0])
else:
tex = r"\frac{\partial}{\partial %s}" % self._print(expr.variables[0])
else:
multiplicity, i, tex = [], 1, ""
current = expr.variables[0]
for symbol in expr.variables[1:]:
if symbol == current:
i = i + 1
else:
multiplicity.append((current, i))
current, i = symbol, 1
else:
imax = max(imax, i)
multiplicity.append((current, i))
if GA_LatexPrinter.Dmode and imax == 1:
tmp = ''
dim = 0
for x, i in multiplicity:
dim += i
tmp += r"%s" % (self._print(x), )
tex = r"\partial^{%s}_{" % (dim, ) + tmp + '}'
else:
for x, i in multiplicity:
if i == 1:
tex += r"\partial %s" % self._print(x)
else:
tex += r"\partial^{%s} %s" % (i, self._print(x))
tex = r"\frac{\partial^{%s}}{%s} " % (dim, tex)
if isinstance(expr.expr, C.AssocOp):
return r"%s\left(%s\right)" % (tex, self._print(expr.expr))
else:
return r"%s %s" % (tex, self._print(expr.expr))
def _print_MV(self, expr):
if expr.obj.is_zero:
return '0 \n'
else:
if expr.print_blades:
expr.base_to_blade()
ostr = expr.get_latex_normal_order_str()
return ostr
def _print_Matrix(self, expr):
lines = []
for line in range(expr. rows): # horrible, should be 'rows'
lines.append(" & ".join([self._print(i) for i in expr[line, :]]))
ncols = 0
for i in expr[line, :]:
ncols += 1
out_str = '\\left [ \\begin{array}{' + ncols * 'c' + '} '
for line in lines[:-1]:
out_str += line + ' \\\\ '
out_str += lines[-1] + ' \\end{array}\\right ] '
return out_str
[docs]def latex(expr, **settings):
"Return the LaTeX representation of the given expression."
return GA_LatexPrinter(settings).doprint(expr)
[docs]def print_latex(expr, **settings):
"Print the LaTeX representation of the given expression."
print(latex(expr, **settings))
[docs]def xdvi(filename=None, debug=False, paper=(14, 11)):
"""
Post processes LaTeX output (see comments below), adds preamble and
postscript, generates tex file, inputs file to latex, displays resulting
pdf file.
"""
if GA_LatexPrinter.ipy:
GA_LatexPrinter.restore(GA_LatexPrinter.ipy)
return
sys_cmd = SYS_CMD[sys.platform]
latex_str = sys.stdout.getvalue()
GA_LatexPrinter.restore()
latex_lst = latex_str.split('\n')
latex_str = ''
lhs = ''
code_flg = False
for latex_line in latex_lst:
if len(latex_line) > 0 and '##' == latex_line[:2]:
if code_flg:
code_flg = False
latex_line = latex_line[2:]
else:
code_flg = True
latex_line = latex_line[2:]
elif code_flg:
pass
elif len(latex_line) > 0 and '#' in latex_line: # Non equation mode output (comment)
latex_line = latex_line.replace('#', '')
if '%' in latex_line: # Equation mode with no variables to print (comment)
latex_line = latex_line.replace('%', '')
latex_line = '\\begin{equation*} ' + latex_line + ' \\end{equation*}\n'
else:
latex_line = latex_line.replace('.', r' \cdot ') # For components of metric tensor
if '=' in latex_line: # determing lhs of equation/align
eq_index = latex_line.rindex('=') + 1
lhs = latex_line[:eq_index]
latex_line = latex_line.replace(lhs, '')
if '%' in lhs: # Do not preprocess lhs of equation/align
lhs = lhs.replace('%', '')
else: # preprocess lhs of equation/align
lhs = lhs.replace('|', r'\cdot ')
lhs = lhs.replace('^', r'\W ')
lhs = lhs.replace('*', ' ')
lhs = lhs.replace('grad', r'\bm{\nabla} ')
lhs = lhs.replace('<<', r'\rfloor ')
lhs = lhs.replace('<', r'\rfloor ')
lhs = lhs.replace('>>', r'\lfloor ')
lhs = lhs.replace('>', r'\lfloor ')
latex_line = lhs + latex_line
if r'\begin{align*}' in latex_line: # insert lhs of align environment
latex_line = latex_line = latex_line.replace(lhs, '')
latex_line = latex_line.replace(r'\begin{align*}', r'\begin{align*} ' + lhs)
lhs = ''
else: # normal sympy equation
latex_line = latex_line.strip()
if len(latex_line) > 0:
latex_line = '\\begin{equation*} ' + latex_line + ' \\end{equation*}'
latex_str += latex_line + '\n'
latex_str = latex_str.replace('\n\n', '\n')
if debug:
print(latex_str)
if paper == 'letter':
paper_size = \
"""
\\documentclass[10pt,fleqn]{report}
"""
else:
paper_size = \
"""
\\documentclass[10pt,fleqn]{report}
\\usepackage[vcentering]{geometry}
"""
paper_size += '\\geometry{papersize={' + str(paper[0]) + \
'in,' + str(paper[1]) + 'in},total={' + str(paper[0] - 1) + \
'in,' + str(paper[1] - 1) + 'in}}\n'
latex_str = paper_size + GA_LatexPrinter.preamble + latex_str + GA_LatexPrinter.postscript
if filename is None:
pyfilename = sys.argv[0]
rootfilename = pyfilename.replace('.py', '')
filename = rootfilename + '.tex'
print('latex file =', filename)
latex_file = open(filename, 'w')
latex_file.write(latex_str)
latex_file.close()
latex_str = None
pdflatex = find_executable('pdflatex')
print('pdflatex path =', pdflatex)
if pdflatex is not None:
latex_str = 'pdflatex'
else:
return
if latex_str is not None:
if debug: # Display latex excution output for debugging purposes
os.system(latex_str + ' ' + filename[:-4])
else: # Works for Linux don't know about Windows
os.system(latex_str + ' ' + filename[:-4] + sys_cmd['null'])
print_cmd = sys_cmd['evince'] + ' ' + filename[:-4] + '.pdf ' + sys_cmd['&']
print(print_cmd)
os.system(print_cmd)
raw_input('!!!!Return to continue!!!!\n')
if debug:
os.system(sys_cmd['rm'] + ' ' + filename[:-4] + '.aux ' + filename[:-4] + '.log')
else:
os.system(sys_cmd['rm'] + ' ' + filename[:-4] + '.aux ' + filename[:-4] + '.log ' + filename[:-4] + '.tex')
return
prog_str = ''
off_mode = False
[docs]def Get_Program(off=False):
global prog_str, off_mode
off_mode = off
if off_mode:
return
prog_file = open(sys.argv[0], 'r')
prog_str = prog_file.read()
prog_file.close()
return
[docs]def Print_Function():
global prog_str, off_mode
if off_mode:
return
fct_name = str(sys._getframe(1).f_code.co_name)
ifct = prog_str.find('def ' + fct_name)
iend = prog_str.find('def ', ifct + 4)
tmp_str = prog_str[ifct:iend - 1]
fct_name = fct_name.replace('_', ' ')
if GA_LatexPrinter.latex_flg:
print('##\\begin{lstlisting}[language=Python,showspaces=false,' +
'showstringspaces=false,backgroundcolor=\color{gray},frame=single]')
print(tmp_str)
print('##\\end{lstlisting}')
print('#Code Output:')
else:
print('\n' + 80 * '*')
print(tmp_str)
print('Code output:\n')
return