vicious_101
vicious_101

Reputation: 51

why the returned object of os.popen doesn't support next() call

Python Docs: os.popen:

Open a pipe to or from command. The return value is an open file object connected to the pipe, which can be read or written depending on whether mode is 'r' (default) or 'w'.

I'm able to use the next method X.__next__() / X.next() (2.X) but not the next(x) call,

Last but not least, how do next() and next method really work ?

Upvotes: 5

Views: 4115

Answers (2)

pts
pts

Reputation: 87361

https://docs.python.org/2/library/functions.html#next says about next:

Retrieve the next item from the iterator by calling its next() method. If default is given, it is returned if the iterator is exhausted, otherwise StopIteration is raised.

The error message:

TypeError: _wrap_close object is not an iterator

indicates that it's not an iterator. Most probably the __iter__ method is missing.

It's strange that you're getting an error, because this works for me in Python 2.x:

>>> next(os.popen('ls'))
'foo.txt\n'

Upvotes: 0

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251116

Looking at the source code(Python 3.4) it seems the __next__ method is not implemented in_wrap_close class, so the next() call fails because it fails to find the __next__ method on the class. And the explicit __next__ call works because of the overridden __getattr__ method.

Related source code:

def popen(cmd, mode="r", buffering=-1):
    if not isinstance(cmd, str):
        raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
    if mode not in ("r", "w"):
        raise ValueError("invalid mode %r" % mode)
    if buffering == 0 or buffering is None:
        raise ValueError("popen() does not support unbuffered streams")
    import subprocess, io
    if mode == "r":
        proc = subprocess.Popen(cmd,
                                shell=True,
                                stdout=subprocess.PIPE,
                                bufsize=buffering)
        return _wrap_close(io.TextIOWrapper(proc.stdout), proc)
    else:
        proc = subprocess.Popen(cmd,
                                shell=True,
                                stdin=subprocess.PIPE,
                                bufsize=buffering)
        return _wrap_close(io.TextIOWrapper(proc.stdin), proc)

# Helper for popen() -- a proxy for a file whose close waits for the process
class _wrap_close:
    def __init__(self, stream, proc):
        self._stream = stream
        self._proc = proc
    def close(self):
        self._stream.close()
        returncode = self._proc.wait()
        if returncode == 0:
            return None
        if name == 'nt':
            return returncode
        else:
            return returncode << 8  # Shift left to match old behavior
    def __enter__(self):
        return self
    def __exit__(self, *args):
        self.close()
    def __getattr__(self, name):
        return getattr(self._stream, name)
    def __iter__(self):
        return iter(self._stream)

Upvotes: 6

Related Questions