1
0
mirror of https://github.com/gsi-upm/senpy synced 2025-08-23 18:12:20 +00:00

Loads of changes!

* Added conversion plugins (API might change!)
* Added conversion to the analysis pipeline
* Changed behaviour of --default-plugins (it adds conversion plugins regardless)
* Added emotionModel [sic] and emotionConversion models

//TODO add conversion tests
//TODO add conversion to docs
This commit is contained in:
J. Fernando Sánchez
2017-02-27 11:37:43 +01:00
parent 3cea7534ef
commit 9f6a6f5ecd
55 changed files with 986 additions and 461 deletions

View File

@@ -1,7 +0,0 @@
from senpy.plugins import SentimentPlugin
from senpy.models import Results
class DummyPlugin(SentimentPlugin):
def analyse(self, *args, **kwargs):
return Results()

View File

@@ -1,7 +0,0 @@
{
"name": "Dummy",
"module": "dummy",
"description": "I am dummy",
"author": "@balkian",
"version": "0.1"
}

View File

@@ -0,0 +1,7 @@
from senpy.plugins import SentimentPlugin
class DummyPlugin(SentimentPlugin):
def analyse_entry(self, entry, params):
entry.text = entry.text[::-1]
yield entry

View File

@@ -0,0 +1,15 @@
{
"name": "Dummy",
"module": "dummy",
"description": "I am dummy",
"author": "@balkian",
"version": "0.1",
"extra_params": {
"example": {
"@id": "example_parameter",
"aliases": ["example", "ex"],
"required": false,
"default": 0
}
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "DummyRequired",
"module": "dummy",
"description": "I am dummy",
"author": "@balkian",
"version": "0.1",
"extra_params": {
"example": {
"@id": "example_parameter",
"aliases": ["example", "ex"],
"required": true
}
}
}

View File

@@ -1,5 +1,4 @@
from senpy.plugins import SenpyPlugin
from senpy.models import Results
from time import sleep
@@ -7,6 +6,6 @@ class SleepPlugin(SenpyPlugin):
def activate(self, *args, **kwargs):
sleep(self.timeout)
def analyse(self, *args, **kwargs):
sleep(float(kwargs.get("timeout", self.timeout)))
return Results()
def analyse_entry(self, entry, params):
sleep(float(params.get("timeout", self.timeout)))
yield entry

View File

@@ -25,6 +25,8 @@ class BlueprintsTest(TestCase):
self.dir = os.path.join(os.path.dirname(__file__), "..")
self.senpy.add_folder(self.dir)
self.senpy.activate_plugin("Dummy", sync=True)
self.senpy.activate_plugin("DummyRequired", sync=True)
self.senpy.default_plugin = 'Dummy'
def assertCode(self, resp, code):
self.assertEqual(resp.status_code, code)
@@ -34,12 +36,12 @@ class BlueprintsTest(TestCase):
Calling with no arguments should ask the user for more arguments
"""
resp = self.client.get("/api/")
self.assertCode(resp, 404)
self.assertCode(resp, 400)
js = parse_resp(resp)
logging.debug(js)
assert js["status"] == 404
assert js["status"] == 400
atleast = {
"status": 404,
"status": 400,
"message": "Missing or invalid parameters",
}
assert check_dict(js, atleast)
@@ -56,6 +58,28 @@ class BlueprintsTest(TestCase):
assert "@context" in js
assert "entries" in js
def test_analysis_extra(self):
"""
Extra params that have a default should
"""
resp = self.client.get("/api/?i=My aloha mohame&algo=Dummy")
self.assertCode(resp, 200)
js = parse_resp(resp)
logging.debug("Got response: %s", js)
assert "@context" in js
assert "entries" in js
def test_analysis_extra_required(self):
"""
Extra params that have a required argument that does not
have a default should raise an error.
"""
resp = self.client.get("/api/?i=My aloha mohame&algo=DummyRequired")
self.assertCode(resp, 400)
js = parse_resp(resp)
logging.debug("Got response: %s", js)
assert isinstance(js, models.Error)
def test_error(self):
"""
The dummy plugin returns an empty response,\
@@ -102,7 +126,7 @@ class BlueprintsTest(TestCase):
js = parse_resp(resp)
logging.debug(js)
assert "@id" in js
assert js["@id"] == "Dummy_0.1"
assert js["@id"] == "plugins/Dummy_0.1"
def test_default(self):
""" Show only one plugin"""
@@ -111,7 +135,7 @@ class BlueprintsTest(TestCase):
js = parse_resp(resp)
logging.debug(js)
assert "@id" in js
assert js["@id"] == "Dummy_0.1"
assert js["@id"] == "plugins/Dummy_0.1"
def test_context(self):
resp = self.client.get("/api/contexts/context.jsonld")

View File

@@ -9,9 +9,10 @@ from senpy.models import Results, Error
class Call(dict):
def __init__(self, obj):
self.obj = obj.jsonld()
self.status_code = 200
self.content = self.json()
def json(self):
return self.obj
@@ -29,14 +30,14 @@ class ModelsTest(TestCase):
with patch('requests.request', return_value=success) as patched:
resp = client.analyse('hello')
assert isinstance(resp, Results)
patched.assert_called_with(url=endpoint + '/',
method='GET',
params={'input': 'hello'})
patched.assert_called_with(
url=endpoint + '/', method='GET', params={'input': 'hello'})
error = Call(Error('Nothing'))
with patch('requests.request', return_value=error) as patched:
resp = client.analyse(input='hello', algorithm='NONEXISTENT')
assert isinstance(resp, Error)
patched.assert_called_with(url=endpoint + '/',
method='GET',
params={'input': 'hello',
'algorithm': 'NONEXISTENT'})
patched.assert_called_with(
url=endpoint + '/',
method='GET',
params={'input': 'hello',
'algorithm': 'NONEXISTENT'})

View File

@@ -16,7 +16,7 @@ from unittest import TestCase
class ExtensionsTest(TestCase):
def setUp(self):
self.app = Flask("test_extensions")
self.app = Flask('test_extensions')
self.dir = os.path.join(os.path.dirname(__file__))
self.senpy = Senpy(plugin_folder=self.dir,
app=self.app,
@@ -45,7 +45,7 @@ class ExtensionsTest(TestCase):
'requirements': ['noop'],
'version': 0
}
root = os.path.join(self.dir, 'dummy_plugin')
root = os.path.join(self.dir, 'plugins', 'dummy_plugin')
name, module = self.senpy._load_plugin_from_info(info, root=root)
assert name == 'TestPip'
assert module
@@ -55,7 +55,7 @@ class ExtensionsTest(TestCase):
def test_installing(self):
""" Enabling a plugin """
self.senpy.activate_all(sync=True)
assert len(self.senpy.plugins) == 2
assert len(self.senpy.plugins) >= 3
assert self.senpy.plugins["Sleep"].is_activated
def test_disabling(self):
@@ -75,11 +75,12 @@ class ExtensionsTest(TestCase):
def test_noplugin(self):
""" Don't analyse if there isn't any plugin installed """
self.senpy.deactivate_all(sync=True)
self.assertRaises(Error, partial(self.senpy.analyse,
input="tupni"))
self.assertRaises(Error, partial(self.senpy.analyse,
input="tupni",
algorithm='Dummy'))
self.assertRaises(Error, partial(self.senpy.analyse, input="tupni"))
self.assertRaises(Error,
partial(
self.senpy.analyse,
input="tupni",
algorithm='Dummy'))
def test_analyse(self):
""" Using a plugin """
@@ -88,17 +89,20 @@ class ExtensionsTest(TestCase):
r1 = self.senpy.analyse(
algorithm="Dummy", input="tupni", output="tuptuo")
r2 = self.senpy.analyse(input="tupni", output="tuptuo")
assert r1.analysis[0].id[:5] == "Dummy"
assert r2.analysis[0].id[:5] == "Dummy"
assert r1.analysis[0] == "plugins/Dummy_0.1"
assert r2.analysis[0] == "plugins/Dummy_0.1"
assert r1.entries[0].text == 'input'
def test_analyse_error(self):
mm = mock.MagicMock()
mm.analyse.side_effect = Error('error on analysis', status=900)
mm.analyse_entry.side_effect = Error('error on analysis', status=900)
self.senpy.plugins['MOCK'] = mm
resp = self.senpy.analyse(input='nothing', algorithm='MOCK')
assert resp['message'] == 'error on analysis'
assert resp['status'] == 900
mm.analyse.side_effect = Exception('generic exception on analysis')
mm.analyse_entry.side_effect = Exception(
'generic exception on analysis')
resp = self.senpy.analyse(input='nothing', algorithm='MOCK')
assert resp['message'] == 'generic exception on analysis'
assert resp['status'] == 500
@@ -110,8 +114,7 @@ class ExtensionsTest(TestCase):
assert self.senpy.filter_plugins(name="Dummy", is_activated=True)
self.senpy.deactivate_plugin("Dummy", sync=True)
assert not len(
self.senpy.filter_plugins(
name="Dummy", is_activated=True))
self.senpy.filter_plugins(name="Dummy", is_activated=True))
def test_load_default_plugins(self):
senpy = Senpy(plugin_folder=self.dir, default_plugins=True)

View File

@@ -3,20 +3,25 @@ import logging
import jsonschema
import json
import rdflib
from unittest import TestCase
from senpy.models import Entry, Results, Sentiment, EmotionSet, Error
from senpy.models import (Emotion,
EmotionAnalysis,
EmotionSet,
Entry,
Error,
Results,
Sentiment)
from senpy.plugins import SenpyPlugin
from pprint import pprint
class ModelsTest(TestCase):
def test_jsonld(self):
prueba = {"id": "test",
"analysis": [],
"entries": []}
prueba = {"id": "test", "analysis": [], "entries": []}
r = Results(**prueba)
print("Response's context: ")
pprint(r.context)
pprint(r._context)
assert r.id == "test"
@@ -30,14 +35,11 @@ class ModelsTest(TestCase):
assert "id" not in j
r6 = Results(**prueba)
e = Entry({
"@id": "ohno",
"nif:isString": "Just testing"
})
e = Entry({"@id": "ohno", "nif:isString": "Just testing"})
r6.entries.append(e)
logging.debug("Reponse 6: %s", r6)
assert ("marl" in r6.context)
assert ("entries" in r6.context)
assert ("marl" in r6._context)
assert ("entries" in r6._context)
j6 = r6.jsonld(with_context=True)
logging.debug("jsonld: %s", j6)
assert ("@context" in j6)
@@ -113,5 +115,35 @@ class ModelsTest(TestCase):
s = str(r)
assert "_testing" not in s
def test_frame_response(self):
def test_turtle(self):
"""Any model should be serializable as a turtle file"""
ana = EmotionAnalysis()
res = Results()
res.analysis.append(ana)
entry = Entry(text='Just testing')
eSet = EmotionSet()
emotion = Emotion()
entry.emotions.append(eSet)
res.entries.append(entry)
eSet.onyx__hasEmotion.append(emotion)
eSet.prov__wasGeneratedBy = ana.id
triples = ('ana a :Analysis',
'entry a :entry',
' nif:isString "Just testing"',
' onyx:hasEmotionSet eSet',
'eSet a onyx:EmotionSet',
' prov:wasGeneratedBy ana',
' onyx:hasEmotion emotion',
'emotion a onyx:Emotion',
'res a :results',
' me:AnalysisInvoloved ana',
' prov:used entry')
t = res.serialize(format='turtle')
print(t)
g = rdflib.Graph().parse(data=t, format='turtle')
assert len(g) == len(triples)
def test_convert_emotions(self):
"""It should be possible to convert between different emotion models"""
pass

View File

@@ -77,6 +77,7 @@ class PluginsTest(TestCase):
})
a.activate()
assert a.shelf_file == self.shelf_file
res1 = a.analyse(input=1)
assert res1.entries[0].nif__isString == 1
res2 = a.analyse(input=1)
@@ -103,3 +104,19 @@ class PluginsTest(TestCase):
assert b.sh['a'] == 'fromA'
b.sh['a'] = 'fromB'
assert b.sh['a'] == 'fromB'
def test_extra_params(self):
''' Should be able to set extra parameters'''
a = ShelfDummyPlugin(info={
'name': 'shelve',
'version': 'test',
'shelf_file': self.shelf_file,
'extra_params': {
'example': {
'aliases': ['example', 'ex'],
'required': True,
'default': 'nonsense'
}
}
})
assert 'example' in a.extra_params