mirror of
https://github.com/gsi-upm/senpy
synced 2025-09-16 19:42:21 +00:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b48730137d | ||
|
f1ec057b16 | ||
|
f6ca82cac8 | ||
|
318acd5a71 | ||
|
c8f6f5613d | ||
|
748d1a00bd | ||
|
a82e4ed440 | ||
|
c939b095de | ||
|
6dd4a44924 |
@@ -31,29 +31,19 @@ test-2.7:
|
||||
variables:
|
||||
PYTHON_VERSION: "2.7"
|
||||
|
||||
.image: &image_definition
|
||||
push:
|
||||
stage: push
|
||||
script:
|
||||
- make -e push-$PYTHON_VERSION
|
||||
- make -e push
|
||||
only:
|
||||
- tags
|
||||
- triggers
|
||||
- fix-makefiles
|
||||
|
||||
push-3.5:
|
||||
<<: *image_definition
|
||||
variables:
|
||||
PYTHON_VERSION: "3.5"
|
||||
|
||||
push-2.7:
|
||||
<<: *image_definition
|
||||
variables:
|
||||
PYTHON_VERSION: "2.7"
|
||||
|
||||
push-latest:
|
||||
<<: *image_definition
|
||||
variables:
|
||||
PYTHON_VERSION: latest
|
||||
stage: push
|
||||
script:
|
||||
- make -e push-latest
|
||||
only:
|
||||
- master
|
||||
- triggers
|
||||
|
@@ -22,7 +22,4 @@ else
|
||||
rm $(KEY_FILE)
|
||||
endif
|
||||
|
||||
push:: git-push
|
||||
pull:: git-pull
|
||||
|
||||
.PHONY:: commit tag push git-push git-pull push-github
|
||||
.PHONY:: commit tag git-push git-pull push-github
|
||||
|
@@ -1,17 +1,15 @@
|
||||
makefiles-remote:
|
||||
@git remote add makefiles ssh://git@lab.cluster.gsi.dit.upm.es:2200/docs/templates/makefiles.git 2>/dev/null || true
|
||||
git ls-remote --exit-code makefiles 2> /dev/null || git remote add makefiles ssh://git@lab.cluster.gsi.dit.upm.es:2200/docs/templates/makefiles.git
|
||||
|
||||
makefiles-commit: makefiles-remote
|
||||
git add -f .makefiles
|
||||
git commit -em "Updated makefiles from ${NAME}"
|
||||
|
||||
makefiles-push:
|
||||
git fetch makefiles $(NAME)
|
||||
git subtree push --prefix=.makefiles/ makefiles $(NAME)
|
||||
|
||||
makefiles-pull: makefiles-remote
|
||||
git subtree pull --prefix=.makefiles/ makefiles master --squash
|
||||
|
||||
pull:: makefiles-pull
|
||||
push:: makefiles-push
|
||||
|
||||
.PHONY:: makefiles-remote makefiles-commit makefiles-push makefiles-pull pull push
|
||||
.PHONY:: makefiles-remote makefiles-commit makefiles-push makefiles-pull
|
||||
|
@@ -11,7 +11,7 @@ class Async(AnalysisPlugin):
|
||||
'''An example of an asynchronous module'''
|
||||
author = '@balkian'
|
||||
version = '0.2'
|
||||
async = True
|
||||
sync = False
|
||||
|
||||
def _do_async(self, num_processes):
|
||||
pool = multiprocessing.Pool(processes=num_processes)
|
||||
|
@@ -175,8 +175,8 @@ def parse_params(indict, *specs):
|
||||
parameters=outdict,
|
||||
errors=wrong_params)
|
||||
raise message
|
||||
if 'algorithm' in outdict and not isinstance(outdict['algorithm'], list):
|
||||
outdict['algorithm'] = list(outdict['algorithm'].split(','))
|
||||
if 'algorithm' in outdict and not isinstance(outdict['algorithm'], tuple):
|
||||
outdict['algorithm'] = tuple(outdict['algorithm'].split(','))
|
||||
return outdict
|
||||
|
||||
|
||||
|
@@ -69,7 +69,7 @@ def encoded_url(url=None, base=None):
|
||||
if request.method == 'GET':
|
||||
url = request.full_path[1:] # Remove the first slash
|
||||
else:
|
||||
hash(frozenset(request.form.params().items()))
|
||||
hash(frozenset(tuple(request.parameters.items())))
|
||||
code = 'hash:{}'.format(hash)
|
||||
|
||||
code = code or base64.urlsafe_b64encode(url.encode()).decode()
|
||||
@@ -184,14 +184,19 @@ def basic_api(f):
|
||||
return decorated_function
|
||||
|
||||
|
||||
@api_blueprint.route('/', methods=['POST', 'GET'])
|
||||
@api_blueprint.route('/', defaults={'plugin': None}, methods=['POST', 'GET'])
|
||||
@api_blueprint.route('/<path:plugin>', methods=['POST', 'GET'])
|
||||
@basic_api
|
||||
def api_root():
|
||||
def api_root(plugin):
|
||||
if request.parameters['help']:
|
||||
dic = dict(api.API_PARAMS, **api.NIF_PARAMS)
|
||||
response = Help(valid_parameters=dic)
|
||||
return response
|
||||
req = api.parse_call(request.parameters)
|
||||
if plugin:
|
||||
plugin = plugin.replace('+', '/')
|
||||
plugin = plugin.split('/')
|
||||
req.parameters['algorithm'] = tuple(plugin)
|
||||
return current_app.senpy.analyse(req)
|
||||
|
||||
|
||||
@@ -221,7 +226,7 @@ def plugins():
|
||||
|
||||
@api_blueprint.route('/plugins/<plugin>/', methods=['POST', 'GET'])
|
||||
@basic_api
|
||||
def plugin(plugin=None):
|
||||
def plugin(plugin):
|
||||
sp = current_app.senpy
|
||||
return sp.get_plugin(plugin)
|
||||
|
||||
|
@@ -25,7 +25,11 @@ class Client(object):
|
||||
|
||||
def request(self, path=None, method='GET', **params):
|
||||
url = '{}{}'.format(self.endpoint.rstrip('/'), path)
|
||||
response = requests.request(method=method, url=url, params=params)
|
||||
if method == 'POST':
|
||||
response = requests.post(url=url, data=params)
|
||||
else:
|
||||
response = requests.request(method=method, url=url, params=params)
|
||||
|
||||
try:
|
||||
resp = models.from_dict(response.json())
|
||||
except Exception as ex:
|
||||
|
@@ -153,7 +153,6 @@ class Senpy(object):
|
||||
yield i
|
||||
return
|
||||
plugin = plugins[0]
|
||||
self._activate(plugin) # Make sure the plugin is activated
|
||||
specific_params = api.parse_extra_params(req, plugin)
|
||||
req.analysis.append({'plugin': plugin,
|
||||
'parameters': specific_params})
|
||||
@@ -352,7 +351,7 @@ class Senpy(object):
|
||||
|
||||
logger.info("Activating plugin: {}".format(plugin.name))
|
||||
|
||||
if sync or 'async' in plugin and not plugin.async:
|
||||
if sync or not getattr(plugin, 'async', True) or getattr(plugin, 'sync', False):
|
||||
return self._activate(plugin)
|
||||
else:
|
||||
th = Thread(target=partial(self._activate, plugin))
|
||||
@@ -375,7 +374,7 @@ class Senpy(object):
|
||||
|
||||
self._set_active(plugin, False)
|
||||
|
||||
if sync or 'async' in plugin and not plugin.async:
|
||||
if sync or not getattr(plugin, 'async', True) or not getattr(plugin, 'sync', False):
|
||||
self._deactivate(plugin)
|
||||
else:
|
||||
th = Thread(target=partial(self._deactivate, plugin))
|
||||
|
@@ -1,5 +1,7 @@
|
||||
import logging
|
||||
|
||||
from pkg_resources import parse_version, get_distribution, DistributionNotFound
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MSG = 'GSITK is not (properly) installed.'
|
||||
@@ -12,12 +14,18 @@ def raise_exception(*args, **kwargs):
|
||||
|
||||
|
||||
try:
|
||||
gsitk_distro = get_distribution("gsitk")
|
||||
GSITK_VERSION = parse_version(gsitk_distro.version)
|
||||
GSITK_AVAILABLE = GSITK_VERSION > parse_version("0.1.9.1") # Earlier versions have a bug
|
||||
except DistributionNotFound:
|
||||
GSITK_AVAILABLE = False
|
||||
GSITK_VERSION = ()
|
||||
|
||||
if GSITK_AVAILABLE:
|
||||
from gsitk.datasets.datasets import DatasetManager
|
||||
from gsitk.evaluation.evaluation import Evaluation as Eval
|
||||
from sklearn.pipeline import Pipeline
|
||||
GSITK_AVAILABLE = True
|
||||
modules = locals()
|
||||
except ImportError:
|
||||
logger.warn(IMPORTMSG)
|
||||
GSITK_AVAILABLE = False
|
||||
else:
|
||||
logger.warning(IMPORTMSG)
|
||||
DatasetManager = Eval = Pipeline = raise_exception
|
||||
|
@@ -67,10 +67,25 @@ class BlueprintsTest(TestCase):
|
||||
logging.debug("Got response: %s", js)
|
||||
assert "@context" in js
|
||||
assert "entries" in js
|
||||
assert len(js['analysis']) == 1
|
||||
|
||||
def test_analysis_post(self):
|
||||
"""
|
||||
The results for a POST request should be the same as for a GET request.
|
||||
"""
|
||||
resp = self.client.post("/api/", data={'i': 'My aloha mohame',
|
||||
'algorithm': 'rand',
|
||||
'with_parameters': True})
|
||||
self.assertCode(resp, 200)
|
||||
js = parse_resp(resp)
|
||||
logging.debug("Got response: %s", js)
|
||||
assert "@context" in js
|
||||
assert "entries" in js
|
||||
assert len(js['analysis']) == 1
|
||||
|
||||
def test_analysis_extra(self):
|
||||
"""
|
||||
Extra params that have a default should
|
||||
Extra params that have a default should use it
|
||||
"""
|
||||
resp = self.client.get("/api/?i=My aloha mohame&algo=Dummy&with_parameters=true")
|
||||
self.assertCode(resp, 200)
|
||||
@@ -95,6 +110,44 @@ class BlueprintsTest(TestCase):
|
||||
resp = self.client.get("/api/?i=My aloha mohame&algo=DummyRequired&example=a")
|
||||
self.assertCode(resp, 200)
|
||||
|
||||
def test_analysis_url(self):
|
||||
"""
|
||||
The algorithm can also be specified as part of the URL
|
||||
"""
|
||||
self.app.config['TESTING'] = False # Errors are expected in this case
|
||||
resp = self.client.get("/api/DummyRequired?i=My aloha mohame")
|
||||
self.assertCode(resp, 400)
|
||||
js = parse_resp(resp)
|
||||
logging.debug("Got response: %s", js)
|
||||
assert isinstance(js, models.Error)
|
||||
resp = self.client.get("/api/DummyRequired?i=My aloha mohame&example=notvalid")
|
||||
self.assertCode(resp, 400)
|
||||
resp = self.client.get("/api/DummyRequired?i=My aloha mohame&example=a")
|
||||
self.assertCode(resp, 200)
|
||||
|
||||
def test_analysis_chain(self):
|
||||
"""
|
||||
More than one algorithm can be specified. Plugins will then be chained
|
||||
"""
|
||||
resp = self.client.get("/api/Dummy?i=My aloha mohame")
|
||||
js = parse_resp(resp)
|
||||
assert len(js['analysis']) == 1
|
||||
assert js['entries'][0]['nif:isString'] == 'My aloha mohame'[::-1]
|
||||
|
||||
resp = self.client.get("/api/Dummy/Dummy?i=My aloha mohame")
|
||||
# Calling dummy twice, should return the same string
|
||||
self.assertCode(resp, 200)
|
||||
js = parse_resp(resp)
|
||||
assert len(js['analysis']) == 2
|
||||
assert js['entries'][0]['nif:isString'] == 'My aloha mohame'
|
||||
|
||||
resp = self.client.get("/api/Dummy+Dummy?i=My aloha mohame")
|
||||
# Same with pluses instead of slashes
|
||||
self.assertCode(resp, 200)
|
||||
js = parse_resp(resp)
|
||||
assert len(js['analysis']) == 2
|
||||
assert js['entries'][0]['nif:isString'] == 'My aloha mohame'
|
||||
|
||||
def test_error(self):
|
||||
"""
|
||||
The dummy plugin returns an empty response,\
|
||||
|
@@ -24,6 +24,19 @@ class ModelsTest(TestCase):
|
||||
except Error:
|
||||
pass
|
||||
|
||||
def test_client_post(self):
|
||||
endpoint = 'http://dummy/'
|
||||
client = Client(endpoint)
|
||||
with patch_requests('http://dummy/', Results()):
|
||||
resp = client.analyse('hello')
|
||||
assert isinstance(resp, Results)
|
||||
with patch_requests('http://dummy/', Error('Nothing'), method='POST'):
|
||||
try:
|
||||
client.analyse(input='hello', method='POST', algorithm='NONEXISTENT')
|
||||
raise Exception('Exceptions should be raised. This is not golang')
|
||||
except Error:
|
||||
pass
|
||||
|
||||
def test_plugins(self):
|
||||
endpoint = 'http://dummy/'
|
||||
client = Client(endpoint)
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#!/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pickle
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
from unittest import TestCase
|
||||
from unittest import TestCase, skipIf
|
||||
from senpy.models import Results, Entry, EmotionSet, Emotion, Plugins
|
||||
from senpy import plugins
|
||||
from senpy.plugins.conversion.emotion.centroids import CentroidConversion
|
||||
from senpy.gsitk_compat import GSITK_AVAILABLE
|
||||
|
||||
import pandas as pd
|
||||
|
||||
@@ -346,13 +346,15 @@ class PluginsTest(TestCase):
|
||||
smart_metrics = results[0].metrics[0]
|
||||
assert abs(smart_metrics['accuracy'] - 1) < 0.01
|
||||
|
||||
@skipIf(not GSITK_AVAILABLE, "GSITK is not available")
|
||||
def test_evaluation(self):
|
||||
if sys.version_info < (3, 0):
|
||||
with self.assertRaises(Exception) as context:
|
||||
self._test_evaluation()
|
||||
self.assertTrue('GSITK ' in str(context.exception))
|
||||
else:
|
||||
self._test_evaluation()
|
||||
|
||||
@skipIf(GSITK_AVAILABLE, "GSITK is available")
|
||||
def test_evaluation_unavailable(self):
|
||||
with self.assertRaises(Exception) as context:
|
||||
self._test_evaluation()
|
||||
self.assertTrue('GSITK ' in str(context.exception))
|
||||
|
||||
|
||||
def make_mini_test(fpath):
|
||||
|
Reference in New Issue
Block a user