Struggling with os.path.join and fileinput (was 'Path, strings, and lines'

Ian Kelly ian.g.kelly at gmail.com
Mon Jun 15 22:44:06 EDT 2015


On Mon, Jun 15, 2015 at 8:00 PM, Malik Rumi <malik.a.rumi at gmail.com> wrote:
> I have struggled with this for several hours and not made much progress. I was not sure if your 'names' variable was supposed to be the same as 'filenames'. Also, it should be 'os.path.join', not os.join. Anyway, I thought you had some good ideas so I worked with them but as I say I keep getting stuck at one particular point. Here is the current version of my code:
>
> # -*- coding: utf-8 -*-
> import os
> import fileinput
>
> path1 = os.path.join('Projects', 'P5', 'shortstories', '/')

You don't need to join the trailing slash on. Also, you don't really
need os.path.join here, unless you're trying to be compatible with
systems that don't allow / as a path separator, which is probably not
worth worrying about, so you could leave out the join call here and
just write '/Projects/P5/shortstories'.

> path2 = os.path.join('Projects', 'P5')

Ditto.

> targets = os.listdir(path1)
> path3 = ((path1 + target) for target in targets)

This however is not just a constant so you *should* use os.path.join
rather than concatenation.

> path4 = os.path.join(path2,'list_stories')
>
> with open(path4) as arrows:
>     quiver = arrows.readlines()
> <snip>
>
> And here is my error message:
>
> In [112]: %run algo_h1.py
> ---------------------------------------------------------------------------
> FileNotFoundError                         Traceback (most recent call last)
> /home/malikarumi/Projects/algo_h1.py in <module>()
>       9 path4 = os.path.join(path2,'list_stories')
>      10
> ---> 11 with open(path4) as arrows:
>      12     quiver = arrows.readlines()
>      13     for arrow in quiver:
>
> FileNotFoundError: [Errno 2] No such file or directory: 'Projects/P5/list_stories'

Before you were using '/Projects/P5/list_stories'. Now as the error
message shows you are using 'Projects/P5/list_stories', which is not
the same thing. The former is an absolute path and the latter is
relative to the current directory. You can fix that by adding the
leading / to the os.path.join call above, or just include it in the
string constant as I suggested.

> As I continued to work on this on my own, I learned that I could use the class, fileinput.FileInput, instead of fileinput.input. The supposed advantage is that there can be many simultaneous instances with the class. http://stackoverflow.com/questions/21443601/runtimeerror-input-already-active-file-loop. I tried this with a very basic version of my code, one that had worked with fileinput.input, and FileInput worked just as well. Then I wanted to try a 'with' statement, because that would take care of closing the file objects for me. I took my formulation directly from the docs, https://docs.python.org/3.4/library/fileinput.html#fileinput.FileInput, but got a NameError:
>
> In [81]: %run algo_g3.py
> ---------------------------------------------------------------------------
> NameError                                 Traceback (most recent call last)
> /home/malikarumi/Projects/P5/shortstories/algo_g3.py in <module>()
>       4 ss = os.listdir()
>       5
> ----> 6 with FileInput(files = ss) as input:
>       7     if 'Penelope' in input:
>       8         print(input)
>
> NameError: name 'FileInput' is not defined
>
> Well, I am pretty much stumped by that. If it isn't right in the docs, what hope do I have? What am I missing here? Why did I get this error?

How did you import it? If you just did 'import fileinput' then the
name that you imported is just the name of the module, fileinput, so
you would have to write 'fileinput.FileInput', not just 'FileInput'.
If OTOH you had used 'from fileinput import FileInput', then the name
you would have imported would be the name of the class, and in that
case the above should be correct.

> I decided to try tinkering with the parens
>
> with FileInput(files = (ss)) as input:
>
> But that got me the same result
>
> NameError: name 'FileInput' is not defined

As the error says, the issue is that the name 'FileInput' is not
defined, not anything to do with the arguments that you're passing to
it. As it happens, the change that you made was a no-op. The parens
only affect grouping, and the grouping is the same as before.

> Then I changed how FileInput was called:
>
> with fileinput.FileInput(ss) as input:
>
> This time I got nothing. Zip. Zero:

Because it worked this time, meaning that it successfully opened the
files, but then it failed to find the string that you were searching
for. Your "if 'Penelope' in input" conditional will iterate over each
line in input, and if it finds a line that is exactly 'Penelope'
without any trailing newline, then it will print the line. You
probably wanted this instead:

with fileinput.FileInput(ss) as input:
    for line in input:
        if 'Penelope' in line:
            print(line)

> Then I ran a different function
>
> In [85]: fileinput.filename()
>
> and got
>
> RuntimeError: no active input()
>
> Which means the file object is closed. But when? How? As part of the with statement that got the NameError? And since it is closed, why didn't running the last iteration of my script re-open it?

This is after the with statement above, so the fileinput object will
have been closed when the with statement was exited.



More information about the Python-list mailing list