From cb38bf517614ae8a3ec6ecc16ffe48f2b3be607f Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 00:31:58 -0400 Subject: [PATCH 01/11] Fix numerous flake8 warnings --- .pre-commit | 2 +- elodie/geolocation.py | 6 +++--- elodie/media/media.py | 22 ++++++++-------------- elodie/media/photo.py | 6 ++---- elodie/media/video.py | 15 ++++----------- 5 files changed, 18 insertions(+), 33 deletions(-) diff --git a/.pre-commit b/.pre-commit index 76f60de..12c1810 100755 --- a/.pre-commit +++ b/.pre-commit @@ -1,3 +1,3 @@ #!/usr/bin/env bash -flake8 elodie --exclude=tests && nosetests -w elodie/tests +flake8 elodie --exclude=tests,external && nosetests -w elodie/tests diff --git a/elodie/geolocation.py b/elodie/geolocation.py index f83bdd1..158a931 100644 --- a/elodie/geolocation.py +++ b/elodie/geolocation.py @@ -76,11 +76,11 @@ def coordinates_by_name(name): def decimal_to_dms(decimal): decimal = float(decimal) decimal_abs = abs(decimal) - minutes,seconds = divmod(decimal_abs*3600,60) - degrees,minutes = divmod(minutes,60) + minutes, seconds = divmod(decimal_abs*3600, 60) + degrees, minutes = divmod(minutes, 60) degrees = degrees sign = 1 if decimal >= 0 else -1 - return (degrees,minutes,seconds, sign) + return (degrees, minutes, seconds, sign) def dms_to_decimal(degrees, minutes, seconds, direction=' '): diff --git a/elodie/media/media.py b/elodie/media/media.py index 2bb7846..2e8f9b6 100644 --- a/elodie/media/media.py +++ b/elodie/media/media.py @@ -15,10 +15,6 @@ from elodie.dependencies import get_exiftool from elodie.external.pyexiftool import ExifTool from elodie.media.base import Base -import os -import re -import subprocess - class Media(Base): @@ -92,12 +88,16 @@ class Media(Base): for key in self.latitude_keys + self.longitude_keys: # TODO: verify that we need to check ref key # when self.set_gps_ref != True - if type == 'latitude' and key in self.latitude_keys and key in exif: - if self.latitude_ref_key in exif and exif[self.latitude_ref_key] == 'S': #noqa + if type == 'latitude' and key in self.latitude_keys and \ + key in exif: + if self.latitude_ref_key in exif and \ + exif[self.latitude_ref_key] == 'S': direction_multiplier = -1 return exif[key] * direction_multiplier - elif type == 'longitude' and key in self.longitude_keys and key in exif: #noqa - if self.longitude_ref_key in exif and exif[self.longitude_ref_key] == 'W': #noqa + elif type == 'longitude' and key in self.longitude_keys and \ + key in exif: + if self.longitude_ref_key in exif and \ + exif[self.longitude_ref_key] == 'W': direction_multiplier = -1 return exif[key] * direction_multiplier @@ -170,8 +170,6 @@ class Media(Base): if(time is None): return False - source = self.source - tags = {} formatted_time = time.strftime('%Y:%m:%d %H:%M:%S') for key in self.exif_map['date_taken']: @@ -185,8 +183,6 @@ class Media(Base): if(not self.is_valid()): return None - source = self.source - # The lat/lon _keys array has an order of precedence. # The first key is writable and we will give the writable # key precence when reading. @@ -222,8 +218,6 @@ class Media(Base): if(title is None): return None - source = self.source - tags = {self.title_key: title} status = self.__set_tags(tags) self.reset_cache() diff --git a/elodie/media/photo.py b/elodie/media/photo.py index 5d994e6..99b27a5 100644 --- a/elodie/media/photo.py +++ b/elodie/media/photo.py @@ -15,8 +15,6 @@ from re import compile from elodie import constants -from elodie import geolocation -from elodie.external.pyexiftool import ExifTool from media import Media @@ -69,7 +67,7 @@ class Photo(Media): """ if(not self.is_valid()): return None - + source = self.source seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source)) # noqa @@ -80,7 +78,7 @@ class Photo(Media): # We need to parse a string from EXIF into a timestamp. # EXIF DateTimeOriginal and EXIF DateTime are both stored # in %Y:%m:%d %H:%M:%S format - # we use split on a space and then r':|-' -> convert to int -> .timetuple() + # we split on a space and then r':|-' -> convert to int -> .timetuple() # the conversion in the local timezone # EXIF DateTime is already stored as a timestamp # Sourced from https://github.com/photo/frontend/blob/master/src/libraries/models/Photo.php#L500 # noqa diff --git a/elodie/media/video.py b/elodie/media/video.py index 7083294..b49f50a 100644 --- a/elodie/media/video.py +++ b/elodie/media/video.py @@ -7,19 +7,12 @@ objects (AVI, MOV, etc.). # load modules from distutils.spawn import find_executable -import tempfile from datetime import datetime import os import re -import shutil -import subprocess import time -from elodie import constants -from elodie import plist_parser -from elodie.dependencies import get_exiftool -from media import Base from media import Media @@ -45,12 +38,12 @@ class Video(Media): self.title_key = 'XMP:DisplayName' self.latitude_keys = [ 'XMP:GPSLatitude', - #'QuickTime:GPSLatitude', + # 'QuickTime:GPSLatitude', 'Composite:GPSLatitude' ] self.longitude_keys = [ 'XMP:GPSLongitude', - #'QuickTime:GPSLongitude', + # 'QuickTime:GPSLongitude', 'Composite:GPSLongitude' ] self.latitude_ref_key = 'EXIF:GPSLatitudeRef' @@ -81,7 +74,7 @@ class Video(Media): """ if(not self.is_valid()): return None - + source = self.source seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source)) # noqa @@ -107,7 +100,7 @@ class Video(Media): if date_offset is not None: offset_parts = date_offset[1:].split(':') offset_seconds = int(offset_parts[0]) * 3600 - offset_seconds = offset_seconds + int(offset_parts[1]) * 60 #noqa + offset_seconds = offset_seconds + int(offset_parts[1]) * 60 # noqa if date_offset[0] == '-': seconds_since_epoch - offset_seconds elif date_offset[0] == '+': From cbfd39a20e5ad817b6fac51b20764a86fe843ddb Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 00:34:51 -0400 Subject: [PATCH 02/11] gh-119 Use XMP-xmpDM:Album instead of user defined tag with fallback support --- Readme.md | 4 ++-- elodie/media/media.py | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Readme.md b/Readme.md index 208c51f..990dfee 100644 --- a/Readme.md +++ b/Readme.md @@ -98,7 +98,7 @@ Here's an example of a very asynchronous setup. * Periodically recategorize photos by fixing their location or date or by adding them to an album. * Have a Synology at home set to automatically sync down from Dropbox/Google Drive. -This setup means you can quickly get photos off your or anyone's phone and know that they'll be organized and backed up in 3 locations by the time they're ready to view them. +This setup means you can quickly get photos off your or anyone's phone and know that they'll be organized and backed up in 3 locations by the time you're ready to view them.

@@ -189,7 +189,7 @@ Organizing your existing photos is great. But I'd be lying if I said I was the o In order to sort new photos that I haven't already organized I need someone to tell me about them. There's no single way to do this. You could use inotify, cron, Automator or my favorite app - Hazel; it doesn't matter. -If you'd like to let me know of a specific photo or group of photos to add to your library you would run one of the following command. Use fully qualified paths for everything since you won't be running this manually. +If you'd like to let me know of a specific photo or group of photos to add to your library you would run one of the following commands. Use fully qualified paths for everything since you won't be running this manually. ``` # I can import a single file into your library. diff --git a/elodie/media/media.py b/elodie/media/media.py index 2e8f9b6..c2a9813 100644 --- a/elodie/media/media.py +++ b/elodie/media/media.py @@ -39,7 +39,7 @@ class Media(Base): 'EXIF:DateTimeDigitized' ] } - self.album_key = 'XMP:Album' + self.album_keys = ['XMP-xmpDM:Album', 'XMP:Album'] self.title_key = 'XMP:Title' self.latitude_keys = ['EXIF:GPSLatitude'] self.longitude_keys = ['EXIF:GPSLongitude'] @@ -64,10 +64,11 @@ class Media(Base): if exiftool_attributes is None: return None - if self.album_key not in exiftool_attributes: - return None + for album_key in self.album_keys: + if album_key in exiftool_attributes: + return exiftool_attributes[album_key] - return exiftool_attributes[self.album_key] + return None def get_coordinate(self, type='latitude'): """Get latitude or longitude of media from EXIF @@ -153,9 +154,7 @@ class Media(Base): if(not self.is_valid()): return None - source = self.source - - tags = {self.album_key: album} + tags = {self.album_keys[0]: album} status = self.__set_tags(tags) self.reset_cache() From 21b7c9fad1e5c0bf771c966856583083d022a0ab Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 00:47:04 -0400 Subject: [PATCH 03/11] gh-120 Update EXIF date taken tags to use EXIF:CreateDate and EXIF:ModifyDate --- Readme.md | 2 +- elodie/media/media.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 990dfee..6d0b189 100644 --- a/Readme.md +++ b/Readme.md @@ -219,7 +219,7 @@ When I organize photos I look at the embedded metadata. Here are the details of | Dimension | Fields | Notes | |---|---|---| -| Date Taken (photo) | EXIF:DateTimeOriginal,EXIF:DateTime, EXIF:DateTimeDigitized, file created, file modified | | +| Date Taken (photo) | EXIF:DateTimeOriginal, EXIF:CreateDate, EXIF:ModifyDate, file created, file modified | | | Date Taken (video, audio) | QuickTime:CreationDate, QuickTime:CreationDate-und-US, QuickTime:MediaCreateDate, file created, file modified | | | Location (photo) | EXIF:GPSLatitude/EXIF:GPSLatitudeRef, EXIF:GPSLongitude/EXIF:GPSLongitudeRef | | | Location (video, audio) | XMP:GPSLatitude, Composite:GPSLatitude, XMP:GPSLongitude, Composite:GPSLongitude | Composite tags are read-only | diff --git a/elodie/media/media.py b/elodie/media/media.py index c2a9813..b3bad78 100644 --- a/elodie/media/media.py +++ b/elodie/media/media.py @@ -35,8 +35,8 @@ class Media(Base): self.exif_map = { 'date_taken': [ 'EXIF:DateTimeOriginal', - 'EXIF:DateTime', - 'EXIF:DateTimeDigitized' + 'EXIF:CreateDate', + 'EXIF:ModifyDate' ] } self.album_keys = ['XMP-xmpDM:Album', 'XMP:Album'] From ea8a13b5af3aafb38f716776eda36fa75a78c72e Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 00:53:27 -0400 Subject: [PATCH 04/11] gh-61 gh-108 Enable audio/video EXIF writing tests on Travis --- elodie/tests/elodie_test.py | 16 ---------------- elodie/tests/filesystem_test.py | 7 ------- elodie/tests/media/audio_test.py | 19 ------------------- elodie/tests/media/video_test.py | 16 ---------------- 4 files changed, 58 deletions(-) diff --git a/elodie/tests/elodie_test.py b/elodie/tests/elodie_test.py index 8c8fa1c..68bb94e 100644 --- a/elodie/tests/elodie_test.py +++ b/elodie/tests/elodie_test.py @@ -87,9 +87,6 @@ def test_import_file_video(): assert helper.path_tz_fix(os.path.join('2015-01-Jan','California','2015-01-19_12-45-11-video.mov')) in dest_path, dest_path def test_update_location_on_audio(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() temporary_folder_destination, folder_destination = helper.create_working_folder() @@ -165,9 +162,6 @@ def test_update_location_on_text(): assert helper.isclose(metadata_processed['longitude'], -122.03635), metadata_processed['longitude'] def test_update_location_on_video(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() temporary_folder_destination, folder_destination = helper.create_working_folder() @@ -193,9 +187,6 @@ def test_update_location_on_video(): assert helper.isclose(metadata_processed['longitude'], -122.03635), metadata_processed['longitude'] def test_update_time_on_audio(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() temporary_folder_destination, folder_destination = helper.create_working_folder() @@ -268,9 +259,6 @@ def test_update_time_on_text(): assert metadata_processed['date_taken'] == helper.time_convert((2000, 1, 1, 12, 0, 0, 5, 1, 0)), metadata_processed['date_taken'] def test_update_time_on_video(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() temporary_folder_destination, folder_destination = helper.create_working_folder() @@ -303,7 +291,3 @@ def restore_hash_db(): hash_db = '{}-test'.format(constants.hash_db) if os.path.isfile(hash_db): os.rename(hash_db, hash_db.replace('-test', '')) - -def can_edit_exif(): - video = Video() - return video.get_avmetareadwrite() diff --git a/elodie/tests/filesystem_test.py b/elodie/tests/filesystem_test.py index a821d0b..dd6a8d4 100644 --- a/elodie/tests/filesystem_test.py +++ b/elodie/tests/filesystem_test.py @@ -342,9 +342,6 @@ def test_process_file_with_album_and_title_and_location(): # gh-89 (setting album then title reverts album) def test_process_video_with_album_then_title(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - filesystem = FileSystem() temporary_folder, folder = helper.create_working_folder() @@ -366,7 +363,3 @@ def test_process_video_with_album_then_title(): assert origin_checksum is not None, origin_checksum assert origin_checksum != destination_checksum, destination_checksum assert helper.path_tz_fix(os.path.join('2015-01-Jan','test_album','2015-01-19_12-45-11-movie-test_title.mov')) in destination, destination - -def can_edit_exif(): - video = Video() - return video.get_avmetareadwrite() diff --git a/elodie/tests/media/audio_test.py b/elodie/tests/media/audio_test.py index 9f4aedc..3618525 100644 --- a/elodie/tests/media/audio_test.py +++ b/elodie/tests/media/audio_test.py @@ -77,9 +77,6 @@ def test_is_not_valid(): assert not audio.is_valid() def test_set_date_taken(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() origin = '%s/audio.m4a' % folder @@ -100,9 +97,6 @@ def test_set_date_taken(): assert date_taken == (2013, 9, 30, 7, 6, 5, 0, 273, 0), metadata['date_taken'] def test_set_location(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() origin = '%s/audio.m4a' % folder @@ -129,9 +123,6 @@ def test_set_location(): assert helper.isclose(metadata['longitude'], 99.9999999999), metadata['longitude'] def test_set_location_minus(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() origin = '%s/audio.m4a' % folder @@ -158,9 +149,6 @@ def test_set_location_minus(): assert helper.isclose(metadata['longitude'], -99.999999), metadata['longitude'] def test_set_title(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() origin = '%s/audio.m4a' % folder @@ -181,9 +169,6 @@ def test_set_title(): assert metadata['title'] == 'my audio title', metadata['title'] def test_set_title_non_ascii(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - raise SkipTest('gh-27, non-ascii characters') temporary_folder, folder = helper.create_working_folder() @@ -203,7 +188,3 @@ def test_set_title_non_ascii(): shutil.rmtree(folder) assert metadata['title'] == '形声字 / 形聲字', metadata['title'] - -def can_edit_exif(): - audio = Audio() - return audio.get_avmetareadwrite() diff --git a/elodie/tests/media/video_test.py b/elodie/tests/media/video_test.py index 96c709f..91ea516 100644 --- a/elodie/tests/media/video_test.py +++ b/elodie/tests/media/video_test.py @@ -101,9 +101,6 @@ def test_set_album(): assert metadata_new['album'] == 'Test Album', metadata_new['album'] def test_set_date_taken(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() origin = '%s/video.mov' % folder @@ -124,9 +121,6 @@ def test_set_date_taken(): assert date_taken == (2013, 9, 30, 7, 6, 5, 0, 273, 0), metadata['date_taken'] def test_set_location(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() origin = '%s/video.mov' % folder @@ -153,9 +147,6 @@ def test_set_location(): assert helper.isclose(metadata['longitude'], 99.9999999999), metadata['longitude'] def test_set_title(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - temporary_folder, folder = helper.create_working_folder() origin = '%s/video.mov' % folder @@ -176,9 +167,6 @@ def test_set_title(): assert metadata['title'] == 'my video title', metadata['title'] def test_set_title_non_ascii(): - if not can_edit_exif(): - raise SkipTest('avmetareadwrite executable not found') - raise SkipTest('gh-27, non-ascii characters') temporary_folder, folder = helper.create_working_folder() @@ -198,7 +186,3 @@ def test_set_title_non_ascii(): shutil.rmtree(folder) assert metadata['title'] == '形声字 / 形聲字', metadata['title'] - -def can_edit_exif(): - video = Video() - return video.get_avmetareadwrite() From 0e9237366a81b4427a45eadf2c1582ce382d307b Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 01:02:15 -0400 Subject: [PATCH 05/11] gh-94 Enable test to write to RW2 files --- elodie/tests/media/photo_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/elodie/tests/media/photo_test.py b/elodie/tests/media/photo_test.py index d9dfa66..d99f8e1 100644 --- a/elodie/tests/media/photo_test.py +++ b/elodie/tests/media/photo_test.py @@ -416,7 +416,6 @@ def test_get_metadata_from_rw2(): assert metadata['date_taken'] == helper.time_convert((2014, 11, 19, 23, 7, 44, 2, 323, 0)), metadata['date_taken'] def test_set_metadata_on_rw2(): - raise SkipTest('gh-94 Writing to RW2 images is not supported') temporary_folder, folder = helper.create_working_folder() photo_file = helper.get_file('photo.rw2') From b89a0d2c2fbce00f626c2bcd9d3923e8d99ecc3c Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 01:19:50 -0400 Subject: [PATCH 06/11] Update Travis to install exiftool 10.20 --- .travis.yml | 8 ++++++++ Readme.md | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fbdc918..4e87c42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,14 @@ install: before_script: - "mkdir ~/.elodie" - "sed 's/your-api-key-goes-here/x8wQLqGhW7qK3sFpjYtVTogVtoMK0S8s/g' config.ini-sample > ~/.elodie/config.ini" + # Get exiftool 10.20 installed + - "export ELODIE_DIR=${PWD}" + - "wget http://www.sno.phy.queensu.ca/~phil/exiftool/Image-ExifTool-10.20.tar.gz" + - "gzip -dc Image-ExifTool-10.20.tar.gz | tar -xf -" + - "cd Image-ExifTool-10.20" + - "perl Makefile.PL" + - "sudo make install" + - "cd ${ELODIE_DIR}" after_success: - "coveralls" script: diff --git a/Readme.md b/Readme.md index 6d0b189..07d34c6 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ Getting started takes just a few minutes. Elodie relies on the great [ExifTool library by Phil Harvey](http://www.sno.phy.queensu.ca/~phil/exiftool/). You'll need to install it for your platform. -Some features for video files will only work with newer versions of ExifTool and have been tested on version 10.15 or higher. Check your version by typing `exiftool -ver` and see the [manual installation instructions for ExifTool](http://www.sno.phy.queensu.ca/~phil/exiftool/install.html#Unix) if needed. +Some features for video files will only work with newer versions of ExifTool and have been tested on version 10.20 or higher. Check your version by typing `exiftool -ver` and see the [manual installation instructions for ExifTool](http://www.sno.phy.queensu.ca/~phil/exiftool/install.html#Unix) if needed. ``` # OSX (uses homebrew, http://brew.sh/) From 792a86190ad05e65ff607f6f3f2533a15f7322b9 Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 01:46:56 -0400 Subject: [PATCH 07/11] Remove plist_parser.py and omit external libraries from code coverage --- .coveragerc | 1 + elodie/plist_parser.py | 44 ------------------------------------------ 2 files changed, 1 insertion(+), 44 deletions(-) delete mode 100644 elodie/plist_parser.py diff --git a/.coveragerc b/.coveragerc index 2301243..cdc54b3 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,4 @@ [report] omit = */tests/* + */external/* diff --git a/elodie/plist_parser.py b/elodie/plist_parser.py deleted file mode 100644 index ba8699b..0000000 --- a/elodie/plist_parser.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Parse OS X plists. - -.. moduleauthor:: Jaisen Mathai -""" - -# load modules -from os import path - -import plistlib - - -class Plist(object): - - """Parse and interact with a plist file. - - This class wraps the `plistlib module`_ from the standard library. - - .. _plistlib module: https://docs.python.org/3/library/plistlib.html - - :param str source: Source to read the plist from. - """ - - def __init__(self, source): - if not path.isfile(source): - raise IOError('Could not load plist file %s' % source) - self.source = source - self.plist = plistlib.readPlist(self.source) - - def update_key(self, key, value): - """Update a value in the plist. - - :param str key: Key to modify. - :param value: New value. - """ - self.plist[key] = value - - def write_file(self, destination): - """Save the plist. - - :param destination: Write the plist here. - :type destination: str or file object - """ - plistlib.writePlist(self.plist, destination) From 4f19c0c00d7ea76d7d8884b201992853b1689c4f Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Fri, 24 Jun 2016 01:59:06 -0400 Subject: [PATCH 08/11] gh-119 Update Readme to include XMP-xmpDM:Album --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 07d34c6..ef96307 100644 --- a/Readme.md +++ b/Readme.md @@ -225,7 +225,7 @@ When I organize photos I look at the embedded metadata. Here are the details of | Location (video, audio) | XMP:GPSLatitude, Composite:GPSLatitude, XMP:GPSLongitude, Composite:GPSLongitude | Composite tags are read-only | | Title (photo) | XMP:Title | | | Title (video, audio) | XMP:DisplayName | | -| Album | XMP:Album | User defined tag in `configs/ExifTool_config` | +| Album | XMP-xmpDM:Album, XMP:Album | XMP:Album is user defined in `configs/ExifTool_config` for backwards compatability | ## Using OpenStreetMap data from MapQuest From af36de091e1746b490bed0adb839adccd4f6d2ef Mon Sep 17 00:00:00 2001 From: zserg Date: Sat, 12 Mar 2016 22:09:28 +0300 Subject: [PATCH 09/11] Python 3 compartibility added --- .travis.yml | 7 ++--- elodie.py | 35 ++++++++++++------------ elodie/arguments.py | 5 ++-- elodie/dependencies.py | 3 ++- elodie/external/pyexiftool.py | 7 ++--- elodie/filesystem.py | 10 ++++--- elodie/geolocation.py | 45 ++++++++++++------------------- elodie/localstorage.py | 8 +++--- elodie/media/audio.py | 3 ++- elodie/media/base.py | 4 +++ elodie/media/media.py | 2 ++ elodie/media/photo.py | 7 +++-- elodie/media/text.py | 2 +- elodie/media/video.py | 8 +++++- elodie/tests/filesystem_test.py | 3 ++- elodie/tests/geolocation_test.py | 12 ++++++--- elodie/tests/helper.py | 12 ++++++--- elodie/tests/localstorage_test.py | 8 +++--- elodie/tests/media/audio_test.py | 3 ++- elodie/tests/media/photo_test.py | 1 + requirements.txt | 1 + 21 files changed, 107 insertions(+), 79 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4e87c42..745ca14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,15 @@ language: python dist: trusty python: - "2.7" + - "3.4" virtualenv: system_site_packages: true before_install: - "sudo apt-get update -qq" - "sudo apt-get install python-dev python-pip libimage-exiftool-perl -y" install: - - "sudo pip install -r elodie/tests/requirements.txt" - - "sudo pip install coveralls" + - "pip install -r elodie/tests/requirements.txt" + - "pip install coveralls" # command to run tests # test mapquest key before_script: @@ -25,5 +26,5 @@ before_script: - "cd ${ELODIE_DIR}" after_success: - "coveralls" -script: +script: - "nosetests --with-coverage --cover-package=elodie -w elodie/tests" diff --git a/elodie.py b/elodie.py index 3340153..bcda4a2 100755 --- a/elodie.py +++ b/elodie.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +from __future__ import print_function import os import re import sys @@ -35,16 +36,16 @@ def import_file(_file, destination, album_from_folder, trash): """ if not os.path.exists(_file): if constants.debug: - print 'Could not find %s' % _file - print '{"source":"%s", "error_msg":"Could not find %s"}' % \ - (_file, _file) + print('Could not find %s' % _file) + print('{"source":"%s", "error_msg":"Could not find %s"}' % \ + (_file, _file)) return media = Media.get_class_by_file(_file, [Text, Audio, Photo, Video]) if not media: if constants.debug: - print 'Not a supported file (%s)' % _file - print '{"source":"%s", "error_msg":"Not a supported file"}' % _file + print('Not a supported file (%s)' % _file) + print('{"source":"%s", "error_msg":"Not a supported file"}' % _file) return if media.__name__ == 'Video': @@ -56,7 +57,7 @@ def import_file(_file, destination, album_from_folder, trash): dest_path = FILESYSTEM.process_file(_file, destination, media, allowDuplicate=False, move=False) if dest_path: - print '%s -> %s' % (_file, dest_path) + print('%s -> %s' % (_file, dest_path)) if trash: send2trash(_file) @@ -109,9 +110,9 @@ def update_location(media, file_path, location_name): 'latitude'], location_coords['longitude']) if not location_status: if constants.debug: - print 'Failed to update location' - print ('{"source":"%s",' % file_path, - '"error_msg":"Failed to update location"}') + print('Failed to update location') + print(('{"source":"%s",' % file_path, + '"error_msg":"Failed to update location"}')) sys.exit(1) return True @@ -125,8 +126,8 @@ def update_time(media, file_path, time_string): elif re.match(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}\d{2}$', time_string): msg = ('Invalid time format. Use YYYY-mm-dd hh:ii:ss or YYYY-mm-dd') if constants.debug: - print msg - print '{"source":"%s", "error_msg":"%s"}' % (file_path, msg) + print(msg) + print('{"source":"%s", "error_msg":"%s"}' % (file_path, msg)) sys.exit(1) time = datetime.strptime(time_string, time_format) @@ -150,9 +151,9 @@ def _update(album, location, time, title, files): for file_path in files: if not os.path.exists(file_path): if constants.debug: - print 'Could not find %s' % file_path - print '{"source":"%s", "error_msg":"Could not find %s"}' % \ - (file_path, file_path) + print('Could not find %s' % file_path) + print('{"source":"%s", "error_msg":"Could not find %s"}' % \ + (file_path, file_path)) continue file_path = os.path.expanduser(file_path) @@ -209,9 +210,9 @@ def _update(album, location, time, title, files): dest_path = FILESYSTEM.process_file(file_path, destination, updated_media, move=True, allowDuplicate=True) if constants.debug: - print u'%s -> %s' % (file_path, dest_path) - print '{"source":"%s", "destination":"%s"}' % (file_path, - dest_path) + print(u'%s -> %s' % (file_path, dest_path)) + print('{"source":"%s", "destination":"%s"}' % (file_path, + dest_path)) # If the folder we moved the file out of or its parent are empty # we delete it. FILESYSTEM.delete_directory_if_empty(os.path.dirname(file_path)) diff --git a/elodie/arguments.py b/elodie/arguments.py index fc43f95..f181b18 100644 --- a/elodie/arguments.py +++ b/elodie/arguments.py @@ -1,6 +1,7 @@ """ Command line argument parsing for helper scripts. """ +from __future__ import print_function import getopt import sys @@ -20,13 +21,13 @@ def parse(argv, options, long_options, usage): try: opts, args = getopt.getopt(argv, options, long_options) except getopt.GetoptError: - print usage + print(usage) sys.exit(2) return_arguments = {} for opt, arg in opts: if opt == '-h': - print usage + print(usage) sys.exit() else: return_arguments[sub('^-+', '', opt)] = arg diff --git a/elodie/dependencies.py b/elodie/dependencies.py index 09ab6b8..e575b5d 100644 --- a/elodie/dependencies.py +++ b/elodie/dependencies.py @@ -2,6 +2,7 @@ Helpers for checking for an interacting with external dependencies. These are things that Elodie requires, but aren't installed automatically for the user. """ +from __future__ import print_function import os import sys @@ -43,7 +44,7 @@ def verify_dependencies(): """ exiftool = get_exiftool() if exiftool is None: - print >>sys.stderr, EXIFTOOL_ERROR + print(EXIFTOOL_ERROR, file=sys.stderr) return False return True diff --git a/elodie/external/pyexiftool.py b/elodie/external/pyexiftool.py index 540ecc5..52b187e 100644 --- a/elodie/external/pyexiftool.py +++ b/elodie/external/pyexiftool.py @@ -273,8 +273,7 @@ class ExifTool(object): """ if not self.running: raise ValueError("ExifTool instance not running.") - cmd_txt = b"\n".join(params + (b"-execute\n",)) - self._process.stdin.write(cmd_txt.encode("utf-8")) + self._process.stdin.write(b"\n".join(params + (b"-execute\n",))) self._process.stdin.flush() output = b"" fd = self._process.stdout.fileno() @@ -403,11 +402,13 @@ class ExifTool(object): "an iterable of strings") params = [] + params_b = [] for tag, value in tags.items(): params.append(u'-%s=%s' % (tag, value)) params.extend(filenames) - return self.execute(*params) + params_b = [x.encode('utf-8') for x in params] + return self.execute(*params_b) def set_tags(self, tags, filename): """Writes the values of the specified tags for the given file. diff --git a/elodie/filesystem.py b/elodie/filesystem.py index 50d5b5c..79ca367 100644 --- a/elodie/filesystem.py +++ b/elodie/filesystem.py @@ -3,6 +3,8 @@ General file system methods. .. moduleauthor:: Jaisen Mathai """ +from __future__ import print_function +from builtins import object import os import re @@ -176,7 +178,7 @@ class FileSystem(object): allow_duplicate = kwargs['allowDuplicate'] if(not media.is_valid()): - print '%s is not a valid media file. Skipping...' % _file + print('%s is not a valid media file. Skipping...' % _file) return metadata = media.get_metadata() @@ -191,17 +193,17 @@ class FileSystem(object): checksum = db.checksum(_file) if(checksum is None): if(constants.debug is True): - print 'Could not get checksum for %s. Skipping...' % _file + print('Could not get checksum for %s. Skipping...' % _file) return # If duplicates are not allowed and this hash exists in the db then we # return if(allow_duplicate is False and db.check_hash(checksum) is True): if(constants.debug is True): - print '%s already exists at %s. Skipping...' % ( + print('%s already exists at %s. Skipping...' % ( _file, db.get_hash(checksum) - ) + )) return self.create_directory(dest_directory) diff --git a/elodie/geolocation.py b/elodie/geolocation.py index 158a931..925bc83 100644 --- a/elodie/geolocation.py +++ b/elodie/geolocation.py @@ -1,32 +1,21 @@ """Look up geolocation information for media objects.""" +from __future__ import print_function +from __future__ import division +from future import standard_library +standard_library.install_aliases() +from past.utils import old_div from os import path -from ConfigParser import ConfigParser +from configparser import ConfigParser import fractions import requests -import urllib +import urllib.request, urllib.parse, urllib.error from elodie import constants from elodie.localstorage import Db -class Fraction(fractions.Fraction): - - """Only create Fractions from floats. - - Should be compatible with Python 2.6, though untested. - - >>> Fraction(0.3) - Fraction(3, 10) - >>> Fraction(1.1) - Fraction(11, 10) - """ - - def __new__(cls, value, ignore=None): - return fractions.Fraction.from_float(value).limit_denominator(99999) - - def coordinates_by_name(name): # Try to get cached location first db = Db() @@ -88,7 +77,7 @@ def dms_to_decimal(degrees, minutes, seconds, direction=' '): if(direction[0] in 'WSws'): sign = -1 return ( - float(degrees) + float(minutes) / 60 + float(seconds) / 3600 + float(degrees) + old_div(float(minutes), 60) + old_div(float(seconds), 3600) ) * sign @@ -159,17 +148,17 @@ def reverse_lookup(lat, lon): headers = {"Accept-Language": constants.accepted_language} r = requests.get( 'http://open.mapquestapi.com/nominatim/v1/reverse.php?%s' % - urllib.urlencode(params), headers=headers + urllib.parse.urlencode(params),headers=headers ) return r.json() except requests.exceptions.RequestException as e: if(constants.debug is True): - print e + print(e) return None except ValueError as e: if(constants.debug is True): - print r.text - print e + print(r.text) + print(e) return None @@ -182,18 +171,18 @@ def lookup(name): try: params = {'format': 'json', 'key': key, 'location': name} if(constants.debug is True): - print 'http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.urlencode(params) # noqa + print('http://open.mapquestapi.com/geocoding/v1/address?%s' % urllib.parse.urlencode(params)) # noqa r = requests.get( 'http://open.mapquestapi.com/geocoding/v1/address?%s' % - urllib.urlencode(params) + urllib.parse.urlencode(params) ) return r.json() except requests.exceptions.RequestException as e: if(constants.debug is True): - print e + print(e) return None except ValueError as e: if(constants.debug is True): - print r.text - print e + print(r.text) + print(e) return None diff --git a/elodie/localstorage.py b/elodie/localstorage.py index 8f1d837..3ce5f51 100644 --- a/elodie/localstorage.py +++ b/elodie/localstorage.py @@ -1,6 +1,8 @@ """ Methods for interacting with information Elodie caches about stored media. """ +from builtins import map +from builtins import object import hashlib import json @@ -141,17 +143,17 @@ class Db(object): the given latitude and longitude. :returns: str, or None if a matching location couldn't be found. """ - last_d = sys.maxint + last_d = sys.maxsize name = None for data in self.location_db: # As threshold is quite small use simple math # From http://stackoverflow.com/questions/15736995/how-can-i-quickly-estimate-the-distance-between-two-latitude-longitude-points # noqa # convert decimal degrees to radians - lon1, lat1, lon2, lat2 = map( + lon1, lat1, lon2, lat2 = list(map( radians, [longitude, latitude, data['long'], data['lat']] - ) + )) r = 6371000 # radius of the earth in m x = (lon2 - lon1) * cos(0.5 * (lat2 + lat1)) diff --git a/elodie/media/audio.py b/elodie/media/audio.py index fdf2517..8409512 100644 --- a/elodie/media/audio.py +++ b/elodie/media/audio.py @@ -5,8 +5,9 @@ class. .. moduleauthor:: Jaisen Mathai """ +from __future__ import absolute_import -from video import Video +from .video import Video class Audio(Video): diff --git a/elodie/media/base.py b/elodie/media/base.py index 7cf27c4..167ad7d 100644 --- a/elodie/media/base.py +++ b/elodie/media/base.py @@ -13,6 +13,10 @@ are used to represent the actual files. import mimetypes import os +try: + basestring +except NameError: + basestring = str class Base(object): diff --git a/elodie/media/media.py b/elodie/media/media.py index b3bad78..ddfd9b8 100644 --- a/elodie/media/media.py +++ b/elodie/media/media.py @@ -8,6 +8,8 @@ are used to represent the actual files. .. moduleauthor:: Jaisen Mathai """ +from __future__ import print_function +from builtins import object # load modules from elodie import constants diff --git a/elodie/media/photo.py b/elodie/media/photo.py index 99b27a5..cca402c 100644 --- a/elodie/media/photo.py +++ b/elodie/media/photo.py @@ -4,6 +4,9 @@ image objects (JPG, DNG, etc.). .. moduleauthor:: Jaisen Mathai """ +from __future__ import print_function +from __future__ import absolute_import +from builtins import str import imghdr import os @@ -15,7 +18,7 @@ from re import compile from elodie import constants -from media import Media +from .media import Media class Photo(Media): @@ -95,7 +98,7 @@ class Photo(Media): break except BaseException as e: if(constants.debug is True): - print e + print(e) pass if(seconds_since_epoch == 0): diff --git a/elodie/media/text.py b/elodie/media/text.py index 7219591..ccdb6d3 100644 --- a/elodie/media/text.py +++ b/elodie/media/text.py @@ -123,7 +123,7 @@ class Text(Base): self.metadata_line = parsed_json except ValueError: if(constants.debug is True): - print 'Could not parse JSON from first line: %s' % first_line + print('Could not parse JSON from first line: %s' % first_line) pass def write_metadata(self, **kwargs): diff --git a/elodie/media/video.py b/elodie/media/video.py index b49f50a..d13885c 100644 --- a/elodie/media/video.py +++ b/elodie/media/video.py @@ -4,6 +4,12 @@ objects (AVI, MOV, etc.). .. moduleauthor:: Jaisen Mathai """ +from __future__ import print_function +from __future__ import absolute_import +from __future__ import division +from builtins import str +from builtins import object +from past.utils import old_div # load modules from distutils.spawn import find_executable @@ -13,7 +19,7 @@ import os import re import time -from media import Media +from .media import Media class Video(Media): diff --git a/elodie/tests/filesystem_test.py b/elodie/tests/filesystem_test.py index dd6a8d4..dfb13d1 100644 --- a/elodie/tests/filesystem_test.py +++ b/elodie/tests/filesystem_test.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import # Project imports import os import re @@ -11,7 +12,7 @@ import mock sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))) -import helper +from . import helper from elodie.filesystem import FileSystem from elodie.media.media import Media from elodie.media.photo import Photo diff --git a/elodie/tests/geolocation_test.py b/elodie/tests/geolocation_test.py index fb85493..02ab5e3 100644 --- a/elodie/tests/geolocation_test.py +++ b/elodie/tests/geolocation_test.py @@ -1,3 +1,7 @@ +from __future__ import absolute_import +from __future__ import division +from builtins import range +from past.utils import old_div # Project imports import os import random @@ -6,7 +10,7 @@ import sys sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))) -import helper +from . import helper from elodie import geolocation os.environ['TZ'] = 'GMT' @@ -18,7 +22,7 @@ def test_decimal_to_dms(): target_decimal_value = random.uniform(0.0, 180.0) if(x % 2 == 1): target_decimal_value = target_decimal_value * -1 - + dms = geolocation.decimal_to_dms(target_decimal_value) check_value = (dms[0] + dms[1] / 60 + dms[2] / 3600) * dms[3] @@ -34,7 +38,7 @@ def test_dms_string_latitude(): target_decimal_value = random.uniform(0.0, 180.0) if(x % 2 == 1): target_decimal_value = target_decimal_value * -1 - + dms = geolocation.decimal_to_dms(target_decimal_value) dms_string = geolocation.dms_string(target_decimal_value, 'latitude') @@ -49,7 +53,7 @@ def test_dms_string_longitude(): target_decimal_value = random.uniform(0.0, 180.0) if(x % 2 == 1): target_decimal_value = target_decimal_value * -1 - + dms = geolocation.decimal_to_dms(target_decimal_value) dms_string = geolocation.dms_string(target_decimal_value, 'longitude') diff --git a/elodie/tests/helper.py b/elodie/tests/helper.py index 5e07309..102ad29 100644 --- a/elodie/tests/helper.py +++ b/elodie/tests/helper.py @@ -1,3 +1,7 @@ +from __future__ import division +from __future__ import unicode_literals +from builtins import range +from past.utils import old_div import hashlib import os import random @@ -12,7 +16,7 @@ from datetime import timedelta def checksum(file_path, blocksize=65536): hasher = hashlib.sha256() - with open(file_path, 'r') as f: + with open(file_path, 'rb') as f: buf = f.read(blocksize) while len(buf) > 0: @@ -73,7 +77,7 @@ def random_decimal(): def random_coordinate(coordinate, precision): # Here we add to the decimal section of the coordinate by a given precision - return coordinate + ((10.0 / (10.0**precision)) * random_decimal()) + return coordinate + ((old_div(10.0, (10.0**precision))) * random_decimal()) def temp_dir(): return tempfile.gettempdir() @@ -91,8 +95,8 @@ def is_windows(): def path_tz_fix(file_name): if is_windows(): # Calculate the offset between UTC and local time - tz_shift = (datetime.fromtimestamp(0) - - datetime.utcfromtimestamp(0)).seconds/3600 + tz_shift = old_div((datetime.fromtimestamp(0) - + datetime.utcfromtimestamp(0)).seconds,3600) # replace timestamp in file_name m = re.search('(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})',file_name) t_date = datetime.fromtimestamp(time.mktime(time.strptime(m.group(0), '%Y-%m-%d_%H-%M-%S'))) diff --git a/elodie/tests/localstorage_test.py b/elodie/tests/localstorage_test.py index a7077df..fc58e11 100644 --- a/elodie/tests/localstorage_test.py +++ b/elodie/tests/localstorage_test.py @@ -1,10 +1,12 @@ +from __future__ import print_function +from __future__ import absolute_import # Project imports import os import sys sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))) -import helper +from . import helper from elodie.localstorage import Db from elodie import constants @@ -154,10 +156,10 @@ def test_get_location_name_within_threshold(): latitude, longitude, name = helper.get_test_location() db.add_location(latitude, longitude, name) - print latitude + print(latitude) new_latitude = helper.random_coordinate(latitude, 4) new_longitude = helper.random_coordinate(longitude, 4) - print new_latitude + print(new_latitude) # 10 miles retrieved_name = db.get_location_name(new_latitude, new_longitude, 1600*10) diff --git a/elodie/tests/media/audio_test.py b/elodie/tests/media/audio_test.py index 3618525..cdc4f70 100644 --- a/elodie/tests/media/audio_test.py +++ b/elodie/tests/media/audio_test.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 # Project imports +from __future__ import print_function import os import sys @@ -56,7 +57,7 @@ def test_get_date_taken(): audio = Audio(helper.get_file('audio.m4a')) date_taken = audio.get_date_taken() - print '%r' % date_taken + print('%r' % date_taken) assert date_taken == (2016, 1, 4, 5, 24, 15, 0, 19, 0), date_taken def test_get_exiftool_attributes(): diff --git a/elodie/tests/media/photo_test.py b/elodie/tests/media/photo_test.py index d99f8e1..75ed3d6 100644 --- a/elodie/tests/media/photo_test.py +++ b/elodie/tests/media/photo_test.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 # Project imports +from __future__ import unicode_literals import os import sys diff --git a/requirements.txt b/requirements.txt index 3d208c7..c5489ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ click>=6.2,<7.0 requests>=2.9.1,<3.0 send2trash>=1.3.0,<2.0 +future From ad1cbefb15077844a6f64dca567ea5600477dd52 Mon Sep 17 00:00:00 2001 From: ZSerg Date: Mon, 22 Aug 2016 09:10:45 +0300 Subject: [PATCH 10/11] PEP8 fix --- elodie/external/pyexiftool.py | 6 +++--- elodie/geolocation.py | 13 ++++++++----- elodie/media/base.py | 7 ++++--- elodie/media/media.py | 1 - elodie/media/photo.py | 1 - elodie/media/video.py | 3 --- elodie/tests/media/audio_test.py | 1 - 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/elodie/external/pyexiftool.py b/elodie/external/pyexiftool.py index 52b187e..f6850f6 100644 --- a/elodie/external/pyexiftool.py +++ b/elodie/external/pyexiftool.py @@ -402,13 +402,13 @@ class ExifTool(object): "an iterable of strings") params = [] - params_b = [] + params_utf8 = [] for tag, value in tags.items(): params.append(u'-%s=%s' % (tag, value)) params.extend(filenames) - params_b = [x.encode('utf-8') for x in params] - return self.execute(*params_b) + params_utf8 = [x.encode('utf-8') for x in params] + return self.execute(*params_utf8) def set_tags(self, tags, filename): """Writes the values of the specified tags for the given file. diff --git a/elodie/geolocation.py b/elodie/geolocation.py index 925bc83..e0f4780 100644 --- a/elodie/geolocation.py +++ b/elodie/geolocation.py @@ -2,15 +2,17 @@ from __future__ import print_function from __future__ import division from future import standard_library -standard_library.install_aliases() from past.utils import old_div from os import path from configparser import ConfigParser -import fractions + +standard_library.install_aliases() # noqa import requests -import urllib.request, urllib.parse, urllib.error +import urllib.request +import urllib.parse +import urllib.error from elodie import constants from elodie.localstorage import Db @@ -77,7 +79,8 @@ def dms_to_decimal(degrees, minutes, seconds, direction=' '): if(direction[0] in 'WSws'): sign = -1 return ( - float(degrees) + old_div(float(minutes), 60) + old_div(float(seconds), 3600) + float(degrees) + old_div(float(minutes), 60) + + old_div(float(seconds), 3600) ) * sign @@ -148,7 +151,7 @@ def reverse_lookup(lat, lon): headers = {"Accept-Language": constants.accepted_language} r = requests.get( 'http://open.mapquestapi.com/nominatim/v1/reverse.php?%s' % - urllib.parse.urlencode(params),headers=headers + urllib.parse.urlencode(params), headers=headers ) return r.json() except requests.exceptions.RequestException as e: diff --git a/elodie/media/base.py b/elodie/media/base.py index 167ad7d..2d1410b 100644 --- a/elodie/media/base.py +++ b/elodie/media/base.py @@ -13,10 +13,11 @@ are used to represent the actual files. import mimetypes import os -try: - basestring +try: # Py3k compatibility + basestring except NameError: - basestring = str + basestring = (bytes, str) + class Base(object): diff --git a/elodie/media/media.py b/elodie/media/media.py index ddfd9b8..ae2e82d 100644 --- a/elodie/media/media.py +++ b/elodie/media/media.py @@ -9,7 +9,6 @@ are used to represent the actual files. .. moduleauthor:: Jaisen Mathai """ from __future__ import print_function -from builtins import object # load modules from elodie import constants diff --git a/elodie/media/photo.py b/elodie/media/photo.py index cca402c..221438b 100644 --- a/elodie/media/photo.py +++ b/elodie/media/photo.py @@ -6,7 +6,6 @@ image objects (JPG, DNG, etc.). """ from __future__ import print_function from __future__ import absolute_import -from builtins import str import imghdr import os diff --git a/elodie/media/video.py b/elodie/media/video.py index d13885c..2becef6 100644 --- a/elodie/media/video.py +++ b/elodie/media/video.py @@ -7,9 +7,6 @@ objects (AVI, MOV, etc.). from __future__ import print_function from __future__ import absolute_import from __future__ import division -from builtins import str -from builtins import object -from past.utils import old_div # load modules from distutils.spawn import find_executable diff --git a/elodie/tests/media/audio_test.py b/elodie/tests/media/audio_test.py index cdc4f70..cfc9cd2 100644 --- a/elodie/tests/media/audio_test.py +++ b/elodie/tests/media/audio_test.py @@ -57,7 +57,6 @@ def test_get_date_taken(): audio = Audio(helper.get_file('audio.m4a')) date_taken = audio.get_date_taken() - print('%r' % date_taken) assert date_taken == (2016, 1, 4, 5, 24, 15, 0, 19, 0), date_taken def test_get_exiftool_attributes(): From 10e078baa586c8e17dc36a713eda7c4d36d1f09b Mon Sep 17 00:00:00 2001 From: Jaisen Mathai Date: Sun, 4 Sep 2016 16:10:30 -0700 Subject: [PATCH 11/11] gh-124 Add support for cr2 files --- elodie/media/photo.py | 2 +- elodie/tests/media/photo_test.py | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/elodie/media/photo.py b/elodie/media/photo.py index 5d994e6..d85c6f8 100644 --- a/elodie/media/photo.py +++ b/elodie/media/photo.py @@ -30,7 +30,7 @@ class Photo(Media): __name__ = 'Photo' #: Valid extensions for photo files. - extensions = ('arw', 'dng', 'gif', 'jpeg', 'jpg', 'nef', 'rw2') + extensions = ('arw', 'cr2', 'dng', 'gif', 'jpeg', 'jpg', 'nef', 'rw2') def __init__(self, source=None): super(Photo, self).__init__(source) diff --git a/elodie/tests/media/photo_test.py b/elodie/tests/media/photo_test.py index d9dfa66..24ce4ad 100644 --- a/elodie/tests/media/photo_test.py +++ b/elodie/tests/media/photo_test.py @@ -498,3 +498,57 @@ def test_set_metadata_on_arw(): assert metadata['date_taken'] == helper.time_convert((2007, 4, 8, 17, 41, 18, 6, 98, 0)), metadata['date_taken'] assert helper.isclose(metadata['latitude'], 11.1111111111), metadata['latitude'] assert helper.isclose(metadata['longitude'], 99.9999999999), metadata['longitude'] + +def test_get_metadata_from_cr2(): + temporary_folder, folder = helper.create_working_folder() + + photo_file = helper.get_file('photo.cr2') + origin = '%s/photo.cr2' % folder + + if not photo_file: + photo_file = helper.download_file('photo.cr2', folder) + if not photo_file or not os.path.isfile(photo_file): + raise SkipTest('cr2 file not downlaoded') + + # downloading for each test is costly so we save it in the working directory + file_path_save_as = helper.get_file_path('photo.cr2') + if os.path.isfile(photo_file): + shutil.copyfile(photo_file, file_path_save_as) + + shutil.copyfile(photo_file, origin) + + photo = Photo(origin) + metadata = photo.get_metadata() + + shutil.rmtree(folder) + + assert metadata['date_taken'] == helper.time_convert((2005, 10, 29, 16, 14, 44, 5, 302, 0)), metadata['date_taken'] + +def test_set_metadata_on_cr2(): + temporary_folder, folder = helper.create_working_folder() + + photo_file = helper.get_file('photo.cr2') + origin = '%s/photo.cr2' % folder + + if not photo_file: + photo_file = helper.download_file('photo.cr2', folder) + if not photo_file or not os.path.isfile(photo_file): + raise SkipTest('cr2 file not downlaoded') + + shutil.copyfile(photo_file, origin) + + photo = Photo(origin) + origin_metadata = photo.get_metadata() + + status = photo.set_location(11.1111111111, 99.9999999999) + + assert status == True, status + + photo_new = Photo(origin) + metadata = photo_new.get_metadata() + + shutil.rmtree(folder) + + assert metadata['date_taken'] == helper.time_convert((2005, 10, 29, 16, 14, 44, 5, 302, 0)), metadata['date_taken'] + assert helper.isclose(metadata['latitude'], 11.1111111111), metadata['latitude'] + assert helper.isclose(metadata['longitude'], 99.9999999999), metadata['longitude']