JeffLIrion / adb_shell

A Python implementation of ADB with shell and FileSync functionality.
Apache License 2.0
546 stars 60 forks source link

Cannot catch adb_shell.exceptions.UsbDeviceNotFoundError #124

Closed threadreaper closed 4 years ago

threadreaper commented 4 years ago

I'm having some trouble implementing graceful error handling for this particular exception.

My code currently looks like this:

import os
import usb1
import sys
import adb_shell.exceptions
from adb_shell.adb_device import AdbDeviceUsb
from adb_shell.auth.sign_pythonrsa import PythonRSASigner

home = os.path.expanduser("~")
adbkey = home + "/.android/adbkey"

with open(adbkey) as f:
    priv = f.read()
with open(adbkey + '.pub') as f:
    pub = f.read()
signer = PythonRSASigner(pub, priv)

"""Need to kill adb server if it's running"""
device = AdbDeviceUsb()
try:
    device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
except exceptions.UsbDeviceNotFoundError:
    print("Error, device not found")
    sys.exit(1)
except usb1.USBErrorBusy:
    os.system('adb kill-server')
    device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
finally:
    print("Successfully connected to device.")

I figured out that I needed to import usb1 to catch the USBErrorBusy, and that part works. But I'm not having any luck catching the USBDeviceNotFoundError. I noticed that it gets raised from within a try except block that catches an exception called StopIteration, so I tried to catch that one, which failed because it's already being handled by your code. I have tried various ways of importing the class, the module, etc and can't figure out how to address this error.

I have tried:

import adb_shell
...
except adb_shell.exceptions.USBDeviceNotFoundError:

import adb_shell.exceptions
...
except exceptions.USBDeviceNotFoundError:

from adb_shell.exceptions import USBDeviceNotFoundError:
...
except USBDeviceNotFoundError:

import adb_shell
...
except adb_shell.exceptions.Exception:
except adb_shell.Exception:

I even experimentally tried the ill-advised:

except Exception:
    pass

And the exception goes uncaught. I assume that I could modify the code, remove your try/except block and catch the StopIteration myself and that would probably work, but I'm not familiar enough with the underlying structure to know if this is a good idea or not. And as StopIteration is not very descriptive of the problem in that situation, I agree with your idea of trying to raise a more descriptive exception.

Any ideas?

JeffLIrion commented 4 years ago

Change except exceptions.UsbDeviceNotFoundError: to except adb_shell.exceptions.UsbDeviceNotFoundError:

threadreaper commented 4 years ago

Already tried that, as I detailed above.

JeffLIrion commented 4 years ago

The name exceptions is not defined. It's the same as if you did this:

try:
    1/0
except exceptions.Something:
    print("Caught!")

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-1-12d64cb3b5d5> in <module>()
      1 try:
----> 2     1/0
      3 except exceptions.Something:

ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

NameError                                 Traceback (most recent call last)
<ipython-input-1-12d64cb3b5d5> in <module>()
      1 try:
      2     1/0
----> 3 except exceptions.Something:
      4     print("Caught!")
      5 

NameError: name 'exceptions' is not defined
threadreaper commented 4 years ago

That was my inclination as well, but again, I have already tried that. But the error I'm getting is not related to exceptions not being defined. Here's the complete error message:

Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/adb_shell/transport/usb_transport.py", line 597, in _find_first
    return next(cls._find_devices(setting_matcher, device_matcher=device_matcher, usb_info=usb_info, default_transport_timeout_s=default_transport_timeout_s))
StopIteration

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/michael/projects/HUprojects/scatter/shell.py", line 22, in <module>
    device = AdbDeviceUsb()
  File "/usr/lib/python3.8/site-packages/adb_shell/adb_device.py", line 1200, in __init__
    transport = UsbTransport.find_adb(serial, port_path, default_transport_timeout_s)
  File "/usr/lib/python3.8/site-packages/adb_shell/transport/usb_transport.py", line 620, in find_adb
    return cls._find(
  File "/usr/lib/python3.8/site-packages/adb_shell/transport/usb_transport.py", line 507, in _find
    return cls._find_first(setting_matcher, device_matcher, usb_info=usb_info, default_transport_timeout_s=default_transport_timeout_s)
  File "/usr/lib/python3.8/site-packages/adb_shell/transport/usb_transport.py", line 599, in _find_first
    raise exceptions.UsbDeviceNotFoundError('No device available, or it is in the wrong configuration.')
adb_shell.exceptions.UsbDeviceNotFoundError: No device available, or it is in the wrong configuration.

As you can see, no reference to exceptions not being defined.

This is my try/except block currently:

try:
    device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
except adb_shell.exceptions.UsbDeviceNotFoundError:
    print('Error: Device.not found')
    sys.exit(1)
except usb1.USBErrorBusy:
    os.system('adb kill-server')
    device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
finally:
    if device.available:
        print("Device successfully connected.")
JeffLIrion commented 4 years ago

The traceback is what I needed to see. You didn't get a "name is not defined" error because the code never got that far.

  File "/home/michael/projects/HUprojects/scatter/shell.py", line 22, in <module>
    device = AdbDeviceUsb()

This is where your exception occurred. It's looking for the USB device, but it doesn't find it.

Unfortunately, I don't know the solution. Catching the exception won't help because if it can't find the USB device then nothing after that will work. Maybe if you kill the ADB server first it would work?

This is why USB support is marked as experimental. If you figure out how the solution, please share it!

threadreaper commented 4 years ago

Oh geez, now I feel dumb. I don't know how I managed to overlook this. All I needed to do was add:

try:
    device = AdbDeviceUsb()
except adb_shell.exceptions.UsbDeviceNotFoundError:
    print('Error: Device not found')
    sys.exit(1)

This handles the error condition I was looking for. I was so sure it was coming from the device.connect() attempt I wasn't reading the traceback as closely as I should have. Thank you for your assistance.