4

I have a Python 3 script that runs fine in Linux. When I run it under Windows, I get the following traceback every time I try to play a sound:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Program Files (x86)\Python35-32\lib\multiprocessing\spawn.py", line 106, in spawn_main
    exitcode = _main(fd)
  File "C:\Program Files (x86)\Python35-32\lib\multiprocessing\spawn.py", line 116, in _main
    self = pickle.load(from_parent)
EOFError: Ran out of input

I've looked at the code that I think might be responsible for this, but I don't see how multiprocessing is even relevant here as I've already caught EOFError, or so it appears to me. (Note that this exception doesn't cause my script to exit.)

My biggest issue is that there's no information about where Python thinks the problem occurred. It refers to File "<string>", line 1, in <module>, which is unhelpful. How can I figure out where the exception is actually getting raised?

Here's the method that I think must be responsible, as it's the only place I use multiprocessing:

# imported earlier:
import multiprocessing as mp

def _play(self, name):
    '''Plays the sound given by name'''
    if self.silent:
        return True
    def play_sound(q=None):  # Called in a separate process so playing the sound doesn't block anything else.
        '''q is a multiprocessing.Queue object for interprocess communication.'''
        try:
            snd = self.sounds[name]
            if self._use_subprocess:
                s = subprocess
                return s.call([self.player, snd], stdout=s.DEVNULL, stderr=s.DEVNULL, timeout=20)
            else:
                return self.player(snd, self._winsound_options)
        except (KeyboardInterrupt, EOFError):
            sys.exit(0)
        except subprocess.TimeoutExpired as e:
            #if q:
            #    q.put(e)
            sys.stderr.write('\nSOUND ERROR: Unable to play the sound "{}": Timeout expired.\n\n'.format(snd))
            sys.exit(1)
        except FileNotFoundError:
            sys.stderr.write('\nSOUND ERROR: Unable to locate the sound player "{}".\n\n'.format(self.player))
            sys.exit(2)
        except EOFError:
            pass
    #q = mp.Queue()
    proc_name = 'Play sound: {}; time: {}'.format(name, datetime.datetime.now().strftime('%I:%M:%S %p'))
    try:
        proc = mp.Process(target=play_sound, name=proc_name)#, args=(q,))
        proc.start()
    # On Windows, multiprocessing attempts to pickle this method, which fails
    # because it's called by an inner function defined in __getattr__. We'll
    # Skip using multiprocessing in this case.
    # References: https://github.com/ouspg/trytls/issues/196 and http://stackoverflow.com/a/36995008/713735
    except (AttributeError, EOFError):
        play_sound()
Scott Severance
  • 943
  • 10
  • 27
  • 1
    The `File ""` part can come from running a python code snippet directly from the command line with `python -c 'some code here'`. Are you doing that anywhere in your launcher script? – John Gordon Dec 02 '16 at 17:36
  • That's certainly what it looks like, but I can assure you that I'm not doing that. Other tracebacks I get look normal. – Scott Severance Dec 02 '16 at 17:37
  • 1
    One potential problem with your code is that to use `multiprocessing` on Windows you need to put the code for the main process in an `if __name__ == '__main__':` block. See the **Safe importing of main module** subsection of the [Windows](https://docs.python.org/2/library/multiprocessing.html#windows) section of the [_multiprocessing Programming guidelines_](https://docs.python.org/2/library/multiprocessing.html#programming-guidelines). – martineau Dec 02 '16 at 17:49
  • Yes, that's how the script is launched: `if __name__ == '__main__':\n main()` – Scott Severance Dec 02 '16 at 18:16

1 Answers1

0

I still don't understand the traceback I was getting, but I worked around the exception by changing:

proc = mp.Process(target=play_sound, name=proc_name)
proc.start()

to:

if os.name == 'nt':
    play_sound()
else:
    proc = mp.Process(target=play_sound, name=proc_name)
    proc.start()

Yes, I lose functionality this way, but the script is already crippled on Windows due to its lack of a good terminal. (And that I don't really have a deep understanding of Windows.)

Scott Severance
  • 943
  • 10
  • 27