I've tested both painfullness and time of my inline docs suggestion.
On a whim (with no relation to the doc-sig) I wrote a small generic dict
module. Then I decided to document it and see how much it puts me off. I
discovered that it was pretty easy. (This was with vi -- if you're using
an editor that's less friendly it might be harder).
I then decided to re-do fileinput.py's doc-string (it has only a module
level doc-string) in the new output.
I've discovered that most of my time was in filling out neccessary
information, rather then in markup technicalities.
Attached are the results of this test.
It rather suprised me, because it reminded me more of writing LaTeX then
writing HTML or XML: I did both pretty heavily be hand, and LaTeX writing
is much easier.
I have a small request: would anyone be willing to take a doc-string'ed
module a redo it in my suggested syntax and return to tell us of the
experience? (See, Randy got to me too)
--
Moshe Zadka <mzadka(a)geocities.com>.
INTERNET: Learn what you know.
Share what you don't.
"""Helper class to quickly write a loop over all standard input files.
Typical use is:
example::
import fileinput
for line in fileinput.input():
process(line)
This iterates over the lines of all files listed in [sys.argv[1:]],
defaulting to [var sys.stdin] if the list is empty. If a filename is
[code '-'] it is also replaced by [code sys.stdin]. To specify an alternative
list of filenames, pass it as the argument to [function input()]. A single
file name is also allowed.
Functions [function filename()], [function lineno()] return the filename and
cumulative line number of the line that has just been read;
[function filelineno()] returns its line number in the current file;
[function isfirstline()] returns true iff the line just read is the first line
of its file; [function isstdin()] returns true iff the line was read from
[var sys.stdin]. Function [function nextfile()] closes the
current file so that the next iteration will read the first line from
the next file (if any); lines not read from the file will not count
towards the cumulative line count; the filename is not changed until
after the first line of the next file has been read. Function
[function close()] closes the sequence.
Before any lines have been read, [function filename()] returns [var None] and
both line numbers are zero; [function nextfile()] has no effect. After all
lines have been read, [function filename()] and the line number functions
return the values pertaining to the last line read; [function nextfile()] has
no effect.
All files are opened in text mode. If an I/O error occurs during
opening or reading a file, the [exception IOError] exception is raised.
If [var sys.stdin] is used more than once, the second and further use will
return no lines, except perhaps for interactive use, or if it has been
explicitly reset (e.g. using [code sys.stdin.seek(0))].
Empty files are opened and immediately closed; the only time their
presence in the list of filenames is noticeable at all is when the
last file opened is empty.
It is possible that the last line of a file doesn't end in a newline
character; otherwise lines are returned including the trailing
newline.
Class [class FileInput] is the implementation; its methods
[function filename()], [function lineno()], [function fileline()],
[function isfirstline()], [function isstdin()], [function nextfile()] and
[function close()] correspond to the functions in the module. In addition it
has a [function readline()] method which returns the next input line, and a
[function __getitem__()] method which implements the sequence behavior. The
sequence must be accessed in strictly sequential order; sequence
access and [function readline()] cannot be mixed.
Optional in-place filtering: if the keyword argument [var inplace] is passed
to [function input()] with a true value or to the [class FileInput]
constructor, the file is moved to a backup file and standard output is
directed to the input file. This makes it possible to write a filter that
rewrites its input file in place. If the keyword argument [var backup] is
passed to [function input()] or to the constructor of [class FileInput],
it is treated as the extension for the backup file, and the backup
file remains around; by default, the extension is [code ".bak"] and it is
deleted when the output file is closed. In-place filtering is
disabled when standard input is read. XXX The current implementation
does not work for MS-DOS 8+3 filesystems.
XXX Possible additions:
list::
item:: optional [module getopt] argument processing
item:: specify open mode ([code 'r'] or [code 'rb'])
item:: specify buffer size
item:: [function fileno()]
item:: [function isatty()]
item:: [function read()], [function read(size)], even [function readlines()]
"""
class GeneralDict:
'''\
A dictionary which can be indexed by any type, including mutable types.
This class implements a dictionary which can be indexed by any type,
including mutables like lists and dictionaries.
'''
def __init__(self):
self._dict={}
self._temp_keys={}
def __getitem__(self, name):
'''\
get an item by name.
[emph caveat]: if [var name] is mutable, then object
equality among keys is not enough. In other words,
example::
>>> a = GeneralDict()
>>> a[[1,2,3]]=1
>>> try:
... a[[1,2,3]]
... except KeyError:
... print "Caveat!"
...
Caveat!
arg name=name::
the name to lookup in the dictionary
'''
try:
hash(name)
except TypeError:
return self._dict[id(name)]
else:
return self._dict[1, name]
def __setitem__(self, name, value):
'''\
set a name/value mapping
arg name=name::
the name to associate a value with.
arg name=value::
the value to associate with the name
'''
try:
self._dict[1, name]=value
except TypeError:
# keep a reference to 'name'
self._temp_keys[id(name)]=name
self._dict[id(name)]=value
def __delitem__(self, name):
'''\
delete an association from the mapping.
arg name=name::
the name to delete the association to.
'''
# I'd rather explicitly test for hash, because
# otherwise the exceptions get mixed
try:
hash(name)
except TypeError:
del self._dict[id(name)]
del self._temp_keys[id(name)]
else:
del self._dict[1, name]
def keys(self):
'''return a list of all keys in the mapping'''
ret = []
for k in self._dict.keys():
if type(k) is type(()):
ret.append(k[1])
else:
ret.append(self._temp_keys[k])
return ret
def _test():
a=GeneralDict()
a[ [1, 2, 3] ] = 1
seq = k = a.keys()[0]
assert a[k] == 1
a[ 2 ] = 6
for k in a.keys():
if k == 2:
assert a[k] == 6
if k == [1, 2, 3]:
assert a[k] == 1
del a[seq]
assert len(a.keys()) == 1
assert a[a.keys()[0]] == 6
if __name__ == '__main__':
_test()