1
0
mirror of https://github.com/gsi-upm/senpy synced 2025-09-18 12:32:21 +00:00

Compare commits

..

8 Commits

Author SHA1 Message Date
J. Fernando Sánchez
b48730137d Remove makefiles from auto push/pull 2018-11-06 17:12:54 +01:00
J. Fernando Sánchez
f1ec057b16 Add fetch to makefiles push 2018-11-06 17:02:59 +01:00
J. Fernando Sánchez
f6ca82cac8 Merge branch '56-exception-when-using-post' into 'master'
Replace algorithm list with a tuple

Closes #56

See merge request senpy/senpy!25
2018-11-06 14:56:00 +00:00
J. Fernando Sánchez
318acd5a71 Replace algorithm list with a tuple 2018-11-06 15:52:05 +01:00
J. Fernando Sánchez
c8f6f5613d Change CI to include make push
This replaces the makes for each python version with a simple `make push`.
It will also add a "main image" for each version, i.e. `gsiupm/senpy:1.0.0` in
addition to `gsiupm/senpy:1.0.0-python2.7` and `gsiupm/senpy:1.0.0-python3.5`.
2018-10-30 17:45:44 +01:00
J. Fernando Sánchez
748d1a00bd Fix bug in POST 2018-10-30 16:35:17 +01:00
J. Fernando Sánchez
a82e4ed440 Fix bug in py3.5 2018-10-30 16:14:06 +01:00
J. Fernando Sánchez
c939b095de Fix POST. Closes senpy/senpy#56 2018-10-30 15:15:37 +01:00
13 changed files with 70 additions and 230 deletions

View File

@@ -31,29 +31,19 @@ test-2.7:
variables: variables:
PYTHON_VERSION: "2.7" PYTHON_VERSION: "2.7"
.image: &image_definition push:
stage: push stage: push
script: script:
- make -e push-$PYTHON_VERSION - make -e push
only: only:
- tags - tags
- triggers - triggers
- fix-makefiles - fix-makefiles
push-3.5:
<<: *image_definition
variables:
PYTHON_VERSION: "3.5"
push-2.7:
<<: *image_definition
variables:
PYTHON_VERSION: "2.7"
push-latest: push-latest:
<<: *image_definition stage: push
variables: script:
PYTHON_VERSION: latest - make -e push-latest
only: only:
- master - master
- triggers - triggers

View File

@@ -22,7 +22,4 @@ else
rm $(KEY_FILE) rm $(KEY_FILE)
endif endif
push:: git-push .PHONY:: commit tag git-push git-pull push-github
pull:: git-pull
.PHONY:: commit tag push git-push git-pull push-github

View File

@@ -1,17 +1,15 @@
makefiles-remote: 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 makefiles-commit: makefiles-remote
git add -f .makefiles git add -f .makefiles
git commit -em "Updated makefiles from ${NAME}" git commit -em "Updated makefiles from ${NAME}"
makefiles-push: makefiles-push:
git fetch makefiles $(NAME)
git subtree push --prefix=.makefiles/ makefiles $(NAME) git subtree push --prefix=.makefiles/ makefiles $(NAME)
makefiles-pull: makefiles-remote makefiles-pull: makefiles-remote
git subtree pull --prefix=.makefiles/ makefiles master --squash git subtree pull --prefix=.makefiles/ makefiles master --squash
pull:: makefiles-pull .PHONY:: makefiles-remote makefiles-commit makefiles-push makefiles-pull
push:: makefiles-push
.PHONY:: makefiles-remote makefiles-commit makefiles-push makefiles-pull pull push

View File

@@ -11,7 +11,7 @@ class Async(AnalysisPlugin):
'''An example of an asynchronous module''' '''An example of an asynchronous module'''
author = '@balkian' author = '@balkian'
version = '0.2' version = '0.2'
async = True sync = False
def _do_async(self, num_processes): def _do_async(self, num_processes):
pool = multiprocessing.Pool(processes=num_processes) pool = multiprocessing.Pool(processes=num_processes)

View File

@@ -175,8 +175,8 @@ def parse_params(indict, *specs):
parameters=outdict, parameters=outdict,
errors=wrong_params) errors=wrong_params)
raise message raise message
if 'algorithm' in outdict and not isinstance(outdict['algorithm'], list): if 'algorithm' in outdict and not isinstance(outdict['algorithm'], tuple):
outdict['algorithm'] = list(outdict['algorithm'].split(',')) outdict['algorithm'] = tuple(outdict['algorithm'].split(','))
return outdict return outdict

View File

@@ -69,7 +69,7 @@ def encoded_url(url=None, base=None):
if request.method == 'GET': if request.method == 'GET':
url = request.full_path[1:] # Remove the first slash url = request.full_path[1:] # Remove the first slash
else: else:
hash(frozenset(request.form.params().items())) hash(frozenset(tuple(request.parameters.items())))
code = 'hash:{}'.format(hash) code = 'hash:{}'.format(hash)
code = code or base64.urlsafe_b64encode(url.encode()).decode() code = code or base64.urlsafe_b64encode(url.encode()).decode()
@@ -196,7 +196,7 @@ def api_root(plugin):
if plugin: if plugin:
plugin = plugin.replace('+', '/') plugin = plugin.replace('+', '/')
plugin = plugin.split('/') plugin = plugin.split('/')
req.parameters['algorithm'] = plugin req.parameters['algorithm'] = tuple(plugin)
return current_app.senpy.analyse(req) return current_app.senpy.analyse(req)

View File

@@ -25,7 +25,11 @@ class Client(object):
def request(self, path=None, method='GET', **params): def request(self, path=None, method='GET', **params):
url = '{}{}'.format(self.endpoint.rstrip('/'), path) 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: try:
resp = models.from_dict(response.json()) resp = models.from_dict(response.json())
except Exception as ex: except Exception as ex:

View File

@@ -351,7 +351,7 @@ class Senpy(object):
logger.info("Activating plugin: {}".format(plugin.name)) logger.info("Activating plugin: {}".format(plugin.name))
if sync or not getattr(plugin, 'async', True): if sync or not getattr(plugin, 'async', True) or getattr(plugin, 'sync', False):
return self._activate(plugin) return self._activate(plugin)
else: else:
th = Thread(target=partial(self._activate, plugin)) th = Thread(target=partial(self._activate, plugin))
@@ -374,7 +374,7 @@ class Senpy(object):
self._set_active(plugin, False) self._set_active(plugin, False)
if sync or not getattr(plugin, 'async', True): if sync or not getattr(plugin, 'async', True) or not getattr(plugin, 'sync', False):
self._deactivate(plugin) self._deactivate(plugin)
else: else:
th = Thread(target=partial(self._deactivate, plugin)) th = Thread(target=partial(self._deactivate, plugin))

View File

@@ -1,5 +1,7 @@
import logging import logging
from pkg_resources import parse_version, get_distribution, DistributionNotFound
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
MSG = 'GSITK is not (properly) installed.' MSG = 'GSITK is not (properly) installed.'
@@ -12,12 +14,18 @@ def raise_exception(*args, **kwargs):
try: 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.datasets.datasets import DatasetManager
from gsitk.evaluation.evaluation import Evaluation as Eval from gsitk.evaluation.evaluation import Evaluation as Eval
from sklearn.pipeline import Pipeline from sklearn.pipeline import Pipeline
GSITK_AVAILABLE = True
modules = locals() modules = locals()
except ImportError: else:
logger.warn(IMPORTMSG) logger.warning(IMPORTMSG)
GSITK_AVAILABLE = False
DatasetManager = Eval = Pipeline = raise_exception DatasetManager = Eval = Pipeline = raise_exception

View File

@@ -1,187 +0,0 @@
from senpy import AnalysisPlugin, easy
class maxSentiment(AnalysisPlugin):
'''Plugin to extract max emotion from a multi-empotion set'''
author = '@dsuarezsouto'
version = '0.1'
extra_params = {
'max': {
"aliases": ["maximum", "max"],
'required': True,
'options': [True, False],
"@id": 'maxSentiment',
'default': False
}
}
def analyse_entry(self, entry, params):
if not params["max"]:
yield entry
return
set_emotions= entry.emotions[0]['onyx:hasEmotion']
max_emotion =set_emotions[0]
# Extract max emotion from the set emotions (emotion with highest intensity)
for tmp_emotion in set_emotions:
if tmp_emotion['onyx:hasEmotionIntensity']>max_emotion['onyx:hasEmotionIntensity']:
max_emotion=tmp_emotion
if max_emotion['onyx:hasEmotionIntensity'] == 0:
max_emotion['onyx:hasEmotionCategory'] = "neutral"
max_emotion['onyx:hasEmotionIntensity'] = 1.0
entry.emotions[0]['onyx:hasEmotion'] = [max_emotion]
entry.emotions[0]['prov:wasGeneratedBy'] = "maxSentiment"
#print(entry)
yield entry
# Test Cases:
# 1 Normal Situation.
# 2 Case to return a Neutral Emotion.
test_cases = [{
"entry": {
"@type": "entry",
"emotions": [
{
"@id": "Emotions0",
"@type": "emotionSet",
"onyx:hasEmotion": [
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "anger",
"onyx:hasEmotionIntensity": 0
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "joy",
"onyx:hasEmotionIntensity": 0.3333333333333333
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "negative-fear",
"onyx:hasEmotionIntensity": 0
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "sadness",
"onyx:hasEmotionIntensity": 0
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "disgust",
"onyx:hasEmotionIntensity": 0
}
]
},
],
"nif:isString": "This text makes me sad.\nwhilst this text makes me happy and surprised at the same time.\nI cannot believe it!"
},
'params': {
'max': True
},
'expected' : {
"@type": "entry",
"emotions": [
{
"@id": "Emotions0",
"@type": "emotionSet",
"onyx:hasEmotion": [
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "joy",
"onyx:hasEmotionIntensity": 0.3333333333333333
}
],
"prov:wasGeneratedBy" : 'maxSentiment'
}
],
"nif:isString": "This text makes me sad.\nwhilst this text makes me happy and surprised at the same time.\nI cannot believe it!"
}
},
{
"entry": {
"@type": "entry",
"emotions": [
{
"@id": "Emotions0",
"@type": "emotionSet",
"onyx:hasEmotion": [
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "anger",
"onyx:hasEmotionIntensity": 0
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "joy",
"onyx:hasEmotionIntensity": 0
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "negative-fear",
"onyx:hasEmotionIntensity": 0
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "sadness",
"onyx:hasEmotionIntensity": 0
},
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "disgust",
"onyx:hasEmotionIntensity": 0
}
]
}
],
"nif:isString": "This text makes me sad.\nwhilst this text makes me happy and surprised at the same time.\nI cannot believe it!"
},
'params': {
'max': True
},
'expected' : {
"@type": "entry",
"emotions": [
{
"@id": "Emotions0",
"@type": "emotionSet",
"onyx:hasEmotion": [
{
"@id": "_:Emotion_1538121033.74",
"@type": "emotion",
"onyx:hasEmotionCategory": "neutral",
"onyx:hasEmotionIntensity": 1
}
],
"prov:wasGeneratedBy" : 'maxSentiment'
}
],
"nif:isString": "This text makes me sad.\nwhilst this text makes me happy and surprised at the same time.\nI cannot believe it!"
}
}]
if __name__ == '__main__':
easy()

View File

@@ -67,6 +67,21 @@ class BlueprintsTest(TestCase):
logging.debug("Got response: %s", js) logging.debug("Got response: %s", js)
assert "@context" in js assert "@context" in js
assert "entries" 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): def test_analysis_extra(self):
""" """

View File

@@ -24,6 +24,19 @@ class ModelsTest(TestCase):
except Error: except Error:
pass 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): def test_plugins(self):
endpoint = 'http://dummy/' endpoint = 'http://dummy/'
client = Client(endpoint) client = Client(endpoint)

View File

@@ -1,15 +1,15 @@
#!/bin/env python #!/bin/env python
import os import os
import sys
import pickle import pickle
import shutil import shutil
import tempfile import tempfile
from unittest import TestCase from unittest import TestCase, skipIf
from senpy.models import Results, Entry, EmotionSet, Emotion, Plugins from senpy.models import Results, Entry, EmotionSet, Emotion, Plugins
from senpy import plugins from senpy import plugins
from senpy.plugins.conversion.emotion.centroids import CentroidConversion from senpy.plugins.conversion.emotion.centroids import CentroidConversion
from senpy.gsitk_compat import GSITK_AVAILABLE
import pandas as pd import pandas as pd
@@ -346,13 +346,15 @@ class PluginsTest(TestCase):
smart_metrics = results[0].metrics[0] smart_metrics = results[0].metrics[0]
assert abs(smart_metrics['accuracy'] - 1) < 0.01 assert abs(smart_metrics['accuracy'] - 1) < 0.01
@skipIf(not GSITK_AVAILABLE, "GSITK is not available")
def test_evaluation(self): def test_evaluation(self):
if sys.version_info < (3, 0): self._test_evaluation()
with self.assertRaises(Exception) as context:
self._test_evaluation() @skipIf(GSITK_AVAILABLE, "GSITK is available")
self.assertTrue('GSITK ' in str(context.exception)) def test_evaluation_unavailable(self):
else: with self.assertRaises(Exception) as context:
self._test_evaluation() self._test_evaluation()
self.assertTrue('GSITK ' in str(context.exception))
def make_mini_test(fpath): def make_mini_test(fpath):