[Tutor] No file or directory error using subprocess and Popen

Peter Otten __peter__ at web.de
Mon May 15 08:03:02 EDT 2017


Jim wrote:

> I am running this on Mint 18.
> This is the third script I have written to open and position windows in
> workspaces. The first two work, but trying to open ebook-viewe r
> (calibre) with a specific book produces the following error.
> If I run the same command in the terminal it works without an error.
> 
> 
> Exception in thread Thread-4:
> Traceback (most recent call last):
>    File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
>      self.run()
>    File "/usr/lib/python3.5/threading.py", line 862, in run
>      self._target(*self._args, **self._kwargs)
>    File "/home/jfb/MyProgs/Scripts/place_windows_OO_WS3.py", line 24, in
> open_it
>      subprocess.call([self.program])
>    File "/usr/lib/python3.5/subprocess.py", line 557, in call
>      with Popen(*popenargs, **kwargs) as p:
>    File "/usr/lib/python3.5/subprocess.py", line 947, in __init__
>      restore_signals, start_new_session)
>    File "/usr/lib/python3.5/subprocess.py", line 1551, in _execute_child
>      raise child_exception_type(errno_num, err_msg)
> FileNotFoundError: [Errno 2] No such file or directory: 'ebook-viewer
> 
/home/jfb/Documents/eBooks/Javascript/GOOGLE_SHEETS/googlespreadsheetprogramming.epub'
> 
> Code:
> 
> # place_windows_OO_WS3.py
> 
> import subprocess
> from subprocess import Popen,PIPE
> import threading
> import time
> 
> class Place():
> 
>      def __init__(self):
>          self.programs = ['jedit', 'google-chrome', 'doublecmd',
>          'ebook-viewer
> 
/home/jfb/Documents/eBooks/Javascript/GOOGLE_SHEETS/googlespreadsheetprogramming.epub']
>          self.classname = {'jedit' : 'sun-awt-X11-XFramePeer',
>                              'google-chrome':'google-chrome',
>                              'doublecmd':'doublecmd',
>                              'calibre-ebook-viewer': 'libprs500'}
>          self.open_and_move()
> 
>      def open_it(self):
>          subprocess.call([self.program])
> 
>      def open_and_move(self):
>          for self.program in self.programs:
>              opener = threading.Thread(target=self.open_it)
>              opener.start()
>              time.sleep(2)
>              p = Popen(['xdotool', 'search', '--classname',
> self.classname[self.program]], stdout=subprocess.PIPE)
> 
>              if self.classname[self.program] == 'sun-awt-X11-XFramePeer':
>                  wid = str(p.stdout.read())
>                  wid = wid[len(wid) - 11 : len(wid) - 3]
>                  x = '0'
>                  y = '0'
>                  print('***jedit***')
>              elif self.classname[self.program] == 'google-chrome':
>                  wid = str(p.stdout.read())
>                  wid = wid[len(wid) - 11 : len(wid) - 3]
>                  x = '1924'
>                  y = '0'
>                  print('***google***')
>              elif self.classname[self.program] == 'doublecmd':
>                  wid = str(p.stdout.read())
>                  wid = wid[len(wid) - 11 : len(wid) - 3]
>                  x = '1924'
>                  y = '537'
>                  print('***double***')
>              else:
>                  wid = str(p.stdout.read())
>                  wid = wid[len(wid) - 11 : len(wid) - 3]
>                  x = '2540' #'1924'
>                  y = '537'
>                  print('***calibre***')
>              subprocess.call(['xdotool', 'windowmove', str(wid), x, y])
> 
> I did some googling and it seems that subprocess does not have a length
> limit in linux. Could someone tell me how to correct the above error.

Not directly related to your question, but I think you should have one 
instance of your Place class per program. That way you keep related 
information together and avoid the need to look it up in a dict or find it 
with a long chain of if ... elif ... tests. For example:

# untested
import subprocess
import threading
import time

DELAY = 3.0  # seconds


class Place:
    def __init__(self, cmd, classname=None, name=None, x=0, y=0):
        if classname is None:
            classname = cmd[0]
        if name is None:
            name = cmd[0]

        self.cmd = cmd
        self.classname = classname
        self.name = name
        self.x = x
        self.y = y

    def open_it(self):
        subprocess.call(self.cmd)

    def open_and_move(self):
        opener = threading.Thread(target=self.open_it)
        opener.start()
        time.sleep(DELAY)
        output = subprocess.Popen(
            ['xdotool', 'search', '--classname', self.classname],
            stdout=subprocess.PIPE
        ).communicate()[0]
        wid = output.split()[-1].decode()
        subprocess.call(
            [
                'xdotool', 'windowmove',
                wid, str(self.x), str(self.y)
            ]
        )
        print("***{}***".format(self.name))

EBOOK = (
    "/home/jfb/Documents/eBooks/Javascript/"
    "GOOGLE_SHEETS/googlespreadsheetprogramming.epub"
)

programs = [
    Place(["jedit"], classname="sun-awt-X11-XFramePeer"),
    Place(["google-chrome"], x=1924),
    Place(["doublecmd"], x=1924, y=537),
    Place(
        ["ebook-viewer", EBOOK],
        classname="libprs500", name="calibre",
        x=2540, y=537
    )
]

for program in programs:
    program.open_and_move()

Now when you add a new program you just append a new `Place` instance to the 
`programs` list.



More information about the Tutor mailing list