Search code examples
pythonstringraspberry-pilibgphoto2

Exception str() failed


I'm starting to create a new 3D scanner with a Raspberry Pi 3B + and a Canon 6D. I have a part of the Python code to recover the images thanks to the gphoto2 library but I can't put my ISO configuration on the reflex.

I have already done several tests but nothing works. I always have the same error:

I use the gp command to send all parameters to the Canon reflex.

Import :

import time
from datetime import datetime
from sh import gphoto2 as gp
import signal, os, subprocess, shutil

Gp command example (all works) :

CaptureImageDownload = ["--capture-image-and-download"]
CaptureImage = ["--capture-image"]

But this line don't work :

ValueISO = ["--set-config iso=0"]

Here is the error displayed in the command terminal

File "CameraShot.py", line 124, in <module>
gp(ValueISO)
File "/usr/local/lib/python2.7/dist-packages/sh.py", line 1427, in __call__
return RunningCommand(cmd, call_args, stdin, stdout, stderr)
File "/usr/local/lib/python2.7/dist-packages/sh.py", line 774, in __init__
self.wait()
File "/usr/local/lib/python2.7/dist-packages/sh.py", line 792, in wait
self.handle_command_exit_code(exit_code)
File "/usr/local/lib/python2.7/dist-packages/sh.py", line 815, in handle_command_exit_code
raise exc
sh.ErrorReturnCode_1: <exception str() failed>

I can not write this command line otherwise my camera does not understand the order.


Solution

  • From the sh documentation on passing in arguments:

    When passing multiple arguments to a command, each argument must be a separate string[.]

    Yours are not separate strings. Split out the different parts (on spaces not surrounded by quotes):

    ValueISO = ["--set-config", "iso=0"]
    

    Also see the project's detailed explanation on why this is; but the short answer is that sh is not parsing arguments into separate strings like a shell would.

    You can also use the shlex.split() function to handle the splitting for you:

    ValueISO = shlex.split("--set-config iso=0")
    

    Note that sh also supports using keyword arguments, where set_config="iso=0" is translated to ["--set-config", "iso=0"] for you. You could use that as:

    value_iso = dict(set_config="iso=0")
    

    then

    gp(**value_iso)
    

    That you get sh.ErrorReturnCode_1: <exception str() failed> is probably a bug in sh. Python uses type(exception).__name__: str(exception) as the last line of a traceback, and the str() call fails on the sh.ErrorReturnCode exception (sh.ErrorReturnCode_1 is a subclass of sh.ErrorReturnCode). I can see from the sh source code for the exception class that the error message is decoded from bytes to Unicode text, and Python 2 can't actually handle Unicode objects returned from a __str__ method. I've filed a bug report with sh to have that fixed.