Automatic Type Conversion to String

Bruce Eckel lists.eckel at
Mon Feb 13 23:01:53 CET 2012

I'm creating a class to encapsulate OS paths, to reduce the visual
noise and typing from the os.path methods. I've got the class and nose
tests below, and everything works except the last test which I've
prefixed with XXX:

    def XXXtest_should_work(self):
        open(self.p2, 'w').write('')
        TypeError: coercing to Unicode: need string or buffer, Path
        open(self.p2, 'w').write('')
        assert self.p2

Note that I *have* a __str__(self) method to perform automatic
conversion to string, and I've commented out the __unicode__(self)
method because it wasn't getting called. The problem appears to be
that open() does not seem to be calling __str__ on its first argument,
but instead it appears to want a basestring and this doesn't
automatically call __str__.

I'm trying to write the Path class so I can just hand a Path object
to, for example, open() and have it produce the path string.

Thanks for any insights.
--------------------------- Class and tests, put in file

import os, os.path

class Path(object):
    def __init__(self, *args):
        Each of *args is a piece of a path. Assemble them together.
        if len(args) == 0:
            self.path = os.path.abspath('.')
            self.path = str(args[0]) # str() so you can add Path
            if self.path.endswith(':'):
                self.path = os.path.join(self.path, os.sep)
        for a in args[1:]:
            self.path = os.path.join(self.path, str(a))
    def __add__(self, other):
        return Path(os.path.join(self.path, other))
    def __iadd__(self, other): # path += path
        self.path = os.path.join(self.path, other)
        return self # Allows chaining
    def __str__(self):
        return self.path
    # def __repr__(self):
        # assert not self.path, "__repr__"
        # return os.path.join(self.path)
    # def __unicode__(self):
        # assert not self.path, "__unicode__"
        # print "Unicode called %s" % self.path
        # return os.path.join(self.path)
    def __nonzero__(self):
        Boolean test: does this path exist?
        So you can say "if path:"
        return bool(os.path.exists(self.path))

Nose tests. To run, you must first install nose:
pip install nose
def test_platform():
    "First draft tests are Windows-based"
    import platform
    assert platform.system() == 'Windows'

class test_paths():
    def setUp(self):
        self.paths = [
            ("C:\\", "Users", "Bruce Eckel", "Downloads",
            ("C:\\", "Users", "Bruce Eckel", "Dropbox",
        self.p1 = Path(self.paths[0])
        self.s1 = os.path.join(self.paths[0], "\\")
        self.p2 = Path(*self.paths[1])
        self.s2 = os.path.join(*self.paths[1])
        self.p3 = Path(*self.paths[2])
        self.s3 = os.path.join(*self.paths[2])
        self.p4 = self.p3 + "TestFile1.tmp"
        self.s4 = os.path.join(self.s3, "TestFile1.tmp")
        self.p5 = self.p3 + "TestFile2.tmp"
        self.s5 = os.path.join(self.s3, "TestFile2.tmp")
        self.p6 = Path("foo") + "bar" + "baz"

    def test1(self):
        "Root directory"
        print self.p1
        print self.s1
        assert str(self.p1) == self.s1

    def test2(self):
        "Full path to file"
        print "p2", self.p2
        print "s2", self.s2
        assert str(self.p2) == self.s2

    def test3(self):
        assert str(self.p3) == self.s3

    def test4(self):
        "Plus operator"
        assert str(self.p4) == self.s4

    def test5(self):
        "Another temp file"
        assert str(self.p5) == self.s5

    def test6(self):
        "Chained operator +"
        assert str(self.p6) == r"foo\bar\baz"

    def test7(self):
        "Operator +="
        self.p6 += "bingo"
        assert str(self.p6) == r"foo\bar\baz\bingo"

    def test8(self):
        "Create a Path from a Path"
        p = Path(self.p3)
        assert p.path == self.s3

class test_existence:
    Test for directory and path existence
    def setUp(self):
        base = Path("C:", "Users", "Bruce Eckel", "Downloads")
        self.p1 = base + "TestFile1.tmp"
        self.p2 = base + "TestFile2.tmp"
        self.p3 = base + "TestFile3.tmp"

    def test_basestring(self):
        print type(self.p1)
        assert isinstance(self.p1.path, basestring)

    def test1(self):
        "p1 existence"
        open(self.p1.path, 'w').write('')
        assert self.p1

    def test2(self):
        "p2 existence"
        open(self.p2.path, 'w').write('')
        assert self.p2

    def test3(self):
        "p3 existence"
        assert not self.p3

    def XXXtest_should_work(self):
        open(self.p2, 'w').write('')
        TypeError: coercing to Unicode: need string or buffer, Path
        open(self.p2, 'w').write('')
        assert self.p2

More information about the Python-list mailing list