diff --git a/indicoio/__init__.py b/indicoio/__init__.py index 9db9de6..8bfa3e3 100644 --- a/indicoio/__init__.py +++ b/indicoio/__init__.py @@ -1,4 +1,5 @@ -from functools import partial +from functools import wraps, partial +import warnings Version, version, __version__, VERSION = ('0.8.1',) * 4 @@ -23,9 +24,26 @@ from indicoio.utils.multi import predict_image, predict_text from indicoio.config import API_NAMES +def deprecation_decorator(f, api): + @wraps(f) + def wrapper(*args, **kwargs): + warnings.warn( + "'batch_" + api + "' will be deprecated in the next major update. Please call '" + api + "' instead with the same arguments.", + DeprecationWarning + ) + return f(*args, **kwargs) + return wrapper +def detect_batch_decorator(f): + @wraps(f) + def wrapper(*args, **kwargs): + if isinstance(args[0], list): + kwargs['batch'] = True + return f(*args, **kwargs) + return wrapper + apis = dict((api, globals().get(api)) for api in API_NAMES) for api in apis: - globals()[api] = partial(apis[api]) - globals()['batch_' + api] = partial(apis[api], batch=True) + globals()[api] = partial(detect_batch_decorator(apis[api])) + globals()['batch_' + api] = partial(deprecation_decorator(apis[api], api), batch=True) diff --git a/indicoio/utils/api.py b/indicoio/utils/api.py index 836b243..141cc0f 100644 --- a/indicoio/utils/api.py +++ b/indicoio/utils/api.py @@ -8,12 +8,15 @@ from indicoio.utils.errors import IndicoError, DataStructureException from indicoio import JSON_HEADERS from indicoio import config -def api_handler(arg, cloud, api, url_params = {"batch":False, "api_key":None}, **kwargs): +def api_handler(arg, cloud, api, url_params=None, **kwargs): + if url_params is None: + url_params = {"api_key":None, batch:False } + data = {'data': arg} data.update(**kwargs) json_data = json.dumps(data) if not cloud: - cloud=config.cloud + cloud = config.cloud if cloud: host = "%s.indico.domains" % cloud diff --git a/indicoio/utils/image.py b/indicoio/utils/image.py index f0ab106..29b3312 100644 --- a/indicoio/utils/image.py +++ b/indicoio/utils/image.py @@ -26,14 +26,8 @@ def image_preprocess(image, size=(48,48), batch=False): elif B64_PATTERN.match(b64_str) is not None: return b64_str else: - raise IndicoError("Snose tring provided must be a valid filepath or base64 encoded string") + raise IndicoError("String provided must be a valid filepath or base64 encoded string") - elif isinstance(image, list): # image passed in is a list and not np.array - warnings.warn( - "Input as lists of pixels will be deprecated in the next major update", - DeprecationWarning - ) - out_image = process_list_image(image) elif isinstance(image, Image.Image): out_image = image elif type(image).__name__ == "ndarray": # image is from numpy/scipy @@ -80,38 +74,3 @@ def get_element_type(_list, dimens): elem = elem[0] return type(elem) - -def process_list_image(_list): - """ - Processes list to be [[(int, int, int), ...]] - """ - # Check if list is empty - if not _list: - return _list - - dimens = get_list_dimensions(_list) - data_type = get_element_type(_list, dimens) - - seq_obj = [] - - out_image = Image.new("RGB", (dimens[0], dimens[1])) - for i in xrange(dimens[0]): - for j in xrange(dimens[1]): - elem = _list[i][j] - if len(dimens) >= 3: - #RGB(A) - if data_type == float: - seq_obj.append((int(elem[0] * 255), int(elem[1] * 255), int(elem[2] * 255))) - else: - seq_obj.append(tuple(elem[0:3])) - elif data_type == float: - #Grayscale 0 - 1.0f - seq_obj.append((int(elem * 255), ) * 3) - else: - #Grayscale 0 - 255 - seq_obj.append((elem, ) * 3) - - #Needs to be 0 - 255 in flattened list of (R, G, B) - out_image.putdata(data = seq_obj) - - return out_image diff --git a/tests/data/48by48.png b/tests/data/48by48.png new file mode 100644 index 0000000..2d893b9 Binary files /dev/null and b/tests/data/48by48.png differ diff --git a/tests/data/48by48rgb.png b/tests/data/48by48rgb.png new file mode 100644 index 0000000..99e612a Binary files /dev/null and b/tests/data/48by48rgb.png differ diff --git a/tests/data/48by48rgba.png b/tests/data/48by48rgba.png new file mode 100644 index 0000000..91ffaf8 Binary files /dev/null and b/tests/data/48by48rgba.png differ diff --git a/tests/data/64by64.png b/tests/data/64by64.png new file mode 100644 index 0000000..44b5961 Binary files /dev/null and b/tests/data/64by64.png differ diff --git a/tests/test_remote.py b/tests/test_remote.py index 85c45b5..5fe482f 100644 --- a/tests/test_remote.py +++ b/tests/test_remote.py @@ -31,74 +31,74 @@ class BatchAPIRun(unittest.TestCase): def test_batch_texttags(self): test_data = ["On Monday, president Barack Obama will be..."] - response = batch_text_tags(test_data, api_key=self.api_key) + response = text_tags(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) def test_batch_keywords(self): test_data = ["A working api is key to the success of our young company"] words = [set(text.lower().split()) for text in test_data] - response = batch_keywords(test_data, api_key=self.api_key) + response = keywords(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(set(response[0].keys()).issubset(words[0])) def test_batch_posneg(self): test_data = ['Worst song ever', 'Best song ever'] - response = batch_sentiment(test_data, api_key=self.api_key) + response = sentiment(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(response[0] < 0.5) def test_batch_sentiment_hq(self): test_data = ['Worst song ever', 'Best song ever'] - response = batch_sentiment_hq(test_data, api_key=self.api_key) + response = sentiment_hq(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(response[0] < 0.5) def test_batch_political(self): test_data = ["Guns don't kill people, people kill people."] - response = batch_political(test_data, api_key=self.api_key) + response = political(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) def test_batch_fer(self): - test_data = [generate_array((48,48))] - response = batch_fer(test_data, api_key=self.api_key) + test_data = [os.path.normpath(os.path.join(DIR, "data/48by48.png"))] + response = fer(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], dict)) def test_batch_content_filtering(self): - test_data = [generate_array((48,48))] - response = batch_content_filtering(test_data, api_key=self.api_key) + test_data = [os.path.normpath(os.path.join(DIR, "data/48by48.png"))] + response = content_filtering(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], float)) def test_batch_fer_bad_b64(self): test_data = ["$bad#FI jeaf9(#0"] - self.assertRaises(IndicoError, batch_fer, test_data, api_key=self.api_key) + self.assertRaises(IndicoError, fer, test_data, api_key=self.api_key) def test_batch_fer_good_b64(self): test_data = ["iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAg5JREFUeNrEV4uNgzAMpegGyAgZgQ3KBscIjMAGx03QEdqbgG5AOwG3AWwAnSCXqLZkuUkwhfYsvaLm5xc7sZ1dIhdtUVjsLZRFTvp+LSaLq8UZ/s+KMSbZCcY5RV9E4QQKHG7QtgeCGv4PFt8WpzkCcztu3TiL0eJgkQmsVFn0MK+LzYkRKEGpG1GDyZdKRdaolhAoJewXnJsO1jtKCFDlChZAFxyJj2PnBRU20KZg7oMlOAENijpi8hwmGkKkZW2GzONtVLA/DxHAhTO2I7MCVBSQ6nGDlEBJDhyVYiUBHXBxzQm0wE4FzPYsGs856dA9SAAP2oENzFYqR6iAFQpHIAUzO/nxnOgthF/lM3w/3U8KYXTwxG/1IgIulF+wPQUXDMl75UoJZIHstRWpaGb8IGYqwBoKlG/lgpzoUEBoj50p8QtVrmHgaaXyC/H3BFC+e9kGFlCB0CtBF7FifQ8D9zjQQHj0pdOM3F1pUBoFKdxtqkMClScHJCSDlSxhHSNRT5K+FaZnHglrz+AGoxZLKNLYH6s3CkkuyJlp58wviZ4PuSCWDXl5hmjZtxcSCGbDUD3gK7EMOZBLCETrgVBF5K0lI5bIZ0wfrYh8NWHIAiNTPHpuTOKpCes1VTFaiNaFdGwPfdmaqlj6LmjJbgoSSfUW74K3voz+/W0oIeB7HWu2s+dfx3N+eLX8CTAAwUmKjK/dHS4AAAAASUVORK5CYII="] - response = batch_fer(test_data, api_key=self.api_key) + response = fer(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], dict)) def test_batch_fer_filepath(self): test_data = [os.path.normpath(os.path.join(DIR, "data/fear.png"))] - response = batch_fer(test_data, api_key=self.api_key) + response = fer(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], dict)) def test_batch_fer_pil_image(self): test_data = [Image.open(os.path.normpath(os.path.join(DIR, "data/fear.png")))] - response = batch_fer(test_data, api_key=self.api_key) + response = fer(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], dict)) def test_batch_fer_nonexistant_filepath(self): test_data = ["data/unhappy.png"] - self.assertRaises(IndicoError, batch_fer, test_data, api_key=self.api_key) + self.assertRaises(IndicoError, fer, test_data, api_key=self.api_key) def test_batch_facial_features(self): - test_data = [generate_array((48,48))] - response = batch_facial_features(test_data, api_key=self.api_key) + test_data = [os.path.normpath(os.path.join(DIR, "data/48by48.png"))] + response = facial_features(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], list)) self.assertEqual(len(response[0]), 48) @@ -117,22 +117,22 @@ class BatchAPIRun(unittest.TestCase): # have decided how we are dealing with them def test_batch_image_features_greyscale(self): - test_data = [generate_array((48,48))] - response = batch_image_features(test_data, api_key=self.api_key) + test_data = [os.path.normpath(os.path.join(DIR, "data/48by48.png"))] + response = image_features(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], list)) self.assertEqual(len(response[0]), 2048) def test_batch_image_features_rgb(self): - test_data = [generate_array((48,48))] - response = batch_image_features(test_data, api_key=self.api_key) + test_data = [os.path.normpath(os.path.join(DIR, "data/48by48rgb.png"))] + response = image_features(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(isinstance(response[0], list)) self.assertEqual(len(response[0]), 2048) def test_batch_language(self): test_data = ['clearly an english sentence'] - response = batch_language(test_data, api_key=self.api_key) + response = language(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, list)) self.assertTrue(response[0]['English'] > 0.25) @@ -140,14 +140,15 @@ class BatchAPIRun(unittest.TestCase): batch = ["London Underground's boss Mike Brown warned that the strike ..."] expected_entities = ("London Underground", "Mike Brown") expected_keys = set(["categories", "confidence"]) - entities = batch_named_entities(batch)[0] + entities = named_entities(batch)[0] for entity in expected_entities: assert entity in expected_entities assert not (set(entities[entity]) - expected_keys) def test_batch_multi_api_image(self): - test_data = [generate_array((48,48)), generate_int_array((48,48))] - response = batch_predict_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key) + test_data = [os.path.normpath(os.path.join(DIR, "data/48by48.png")), + os.path.normpath(os.path.join(DIR, "data/48by48.png"))] + response = predict_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key) self.assertTrue(isinstance(response, dict)) self.assertTrue(set(response.keys()) == set(config.IMAGE_APIS)) @@ -155,21 +156,21 @@ class BatchAPIRun(unittest.TestCase): def test_batch_multi_api_text(self): test_data = ['clearly an english sentence'] - response = batch_predict_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key) + response = predict_text(test_data, apis=config.TEXT_APIS, api_key=self.api_key) self.assertTrue(isinstance(response, dict)) self.assertTrue(set(response.keys()) == set(config.TEXT_APIS)) def test_default_multi_api_text(self): test_data = ['clearly an english sentence'] - response = batch_predict_text(test_data, api_key=self.api_key) + response = predict_text(test_data, api_key=self.api_key) self.assertTrue(isinstance(response, dict)) self.assertTrue(set(response.keys()) == set(config.TEXT_APIS)) def test_multi_api_bad_api(self): self.assertRaises(IndicoError, - batch_predict_text, + predict_text, "this shouldn't work", apis=["sentiment", "somethingbad"]) @@ -180,14 +181,14 @@ class BatchAPIRun(unittest.TestCase): apis=["fer", "sentiment", "facial_features"]) def test_batch_multi_bad_mixed_api(self): self.assertRaises(IndicoError, - batch_predict_text, + predict_text, ["this shouldn't work"], apis=["fer", "sentiment", "facial_features"]) def test_batch_set_cloud(self): test_data = ['clearly an english sentence'] self.assertRaises(ConnectionError, - batch_language, + language, test_data, api_key=self.api_key, cloud='invalid/cloud') @@ -290,7 +291,7 @@ class FullAPIRun(unittest.TestCase): def test_good_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = generate_array((48,48)) + test_face = os.path.normpath(os.path.join(DIR, "data/48by48.png")) response = fer(test_face) self.assertTrue(isinstance(response, dict)) @@ -298,14 +299,14 @@ class FullAPIRun(unittest.TestCase): def test_good_int_array_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = generate_int_array((48,48)) + test_face = os.path.normpath(os.path.join(DIR, "data/48by48.png")) response = fer(test_face) self.assertTrue(isinstance(response, dict)) self.assertEqual(fer_set, set(response.keys())) def test_happy_fer(self): - test_face = self.load_image("data/happy.png", as_grey=True) + test_face = os.path.normpath(os.path.join(DIR, "data/happy.png")) response = fer(test_face) self.assertTrue(isinstance(response, dict)) self.assertTrue(response['Happy'] > 0.5) @@ -317,26 +318,26 @@ class FullAPIRun(unittest.TestCase): self.assertTrue(response['Happy'] > 0.5) def test_fear_fer(self): - test_face = self.load_image("data/fear.png", as_grey=True) + test_face = os.path.normpath(os.path.join(DIR, "data/fear.png")) response = fer(test_face) self.assertTrue(isinstance(response, dict)) self.assertTrue(response['Fear'] > 0.25) def test_bad_fer(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = generate_array((56, 56)) + test_face = os.path.normpath(os.path.join(DIR, "data/64by64.png")) response = fer(test_face) self.assertTrue(isinstance(response, dict)) self.assertEqual(fer_set, set(response.keys())) def test_safe_content_filtering(self): - test_face = self.load_image("data/happy.png", as_grey=True) + test_face = os.path.normpath(os.path.join(DIR, "data/happy.png")) response = content_filtering(test_face) self.assertTrue(response < 0.5) def test_good_facial_features(self): - test_face = generate_array((48,48)) + test_face = os.path.normpath(os.path.join(DIR, "data/48by48.png")) response = facial_features(test_face) self.assertTrue(isinstance(response, list)) @@ -344,7 +345,7 @@ class FullAPIRun(unittest.TestCase): self.check_range(response) def test_rgba_int_array_facial_features(self): - test_face = generate_rgba_int_array((48, 48)) + test_face = os.path.normpath(os.path.join(DIR, "data/48by48rgba.png")) response = facial_features(test_face) self.assertTrue(isinstance(response, list)) @@ -353,7 +354,7 @@ class FullAPIRun(unittest.TestCase): def test_good_int_array_facial_features(self): fer_set = set(['Angry', 'Sad', 'Neutral', 'Surprise', 'Fear', 'Happy']) - test_face = generate_int_array((48,48)) + test_face = os.path.normpath(os.path.join(DIR, "data/48by48.png")) response = facial_features(test_face) self.assertTrue(isinstance(response, list)) @@ -371,7 +372,7 @@ class FullAPIRun(unittest.TestCase): # self.check_range(response) def test_good_image_features_greyscale(self): - test_image = generate_array((48,48)) + test_image = os.path.normpath(os.path.join(DIR, "data/48by48.png")) response = image_features(test_image) self.assertTrue(isinstance(response, list)) @@ -379,7 +380,7 @@ class FullAPIRun(unittest.TestCase): self.check_range(response) def test_good_image_features_rgb(self): - test_image = [[(random.random(),) * 3 for _ in xrange(48)] for _ in xrange(48)] + test_image = os.path.normpath(os.path.join(DIR, "data/48by48rgb.png")) response = image_features(test_image) self.assertTrue(isinstance(response, list)) @@ -387,7 +388,7 @@ class FullAPIRun(unittest.TestCase): self.check_range(response) def test_multi_api_image(self): - test_data = generate_array((48,48)) + test_data = os.path.normpath(os.path.join(DIR, "data/48by48.png")) response = predict_image(test_data, apis=config.IMAGE_APIS, api_key=self.api_key) self.assertTrue(isinstance(response, dict)) @@ -558,15 +559,5 @@ def flatten(container): else: yield i -def generate_array(size): - return [[random.random() for _ in xrange(size[0])] for _ in xrange(size[1])] - -def generate_int_array(size): - return [[random.randint(0, 255) for _ in xrange(size[0])] for _ in xrange(size[1])] - -def generate_rgba_int_array(size): - return [[[random.randint(0, 255) for _ in xrange(3)] for _ in xrange(size[0])] for _ in xrange(size[1])] - - if __name__ == "__main__": unittest.main()