Python3 support
This commit is contained in:
parent
6c75abc9a8
commit
0805f032fb
14 changed files with 131 additions and 96 deletions
|
@ -1,8 +1,8 @@
|
||||||
from openphoto_http import OpenPhotoHttp
|
from .openphoto_http import OpenPhotoHttp
|
||||||
from errors import *
|
from .errors import *
|
||||||
import api_photo
|
from . import api_photo
|
||||||
import api_tag
|
from . import api_tag
|
||||||
import api_album
|
from . import api_album
|
||||||
|
|
||||||
LATEST_API_VERSION = 2
|
LATEST_API_VERSION = 2
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from errors import *
|
from .errors import *
|
||||||
from objects import Album
|
from .objects import Album
|
||||||
|
|
||||||
class ApiAlbums:
|
class ApiAlbums:
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from errors import *
|
from .errors import *
|
||||||
from objects import Photo
|
from .objects import Photo
|
||||||
|
|
||||||
class ApiPhotos:
|
class ApiPhotos:
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
|
@ -80,14 +80,16 @@ class ApiPhoto:
|
||||||
return photo
|
return photo
|
||||||
|
|
||||||
def upload(self, photo_file, **kwds):
|
def upload(self, photo_file, **kwds):
|
||||||
result = self._client.post("/photo/upload.json",
|
with open(photo_file, 'rb') as f:
|
||||||
files={'photo': open(photo_file, 'rb')},
|
result = self._client.post("/photo/upload.json",
|
||||||
**kwds)["result"]
|
files={'photo': f},
|
||||||
|
**kwds)["result"]
|
||||||
return Photo(self._client, result)
|
return Photo(self._client, result)
|
||||||
|
|
||||||
def upload_encoded(self, photo_file, **kwds):
|
def upload_encoded(self, photo_file, **kwds):
|
||||||
""" Base64-encodes and uploads the specified file """
|
""" Base64-encodes and uploads the specified file """
|
||||||
encoded_photo = base64.b64encode(open(photo_file, "rb").read())
|
with open(photo_file, "rb") as f:
|
||||||
|
encoded_photo = base64.b64encode(f.read())
|
||||||
result = self._client.post("/photo/upload.json", photo=encoded_photo,
|
result = self._client.post("/photo/upload.json", photo=encoded_photo,
|
||||||
**kwds)["result"]
|
**kwds)["result"]
|
||||||
return Photo(self._client, result)
|
return Photo(self._client, result)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from errors import *
|
from .errors import *
|
||||||
from objects import Tag
|
from .objects import Tag
|
||||||
|
|
||||||
class ApiTags:
|
class ApiTags:
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import string
|
import string
|
||||||
import urllib
|
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -56,22 +55,22 @@ def main(args=sys.argv[1:]):
|
||||||
try:
|
try:
|
||||||
client = OpenPhoto(config_file=options.config_file)
|
client = OpenPhoto(config_file=options.config_file)
|
||||||
except IOError as error:
|
except IOError as error:
|
||||||
print error
|
print(error)
|
||||||
print
|
print()
|
||||||
print "You must create a configuration file with the following contents:"
|
print("You must create a configuration file with the following contents:")
|
||||||
print " host = your.host.com"
|
print(" host = your.host.com")
|
||||||
print " consumerKey = your_consumer_key"
|
print(" consumerKey = your_consumer_key")
|
||||||
print " consumerSecret = your_consumer_secret"
|
print(" consumerSecret = your_consumer_secret")
|
||||||
print " token = your_access_token"
|
print(" token = your_access_token")
|
||||||
print " tokenSecret = your_access_token_secret"
|
print(" tokenSecret = your_access_token_secret")
|
||||||
print
|
print()
|
||||||
print "To get your credentials:"
|
print("To get your credentials:")
|
||||||
print " * Log into your Trovebox site"
|
print(" * Log into your Trovebox site")
|
||||||
print " * Click the arrow on the top-right and select 'Settings'."
|
print(" * Click the arrow on the top-right and select 'Settings'.")
|
||||||
print " * Click the 'Create a new app' button."
|
print(" * Click the 'Create a new app' button.")
|
||||||
print " * Click the 'View' link beside the newly created app."
|
print(" * Click the 'View' link beside the newly created app.")
|
||||||
print
|
print()
|
||||||
print error
|
print(error)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if options.method == "GET":
|
if options.method == "GET":
|
||||||
|
@ -81,17 +80,17 @@ def main(args=sys.argv[1:]):
|
||||||
result = client.post(options.endpoint, process_response=False, files=files, **params)
|
result = client.post(options.endpoint, process_response=False, files=files, **params)
|
||||||
|
|
||||||
if options.verbose:
|
if options.verbose:
|
||||||
print "==========\nMethod: %s\nHost: %s\nEndpoint: %s" % (options.method, config['host'], options.endpoint)
|
print("==========\nMethod: %s\nHost: %s\nEndpoint: %s" % (options.method, config['host'], options.endpoint))
|
||||||
if len( params ) > 0:
|
if len( params ) > 0:
|
||||||
print "Fields:"
|
print("Fields:")
|
||||||
for kv in params.iteritems():
|
for kv in params.items():
|
||||||
print " %s=%s" % kv
|
print(" %s=%s" % kv)
|
||||||
print "==========\n"
|
print("==========\n")
|
||||||
|
|
||||||
if options.pretty:
|
if options.pretty:
|
||||||
print json.dumps(json.loads(result), sort_keys=True, indent=4, separators=(',',':'))
|
print(json.dumps(json.loads(result), sort_keys=True, indent=4, separators=(',',':')))
|
||||||
else:
|
else:
|
||||||
print result
|
print(result)
|
||||||
|
|
||||||
def extract_files(params):
|
def extract_files(params):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import urllib
|
try:
|
||||||
from errors import *
|
from urllib.parse import quote # Python3
|
||||||
|
except ImportError:
|
||||||
|
from urllib import quote # Python2
|
||||||
|
from .errors import *
|
||||||
|
|
||||||
class OpenPhotoObject:
|
class OpenPhotoObject:
|
||||||
""" Base object supporting the storage of custom fields as attributes """
|
""" Base object supporting the storage of custom fields as attributes """
|
||||||
|
@ -128,13 +131,13 @@ class Tag(OpenPhotoObject):
|
||||||
Returns True if successful.
|
Returns True if successful.
|
||||||
Raises an OpenPhotoError if not.
|
Raises an OpenPhotoError if not.
|
||||||
"""
|
"""
|
||||||
result = self._openphoto.post("/tag/%s/delete.json" % urllib.quote(self.id), **kwds)["result"]
|
result = self._openphoto.post("/tag/%s/delete.json" % quote(self.id), **kwds)["result"]
|
||||||
self._replace_fields({})
|
self._replace_fields({})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def update(self, **kwds):
|
def update(self, **kwds):
|
||||||
""" Update this tag with the specified parameters """
|
""" Update this tag with the specified parameters """
|
||||||
new_dict = self._openphoto.post("/tag/%s/update.json" % urllib.quote(self.id),
|
new_dict = self._openphoto.post("/tag/%s/update.json" % quote(self.id),
|
||||||
**kwds)["result"]
|
**kwds)["result"]
|
||||||
self._replace_fields(new_dict)
|
self._replace_fields(new_dict)
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,36 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import sys
|
||||||
import os
|
import os
|
||||||
import urlparse
|
try:
|
||||||
import urllib
|
from urllib.parse import urlunparse # Python3
|
||||||
|
except ImportError:
|
||||||
|
from urlparse import urlunparse # Python2
|
||||||
import requests
|
import requests
|
||||||
import requests_oauthlib
|
import requests_oauthlib
|
||||||
import logging
|
import logging
|
||||||
import StringIO
|
|
||||||
import ConfigParser
|
|
||||||
try:
|
try:
|
||||||
import json
|
import io # Python3
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import simplejson as json
|
import StringIO as io # Python2
|
||||||
|
try:
|
||||||
|
from configparser import ConfigParser # Python3
|
||||||
|
except ImportError:
|
||||||
|
from ConfigParser import SafeConfigParser as ConfigParser # Python2
|
||||||
|
|
||||||
from objects import OpenPhotoObject
|
if sys.version < '3':
|
||||||
from errors import *
|
text_type = unicode # Python2
|
||||||
|
else:
|
||||||
|
text_type = str # Python3
|
||||||
|
|
||||||
|
from .objects import OpenPhotoObject
|
||||||
|
from .errors import *
|
||||||
|
|
||||||
|
if sys.version < '3':
|
||||||
|
# requests_oauth needs to decode to ascii for Python2
|
||||||
|
_oauth_decoding = "utf-8"
|
||||||
|
else:
|
||||||
|
# requests_oauth needs to use (unicode) strings for Python3
|
||||||
|
_oauth_decoding = None # Python3
|
||||||
|
|
||||||
DUPLICATE_RESPONSE = {"code": 409,
|
DUPLICATE_RESPONSE = {"code": 409,
|
||||||
"message": "This photo already exists"}
|
"message": "This photo already exists"}
|
||||||
|
@ -75,15 +93,17 @@ class OpenPhotoHttp:
|
||||||
endpoint = "/" + endpoint
|
endpoint = "/" + endpoint
|
||||||
if self._api_version is not None:
|
if self._api_version is not None:
|
||||||
endpoint = "/v%d%s" % (self._api_version, endpoint)
|
endpoint = "/v%d%s" % (self._api_version, endpoint)
|
||||||
url = urlparse.urlunparse(('http', self._host, endpoint, '', '', ''))
|
url = urlunparse(('http', self._host, endpoint, '', '', ''))
|
||||||
|
|
||||||
if self._consumer_key:
|
if self._consumer_key:
|
||||||
auth = requests_oauthlib.OAuth1(self._consumer_key, self._consumer_secret,
|
auth = requests_oauthlib.OAuth1(self._consumer_key, self._consumer_secret,
|
||||||
self._token, self._token_secret)
|
self._token, self._token_secret,
|
||||||
|
decoding=_oauth_decoding)
|
||||||
else:
|
else:
|
||||||
auth = None
|
auth = None
|
||||||
|
|
||||||
response = requests.get(url, params=params, auth=auth)
|
with requests.Session() as s:
|
||||||
|
response = s.get(url, params=params, auth=auth)
|
||||||
|
|
||||||
self._logger.info("============================")
|
self._logger.info("============================")
|
||||||
self._logger.info("GET %s" % url)
|
self._logger.info("GET %s" % url)
|
||||||
|
@ -115,20 +135,22 @@ class OpenPhotoHttp:
|
||||||
endpoint = "/" + endpoint
|
endpoint = "/" + endpoint
|
||||||
if self._api_version is not None:
|
if self._api_version is not None:
|
||||||
endpoint = "/v%d%s" % (self._api_version, endpoint)
|
endpoint = "/v%d%s" % (self._api_version, endpoint)
|
||||||
url = urlparse.urlunparse(('http', self._host, endpoint, '', '', ''))
|
url = urlunparse(('http', self._host, endpoint, '', '', ''))
|
||||||
|
|
||||||
if not self._consumer_key:
|
if not self._consumer_key:
|
||||||
raise OpenPhotoError("Cannot issue POST without OAuth tokens")
|
raise OpenPhotoError("Cannot issue POST without OAuth tokens")
|
||||||
|
|
||||||
auth = requests_oauthlib.OAuth1(self._consumer_key, self._consumer_secret,
|
auth = requests_oauthlib.OAuth1(self._consumer_key, self._consumer_secret,
|
||||||
self._token, self._token_secret)
|
self._token, self._token_secret,
|
||||||
if files:
|
decoding=_oauth_decoding)
|
||||||
# Need to pass parameters as URL query, so they get OAuth signed
|
with requests.Session() as s:
|
||||||
response = requests.post(url, params=params, files=files, auth=auth)
|
if files:
|
||||||
else:
|
# Need to pass parameters as URL query, so they get OAuth signed
|
||||||
# Passing parameters as URL query doesn't work if there are no files to send.
|
response = s.post(url, params=params, files=files, auth=auth)
|
||||||
# Send them as form data instead.
|
else:
|
||||||
response = requests.post(url, data=params, auth=auth)
|
# Passing parameters as URL query doesn't work if there are no files to send.
|
||||||
|
# Send them as form data instead.
|
||||||
|
response = s.post(url, data=params, auth=auth)
|
||||||
|
|
||||||
self._logger.info("============================")
|
self._logger.info("============================")
|
||||||
self._logger.info("POST %s" % url)
|
self._logger.info("POST %s" % url)
|
||||||
|
@ -156,9 +178,9 @@ class OpenPhotoHttp:
|
||||||
if isinstance(value, OpenPhotoObject):
|
if isinstance(value, OpenPhotoObject):
|
||||||
value = value.id
|
value = value.id
|
||||||
|
|
||||||
# Use UTF-8 encoding
|
# Ensure value is UTF-8 encoded
|
||||||
if isinstance(value, unicode):
|
if isinstance(value, text_type):
|
||||||
value = value.encode('utf-8')
|
value = value.encode("utf-8")
|
||||||
|
|
||||||
# Handle lists
|
# Handle lists
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
|
@ -168,8 +190,8 @@ class OpenPhotoHttp:
|
||||||
for i, item in enumerate(new_list):
|
for i, item in enumerate(new_list):
|
||||||
if isinstance(item, OpenPhotoObject):
|
if isinstance(item, OpenPhotoObject):
|
||||||
new_list[i] = item.id
|
new_list[i] = item.id
|
||||||
# Convert list to unicode string
|
# Convert list to string
|
||||||
value = u','.join([unicode(item) for item in new_list])
|
value = ','.join([str(item) for item in new_list])
|
||||||
|
|
||||||
# Handle booleans
|
# Handle booleans
|
||||||
if isinstance(value, bool):
|
if isinstance(value, bool):
|
||||||
|
@ -188,7 +210,7 @@ class OpenPhotoHttp:
|
||||||
json_response = response.json()
|
json_response = response.json()
|
||||||
code = json_response["code"]
|
code = json_response["code"]
|
||||||
message = json_response["message"]
|
message = json_response["message"]
|
||||||
except ValueError, KeyError:
|
except (ValueError, KeyError):
|
||||||
# Response wasn't OpenPhoto JSON - check the HTTP status code
|
# Response wasn't OpenPhoto JSON - check the HTTP status code
|
||||||
if 200 <= response.status_code < 300:
|
if 200 <= response.status_code < 300:
|
||||||
# Status code was valid, so just reraise the exception
|
# Status code was valid, so just reraise the exception
|
||||||
|
@ -236,14 +258,18 @@ class OpenPhotoHttp:
|
||||||
'token': '', 'tokenSecret':'',
|
'token': '', 'tokenSecret':'',
|
||||||
}
|
}
|
||||||
# Insert an section header at the start of the config file, so ConfigParser can understand it
|
# Insert an section header at the start of the config file, so ConfigParser can understand it
|
||||||
buf = StringIO.StringIO()
|
buf = io.StringIO()
|
||||||
buf.write('[%s]\n' % section)
|
buf.write('[%s]\n' % section)
|
||||||
buf.write(open(config_file).read())
|
with io.open(config_file, "r") as f:
|
||||||
|
buf.write(f.read())
|
||||||
|
|
||||||
buf.seek(0, os.SEEK_SET)
|
buf.seek(0, os.SEEK_SET)
|
||||||
parser = ConfigParser.SafeConfigParser()
|
parser = ConfigParser()
|
||||||
parser.optionxform = str # Case-sensitive options
|
parser.optionxform = str # Case-sensitive options
|
||||||
parser.readfp(buf)
|
try:
|
||||||
|
parser.read_file(buf) # Python3
|
||||||
|
except AttributeError:
|
||||||
|
parser.readfp(buf) # Python2
|
||||||
|
|
||||||
# Trim quotes
|
# Trim quotes
|
||||||
config = parser.items(section)
|
config = parser.items(section)
|
||||||
|
|
|
@ -3,7 +3,7 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import unittest
|
import unittest
|
||||||
import openphoto
|
import openphoto
|
||||||
import test_base
|
from . import test_base
|
||||||
|
|
||||||
class TestAlbums(test_base.TestBase):
|
class TestAlbums(test_base.TestBase):
|
||||||
testcase_name = "album API"
|
testcase_name = "album API"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
try:
|
try:
|
||||||
|
@ -35,9 +36,9 @@ class TestBase(unittest.TestCase):
|
||||||
""" Ensure there is nothing on the server before running any tests """
|
""" Ensure there is nothing on the server before running any tests """
|
||||||
if cls.debug:
|
if cls.debug:
|
||||||
if cls.api_version is None:
|
if cls.api_version is None:
|
||||||
print "\nTesting Latest %s" % cls.testcase_name
|
print("\nTesting Latest %s" % cls.testcase_name)
|
||||||
else:
|
else:
|
||||||
print "\nTesting %s v%d" % (cls.testcase_name, cls.api_version)
|
print("\nTesting %s v%d" % (cls.testcase_name, cls.api_version))
|
||||||
|
|
||||||
cls.client = openphoto.OpenPhoto(config_file=cls.config_file,
|
cls.client = openphoto.OpenPhoto(config_file=cls.config_file,
|
||||||
api_version=cls.api_version)
|
api_version=cls.api_version)
|
||||||
|
@ -71,9 +72,9 @@ class TestBase(unittest.TestCase):
|
||||||
self.photos = self.client.photos.list()
|
self.photos = self.client.photos.list()
|
||||||
if len(self.photos) != 3:
|
if len(self.photos) != 3:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print "[Regenerating Photos]"
|
print("[Regenerating Photos]")
|
||||||
else:
|
else:
|
||||||
print " ",
|
print(" ", end='')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
if len(self.photos) > 0:
|
if len(self.photos) > 0:
|
||||||
self._delete_all()
|
self._delete_all()
|
||||||
|
@ -85,16 +86,16 @@ class TestBase(unittest.TestCase):
|
||||||
self.tags[0].id != self.TEST_TAG or
|
self.tags[0].id != self.TEST_TAG or
|
||||||
str(self.tags[0].count) != "3"):
|
str(self.tags[0].count) != "3"):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print "[Regenerating Tags]"
|
print("[Regenerating Tags]")
|
||||||
else:
|
else:
|
||||||
print " ",
|
print(" ", end='')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
self._delete_all()
|
self._delete_all()
|
||||||
self._create_test_photos()
|
self._create_test_photos()
|
||||||
self.photos = self.client.photos.list()
|
self.photos = self.client.photos.list()
|
||||||
self.tags = self.client.tags.list()
|
self.tags = self.client.tags.list()
|
||||||
if len(self.tags) != 1:
|
if len(self.tags) != 1:
|
||||||
print "Tags: %s" % self.tags
|
print("Tags: %s" % self.tags)
|
||||||
raise Exception("Tag creation failed")
|
raise Exception("Tag creation failed")
|
||||||
|
|
||||||
self.albums = self.client.albums.list()
|
self.albums = self.client.albums.list()
|
||||||
|
@ -102,9 +103,9 @@ class TestBase(unittest.TestCase):
|
||||||
self.albums[0].name != self.TEST_ALBUM or
|
self.albums[0].name != self.TEST_ALBUM or
|
||||||
self.albums[0].count != "3"):
|
self.albums[0].count != "3"):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print "[Regenerating Albums]"
|
print("[Regenerating Albums]")
|
||||||
else:
|
else:
|
||||||
print " ",
|
print(" ", end='')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
self._delete_all()
|
self._delete_all()
|
||||||
self._create_test_photos()
|
self._create_test_photos()
|
||||||
|
@ -112,7 +113,7 @@ class TestBase(unittest.TestCase):
|
||||||
self.tags = self.client.tags.list()
|
self.tags = self.client.tags.list()
|
||||||
self.albums = self.client.albums.list()
|
self.albums = self.client.albums.list()
|
||||||
if len(self.albums) != 1:
|
if len(self.albums) != 1:
|
||||||
print "Albums: %s" % self.albums
|
print("Albums: %s" % self.albums)
|
||||||
raise Exception("Album creation failed")
|
raise Exception("Album creation failed")
|
||||||
|
|
||||||
logging.info("\nRunning %s..." % self.id())
|
logging.info("\nRunning %s..." % self.id())
|
||||||
|
|
|
@ -27,13 +27,13 @@ class TestConfig(unittest.TestCase):
|
||||||
shutil.rmtree(CONFIG_HOME_PATH, ignore_errors=True)
|
shutil.rmtree(CONFIG_HOME_PATH, ignore_errors=True)
|
||||||
|
|
||||||
def create_config(self, config_file, host):
|
def create_config(self, config_file, host):
|
||||||
f = open(os.path.join(CONFIG_PATH, config_file), "w")
|
with open(os.path.join(CONFIG_PATH, config_file), "w") as f:
|
||||||
f.write("host = %s\n" % host)
|
f.write("host = %s\n" % host)
|
||||||
f.write("# Comment\n\n")
|
f.write("# Comment\n\n")
|
||||||
f.write("consumerKey = \"%s_consumer_key\"\n" % config_file)
|
f.write("consumerKey = \"%s_consumer_key\"\n" % config_file)
|
||||||
f.write("\"consumerSecret\" = %s_consumer_secret\n" % config_file)
|
f.write("\"consumerSecret\" = %s_consumer_secret\n" % config_file)
|
||||||
f.write("'token'=%s_token\n" % config_file)
|
f.write("'token'=%s_token\n" % config_file)
|
||||||
f.write("tokenSecret = '%s_token_secret'\n" % config_file)
|
f.write("tokenSecret = '%s_token_secret'\n" % config_file)
|
||||||
|
|
||||||
def test_default_config(self):
|
def test_default_config(self):
|
||||||
""" Ensure the default config is loaded """
|
""" Ensure the default config is loaded """
|
||||||
|
|
|
@ -4,7 +4,7 @@ except ImportError:
|
||||||
import unittest
|
import unittest
|
||||||
import logging
|
import logging
|
||||||
import openphoto
|
import openphoto
|
||||||
import test_base
|
from . import test_base
|
||||||
|
|
||||||
class TestFramework(test_base.TestBase):
|
class TestFramework(test_base.TestBase):
|
||||||
testcase_name = "framework"
|
testcase_name = "framework"
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
try:
|
try:
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import unittest
|
import unittest
|
||||||
import openphoto
|
import openphoto
|
||||||
import test_base
|
from . import test_base
|
||||||
|
|
||||||
class TestPhotos(test_base.TestBase):
|
class TestPhotos(test_base.TestBase):
|
||||||
testcase_name = "photo API"
|
testcase_name = "photo API"
|
||||||
|
@ -72,7 +73,7 @@ class TestPhotos(test_base.TestBase):
|
||||||
|
|
||||||
def test_update(self):
|
def test_update(self):
|
||||||
""" Update a photo by editing the title """
|
""" Update a photo by editing the title """
|
||||||
title = u"\xfcmlaut" # umlauted umlaut
|
title = "\xfcmlaut" # umlauted umlaut
|
||||||
# Get a photo and check that it doesn't have the magic title
|
# Get a photo and check that it doesn't have the magic title
|
||||||
photo = self.photos[0]
|
photo = self.photos[0]
|
||||||
self.assertNotEqual(photo.title, title)
|
self.assertNotEqual(photo.title, title)
|
||||||
|
|
|
@ -3,7 +3,7 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import unittest
|
import unittest
|
||||||
import openphoto
|
import openphoto
|
||||||
import test_base
|
from . import test_base
|
||||||
|
|
||||||
@unittest.skipIf(test_base.get_test_server_api() == 1,
|
@unittest.skipIf(test_base.get_test_server_api() == 1,
|
||||||
"The tag API didn't work at v1 - see frontend issue #927")
|
"The tag API didn't work at v1 - see frontend issue #927")
|
||||||
|
|
5
tox.ini
5
tox.ini
|
@ -1,7 +1,10 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py27,py26
|
envlist = py26, py27, py33
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
|
commands = python -m unittest discover --catch
|
||||||
|
|
||||||
|
[testenv:py26]
|
||||||
commands = unit2 discover --catch
|
commands = unit2 discover --catch
|
||||||
deps =
|
deps =
|
||||||
unittest2
|
unittest2
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue