You can start an interactive console from inside a script with following code:
import code
# do something here
vars = globals()
vars.update(locals())
shell = code.InteractiveConsole(vars)
shell.interact()
When I run the script like so:
$ python my_script.py
an interactive console opens:
Python 2.7.2+ (default, Jul 20 2012, 22:12:53)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
The console has all globals and locals loaded which is great since I can test stuff easily.
The problem here is that arrows don't work as they normally do when starting an Python console. They simply display escaped characters to the console:
>>> ^[[A^[[B^[[C^[[D
This means that I can't recall previous commands using the up/down arrow keys and I can't edit the lines with the left/right arrow keys either.
Does anyone know why is that and/or how to avoid that?
Check out readline and rlcompleter:
import code
import readline
import rlcompleter
# do something here
vars = globals()
vars.update(locals())
readline.set_completer(rlcompleter.Completer(vars).complete)
readline.parse_and_bind("tab: complete")
shell = code.InteractiveConsole(vars)
shell.interact()
This is the one I use:
def debug_breakpoint():
"""
Python debug breakpoint.
"""
from code import InteractiveConsole
from inspect import currentframe
try:
import readline # noqa
except ImportError:
pass
caller = currentframe().f_back
env = {}
env.update(caller.f_globals)
env.update(caller.f_locals)
shell = InteractiveConsole(env)
shell.interact(
'* Break: {} ::: Line {}\n'
'* Continue with Ctrl+D...'.format(
caller.f_code.co_filename, caller.f_lineno
)
)
For example, consider the following script:
a = 10
b = 20
c = 'Hello'
debug_breakpoint()
a = 20
b = c
c = a
mylist = [a, b, c]
debug_breakpoint()
def bar():
a = '1_one'
b = '2+2'
debug_breakpoint()
bar()
When executed, this file shows to following behavior:
$ python test_debug.py
* Break: test_debug.py ::: Line 24
* Continue with Ctrl+D...
>>> a
10
>>>
* Break: test_debug.py ::: Line 32
* Continue with Ctrl+D...
>>> b
'Hello'
>>> mylist
[20, 'Hello', 20]
>>> mylist.append(a)
>>>
* Break: test_debug.py ::: Line 38
* Continue with Ctrl+D...
>>> a
'1_one'
>>> mylist
[20, 'Hello', 20, 20]
Related
I need to compare two IP version6, if there are equal.
It is not a simple string comparison because the same address can be written in multiple ways.
I can't use third-party packages.
For example:
2041:0000:140F:0000:0000:0000:875B:131B
2041:0000:140F::875B:131B
2041:0:140F::875B:131B
and from windows ip config can be: 2041:0:140F::875B:131B%11
If you are on Python 3.3+ you can use the standard library module ipaddress:
Python 3.7.5 (default, Dec 15 2019, 17:54:26)
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ipaddress
>>> a=ipaddress.ip_address('2041:0000:140F:0000:0000:0000:875B:131B')
>>> b=ipaddress.ip_address('2041:0000:140F::875B:131B')
>>> c=ipaddress.ip_address('2041:0:140F::875B:131B')
>>> a==b==c
True
you can try with socket library :
import socket
ip1 = "2041:0000:140F:0000:0000:0000:875B:131B"
ip2 = "2041:0000:140F::875B:131B"
ip3 = "2041:0000:140F::875B:131B"
if socket.inet_pton(socket.AF_INET6, ip1) == socket.inet_pton(socket.AF_INET6, ip2) == socket.inet_pton(socket.AF_INET6, ip3):
print ("match")
Output:
For example:
import sys
def extend_ipv6(src):
parts = src.split(":")
if '%' in parts[-1]:
parts[-1], _ = parts[-1].split('%', 2)
n_parts = len(parts)
out = list()
for part in parts:
if len(part) == 0:
for i in range(8-n_parts+1):
out.append("0000")
else:
out.append("0"*(4-len(part))+part)
return ":".join(out)
def main():
for arg in sys.argv[1:]:
print(extend_ipv6(arg))
if __name__ == "__main__":
main()
python3 do.py 2041:0000:140F:0000:0000:0000:875B:131B 2041:0000:140F::875B:131B 2041:0:140F::875B:131B 2041:0:140F::875B:131B%11
2041:0000:140F:0000:0000:0000:875B:131B
2041:0000:140F:0000:0000:0000:875B:131B
2041:0000:140F:0000:0000:0000:875B:131B
2041:0000:140F:0000:0000:0000:875B:131B
will be this solution enough for your task?
In an IPython terminal, I want a function deep in main()
to go back to IPython, where I can print, set ... as usual, then keep running main():
IPython
run main.py
...
def callback( *args ):
...
try:
back_to_ipython() # <-- how to do this ?
In[]: print, set *args ...
...
except KeyboardInterrupt: # or IPython magic
pass
return # from callback(), keep running main()
This must run in python2.
(The name callback could be anything, but my use case is scipy.optimize -> callback.
Perhaps some clever scipy person has done this ?)
Added Tuesday 11 Oct: thanks for embed,
but it seems to run into a bug, or my misunderstanding:
# http://stackoverflow.com/questions/39946052/how-to-coroutine-ipython-a-callback
import sys
from IPython import __version__
from IPython import embed # $site/IPython/terminal/embed.py
from IPython.terminal.ipapp import load_default_config
print "versions: IPython %s python %s" % (
__version__, sys.version.split()[0] )
def pdict( header, adict ):
print header
for k, v in sorted( adict.items() ):
print "%s\t: %s" % (k, v)
config = load_default_config()
pdict( "load_default_config:", config )
aglobal = [3]
#...............................................................................
def callback( adict ):
# pdict( "callback:", adict )
t = adict["t"]
x = 3
embed( header="callback: t %d" % t )
# interact: print t x ...
# ^D / EOF
return
def aloop( *args ):
for t in range( 3 ):
callback( locals() )
aloop( 1, 2, 3 ) # works in "run this.py"
# but typing "aloop()" in an IPython terminal ->
# embed.py:218: UserWarning: Failed to get module unknown module
# global_ns.get('__name__', 'unknown module')
You could insert a breakpoint, which would give similar outcome:
import pdb; pdb.set_trace()
https://docs.python.org/3.6/library/pdb.html
Alternative here (embed() function within iPython):
Step-by-step debugging with IPython
Adapting the answer in https://stackoverflow.com/a/24827245/901925, I added an Ipython embed (https://ipython.org/ipython-doc/3/api/generated/IPython.terminal.embed.html)
import numpy as np
from scipy.optimize import minimize, rosen
import time
import warnings
from IPython import embed
class TookTooLong(Warning):
pass
class MinimizeStopper(object):
def __init__(self, max_sec=60):
self.max_sec = max_sec
self.start = time.time()
def __call__(self, xk=None):
elapsed = time.time() - self.start
if elapsed > self.max_sec:
embed(header='FirstTime')
warnings.warn("Terminating optimization: time limit reached",
TookTooLong)
else:
# you might want to report other stuff here
print("Elapsed: %.3f sec" % elapsed)
# example usage
x0 = [1.3, 0.7, 0.8, 1.9, 1.2]
res = minimize(rosen, x0, method='Nelder-Mead', callback=MinimizeStopper(1E-3))
with a run like:
1251:~/mypy$ python3 stack39946052.py
Elapsed: 0.001 sec
Python 3.5.2 (default, Jul 5 2016, 12:43:10)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
FirstTime
In [1]: xk
Out[1]: array([ 1.339, 0.721, 0.824, 1.71 , 1.236])
In [2]: elapsed
Out[2]: 0.0010917186737060547
In [3]: self.max_sec
Out[3]: 0.001
In [4]: self.max_sec=1000
In [5]:
Do you really want to exit ([y]/n)? y
stack39946052.py:20: TookTooLong: Terminating optimization: time limit reached
TookTooLong)
....
This is my code, I have to add a counter into my code so that every time the button is pressed it will count up once and i would like to to keep on counting up every time the button is pressed. I searched online and found out that I have to store the counter data to a file but i do not know how to write a code to do the count and store the count to a file. please help
from time import sleep
import RPi.GPIO as GPIO
import os
import sys
import webbrowser
GPIO.setmode(GPIO.BOARD)
button=40
button1=11
car=("/home/pi/Desktop/htb.mp4")
car2=("/home/pi/Desktop/htb2.mp4")
GPIO.setup(button,GPIO.IN)
GPIO.setup(button1,GPIO.IN)
quit_video=True
player=False
while(1):
if GPIO.input(button)==0 and GPIO.input(button1)==1:
print " thru beam "
os.system('pkill omxplayer')
os.system('omxplayer -r htb.mp4')
sleep(.5)
if GPIO.input(button1)==0 and GPIO.input(button)==1:
print " that other sensor "
os.system('pkill omxplayer')
os.system('omxplayer -r htb2.mp4')
sleep(.5)
else:
print " home "
webbrowser.open('https://www.google.com.sg/')
sleep(.5)
Such a program will help you:
import os
if not os.path.isfile("counter.txt"):
counter = 1
f = open("counter.txt","w+")
f.write(str(counter))
f.close()
print (counter)
else:
f = open("counter.txt","r+")
counter = int(f.readline())
counter += 1
f.seek(0)
f.write(str(counter))
f.close()
print (counter)
As you see below, it shares a counter between different runs:
Python 2.7.10 (default, May 23 2015, 09:44:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
1
>>> ================================ RESTART ================================
>>>
2
>>> ================================ RESTART ================================
>>>
3
>>> ================================ RESTART ================================
>>>
4
>>> ================================ RESTART ================================
>>>
5
>>>
I'm trying to retrieve file information (specifically info about the icon) using SHGetFileInfo. In reality, I don't have the full path of the file, I only have the pidl.
The following code returns (0L, (0, 0, 0, '', '')) and my question is why.
from win32com.shell import shell, shellcon
def get_info():
desktop = shell.SHGetDesktopFolder()
eaten, desktop_pidl, attr = desktop.ParseDisplayName(None, None, r"C:\Users\Ella\Desktop")
return shell.SHGetFileInfo(desktop_pidl, 0, shellcon.SHGFI_PIDL | shellcon.SHGFI_SYSICONINDEX | shellcon.SHGFI_ICON | shellcon.SHGFI_DISPLAYNAME)
On the other hand, the code bellow does work for some reason (it uses full path instead of pidl):
from win32com.shell import shell, shellcon
def get_info2():
return shell.SHGetFileInfo(r"C:\Users\Ella\Desktop", 0, shellcon.SHGFI_SYSICONINDEX | shellcon.SHGFI_ICON | shellcon.SHGFI_DISPLAYNAME)
Thanks!
You've uncovered a bug in PySHGetFileInfo. If SHGFI_PIDL is set in flags, it calls PyObject_AsPIDL and stores the result to pidl_or_name, but it mistakenly passes name to SHGetFileInfo, which in this case is the initial NULL value. See below for more details.
You asked how to set a breakpoint on shell32!SHGetFileInfoW. There's no simple answer to that. Instead allow me to share an overview of what I did to test this. Hopefully this will at least get you started.
Test environment:
64-bit Windows 7 SP1 (6.1.7601)
Windows SDK 7.1 (ensure the debuggers are installed)
Visual Studio 2010 SP1
Visual C++ 2010 SP1 Compiler Update
Python 3.4 (and debug files)
Mercurial (hg.exe, not TortoiseHg)
Set up the shell environment.
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd"
set MSSdk=%WindowsSDKDir%
set SYMDIR=C:\Symbols
set SYMSRV=http://msdl.microsoft.com/download/symbols
set _NT_SYMBOL_PATH=symsrv*symsrv.dll*%SYMDIR%*%SYMSRV%
path C:\Program Files\Debugging Tools for Windows (x64);%PATH%
path C:\Program Files\Mercurial;%PATH%
Create a Python virtual environment.
py -3.4 -m venv --symlinks test
venv doesn't link the .pdb files, so grab those manually in a for loop.
set PYDIR="%ProgramW6432%\Python34"
set CMD=mklink "test\Scripts\%~nxf" "%f"
for /R %PYDIR% %f in (*.pdb) do #%CMD%
Activate the virtual environment.
test\Scripts\activate
Clone the PyWin32 repo. Build and install version 219.
set HGSRV=http://pywin32.hg.sourceforge.net
hg clone %HGSRV%/hgroot/pywin32/pywin32
cd pywin32
hg up b219
I edited setup.py to comment out everything related to building
win32com.mapi. My setup didn't even have the required headers,
and when I obtained them there were problems building the
extension for WIN64.
Build and install the package.
python setup3.py install
Run Python under the console debugger, cdb.exe.
>cdb -xi ld python
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: python
Symbol search path is: symsrv*symsrv.dll*C:\Symbols*
http://msdl.microsoft.com/download/symbols
Executable search path is:
(d50.1174): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`770bcb70 cc int 3
0:000> bp shell32!SHGetFileInfoW
0:000> g
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:16:31)
[MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
The option -xi ld in the above command line sets a filter to ignore printing loaded modules. There are lots of tutorials and 'cheat sheets' online for using Microsoft's debuggers such as WinDbg, cdb, and kd. The debuggers all use the same engine, so they support a common set of debugging commands.
The attached debugger has a breakpoint set on shell32!SHGetFileInfoW. When the breakpoint is triggered, the debugger grabs the console. One of the few redeeming features of the Windows console is its per-application input history and aliases. This makes it convenient to recall commands when bouncing in and out of the debugger and debuggee in the same console window.
>>> import os
>>> from win32com.shell import shell, shellcon
>>> print(shell.__file__)
C:\Temp\test\lib\site-packages\win32comext\shell\shell.pyd
>>> path = os.path.expanduser(r'~\Desktop\desktop.ini')
>>> pidl = shell.SHParseDisplayName(path, 0, None)[0]
>>> flags = (shellcon.SHGFI_PIDL |
... shellcon.SHGFI_SYSICONINDEX |
... shellcon.SHGFI_ICON |
... shellcon.SHGFI_DISPLAYNAME)
>>> shell.SHGetFileInfo(pidl, 0, flags)
Breakpoint 0 hit
SHELL32!SHGetFileInfoW:
000007fe`fd692290 fff3 push rbx
0:000> k 5
*** WARNING: Unable to verify checksum for
C:\Temp\test\lib\site-packages\win32comext\shell\shell.pyd
Child-SP RetAddr Call Site
00000000`003ff2d8 00000000`5f44c5e8 SHELL32!SHGetFileInfoW
00000000`003ff2e0 00000000`5f5af8bd shell!PySHGetFileInfo+0xf8
00000000`003ff610 00000000`5f62385b python34!PyCFunction_Call+0x12d
00000000`003ff640 00000000`5f625c89 python34!call_function+0x2ab
00000000`003ff6a0 00000000`5f62770c python34!PyEval_EvalFrameEx+0x2279
0:000> r rcx
rcx=0000000000000000
0:000> g
(0, (0, 0, 0, '', ''))
In the Windows x64 ABI, the first argument of a function is passed in register rcx. We know from the SHGetFileInfo docs that this should be the PIDL, but actually NULL is being passed. Clearly this is a bug. The stack trace lays the blame on shell!PySHGetFileInfo. Here's a snippet of the problematic code:
if (flags & SHGFI_PIDL) {
ok = PyObject_AsPIDL(obName, &pidl, FALSE);
pidl_or_name = (TCHAR *)pidl;
} else {
ok = PyWinObject_AsTCHAR(obName, &name, FALSE);
pidl_or_name = name;
}
if (!ok)
return NULL;
SHFILEINFO info;
memset(&info, 0, sizeof(info));
info.dwAttributes = info_attrs;
PY_INTERFACE_PRECALL;
DWORD_PTR dw = SHGetFileInfo(name, attr, &info, sizeof(info), flags);
The mistake is passing name as the first argument instead of pidl_or_name.
The question is tagged ctypes. IMO, using ctypes is worth it if doing so eliminates a large dependency such as PyWin32. I wouldn't normally use ctypes by itself for a COM-based API. The comtypes package builds on ctypes if you want to try that. In this case directly calling COM methods can be avoided by instead calling SHParseDisplayName. Other than using HRESULT return codes, it's pretty much like any other Win32 API.
import types as _types
import ctypes as _ctypes
from ctypes import wintypes as _wtypes
_mtypes = _types.ModuleType('_mtypes')
_ole32 = _ctypes.WinDLL('ole32')
_shell32 = _ctypes.WinDLL('shell32')
_user32 = _ctypes.WinDLL('user32')
try:
from win32com.shell import shell as _shell
except ImportError:
_shell = None
try:
from win32com.shell import shellcon
except ImportError:
shellcon = _types.ModuleType('shellcon')
shellcon.SHGFI_LARGEICON = 0x00000
shellcon.SHGFI_SMALLICON = 0x00001
shellcon.SHGFI_OPENICON = 0x00002
shellcon.SHGFI_SHELLICONSIZE = 0x00004
shellcon.SHGFI_PIDL = 0x00008
shellcon.SHGFI_USEFILEATTRIBUTES = 0x00010
shellcon.SHGFI_ICON = 0x00100
shellcon.SHGFI_DISPLAYNAME = 0x00200
shellcon.SHGFI_TYPENAME = 0x00400
shellcon.SHGFI_ATTRIBUTES = 0x00800
shellcon.SHGFI_ICONLOCATION = 0x01000
shellcon.SHGFI_EXETYPE = 0x02000
shellcon.SHGFI_SYSICONINDEX = 0x04000
shellcon.SHGFI_LINKOVERLAY = 0x08000
shellcon.SHGFI_SELECTED = 0x10000
shellcon.SHGFI_ATTR_SPECIFIED = 0x20000
try:
import win32con
except ImportError:
win32con = _types.ModuleType('win32con')
win32con.MAX_PATH = 260
win32con.FILE_ATTRIBUTE_READONLY = 0x00001
win32con.FILE_ATTRIBUTE_HIDDEN = 0x00002
win32con.FILE_ATTRIBUTE_SYSTEM = 0x00004
win32con.FILE_ATTRIBUTE_DIRECTORY = 0x00010
win32con.FILE_ATTRIBUTE_ARCHIVE = 0x00020
win32con.FILE_ATTRIBUTE_DEVICE = 0x00040
win32con.FILE_ATTRIBUTE_NORMAL = 0x00080
win32con.FILE_ATTRIBUTE_TEMPORARY = 0x00100
win32con.FILE_ATTRIBUTE_ATOMIC_WRITE = 0x00200
win32con.FILE_ATTRIBUTE_SPARSE_FILE = 0x00200
win32con.FILE_ATTRIBUTE_REPARSE_POINT = 0x00400
win32con.FILE_ATTRIBUTE_XACTION_WRITE = 0x00400
win32con.FILE_ATTRIBUTE_COMPRESSED = 0x00800
win32con.FILE_ATTRIBUTE_OFFLINE = 0x01000
win32con.FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x02000
win32con.FILE_ATTRIBUTE_ENCRYPTED = 0x04000
win32con.FILE_ATTRIBUTE_VIRTUAL = 0x10000
_mtypes.CData = _ctypes.Array.__bases__[0]
_mtypes.PPIDLIST_ABSOLUTE = _ctypes.POINTER(_ctypes.c_void_p)
_mtypes.SFGAOF = _wtypes.ULONG
_mtypes.PSFGAOF = _ctypes.POINTER(_mtypes.SFGAOF)
_ole32.CoInitialize.restype = _ctypes.HRESULT # checked
_ole32.CoInitialize.argtypes = (_ctypes.c_void_p,)
_ole32.CoUninitialize.restype = None
_ole32.CoUninitialize.argtypes = ()
_ole32.CoTaskMemFree.restype = None
_ole32.CoTaskMemFree.argtypes = (_ctypes.c_void_p,)
_user32.DestroyIcon.argtypes = (_wtypes.HICON,)
_shell32.SHParseDisplayName.restype = _ctypes.HRESULT # checked
_shell32.SHParseDisplayName.argtypes = (
_wtypes.LPCWSTR, # pszName, _In_
_ctypes.c_void_p, # pbc, _In_opt_
_mtypes.PPIDLIST_ABSOLUTE, # ppidl, _Out_
_mtypes.SFGAOF, # sfgaoIn, _In_
_mtypes.PSFGAOF) # psfgaoOut, _Out_opt_
class SHFILEINFO(_ctypes.Structure):
_fields_ = (('hIcon', _wtypes.HICON),
('iIcon', _ctypes.c_int),
('dwAttributes', _wtypes.DWORD),
('szDisplayName', _wtypes.WCHAR * win32con.MAX_PATH),
('szTypeName', _wtypes.WCHAR * 80))
_mtypes.SHFILEINFO = SHFILEINFO
_mtypes.PSHFILEINFO = _ctypes.POINTER(SHFILEINFO)
_shell32.SHGetFileInfoW.restype = _ctypes.c_void_p
_shell32.SHGetFileInfoW.argtypes = (
_wtypes.LPVOID, # pszPath, _In_
_wtypes.DWORD, # dwFileAttributes,
_mtypes.PSHFILEINFO, # psfi, _Inout_
_wtypes.UINT, # cbFileInfo,
_wtypes.UINT) # uFlags
def SHGetFileInfo(pidl, attributes=0, flags=0):
if _shell is not None:
if not isinstance(pidl, (str, bytes, _mtypes.CData)):
pidl = _shell.PIDLAsString(pidl)
finfo = SHFILEINFO()
_ole32.CoInitialize(None)
try:
retval = _shell32.SHGetFileInfoW(pidl,
attributes,
_ctypes.byref(finfo),
_ctypes.sizeof(finfo),
flags)
finally:
_ole32.CoUninitialize()
if not retval:
if flags != shellcon.SHGFI_EXETYPE:
raise _ctypes.WinError()
return retval, finfo
Example:
if __name__ == '__main__':
import os
path = os.path.expanduser(r'~\Desktop\desktop.ini')
pidl = _shell.SHParseDisplayName(path, 0)[0]
assert isinstance(pidl, list)
flags = (shellcon.SHGFI_PIDL |
shellcon.SHGFI_ICON |
shellcon.SHGFI_DISPLAYNAME |
shellcon.SHGFI_TYPENAME |
shellcon.SHGFI_ATTRIBUTES |
shellcon.SHGFI_SYSICONINDEX)
hImageList, finfo = SHGetFileInfo(pidl, 0, flags)
print('hImageList:', hImageList)
for name, typ in finfo._fields_:
print(name, ': ', ascii(getattr(finfo, name)), sep='')
if finfo.hIcon:
_user32.DestroyIcon(finfo.hIcon)
Output:
hImageList: 4411024
hIcon: 10617107
iIcon: 7
dwAttributes: 1078497655
szDisplayName: 'desktop.ini'
szTypeName: 'Configuration settings'
This question already has answers here:
How to duplicate sys.stdout to a log file?
(19 answers)
Closed 9 years ago.
Newb python question. I've been reading up on tee() and different ways of splitting output. But i cant find a good example for splitting output to the terminal and to a log file. I've been playing around with some options and this is what I have so far:
def logname():
env.warn_only = True
timestamp = time.strftime("%d_%b_%Y")
return "%s_%s" % (env.host_string, timestamp)
sys.stdout = open('/home/path/to/my/log/directory/%s' % logname(), 'w')
The above will log to a file with the host name_datestamp but won't display anything on screen. Then when I want to stop logging i do:
sys.stdout = sys.__stdout__
How can I log to my file with the definiton above and display to the terminal at the same time? Am I on the right path with tee()?
Like this?
[user#machine ~]$ python
Python 2.7.3 (default, Aug 9 2012, 17:23:57)
[GCC 4.7.1 20120720 (Red Hat 4.7.1-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>>
>>> class Tee(object):
... def __init__(self, logfile, stdio = sys.__stdout__):
... self.logf = open(logfile, 'w')
... self.stdio = stdio
... def write(self, data):
... self.logf.write(data)
... self.stdio.write(data)
... def flush(self):
... self.logf.flush()
... self.stdio.flush()
... def __getattr__(self, k):
... return getattr(self.stdio, k)
... def __dir__(self):
... return dir(self.stdio)
...
>>> sys.stdout = Tee('/tmp/output')
>>> print 'some test output'
some test output
>>>
[user#machine ~]$ cat /tmp/output
some test output
[user#machine ~]$