added PEP 355, Path - Object oriented filesystem paths, by B. Lindqvist
This commit is contained in:
parent
98dd3dcbe4
commit
dda6d09e62
|
@ -109,6 +109,7 @@ Index by Category
|
||||||
S 352 Required Superclass for Exceptions GvR, Cannon
|
S 352 Required Superclass for Exceptions GvR, Cannon
|
||||||
S 353 Using ssize_t as the index type von Loewis
|
S 353 Using ssize_t as the index type von Loewis
|
||||||
S 354 Enumerations in Python Finney
|
S 354 Enumerations in Python Finney
|
||||||
|
S 355 Path - Object oriented filesystem paths Lindqvist
|
||||||
S 754 IEEE 754 Floating Point Special Values Warnes
|
S 754 IEEE 754 Floating Point Special Values Warnes
|
||||||
|
|
||||||
Finished PEPs (done, implemented in Subversion)
|
Finished PEPs (done, implemented in Subversion)
|
||||||
|
@ -404,6 +405,7 @@ Numerical Index
|
||||||
S 352 Required Superclass for Exceptions GvR, Cannon
|
S 352 Required Superclass for Exceptions GvR, Cannon
|
||||||
S 353 Using ssize_t as the index type von Loewis
|
S 353 Using ssize_t as the index type von Loewis
|
||||||
S 354 Enumerations in Python Finney
|
S 354 Enumerations in Python Finney
|
||||||
|
S 355 Path - Object oriented filesystem paths Lindqvist
|
||||||
SR 666 Reject Foolish Indentation Creighton
|
SR 666 Reject Foolish Indentation Creighton
|
||||||
S 754 IEEE 754 Floating Point Special Values Warnes
|
S 754 IEEE 754 Floating Point Special Values Warnes
|
||||||
I 3000 Python 3.0 Plans Kuchling, Cannon
|
I 3000 Python 3.0 Plans Kuchling, Cannon
|
||||||
|
@ -474,6 +476,7 @@ Owners
|
||||||
Kuchling, A.M. amk@amk.ca
|
Kuchling, A.M. amk@amk.ca
|
||||||
Lemburg, Marc-Andre mal@lemburg.com
|
Lemburg, Marc-Andre mal@lemburg.com
|
||||||
Lielens, Gregory gregory.lielens@fft.be
|
Lielens, Gregory gregory.lielens@fft.be
|
||||||
|
Lindqvist, Björn bjourne@gmail.com
|
||||||
von Loewis, Martin loewis@informatik.hu-berlin.de
|
von Loewis, Martin loewis@informatik.hu-berlin.de
|
||||||
Martelli, Alex aleax@aleax.it
|
Martelli, Alex aleax@aleax.it
|
||||||
McClelland, Andrew eternalsquire@comcast.net
|
McClelland, Andrew eternalsquire@comcast.net
|
||||||
|
|
|
@ -0,0 +1,506 @@
|
||||||
|
PEP: 355
|
||||||
|
Title: Path - Object oriented filesystem paths
|
||||||
|
Version: $Revision$
|
||||||
|
Last-Modified: $Date$
|
||||||
|
Author: Björn Lindqvist <bjourne@gmail.com>
|
||||||
|
Status: Draft
|
||||||
|
Type: Standards Track (library)
|
||||||
|
Created: 24-Jan-2006
|
||||||
|
Content-Type: text/plain
|
||||||
|
Python-Version: 2.5
|
||||||
|
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
|
||||||
|
This PEP describes a new class, Path, to be added to the os
|
||||||
|
module, for handling paths in an object oriented fashion. The
|
||||||
|
"weak" deprecation of various related functions is also discussed
|
||||||
|
and recommended.
|
||||||
|
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
|
||||||
|
Dealing with filesystem paths is a common task in any programming
|
||||||
|
language, and very common in a high-level language like Python.
|
||||||
|
Good support for this task is needed, because:
|
||||||
|
|
||||||
|
- Almost every program uses paths to access files. It makes sense
|
||||||
|
that a task, that is so often performed, should be as intuitive
|
||||||
|
and as easy to perform as possible.
|
||||||
|
|
||||||
|
- It makes Python an even better replacement language for
|
||||||
|
over-complicated shell scripts.
|
||||||
|
|
||||||
|
Currently, Python has a large number of different functions
|
||||||
|
scattered over half a dozen modules for handling paths. This
|
||||||
|
makes it hard for newbies and experienced developers to to choose
|
||||||
|
the right method.
|
||||||
|
|
||||||
|
The Path class provides the following enhancements over the
|
||||||
|
current common practice:
|
||||||
|
|
||||||
|
- One "unified" object provides all functionality from previous
|
||||||
|
functions.
|
||||||
|
|
||||||
|
- Subclassability - the Path object can be extended to support
|
||||||
|
paths other than filesystem paths. The programmer does not need
|
||||||
|
to learn a new API, but can reuse his or her knowledge of Path
|
||||||
|
to deal with the extended class.
|
||||||
|
|
||||||
|
- With all related functionality in one place, the right approach
|
||||||
|
is easier to learn as one does not have to hunt through many
|
||||||
|
different modules for the right functions.
|
||||||
|
|
||||||
|
- Python is an object oriented language. Just like files,
|
||||||
|
datetimes and sockets are objects so are paths, they are not
|
||||||
|
merely strings to be passed to functions. Path objects is
|
||||||
|
inherently a pythonic idea.
|
||||||
|
|
||||||
|
- Path takes advantage of properties. Properties make for more
|
||||||
|
readable code.
|
||||||
|
|
||||||
|
if imgpath.ext == 'jpg':
|
||||||
|
jpegdecode(imgpath)
|
||||||
|
|
||||||
|
Is better than:
|
||||||
|
|
||||||
|
if os.path.splitexit(imgpath)[1] == 'jpg':
|
||||||
|
jpegdecode(imgpath)
|
||||||
|
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
|
||||||
|
The following points summarize the design:
|
||||||
|
|
||||||
|
- Path extends from string, therefore all code which expects
|
||||||
|
string pathnames need not be modified and no existing code will
|
||||||
|
break.
|
||||||
|
|
||||||
|
- A Path object can be created either by using the classmethod
|
||||||
|
Path.cwd, by instantiating the class with a string representing
|
||||||
|
a path or by using the default constructor which is equivalent
|
||||||
|
to Path(".").
|
||||||
|
|
||||||
|
- Path provides common pathname manipulation, pattern expansion,
|
||||||
|
pattern matching and other high-level file operations including
|
||||||
|
copying. Basically Path provides everything path-related except
|
||||||
|
the manipulation of file contents, for which file objects are
|
||||||
|
better suited.
|
||||||
|
|
||||||
|
- Platform incompatibilites are dealt with by not instantiating
|
||||||
|
system specific methods.
|
||||||
|
|
||||||
|
|
||||||
|
Specification
|
||||||
|
|
||||||
|
This class defines the following public interface (docstrings have
|
||||||
|
been extracted from the reference implementation, and shortened
|
||||||
|
for brevity; see the reference implementation for more detail):
|
||||||
|
|
||||||
|
class Path(str):
|
||||||
|
|
||||||
|
# Special Python methods:
|
||||||
|
def __new__(cls, *args) => Path
|
||||||
|
"""
|
||||||
|
Creates a new path object concatenating the *args. *args
|
||||||
|
may only contain Path objects or strings. If *args is
|
||||||
|
empty, Path(os.curdir) is created.
|
||||||
|
"""
|
||||||
|
def __repr__(self): ...
|
||||||
|
def __add__(self, more): ...
|
||||||
|
def __radd__(self, other): ...
|
||||||
|
|
||||||
|
# Alternative constructor.
|
||||||
|
def cwd(cls): ...
|
||||||
|
|
||||||
|
# Operations on path strings:
|
||||||
|
def abspath(self) => Path
|
||||||
|
"""Returns the absolute path of self as a new Path object."""
|
||||||
|
def normcase(self): ...
|
||||||
|
def normpath(self): ...
|
||||||
|
def realpath(self): ...
|
||||||
|
def expanduser(self): ...
|
||||||
|
def expandvars(self): ...
|
||||||
|
def basename(self): ...
|
||||||
|
def expand(self): ...
|
||||||
|
def splitpath(self) => (Path, str)
|
||||||
|
"""p.splitpath() -> Return (p.parent, p.name)."""
|
||||||
|
def stripext(self) => Path
|
||||||
|
"""p.stripext() -> Remove one file extension from the path."""
|
||||||
|
def splitunc(self): ... [1]
|
||||||
|
def splitall(self): ...
|
||||||
|
def relpath(self): ...
|
||||||
|
def relpathto(self, dest): ...
|
||||||
|
|
||||||
|
# Properties about the path:
|
||||||
|
parent => Path
|
||||||
|
"""This Path's parent directory as a new path object."""
|
||||||
|
name => str
|
||||||
|
"""The name of this file or directory without the full path."""
|
||||||
|
ext => str
|
||||||
|
"""
|
||||||
|
The file extension or an empty string if Path refers to a
|
||||||
|
file without an extension or a directory.
|
||||||
|
"""
|
||||||
|
drive => str
|
||||||
|
"""
|
||||||
|
The drive specifier. Always empty on systems that don't
|
||||||
|
use drive specifiers.
|
||||||
|
"""
|
||||||
|
namebase => str
|
||||||
|
"""
|
||||||
|
The same as path.name, but with one file extension
|
||||||
|
stripped off.
|
||||||
|
"""
|
||||||
|
uncshare[1]
|
||||||
|
|
||||||
|
# Operations that return lists of paths:
|
||||||
|
def listdir(self, pattern = None): ...
|
||||||
|
def dirs(self, pattern = None): ...
|
||||||
|
def files(self, pattern = None): ...
|
||||||
|
def walk(self, pattern = None): ...
|
||||||
|
def walkdirs(self, pattern = None): ...
|
||||||
|
def walkfiles(self, pattern = None): ...
|
||||||
|
def match(self, pattern) => bool
|
||||||
|
"""Returns True if self.name matches the given pattern."""
|
||||||
|
|
||||||
|
def matchcase(self, pattern) => bool
|
||||||
|
"""
|
||||||
|
Like match() but is guaranteed to be case sensitive even
|
||||||
|
on platforms with case insensitive filesystems.
|
||||||
|
"""
|
||||||
|
def glob(self, pattern):
|
||||||
|
|
||||||
|
# Methods for retrieving information about the filesystem
|
||||||
|
# path:
|
||||||
|
def exists(self): ...
|
||||||
|
def isabs(self): ...
|
||||||
|
def isdir(self): ...
|
||||||
|
def isfile(self): ...
|
||||||
|
def islink(self): ...
|
||||||
|
def ismount(self): ...
|
||||||
|
def samefile(self, other): ... [1]
|
||||||
|
def getatime(self): ...
|
||||||
|
def getmtime(self): ...
|
||||||
|
def getctime(self): ...
|
||||||
|
def getsize(self): ...
|
||||||
|
def access(self, mode): ... [1]
|
||||||
|
def stat(self): ...
|
||||||
|
def lstat(self): ...
|
||||||
|
def statvfs(self): ... [1]
|
||||||
|
def pathconf(self, name): ... [1]
|
||||||
|
|
||||||
|
# Filesystem properties for path.
|
||||||
|
atime, mtime, ctime, size
|
||||||
|
|
||||||
|
# Methods for manipulating information about the filesystem
|
||||||
|
# path.
|
||||||
|
def utime(self, times) => None
|
||||||
|
def chmod(self, mode) => None
|
||||||
|
def chown(self, uid, gid) => None [1]
|
||||||
|
def rename(self, new) => None
|
||||||
|
def renames(self, new) => None
|
||||||
|
|
||||||
|
# Create/delete operations on directories
|
||||||
|
def mkdir(self, mode = 0777): ...
|
||||||
|
def makedirs(self, mode = 0777): ...
|
||||||
|
def rmdir(self): ...
|
||||||
|
def removedirs(self): ...
|
||||||
|
|
||||||
|
# Modifying operations on files
|
||||||
|
def touch(self): ...
|
||||||
|
def remove(self): ...
|
||||||
|
def unlink(self): ...
|
||||||
|
|
||||||
|
# Modifying operations on links
|
||||||
|
def link(self, newpath): ...
|
||||||
|
def symlink(self, newlink): ...
|
||||||
|
def readlink(self): ...
|
||||||
|
def readlinkabs(self): ...
|
||||||
|
|
||||||
|
# High-level functions from shutil
|
||||||
|
def copyfile(self, dst): ...
|
||||||
|
def copymode(self, dst): ...
|
||||||
|
def copystat(self, dst): ...
|
||||||
|
def copy(self, dst): ...
|
||||||
|
def copy2(self, dst): ...
|
||||||
|
def copytree(self, dst, symlinks = True): ...
|
||||||
|
def move(self, dst): ...
|
||||||
|
def rmtree(self, ignore_errors = False, onerror = None): ...
|
||||||
|
|
||||||
|
# Special stuff from os
|
||||||
|
def chroot(self): ... [1]
|
||||||
|
def startfile(self): ... [1]
|
||||||
|
|
||||||
|
|
||||||
|
Replacing older functions with the Path class
|
||||||
|
|
||||||
|
In this section, "a ==> b" means that b can be used as a
|
||||||
|
replacement for a.
|
||||||
|
|
||||||
|
In the following examples, we assume that the Path class is
|
||||||
|
imported with "from path import Path".
|
||||||
|
|
||||||
|
1. Replacing os.path.join
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
os.path.join(os.getcwd(), "foobar")
|
||||||
|
==>
|
||||||
|
Path(Path.cwd(), "foobar")
|
||||||
|
|
||||||
|
os.path.join("foo", "bar", "baz")
|
||||||
|
==>
|
||||||
|
Path("foo", "bar", "baz")
|
||||||
|
|
||||||
|
|
||||||
|
2. Replacing os.path.splitext
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
fname = "Python2.4.tar.gz"
|
||||||
|
os.path.splitext(fname)[1]
|
||||||
|
==>
|
||||||
|
fname = Path("Python2.4.tar.gz")
|
||||||
|
fname.ext
|
||||||
|
|
||||||
|
Or if you want both parts:
|
||||||
|
|
||||||
|
fname = "Python2.4.tar.gz"
|
||||||
|
base, ext = os.path.splitext(fname)
|
||||||
|
==>
|
||||||
|
fname = Path("Python2.4.tar.gz")
|
||||||
|
base, ext = fname.namebase, fname.extx
|
||||||
|
|
||||||
|
|
||||||
|
3. Replacing glob.glob
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
lib_dir = "/lib"
|
||||||
|
libs = glob.glob(os.path.join(lib_dir, "*s.o"))
|
||||||
|
==>
|
||||||
|
lib_dir = Path("/lib")
|
||||||
|
libs = lib_dir.files("*.so")
|
||||||
|
|
||||||
|
|
||||||
|
Deprecations
|
||||||
|
|
||||||
|
Introducing this module to the standard library introduces a need
|
||||||
|
for the "weak" deprecation of a number of existing modules and
|
||||||
|
functions. These modules and functions are so widely used that
|
||||||
|
they cannot be truly deprecated, as in generating
|
||||||
|
DeprecationWarning. Here "weak deprecation" means notes in the
|
||||||
|
documentation only.
|
||||||
|
|
||||||
|
The table below lists the existing functionality that should be
|
||||||
|
deprecated.
|
||||||
|
|
||||||
|
Path method/property Deprecates function
|
||||||
|
-------------------- -------------------
|
||||||
|
normcase() os.path.normcase()
|
||||||
|
normpath() os.path.normpath()
|
||||||
|
realpath() os.path.realpath()
|
||||||
|
expanduser() os.path.expanduser()
|
||||||
|
expandvars() os.path.expandvars()
|
||||||
|
parent os.path.dirname()
|
||||||
|
name os.path.basename()
|
||||||
|
splitpath() os.path.split()
|
||||||
|
drive os.path.splitdrive()
|
||||||
|
ext os.path.splitext()
|
||||||
|
splitunc() os.path.splitunc()
|
||||||
|
__new__() os.path.join(), os.curdir
|
||||||
|
listdir() os.listdir() [fnmatch.filter()]
|
||||||
|
match() fnmatch.fnmatch()
|
||||||
|
matchcase() fnmatch.fnmatchcase()
|
||||||
|
glob() glob.glob()
|
||||||
|
exists() os.path.exists()
|
||||||
|
isabs() os.path.isabs()
|
||||||
|
isdir() os.path.isdir()
|
||||||
|
isfile() os.path.isfile()
|
||||||
|
islink() os.path.islink()
|
||||||
|
ismount() os.path.ismount()
|
||||||
|
samefile() os.path.samefile()
|
||||||
|
getatime()/atime os.path.getatime()
|
||||||
|
getctime()/ctime os.path.getctime()
|
||||||
|
getmtime()/mtime os.path.getmtime()
|
||||||
|
getsize()/size os.path.getsize()
|
||||||
|
cwd() os.getcwd()
|
||||||
|
access() os.access()
|
||||||
|
stat() os.stat()
|
||||||
|
lstat() os.lstat()
|
||||||
|
statvfs() os.statvfs()
|
||||||
|
pathconf() os.pathconf()
|
||||||
|
utime() os.utime()
|
||||||
|
chmod() os.chmod()
|
||||||
|
chown() os.chown()
|
||||||
|
rename() os.rename()
|
||||||
|
renames() os.renames()
|
||||||
|
mkdir() os.mkdir()
|
||||||
|
makedirs() os.makedirs()
|
||||||
|
rmdir() os.rmdir()
|
||||||
|
removedirs() os.removedirs()
|
||||||
|
remove() os.remove()
|
||||||
|
unlink() os.unlink()
|
||||||
|
link() os.link()
|
||||||
|
symlink() os.symlink()
|
||||||
|
readlink() os.readlink()
|
||||||
|
chroot() os.chroot()
|
||||||
|
startfile() os.startfile()
|
||||||
|
copyfile() shutil.copyfile()
|
||||||
|
copymode() shutil.copymode()
|
||||||
|
copystat() shutil.copystat()
|
||||||
|
copy() shutil.copy()
|
||||||
|
copy2() shutil.copy2()
|
||||||
|
copytree() shutil.copytree()
|
||||||
|
move() shutil.move()
|
||||||
|
rmtree() shutil.rmtree()
|
||||||
|
|
||||||
|
The Path class deprecates the whole of os.path, shutil, fnmatch
|
||||||
|
and glob. A big chunk of os is also deprecated.
|
||||||
|
|
||||||
|
|
||||||
|
Closed Issues
|
||||||
|
|
||||||
|
A number contentious issues have been resolved since this PEP
|
||||||
|
first appeared on python-dev:
|
||||||
|
|
||||||
|
* The __div__() method was removed. Overloading the / (division)
|
||||||
|
operator may be "too much magic" and make path concatenation
|
||||||
|
appear to be division. The method can always be re-added later
|
||||||
|
if the BFDL so desires. In its place, __new__() got an *args
|
||||||
|
argument that accepts both Path and string objects. The *args
|
||||||
|
are concatenated with os.path.join() which is used to construct
|
||||||
|
the Path object. These changes obsoleted the problematic
|
||||||
|
joinpath() method which was removed.
|
||||||
|
|
||||||
|
|
||||||
|
Open Issues
|
||||||
|
|
||||||
|
Some functionality of Jason Orendorff's path module have been
|
||||||
|
omitted:
|
||||||
|
|
||||||
|
* Function for opening a path - better handled by the builtin
|
||||||
|
open().
|
||||||
|
|
||||||
|
* Functions for reading and writing whole files - better handled
|
||||||
|
by file objects' own read() and write() methods.
|
||||||
|
|
||||||
|
* A chdir() function may be a worthy inclusion.
|
||||||
|
|
||||||
|
* A deprecation schedule needs to be set up. How much
|
||||||
|
functionality should Path implement? How much of existing
|
||||||
|
functionality should it deprecate and when?
|
||||||
|
|
||||||
|
* The name obviously has to be either "path" or "Path," but where
|
||||||
|
should it live? In its own module or in os?
|
||||||
|
|
||||||
|
* Path implements two ways to retrieve some filesystem
|
||||||
|
information. Both the properties atime, mtime, ctime and size
|
||||||
|
and the getters getatime(), getmtime(), getctime() and
|
||||||
|
getsize(). This is clearly not optimal, the information should
|
||||||
|
*either* be retrieved using properties or getters. Both methods
|
||||||
|
have advantages and disadvantages.
|
||||||
|
|
||||||
|
The functions and modules that this new module is trying to
|
||||||
|
replace (os.path, shutil, fnmatch, glob and parts of os) are
|
||||||
|
expected to be available in future Python versions for a long
|
||||||
|
time, to preserve backwards compatibility.
|
||||||
|
|
||||||
|
|
||||||
|
Reference Implementation
|
||||||
|
|
||||||
|
Currently, the Path class is implemented as a thin wrapper around
|
||||||
|
the standard library modules fnmatch, glob, os, os.path and
|
||||||
|
shutil. The intention of this PEP is to move functionality from
|
||||||
|
the aforementioned modules to Path while they are being
|
||||||
|
deprecated.
|
||||||
|
|
||||||
|
For more detail and an implementation see:
|
||||||
|
|
||||||
|
http://wiki.python.org/moin/PathModule
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
|
||||||
|
In this section, "a ==> b" means that b can be used as a
|
||||||
|
replacement for a.
|
||||||
|
|
||||||
|
1. Make all python files in the a directory executable
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
DIR = '/usr/home/guido/bin'
|
||||||
|
for f in os.listdir(DIR):
|
||||||
|
if f.endswith('.py'):
|
||||||
|
path = os.path.join(DIR, f)
|
||||||
|
os.chmod(path, 0755)
|
||||||
|
==>
|
||||||
|
for f in Path('/usr/home/guido/bin').files("*.py"):
|
||||||
|
f.chmod(0755)
|
||||||
|
|
||||||
|
2. Delete emacs backup files
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
def delete_backups(arg, dirname, names):
|
||||||
|
for name in names:
|
||||||
|
if name.endswith('~'):
|
||||||
|
os.remove(os.path.join(dirname, name))
|
||||||
|
os.path.walk(os.environ['HOME'], delete_backups, None)
|
||||||
|
==>
|
||||||
|
d = Path(os.environ['HOME'])
|
||||||
|
for f in d.walkfiles('*~'):
|
||||||
|
f.remove()
|
||||||
|
|
||||||
|
3. Finding the relative path to a file
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
b = Path('/users/peter/')
|
||||||
|
a = Path('/users/peter/synergy/tiki.txt')
|
||||||
|
a.relpathto(b)
|
||||||
|
|
||||||
|
4. Splitting a path into directory and filename
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
os.path.split("/path/to/foo/bar.txt")
|
||||||
|
==>
|
||||||
|
Path("/path/to/foo/bar.txt").splitpath()
|
||||||
|
|
||||||
|
5. List all Python scripts in the current directory tree
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
list(Path().walkfiles("*.py"))
|
||||||
|
|
||||||
|
|
||||||
|
References and Footnotes
|
||||||
|
|
||||||
|
[1] Method is not guaranteed to be availible on all platforms.
|
||||||
|
|
||||||
|
Related articles & threads:
|
||||||
|
|
||||||
|
* http://mail.python.org/pipermail/python-dev/2005-June/054439.html
|
||||||
|
|
||||||
|
* http://mail.python.org/pipermail/python-list/2005-July/291071.html
|
||||||
|
|
||||||
|
* http://mail.python.org/pipermail/python-list/2003-July/174289.html
|
||||||
|
|
||||||
|
* "(idea) subclassable string: path object?", van Rossum, 2001
|
||||||
|
http://mail.python.org/pipermail/python-dev/2001-August/016663.html
|
||||||
|
|
||||||
|
* "path module v1.0 released", Orendorff, 2003
|
||||||
|
http://mail.python.org/pipermail/python-announce-list/2003-January/001984.html
|
||||||
|
|
||||||
|
* http://wiki.python.org/moin/PathClass
|
||||||
|
|
||||||
|
* "PRE-PEP: new Path class",
|
||||||
|
http://mail.python.org/pipermail/python-list/2004-January/201672.html
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
|
||||||
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
Local Variables:
|
||||||
|
mode: indented-text
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
sentence-end-double-space: t
|
||||||
|
fill-column: 70
|
||||||
|
coding: latin-1
|
||||||
|
End:
|
Loading…
Reference in New Issue