[Tutor] Pythonic? Building a full path from a "visual" file tree

stv stvsmth at gmail.com
Tue Mar 21 18:42:25 CET 2006


Hey all,

I would like to expand the "visual" representation of a tree
hierarchy, given below, where child-ness is defined by indentation,
and folder-ness is highlighted with a trailing '/'

Input (test.txt):
dir1/
	file1
	file2
	1-1/
		file3
    		file4
dir2/
	file5

The desired output is a fully qualified path for each input line:
dir1/
dir1/file1
dir1/file2
dir1/1-1/
dir1/1-1/file3
dir1/1-1/file4
dir2/
dir2/file5

I considered several brute-force solutions, but I persevered and came
to, what I think, is a more Pythonic solution. What do you think?

import string

def expand_tree(filetree):
  indent = '\t'
  stack = []
  for f in filetree:
    indents = f.count(indent)
    while len(stack) > indents: stack.pop()
    stack.append(f.strip())
    yield string.join(stack,'')
    if not f.endswith('/'): stack.pop()

lines = [line.rstrip() for line in file('test.txt')]	
for i in expand_tree(lines): print i

Those familiar with subversion (particularly, svnlook tree
/path/to/repos) may recognize the problem space and the sample input
(except that I simplified things a bit here, using a tab to indicate
level-of-hierarchy instead of a single space, which could appear in
the filename).  The real-world solution will use a regex to find run
of spaces at the start of element 'f'. It will also get input from
stdin instead of a file.

Questions:

Is the list comprehension the right idiom for getting a file into a
list, without the EOL chars? I'm hard-pressed to see how it could be
more concise, but this is Python :) and the rtrim() feels a little
off.

Is string.join() preferred to ''.join? Does importing all of string
outweigh the readability of string.join()?

Any subversion geeks know of way to eliminate this code with a native
svn command?

Did other folks choke on generators for as long as I did? I'm not
going to admit, publicly, how long that was :) But I found this little
test illustrative:

def gen():
  yield 1
  yield 2
  yield 3

g = gen()
g.next()
>>> 1
g.next()
>>> 2
g.next()
>>> 3
g.next()
>>> [stack trace]

Beyond simple, but the obviousness of it is hidden in many of the
examples I saw.


More information about the Tutor mailing list