Merge branch 'master' into apiv1_fixes
Conflicts: tests/test_base.py tests/test_framework.py
This commit is contained in:
commit
c76ad3f181
8 changed files with 257 additions and 142 deletions
|
@ -8,38 +8,56 @@ Open Photo API / Python Library
|
|||
python setup.py install
|
||||
|
||||
----------------------------------------
|
||||
<a name="credentials"></a>
|
||||
### Credentials
|
||||
|
||||
For full access to your photos, you need to create the following config file in ``~/.config/openphoto/default``
|
||||
|
||||
# ~/.config/openphoto/default
|
||||
host = your.host.com
|
||||
consumerKey = your_consumer_key
|
||||
consumerSecret = your_consumer_secret
|
||||
token = your_access_token
|
||||
tokenSecret = your_access_token_secret
|
||||
|
||||
The ``config_file`` switch lets you specify a different config file.
|
||||
|
||||
To get your credentials:
|
||||
* Log into your Trovebox site
|
||||
* Click the arrow on the top-right and select 'Settings'
|
||||
* Click the 'Create a new app' button
|
||||
* Click the 'View' link beside the newly created app
|
||||
|
||||
----------------------------------------
|
||||
<a name="python"></a>
|
||||
### How to use the library
|
||||
|
||||
To use the library you need to first ``import openphoto`` then instantiate an instance of the class and start making calls.
|
||||
|
||||
You can use the library in one of two ways:
|
||||
|
||||
* Direct GET/POST calls to the server
|
||||
* Access via Python classes/methods
|
||||
|
||||
<a name="get_post"></a>
|
||||
### Direct GET/POST:
|
||||
#### Direct GET/POST:
|
||||
|
||||
from openphoto import OpenPhoto
|
||||
client = OpenPhoto(host, consumerKey, consumerSecret, token, tokenSecret)
|
||||
client = OpenPhoto()
|
||||
resp = client.get("/photos/list.json")
|
||||
resp = client.post("/photo/62/update.json", tags=["tag1", "tag2"])
|
||||
|
||||
<a name="python_classes"></a>
|
||||
### Python classes/methods
|
||||
#### Python classes/methods
|
||||
|
||||
from openphoto import OpenPhoto
|
||||
client = OpenPhoto(host, consumerKey, consumerSecret, token, tokenSecret)
|
||||
client = OpenPhoto()
|
||||
photos = client.photos.list()
|
||||
photos[0].update(tags=["tag1", "tag2"])
|
||||
print photos[0].tags
|
||||
|
||||
The OpenPhoto Python class hierarchy mirrors the [OpenPhoto API](http://theopenphotoproject.org/documentation) endpoint layout. For example, the calls in the example above use the following API endpoints:
|
||||
|
||||
* client.photos.list() -> /photos/list.json
|
||||
* photos[0].update() -> /photo/<id>/update.json
|
||||
* ``client.photos.list() -> /photos/list.json``
|
||||
* ``photos[0].update() -> /photo/<id>/update.json``
|
||||
|
||||
<a name="api_versioning"></a>
|
||||
### API Versioning
|
||||
|
@ -50,38 +68,28 @@ This ensures that future API updates won't cause unexpected breakages.
|
|||
To do this, add the optional ```api_version``` parameter when creating the client object:
|
||||
|
||||
from openphoto import OpenPhoto
|
||||
client = OpenPhoto(host, consumerKey, consumerSecret, token, tokenSecret, api_version=2)
|
||||
client = OpenPhoto(api_version=2)
|
||||
|
||||
----------------------------------------
|
||||
|
||||
<a name="cli"></a>
|
||||
### Using from the command line
|
||||
|
||||
When using the command line tool, you'll want to export your authentication credentials to the environment.
|
||||
The command line tool will look for the following config file in ~/.config/openphoto/default
|
||||
(the -c switch lets you specify a different config file):
|
||||
|
||||
# ~/.config/openphoto/default
|
||||
host = your.host.com
|
||||
consumerKey = your_consumer_key
|
||||
consumerSecret = your_consumer_secret
|
||||
token = your_access_token
|
||||
tokenSecret = your_access_token_secret
|
||||
|
||||
<a href="#credentials">Click here for instructions on getting credentials</a>.
|
||||
You can run commands to the OpenPhoto API from your shell!
|
||||
|
||||
These are the options you can pass to the shell program:
|
||||
|
||||
-h # Display help text
|
||||
-c config_file # Either the name of a config file in ~/.config/openphoto/ or a full path to a config file
|
||||
-H hostname # Overrides config_file for unauthenticated API calls [default=localhost]
|
||||
-H hostname # Overrides config_file for unauthenticated API calls
|
||||
-e endpoint # [default=/photos/list.json]
|
||||
-X method # [default=GET]
|
||||
-F params # e.g. -F 'title=my title' -F 'tags=mytag1,mytag2'
|
||||
-p # Pretty print the json
|
||||
-v # Verbose output
|
||||
|
||||
You can run commands to the OpenPhoto API from your shell!
|
||||
<a name="cli-examples"></a>
|
||||
#### Command line examples
|
||||
|
||||
# Upload a public photo to the host specified in ~/.config/openphoto/default
|
||||
openphoto -p -X POST -e /photo/upload.json -F 'photo=@/path/to/photo/jpg' -F 'permission=1'
|
||||
|
@ -120,9 +128,3 @@ You can run commands to the OpenPhoto API from your shell!
|
|||
...
|
||||
}
|
||||
}
|
||||
|
||||
<a name="credentials"></a>
|
||||
#### Getting your credentials
|
||||
|
||||
You can get your credentals by clicking on the arrow next to your email address once you're logged into your site and then clicking on settings.
|
||||
If you don't have any credentials then you can create one for yourself using the "Create a new app" button.
|
||||
|
|
|
@ -8,18 +8,21 @@ LATEST_API_VERSION = 2
|
|||
|
||||
class OpenPhoto(OpenPhotoHttp):
|
||||
"""
|
||||
Python client library for the specified OpenPhoto host.
|
||||
Client library for OpenPhoto
|
||||
If no parameters are specified, config is loaded from the default
|
||||
location (~/.config/openphoto/default).
|
||||
The config_file parameter is used to specify an alternate config file.
|
||||
If the host parameter is specified, no config file is loaded and
|
||||
OAuth tokens (consumer*, token*) can optionally be specified.
|
||||
|
||||
All requests will include the api_version path, if specified.
|
||||
This should be used to ensure that your application will continue to work
|
||||
even if the OpenPhoto API is updated to a new revision.
|
||||
"""
|
||||
def __init__(self, host,
|
||||
def __init__(self, config_file=None, host=None,
|
||||
consumer_key='', consumer_secret='',
|
||||
token='', token_secret='',
|
||||
api_version=None):
|
||||
OpenPhotoHttp.__init__(self, host,
|
||||
OpenPhotoHttp.__init__(self, config_file, host,
|
||||
consumer_key, consumer_secret,
|
||||
token, token_secret, api_version)
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ import os
|
|||
import sys
|
||||
import string
|
||||
import urllib
|
||||
import StringIO
|
||||
import ConfigParser
|
||||
from optparse import OptionParser
|
||||
|
||||
try:
|
||||
|
@ -14,47 +12,6 @@ except ImportError:
|
|||
|
||||
from openphoto import OpenPhoto
|
||||
|
||||
def get_config_path(config_file):
|
||||
config_path = os.getenv('XDG_CONFIG_HOME')
|
||||
if not config_path:
|
||||
config_path = os.path.join(os.getenv('HOME'), ".config")
|
||||
if not config_file:
|
||||
config_file = "default"
|
||||
return os.path.join(config_path, "openphoto", config_file)
|
||||
|
||||
def read_config(config_file):
|
||||
"""
|
||||
Loads config data from the specified file.
|
||||
If config_file doesn't exist, returns an empty authentication config for localhost.
|
||||
"""
|
||||
section = "DUMMY"
|
||||
defaults = {'host': 'localhost',
|
||||
'consumerKey': '', 'consumerSecret': '',
|
||||
'token': '', 'tokenSecret':'',
|
||||
}
|
||||
# Insert an section header at the start of the config file, so ConfigParser can understand it
|
||||
# Also prepend a [DEFAULT] section, since it's the only way to specify case-sensitive defaults
|
||||
buf = StringIO.StringIO()
|
||||
buf.write("[DEFAULT]\n")
|
||||
for key in defaults:
|
||||
buf.write("%s=%s\n" % (key, defaults[key]))
|
||||
buf.write('[%s]\n' % section)
|
||||
if os.path.isfile(config_file):
|
||||
buf.write(open(config_file).read())
|
||||
else:
|
||||
print "Config file '%s' doesn't exist - authentication won't be used" % config_file
|
||||
|
||||
buf.seek(0, os.SEEK_SET)
|
||||
parser = ConfigParser.SafeConfigParser()
|
||||
parser.optionxform = str # Case-sensitive options
|
||||
parser.readfp(buf)
|
||||
|
||||
# Trim quotes
|
||||
config = parser.items(section)
|
||||
config = [(item[0], item[1].replace('"', '')) for item in config]
|
||||
config = [(item[0], item[1].replace("'", "")) for item in config]
|
||||
return dict(config)
|
||||
|
||||
#################################################################
|
||||
|
||||
def main(args=sys.argv[1:]):
|
||||
|
@ -85,16 +42,28 @@ def main(args=sys.argv[1:]):
|
|||
|
||||
# Host option overrides config file settings
|
||||
if options.host:
|
||||
config = {'host': options.host, 'consumerKey': '', 'consumerSecret': '',
|
||||
'token': '', 'tokenSecret': ''}
|
||||
client = OpenPhoto(host=options.host)
|
||||
else:
|
||||
config_path = get_config_path(options.config_file)
|
||||
config = read_config(config_path)
|
||||
if options.verbose:
|
||||
print "Using config from '%s'" % config_path
|
||||
|
||||
client = OpenPhoto(config['host'], config['consumerKey'], config['consumerSecret'],
|
||||
config['token'], config['tokenSecret'])
|
||||
try:
|
||||
client = OpenPhoto(config_file=options.config_file)
|
||||
except IOError as error:
|
||||
print error
|
||||
print
|
||||
print "You must create a configuration file with the following contents:"
|
||||
print " host = your.host.com"
|
||||
print " consumerKey = your_consumer_key"
|
||||
print " consumerSecret = your_consumer_secret"
|
||||
print " token = your_access_token"
|
||||
print " tokenSecret = your_access_token_secret"
|
||||
print
|
||||
print "To get your credentials:"
|
||||
print " * Log into your Trovebox site"
|
||||
print " * Click the arrow on the top-right and select 'Settings'."
|
||||
print " * Click the 'Create a new app' button."
|
||||
print " * Click the 'View' link beside the newly created app."
|
||||
print
|
||||
print error
|
||||
sys.exit(1)
|
||||
|
||||
if options.method == "GET":
|
||||
result = client.get(options.endpoint, process_response=False, **params)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import os
|
||||
import oauth2 as oauth
|
||||
import urlparse
|
||||
import urllib
|
||||
import httplib2
|
||||
import logging
|
||||
import StringIO
|
||||
import ConfigParser
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
|
@ -16,17 +19,41 @@ DUPLICATE_RESPONSE = {"code": 409,
|
|||
"message": "This photo already exists"}
|
||||
|
||||
class OpenPhotoHttp:
|
||||
""" Base class to handle HTTP requests to an OpenPhoto server """
|
||||
def __init__(self, host, consumer_key='', consumer_secret='',
|
||||
"""
|
||||
Base class to handle HTTP requests to an OpenPhoto server.
|
||||
If no parameters are specified, config is loaded from the default
|
||||
location (~/.config/openphoto/default).
|
||||
The config_file parameter is used to specify an alternate config file.
|
||||
If the host parameter is specified, no config file is loaded and
|
||||
OAuth tokens (consumer*, token*) can optionally be specified.
|
||||
All requests will include the api_version path, if specified.
|
||||
This should be used to ensure that your application will continue to work
|
||||
even if the OpenPhoto API is updated to a new revision.
|
||||
"""
|
||||
def __init__(self, config_file=None, host=None,
|
||||
consumer_key='', consumer_secret='',
|
||||
token='', token_secret='', api_version=None):
|
||||
self._api_version = api_version
|
||||
|
||||
self._logger = logging.getLogger("openphoto")
|
||||
|
||||
if host is None:
|
||||
self.config_path = self._get_config_path(config_file)
|
||||
config = self._read_config(self.config_path)
|
||||
self._host = config['host']
|
||||
self._consumer_key = config['consumerKey']
|
||||
self._consumer_secret = config['consumerSecret']
|
||||
self._token = config['token']
|
||||
self._token_secret = config['tokenSecret']
|
||||
else:
|
||||
self._host = host
|
||||
self._consumer_key = consumer_key
|
||||
self._consumer_secret = consumer_secret
|
||||
self._token = token
|
||||
self._token_secret = token_secret
|
||||
self._api_version = api_version
|
||||
|
||||
self._logger = logging.getLogger("openphoto")
|
||||
if host is not None and config_file is not None:
|
||||
raise ValueError("Cannot specify both host and config_file")
|
||||
|
||||
# Remember the most recent HTTP request and response
|
||||
self.last_url = None
|
||||
|
@ -205,3 +232,42 @@ class OpenPhotoHttp:
|
|||
return []
|
||||
else:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _get_config_path(config_file):
|
||||
config_path = os.getenv('XDG_CONFIG_HOME')
|
||||
if not config_path:
|
||||
config_path = os.path.join(os.getenv('HOME'), ".config")
|
||||
if not config_file:
|
||||
config_file = "default"
|
||||
return os.path.join(config_path, "openphoto", config_file)
|
||||
|
||||
def _read_config(self, config_file):
|
||||
"""
|
||||
Loads config data from the specified file.
|
||||
If config_file doesn't exist, returns an empty authentication config for localhost.
|
||||
"""
|
||||
section = "DUMMY"
|
||||
defaults = {'host': 'localhost',
|
||||
'consumerKey': '', 'consumerSecret': '',
|
||||
'token': '', 'tokenSecret':'',
|
||||
}
|
||||
# Insert an section header at the start of the config file, so ConfigParser can understand it
|
||||
# Also prepend a [DEFAULT] section, since it's the only way to specify case-sensitive defaults
|
||||
buf = StringIO.StringIO()
|
||||
buf.write("[DEFAULT]\n")
|
||||
for key in defaults:
|
||||
buf.write("%s=%s\n" % (key, defaults[key]))
|
||||
buf.write('[%s]\n' % section)
|
||||
buf.write(open(config_file).read())
|
||||
|
||||
buf.seek(0, os.SEEK_SET)
|
||||
parser = ConfigParser.SafeConfigParser()
|
||||
parser.optionxform = str # Case-sensitive options
|
||||
parser.readfp(buf)
|
||||
|
||||
# Trim quotes
|
||||
config = parser.items(section)
|
||||
config = [(item[0].replace('"', ''), item[1].replace('"', '')) for item in config]
|
||||
config = [(item[0].replace("'", ""), item[1].replace("'", "")) for item in config]
|
||||
return dict(config)
|
||||
|
|
|
@ -5,23 +5,27 @@ Tests for the Open Photo API / Python Library
|
|||
----------------------------------------
|
||||
<a name="requirements"></a>
|
||||
### Requirements
|
||||
A computer, Python 2.7 and an empty OpenPhoto instance.
|
||||
A computer, Python 2.7 and an empty OpenPhoto test host.
|
||||
|
||||
---------------------------------------
|
||||
<a name="setup"></a>
|
||||
### Setting up
|
||||
|
||||
Create a tests/tokens.py file containing the following:
|
||||
Create a ``~/.config/openphoto/test`` config file containing the following:
|
||||
|
||||
# tests/tokens.py
|
||||
consumer_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
consumer_secret = "xxxxxxxxxx"
|
||||
token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
token_secret = "xxxxxxxxxx"
|
||||
host = "your_hostname"
|
||||
# ~/.config/openphoto/test
|
||||
host = your.host.com
|
||||
consumerKey = your_consumer_key
|
||||
consumerSecret = your_consumer_secret
|
||||
token = your_access_token
|
||||
tokenSecret = your_access_token_secret
|
||||
|
||||
Make sure this is an empty test server, **not a production OpenPhoto server!!!**
|
||||
|
||||
You can specify an alternate test config file with the following environment variable:
|
||||
|
||||
export OPENPHOTO_TEST_CONFIG=test2
|
||||
|
||||
---------------------------------------
|
||||
<a name="running"></a>
|
||||
### Running the tests
|
||||
|
|
|
@ -1,22 +1,8 @@
|
|||
import unittest
|
||||
import os
|
||||
import unittest
|
||||
import logging
|
||||
import openphoto
|
||||
|
||||
try:
|
||||
import tokens
|
||||
except ImportError:
|
||||
print ("********************************************************************\n"
|
||||
"You need to create a 'tokens.py' file containing the following:\n\n"
|
||||
" host = \"<hostname>\"\n"
|
||||
" consumer_key = \"<test_consumer_key>\"\n"
|
||||
" consumer_secret = \"<test_consumer_secret>\"\n"
|
||||
" token = \"<test_token>\"\n"
|
||||
" token_secret = \"<test_token_secret>\"\n"
|
||||
"WARNING: Don't use a production OpenPhoto instance for this!\n"
|
||||
"********************************************************************\n")
|
||||
raise
|
||||
|
||||
def get_test_server_api():
|
||||
return int(os.getenv("OPENPHOTO_TEST_SERVER_API", openphoto.LATEST_API_VERSION))
|
||||
|
||||
|
@ -27,6 +13,7 @@ class TestBase(unittest.TestCase):
|
|||
MAXIMUM_TEST_PHOTOS = 4 # Never have more the 4 photos on the test server
|
||||
testcase_name = "(unknown testcase)"
|
||||
api_version = None
|
||||
config_file = os.getenv("OPENPHOTO_TEST_CONFIG", "test")
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
unittest.TestCase.__init__(self, *args, **kwds)
|
||||
|
@ -45,25 +32,23 @@ class TestBase(unittest.TestCase):
|
|||
else:
|
||||
print "\nTesting %s v%d" % (cls.testcase_name, cls.api_version)
|
||||
|
||||
cls.client = openphoto.OpenPhoto(tokens.host,
|
||||
tokens.consumer_key, tokens.consumer_secret,
|
||||
tokens.token, tokens.token_secret,
|
||||
cls.api_version)
|
||||
cls.client = openphoto.OpenPhoto(config_file=cls.config_file,
|
||||
api_version=cls.api_version)
|
||||
|
||||
if cls.client.photos.list() != []:
|
||||
raise ValueError("The test server (%s) contains photos. "
|
||||
"Please delete them before running the tests"
|
||||
% tokens.host)
|
||||
% cls.client._host)
|
||||
|
||||
if cls.client.tags.list() != []:
|
||||
raise ValueError("The test server (%s) contains tags. "
|
||||
"Please delete them before running the tests"
|
||||
% tokens.host)
|
||||
% cls.client._host)
|
||||
|
||||
if cls.client.albums.list() != []:
|
||||
raise ValueError("The test server (%s) contains albums. "
|
||||
"Please delete them before running the tests"
|
||||
% tokens.host)
|
||||
% cls.client._host)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
|
90
tests/test_config.py
Normal file
90
tests/test_config.py
Normal file
|
@ -0,0 +1,90 @@
|
|||
import unittest
|
||||
import os
|
||||
import shutil
|
||||
import openphoto
|
||||
|
||||
CONFIG_HOME_PATH = os.path.join("test", "config")
|
||||
CONFIG_PATH = os.path.join(CONFIG_HOME_PATH, "openphoto")
|
||||
|
||||
class TestConfig(unittest.TestCase):
|
||||
def setUp(self):
|
||||
""" Override XDG_CONFIG_HOME env var, to use test configs """
|
||||
try:
|
||||
self.original_xdg_config_home = os.environ["XDG_CONFIG_HOME"]
|
||||
except KeyError:
|
||||
self.original_xdg_config_home = None
|
||||
os.environ["XDG_CONFIG_HOME"] = CONFIG_HOME_PATH
|
||||
os.makedirs(CONFIG_PATH)
|
||||
|
||||
def tearDown(self):
|
||||
if self.original_xdg_config_home is None:
|
||||
del os.environ["XDG_CONFIG_HOME"]
|
||||
else:
|
||||
os.environ["XDG_CONFIG_HOME"] = self.original_xdg_config_home
|
||||
shutil.rmtree(CONFIG_HOME_PATH, ignore_errors=True)
|
||||
|
||||
def create_config(self, config_file, host):
|
||||
f = open(os.path.join(CONFIG_PATH, config_file), "w")
|
||||
f.write("host = %s\n" % host)
|
||||
f.write("# Comment\n\n")
|
||||
f.write("consumerKey = \"%s_consumer_key\"\n" % config_file)
|
||||
f.write("\"consumerSecret\" = %s_consumer_secret\n" % config_file)
|
||||
f.write("'token'=%s_token\n" % config_file)
|
||||
f.write("tokenSecret = '%s_token_secret'\n" % config_file)
|
||||
|
||||
def test_default_config(self):
|
||||
""" Ensure the default config is loaded """
|
||||
self.create_config("default", "Test Default Host")
|
||||
client = openphoto.OpenPhoto()
|
||||
self.assertEqual(client._host, "Test Default Host")
|
||||
self.assertEqual(client._consumer_key, "default_consumer_key")
|
||||
self.assertEqual(client._consumer_secret, "default_consumer_secret")
|
||||
self.assertEqual(client._token, "default_token")
|
||||
self.assertEqual(client._token_secret, "default_token_secret")
|
||||
|
||||
def test_custom_config(self):
|
||||
""" Ensure a custom config can be loaded """
|
||||
self.create_config("default", "Test Default Host")
|
||||
self.create_config("custom", "Test Custom Host")
|
||||
client = openphoto.OpenPhoto(config_file="custom")
|
||||
self.assertEqual(client._host, "Test Custom Host")
|
||||
self.assertEqual(client._consumer_key, "custom_consumer_key")
|
||||
self.assertEqual(client._consumer_secret, "custom_consumer_secret")
|
||||
self.assertEqual(client._token, "custom_token")
|
||||
self.assertEqual(client._token_secret, "custom_token_secret")
|
||||
|
||||
def test_full_config_path(self):
|
||||
""" Ensure a full custom config path can be loaded """
|
||||
self.create_config("path", "Test Path Host")
|
||||
full_path = os.path.abspath(CONFIG_PATH)
|
||||
client = openphoto.OpenPhoto(config_file=os.path.join(full_path, "path"))
|
||||
self.assertEqual(client._host, "Test Path Host")
|
||||
self.assertEqual(client._consumer_key, "path_consumer_key")
|
||||
self.assertEqual(client._consumer_secret, "path_consumer_secret")
|
||||
self.assertEqual(client._token, "path_token")
|
||||
self.assertEqual(client._token_secret, "path_token_secret")
|
||||
|
||||
def test_host_override(self):
|
||||
""" Ensure that specifying a host overrides the default config """
|
||||
self.create_config("default", "Test Default Host")
|
||||
client = openphoto.OpenPhoto(host="host_override")
|
||||
self.assertEqual(client._host, "host_override")
|
||||
self.assertEqual(client._consumer_key, "")
|
||||
self.assertEqual(client._consumer_secret, "")
|
||||
self.assertEqual(client._token, "")
|
||||
self.assertEqual(client._token_secret, "")
|
||||
|
||||
def test_missing_config_files_raise_exceptions(self):
|
||||
""" Ensure that missing config files raise exceptions """
|
||||
with self.assertRaises(IOError):
|
||||
openphoto.OpenPhoto()
|
||||
with self.assertRaises(IOError):
|
||||
openphoto.OpenPhoto(config_file="custom")
|
||||
|
||||
def test_host_and_config_file_raises_exception(self):
|
||||
""" It's not valid to specify both a host and a config_file """
|
||||
self.create_config("custom", "Test Custom Host")
|
||||
with self.assertRaises(ValueError):
|
||||
openphoto.OpenPhoto(config_file="custom", host="host_override")
|
||||
|
||||
|
|
@ -10,17 +10,10 @@ class TestFramework(test_base.TestBase):
|
|||
"""Override the default setUp, since we don't need a populated database"""
|
||||
logging.info("\nRunning %s..." % self.id())
|
||||
|
||||
def create_client_from_base(self, api_version):
|
||||
return openphoto.OpenPhoto(self.client._host,
|
||||
self.client._consumer_key,
|
||||
self.client._consumer_secret,
|
||||
self.client._token,
|
||||
self.client._token_secret,
|
||||
api_version=api_version)
|
||||
|
||||
def test_api_version_zero(self):
|
||||
# API v0 has a special hello world message
|
||||
client = self.create_client_from_base(api_version=0)
|
||||
client = openphoto.OpenPhoto(config_file=self.config_file,
|
||||
api_version=0)
|
||||
result = client.get("hello.json")
|
||||
self.assertEqual(result['message'], "Hello, world! This is version zero of the API!")
|
||||
self.assertEqual(result['result']['__route__'], "/v0/hello.json")
|
||||
|
@ -28,14 +21,16 @@ class TestFramework(test_base.TestBase):
|
|||
def test_specified_api_version(self):
|
||||
# For all API versions >0, we get a generic hello world message
|
||||
for api_version in range(1, test_base.get_test_server_api() + 1):
|
||||
client = self.create_client_from_base(api_version=api_version)
|
||||
client = openphoto.OpenPhoto(config_file=self.config_file,
|
||||
api_version=api_version)
|
||||
result = client.get("hello.json")
|
||||
self.assertEqual(result['message'], "Hello, world!")
|
||||
self.assertEqual(result['result']['__route__'], "/v%d/hello.json" % api_version)
|
||||
|
||||
def test_unspecified_api_version(self):
|
||||
# If the API version is unspecified, we get a generic hello world message
|
||||
client = self.create_client_from_base(api_version=None)
|
||||
client = openphoto.OpenPhoto(config_file=self.config_file,
|
||||
api_version=None)
|
||||
result = client.get("hello.json")
|
||||
self.assertEqual(result['message'], "Hello, world!")
|
||||
self.assertEqual(result['result']['__route__'], "/hello.json")
|
||||
|
@ -43,6 +38,7 @@ class TestFramework(test_base.TestBase):
|
|||
def test_future_api_version(self):
|
||||
# If the API version is unsupported, we should get an error
|
||||
# (it's a ValueError, since the returned 404 HTML page is not valid JSON)
|
||||
client = self.create_client_from_base(api_version=openphoto.LATEST_API_VERSION + 1)
|
||||
client = openphoto.OpenPhoto(config_file=self.config_file,
|
||||
api_version=openphoto.LATEST_API_VERSION + 1)
|
||||
with self.assertRaises(openphoto.OpenPhoto404Error):
|
||||
client.get("hello.json")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue