Merge pull request #64 from noonat/friendly-dep-errors

Added friendly errors when dependencies are not installed
This commit is contained in:
Jaisen Mathai 2016-01-07 23:00:16 -08:00
commit 1d86856a07
7 changed files with 91 additions and 26 deletions

View File

@ -7,7 +7,7 @@ before_install:
- "sudo apt-get update -qq"
- "sudo apt-get install python-dev python-pip python-pyexiv2 libimage-exiftool-perl -y"
install:
- "sudo pip install docopt LatLon nose requests"
- "sudo pip install docopt LatLon mock nose requests"
# command to run tests
# test mapquest key
before_script:

View File

@ -7,6 +7,12 @@ import sys
from datetime import datetime
from docopt import docopt
# Verify that external dependencies are present first, so the user gets a
# more user-friendly error instead of an ImportError traceback.
from elodie.dependencies import verify_dependencies
if not verify_dependencies():
sys.exit(1)
from elodie import constants
from elodie import geolocation
from elodie.media.media import Media

61
elodie/dependencies.py Normal file
View File

@ -0,0 +1,61 @@
"""Helpers for checking external dependencies."""
import os
import sys
from distutils.spawn import find_executable
EXIFTOOL_ERROR = u"""
It looks like you don't have exiftool installed, which Elodie requires.
Please take a look at the installation steps in the readme:
https://github.com/jmathai/elodie#install-everything-you-need
""".lstrip()
PYEXIV2_ERROR = u"""
{error_class_name}: {error}
It looks like you don't have pyexiv2 installed, which Elodie requires for
geolocation. Please take a look at the installation steps in the readme:
https://github.com/jmathai/elodie#install-everything-you-need
""".lstrip()
def get_exiftool():
"""Get path to executable exiftool binary.
We wrap this since we call it in a few places and we do a fallback.
@returns, None or string
"""
path = find_executable('exiftool')
# If exiftool wasn't found we try to brute force the homebrew location
if path is None:
path = '/usr/local/bin/exiftool'
if not os.path.isfile(path) or not os.access(path, os.X_OK):
return None
return path
def verify_dependencies():
"""Verify that external dependencies are installed.
Prints a message to stderr and returns False if any dependencies are
missing.
@returns, bool
"""
exiftool = get_exiftool()
if exiftool is None:
print >>sys.stderr, EXIFTOOL_ERROR
return False
try:
import pyexiv2
except ImportError as e:
print >>sys.stderr, PYEXIV2_ERROR.format(
error_class_name=e.__class__.__name__, error=e)
return False
return True

View File

@ -4,8 +4,8 @@ Media package that's a parent class for media objects
"""
# load modules
from distutils.spawn import find_executable
from elodie import constants
from elodie.dependencies import get_exiftool
import mimetypes
import os
@ -48,22 +48,6 @@ class Media(object):
return exiftool_attributes['album']
"""
Get path to executable exiftool binary.
We wrap this since we call it in a few places and we do a fallback.
@returns, None or string
"""
def get_exiftool(self):
exiftool = find_executable('exiftool')
# If exiftool wasn't found we try to brute force the homebrew location
if(exiftool is None):
exiftool = '/usr/local/bin/exiftool'
if(not os.path.isfile(exiftool) or not os.access(exiftool, os.X_OK)): # noqa
return None
return exiftool
"""
Get the full path to the video.
@ -103,7 +87,7 @@ class Media(object):
if(self.exiftool_attributes is not None):
return self.exiftool_attributes
exiftool = self.get_exiftool()
exiftool = get_exiftool()
if(exiftool is None):
return False
@ -222,7 +206,7 @@ class Media(object):
if(name is None):
return False
exiftool = self.get_exiftool()
exiftool = get_exiftool()
if(exiftool is None):
return False

View File

@ -16,6 +16,7 @@ import time
from elodie import constants
from elodie import plist_parser
from elodie.dependencies import get_exiftool
from media import Media
@ -145,7 +146,7 @@ class Video(Media):
@returns, string or None if exiftool is not found
"""
def get_exif(self):
exiftool = self.get_exiftool()
exiftool = get_exiftool()
if(exiftool is None):
return None

View File

@ -0,0 +1,18 @@
import mock
from elodie.dependencies import get_exiftool
@mock.patch('elodie.dependencies.find_executable')
@mock.patch('elodie.dependencies.os')
def test_exiftool(mock_os, mock_find_executable):
mock_find_executable.return_value = '/path/to/exiftool'
assert get_exiftool() == '/path/to/exiftool'
mock_find_executable.return_value = None
mock_os.path.isfile.return_value = True
mock_os.path.access.return_value = True
assert get_exiftool() == '/usr/local/bin/exiftool'
mock_os.path.isfile.return_value = False
assert get_exiftool() is None

View File

@ -21,11 +21,6 @@ from elodie.media.video import Video
os.environ['TZ'] = 'GMT'
def test_exiftool():
media = Media()
exiftool = media.get_exiftool()
assert exiftool is not None, exiftool
def test_get_file_path():
media = Media(helper.get_file('plain.jpg'))