diff --git a/CHANGES.txt b/CHANGES.txt index 1f6e0b0..7984ade 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -18,4 +18,4 @@ v0.4.12, Fri Dec 19 -- Added batch support interface v0.4.13, Fri Dec 19 -- Added optional arguments to text tags API v0.4.14, Sat Dec 20 -- Fix for batch image features preprocessing, increased test coverage v0.4.15, Sat Dec 20 -- Bug fix release -v0.5.0, Friday Feb 27 -- Updated to support private cloud, allows for indicorc file to reduce redundant authorization calls +v0.5.0, Friday Feb 27 -- Updated to support private cloud, allows for indicorc file to reduce redundant authorization calls, README updates diff --git a/indicoio/__init__.py b/indicoio/__init__.py index 62a09e0..58e53de 100644 --- a/indicoio/__init__.py +++ b/indicoio/__init__.py @@ -12,8 +12,16 @@ from indicoio.images.fer import fer from indicoio.images.features import facial_features from indicoio.images.features import image_features -apis = ['political', 'posneg', 'sentiment', 'language', 'fer', - 'facial_features', 'image_features', 'text_tags'] +apis = [ + 'political', + 'posneg', + 'sentiment', + 'language', + 'fer', + 'facial_features', + 'image_features', + 'text_tags' +] apis = dict((api, globals().get(api)) for api in apis) for api in apis: diff --git a/indicoio/config.py b/indicoio/config.py index c639cd1..5633302 100644 --- a/indicoio/config.py +++ b/indicoio/config.py @@ -44,11 +44,11 @@ class Settings(ConfigParser.ConfigParser): os.getenv("INDICO_PASSWORD") or self.auth_settings.get('password') ) -settings = Settings(files=[ +SETTINGS = Settings(files=[ os.path.expanduser("~/.indicorc"), os.path.join(os.getcwd(), '.indicorc') ]) -auth = settings.auth() -cloud = settings.cloud() -public_api_host = 'apiv1.indico.io' +AUTH = SETTINGS.auth() +CLOUD = SETTINGS.cloud() +PUBLIC_API_HOST = 'apiv1.indico.io' diff --git a/indicoio/images/features.py b/indicoio/images/features.py index e796946..ea9608b 100644 --- a/indicoio/images/features.py +++ b/indicoio/images/features.py @@ -6,7 +6,7 @@ import numpy as np from indicoio.utils import image_preprocess, api_handler import indicoio.config as config -def facial_features(image, cloud=config.cloud, batch=False, auth=None, **kwargs): +def facial_features(image, cloud=config.CLOUD, batch=False, auth=None, **kwargs): """ Given an grayscale input image of a face, returns a 48 dimensional feature vector explaining that face. Useful as a form of feature engineering for face oriented tasks. @@ -30,7 +30,7 @@ def facial_features(image, cloud=config.cloud, batch=False, auth=None, **kwargs) """ return api_handler(image, cloud=cloud, api="facialfeatures", batch=batch, auth=auth, **kwargs) -def image_features(image, cloud=config.cloud, batch=False, auth=None, **kwargs): +def image_features(image, cloud=config.CLOUD, batch=False, auth=None, **kwargs): """ Given an input image, returns a 2048 dimensional sparse feature vector explaining that image. Useful as a form of feature engineering for image oriented tasks. diff --git a/indicoio/images/fer.py b/indicoio/images/fer.py index e8378a7..3365dec 100644 --- a/indicoio/images/fer.py +++ b/indicoio/images/fer.py @@ -6,7 +6,7 @@ import numpy as np from indicoio.utils import api_handler import indicoio.config as config -def fer(image, cloud=config.cloud, batch=False, auth=None, **kwargs): +def fer(image, cloud=config.CLOUD, batch=False, auth=None, **kwargs): """ Given a grayscale input image of a face, returns a probability distribution over emotional state. Input should be in a list of list format, resizing will be attempted internally but for best diff --git a/indicoio/text/lang.py b/indicoio/text/lang.py index 86ffa4c..cf6c1e7 100644 --- a/indicoio/text/lang.py +++ b/indicoio/text/lang.py @@ -1,7 +1,7 @@ from indicoio.utils import api_handler import indicoio.config as config -def language(text, cloud=config.cloud, batch=False, auth=None, **kwargs): +def language(text, cloud=config.CLOUD, batch=False, auth=None, **kwargs): """ Given input text, returns a probability distribution over 33 possible languages of what language the text was written in. diff --git a/indicoio/text/sentiment.py b/indicoio/text/sentiment.py index 494b40e..893fcd7 100644 --- a/indicoio/text/sentiment.py +++ b/indicoio/text/sentiment.py @@ -2,7 +2,7 @@ from indicoio import JSON_HEADERS from indicoio.utils import api_handler import indicoio.config as config -def political(text, cloud=config.cloud, batch=False, auth=None, **kwargs): +def political(text, cloud=config.CLOUD, batch=False, auth=None, **kwargs): """ Given input text, returns a probability distribution over the political alignment of the speaker. @@ -30,7 +30,7 @@ def political(text, cloud=config.cloud, batch=False, auth=None, **kwargs): return api_handler(text, cloud=cloud, api="political", batch=batch, auth=auth, **kwargs) -def posneg(text, cloud=config.cloud, batch=False, auth=None, **kwargs): +def posneg(text, cloud=config.CLOUD, batch=False, auth=None, **kwargs): """ Given input text, returns a scalar estimate of the sentiment of that text. Values are roughly in the range 0 to 1 with 0.5 indicating neutral sentiment. diff --git a/indicoio/text/tagging.py b/indicoio/text/tagging.py index 8848379..52500eb 100644 --- a/indicoio/text/tagging.py +++ b/indicoio/text/tagging.py @@ -1,7 +1,7 @@ from indicoio.utils import api_handler import indicoio.config as config -def text_tags(text, cloud=config.cloud, batch=False, auth=None, **kwargs): +def text_tags(text, cloud=config.CLOUD, batch=False, auth=None, **kwargs): """ Given input text, returns a probability distribution over 100 document categories diff --git a/indicoio/utils/__init__.py b/indicoio/utils/__init__.py index 40f82ae..85fb81d 100644 --- a/indicoio/utils/__init__.py +++ b/indicoio/utils/__init__.py @@ -13,16 +13,18 @@ def api_handler(arg, cloud, api, batch=False, auth=None, **kwargs): json_data = json.dumps(data) if cloud: - host = "%s.indico.domains" + host = "%s.indico.domains" % cloud else: # default to indico public cloud - host = config.public_api_host + host = config.PUBLIC_API_HOST url = "http://%s/%s" % (host, api) - if batch: url += "/batch" + if not auth: + auth = config.AUTH + response = requests.post(url, data=json_data, headers=JSON_HEADERS, auth=auth).json() results = response.get('results', False) if results is False: diff --git a/tests/test_configure.py b/tests/test_configure.py index a992151..9a11cb3 100644 --- a/tests/test_configure.py +++ b/tests/test_configure.py @@ -8,24 +8,36 @@ from indicoio.config import Settings class TestConfigureEnv(unittest.TestCase): + """ + Ensure that environment variables are handled by the `Settings` parser + """ def setUp(self): os.environ = {} def test_set_cloud_from_env_var(self): + """ + Ensure cloud hostname is read in from environment variables + """ cloud = "invalid/cloud" os.environ["INDICO_CLOUD"] = cloud - assert config.settings.cloud() == cloud + assert config.SETTINGS.cloud() == cloud def test_set_auth_from_env_var(self): + """ + Ensure cloud authentication credentials are read in from environment variables + """ username = "test" password = "password" os.environ["INDICO_USERNAME"] = username os.environ["INDICO_PASSWORD"] = password - assert config.settings.auth() == (username, password) + assert config.SETTINGS.auth() == (username, password) class TestConfigurationFile(unittest.TestCase): + """ + Ensure that the `Settings` parser reads in configuration files properly + """ def setUp(self): self.username = "test" @@ -45,13 +57,22 @@ class TestConfigurationFile(unittest.TestCase): os.environ = {} def test_set_cloud_from_config_file(self): + """ + Ensure cloud hostname is read in from file + """ assert self.settings.cloud() == self.cloud def test_set_auth_from_config_file(self): + """ + Ensure cloud authentication credentials are read in from file + """ assert self.settings.auth() == (self.username, self.password) class TestPrecedence(unittest.TestCase): + """ + Ensure that environment variables take precedence to config files + """ def setUp(self): self.file_username = "file-username" @@ -79,13 +100,23 @@ class TestPrecedence(unittest.TestCase): self.settings = Settings(files=[config_file]) def test_set_cloud_from_config_file(self): + """ + Ensure cloud hosts set in environment variables are used over those in config files + """ assert self.settings.cloud() == self.env_cloud def test_set_auth_from_config_file(self): + """ + Ensure cloud authentication credentials set in environment variables + are used over those in config files + """ assert self.settings.auth() == (self.env_username, self.env_password) class TestConfigFilePrecedence(unittest.TestCase): + """ + Ensure that files passed in to a `Settings` object are assigned proper priority + """ def setUp(self): self.high_priority_username = "high-priority-username" @@ -132,7 +163,13 @@ class TestConfigFilePrecedence(unittest.TestCase): ]) def test_cloud_config_file_priority(self): + """ + Ensure the cloud subdomain priority is handled properly + """ assert self.settings.cloud() == self.high_priority_cloud def test_auth_config_file_priority(self): + """ + Ensure the cloud auth priority is handled properly + """ assert self.settings.auth() == (self.high_priority_username, self.high_priority_password) diff --git a/tests/test_remote.py b/tests/test_remote.py index 44e31bd..0c9a218 100644 --- a/tests/test_remote.py +++ b/tests/test_remote.py @@ -16,7 +16,7 @@ DIR = os.path.dirname(os.path.realpath(__file__)) class BatchAPIRun(unittest.TestCase): def setUp(self): - self.auth = config.auth + self.auth = config.AUTH if not all(self.auth): raise SkipTest