a file. Useful for a shortened output statements in the code, and also for reroutable output (to stdout? to file? to both?) and flexible output kind.
184 lines
5.8 KiB
Python
184 lines
5.8 KiB
Python
# $Id: text_output.py,v 1.1 2011-05-11 20:28:51 wirawan Exp $
|
|
#
|
|
# wpylib.iofmt.text_output module
|
|
# Quick-n-dirty text output utilities
|
|
#
|
|
# Wirawan Purwanto
|
|
# Created: 20110511
|
|
#
|
|
# Routines put here are commonly used in my own scripts.
|
|
# They are not necessarily suitable for general-purpose uses; evaluate
|
|
# your needs and see if they can them as well.
|
|
#
|
|
# 20110426: Created as Logger class in my check-git-vs-cvs.py tool.
|
|
# 20110511: Moved to wpylib.iofmt.text_output .
|
|
#
|
|
"""
|
|
Simple text-based output writer.
|
|
This is supposedly the converse of text_input, but with different
|
|
capabilities.
|
|
|
|
This module is part of wpylib project.
|
|
"""
|
|
|
|
import sys
|
|
|
|
class text_output(object):
|
|
"""A simple text output.
|
|
For use as a convenience tool like this:
|
|
|
|
def subroutine(..., out=sys.stdout):
|
|
from pyqmc.iofmt.text_output import text_output
|
|
o = text_output(out)
|
|
o("Line1\n")
|
|
o("Line2\n")
|
|
o("part of Line3: ")
|
|
for x in [2,3,4]:
|
|
o(" this is subpart %s" % x)
|
|
o("\n")
|
|
|
|
The text_output object is file-like for write-only purposes,
|
|
and can be wrapped by yet another text_output object.
|
|
|
|
The object's `_output' attribute can be set to whatever action
|
|
(object method) you like to use (e.g. via subclassing), or
|
|
by defining a stand-alone function that accepts "self" as the
|
|
first argument.
|
|
The set_write_func() function *must* be called for this purpose.
|
|
|
|
To mute the output completely, set the `out' argument to None when
|
|
creating the object.
|
|
|
|
Caveat:
|
|
* If the file-like object is closed, then we will do nothing
|
|
for the rest of the __call__ invocation.
|
|
"""
|
|
|
|
"""---------------------------------------------------------------------
|
|
Private members:
|
|
* _autoopen -- boolean to indicate privately owned file object
|
|
* _output -- method to output the stuff
|
|
* out -- the output
|
|
|
|
Internal notes:
|
|
* A carefully thought hack is required to allow interchangeable
|
|
"_output" method below.
|
|
Here is my collected wisdom:
|
|
- We can't define __call__ as a class attribute, like this:
|
|
|
|
self.__call__ = self.write
|
|
|
|
It won't work when the object is called: i.e. the following will cause
|
|
an exception with "__call__" method not found:
|
|
|
|
self("blah\n")
|
|
|
|
- We shouldn't use the following either:
|
|
|
|
self._output = self.write
|
|
|
|
because the _output has an im_self member, which is a strong reference
|
|
to self.
|
|
This circular dependence causes the object (self) to never vanish when
|
|
it is supposed to.
|
|
|
|
- Some options are available out there to introduce a "weak" object
|
|
method (e.g. WeakMethod, http://code.activestate.com/recipes/81253/)
|
|
but it is too much for what we want to accomplish here.
|
|
|
|
What I chose below is the *most* liberal choice which allow unbound
|
|
function (with "self" as the first argument) to become the
|
|
standard _output routine using slight .
|
|
This is the best and most flexible, in my opinion, rather than imposing
|
|
extra restrictions.
|
|
---------------------------------------------------------------------"""
|
|
|
|
def __init__(self, out=sys.stdout, flush=False):
|
|
"""Initializes the text output.
|
|
Options:
|
|
- flush: if true, will flush every time the default action is invoked.
|
|
"""
|
|
print sys.getrefcount(self)
|
|
self.out = None
|
|
self.open(out)
|
|
print sys.getrefcount(self)
|
|
if flush:
|
|
self.set_write_func(self.write_flush)
|
|
else:
|
|
self.set_write_func(self.write)
|
|
print sys.getrefcount(self)
|
|
def __del__(self):
|
|
print "Deleting object %s, file %s" % (self, self.out)
|
|
self.close()
|
|
def set_write_func(self, method):
|
|
"""Sets the default '_output' function to a python bound method.
|
|
Always use this method, instead of setting self._output directly!
|
|
|
|
NOTE:
|
|
This is intentionally sloppy (no im_class or im_self checks),
|
|
so that it can be used to perform DIRTY hack,such as allowing an
|
|
arbitrary function (bound function from another unrelated class, or
|
|
unbound function) to be attached as the output function."""
|
|
if hasattr(method, "im_func"):
|
|
self._output = method.im_func
|
|
else:
|
|
# assume that method is a stand-alone callable object
|
|
# that can accept "self" as the first argument
|
|
self._output = method
|
|
def open(self, out=sys.stdout):
|
|
self.close()
|
|
self._autoopen = False
|
|
if out == None:
|
|
self.out = None
|
|
elif self.is_file_like(out):
|
|
self.out = out
|
|
else: # assume a string (a filename)
|
|
self.out = open(out, "w")
|
|
self.outfilename = out
|
|
self._autoopen = True
|
|
def close(self):
|
|
"""Closes the text_output's output object.
|
|
At least, flushes everything at the end of the output's association
|
|
with this text_output object.
|
|
"""
|
|
if self.out:
|
|
if self._autoopen:
|
|
print "Closing file " + self.out.name
|
|
self.out.close() # depends on existing close() method
|
|
else:
|
|
self.out.flush()
|
|
self.out = None
|
|
|
|
@staticmethod
|
|
def is_file_like(obj):
|
|
return isinstance(obj, file) \
|
|
or (hasattr(obj, "write") and hasattr(obj, "flush"))
|
|
|
|
def __call__(self, *_list, **_args):
|
|
"""Unfortunately __call__ cannot be a usual class attribute.
|
|
So we have to use a thin dispatcher here."""
|
|
self._output(self, *_list, **_args)
|
|
|
|
# Original I/O routine is preserved by _* method name
|
|
# FIXME: A better optimization can be introduced needed if
|
|
# self.out is yet another text_output instance.
|
|
# But beware of possible method polymorphism if you do this. (!!!)
|
|
def _write(self, s):
|
|
if self.out: self.out.write(s)
|
|
def _flush(self):
|
|
if self.out: self.out.flush()
|
|
def _write_flush(self, s):
|
|
if self.out:
|
|
self.out.write(s)
|
|
self.out.flush()
|
|
# The logger itself is a file-like object, too:
|
|
write = _write
|
|
flush = _flush
|
|
write_flush = _write_flush
|
|
|
|
|
|
def test1():
|
|
O = text_output("/tmp/test1abc.txt", flush=1)
|
|
O("this is a test\n")
|
|
O("--------------\n")
|