1
0
mirror of https://github.com/gsi-upm/senpy synced 2024-11-14 12:42:27 +00:00
senpy/tests/test_extensions.py
J. Fernando Sánchez 21a5a3f201 Macro commit
* Fixed Options for extra_params in UI
* Enhanced meta-programming for models
* Plugins can be imported from a python file if they're named
`senpy_<whatever>.py>` (no need for `.senpy` anymore!)
* Add docstings and tests to most plugins
* Read plugin description from the docstring
* Refactor code to get rid of unnecessary `.senpy`s
* Load models, plugins and utils into the main namespace (see __init__.py)
* Enhanced plugin development/experience with utils (easy_test, easy_serve)
* Fix bug in check_template that wouldn't check objects
* Make model defaults a private variable
* Add option to list loaded plugins in CLI
* Update docs
2018-01-06 21:03:20 +01:00

239 lines
8.4 KiB
Python

from __future__ import print_function
import os
from copy import deepcopy
import logging
try:
from unittest import mock
except ImportError:
import mock
from functools import partial
from senpy.extensions import Senpy
from senpy import plugins
from senpy.models import Error, Results, Entry, EmotionSet, Emotion, Plugin
from senpy import api
from flask import Flask
from unittest import TestCase
def analyse(instance, **kwargs):
request = api.parse_call(kwargs)
return instance.analyse(request)
class ExtensionsTest(TestCase):
def setUp(self):
self.app = Flask('test_extensions')
self.examples_dir = os.path.join(os.path.dirname(__file__), '..', 'example-plugins')
self.senpy = Senpy(plugin_folder=self.examples_dir,
app=self.app,
default_plugins=False)
self.senpy.deactivate_all()
self.senpy.activate_plugin("Dummy", sync=True)
def test_init(self):
""" Initialising the app with the extension. """
assert hasattr(self.app, "senpy")
tapp = Flask("temp app")
self.senpy.init_app(tapp)
assert hasattr(tapp, "senpy")
def test_discovery(self):
""" Discovery of plugins in given folders. """
# noinspection PyProtectedMember
print(self.senpy.plugins())
assert self.senpy.get_plugin("dummy")
def test_add_delete(self):
'''Should be able to add and delete new plugins. '''
new = plugins.Plugin(name='new', description='new', version=0)
self.senpy.add_plugin(new)
assert new in self.senpy.plugins()
self.senpy.delete_plugin(new)
assert new not in self.senpy.plugins()
def test_adding_folder(self):
""" It should be possible for senpy to look for plugins in more folders. """
senpy = Senpy(plugin_folder=None,
app=self.app,
default_plugins=False)
assert not senpy.analysis_plugins
senpy.add_folder(self.examples_dir)
assert senpy.analysis_plugins
self.assertRaises(AttributeError, senpy.add_folder, 'DOES NOT EXIST')
def test_installing(self):
""" Installing a plugin """
info = {
'name': 'TestPip',
'module': 'mynoop',
'description': None,
'requirements': ['noop'],
'version': 0
}
module = plugins.from_info(info, root=self.examples_dir, install=True)
assert module.name == 'TestPip'
assert module
import noop
dir(noop)
def test_enabling(self):
""" Enabling a plugin """
self.senpy.activate_all(sync=True)
assert len(self.senpy.plugins()) >= 3
assert self.senpy.get_plugin("Sleep").is_activated
def test_installing_nonexistent(self):
""" Fail if the dependencies cannot be met """
info = {
'name': 'TestPipFail',
'module': 'dummy',
'description': None,
'requirements': ['IAmMakingThisPackageNameUpToFail'],
'version': 0
}
with self.assertRaises(Error):
plugins.install_deps(info)
def test_disabling(self):
""" Disabling a plugin """
self.senpy.deactivate_all(sync=True)
assert not self.senpy.get_plugin("dummy").is_activated
assert not self.senpy.get_plugin("sleep").is_activated
def test_default(self):
""" Default plugin should be set """
assert self.senpy.default_plugin
assert self.senpy.default_plugin.name == "Dummy"
self.senpy.deactivate_all(sync=True)
logging.debug("Default: {}".format(self.senpy.default_plugin))
assert self.senpy.default_plugin is None
def test_noplugin(self):
""" Don't analyse if there isn't any plugin installed """
self.senpy.deactivate_all(sync=True)
self.assertRaises(Error, partial(analyse, self.senpy, input="tupni"))
def test_analyse(self):
""" Using a plugin """
# I was using mock until plugin started inheriting
# Leaf (defaultdict with __setattr__ and __getattr__.
r1 = analyse(self.senpy, algorithm="Dummy", input="tupni", output="tuptuo")
r2 = analyse(self.senpy, input="tupni", output="tuptuo")
assert r1.analysis[0] == "plugins/Dummy_0.1"
assert r2.analysis[0] == "plugins/Dummy_0.1"
assert r1.entries[0]['nif:isString'] == 'input'
def test_analyse_empty(self):
""" Trying to analyse when no plugins are installed should raise an error."""
senpy = Senpy(plugin_folder=None,
app=self.app,
default_plugins=False)
self.assertRaises(Error, senpy.analyse, Results())
def test_analyse_wrong(self):
""" Trying to analyse with a non-existent plugin should raise an error."""
self.assertRaises(Error, analyse, self.senpy, algorithm='DOES NOT EXIST', input='test')
def test_analyse_jsonld(self):
""" Using a plugin with JSON-LD input"""
js_input = '''{
"@id": "prueba",
"@type": "results",
"entries": [
{"@id": "entry1",
"nif:isString": "tupni",
"@type": "entry"
}
]
}'''
r1 = analyse(self.senpy,
algorithm="Dummy",
input=js_input,
informat="json-ld",
output="tuptuo")
r2 = analyse(self.senpy,
input="tupni",
output="tuptuo")
assert r1.analysis[0] == "plugins/Dummy_0.1"
assert r2.analysis[0] == "plugins/Dummy_0.1"
assert r1.entries[0]['nif:isString'] == 'input'
def test_analyse_error(self):
mm = mock.MagicMock()
mm.id = 'magic_mock'
mm.name = 'mock'
mm.is_activated = True
mm.analyse_entries.side_effect = Error('error in analysis', status=500)
self.senpy.add_plugin(mm)
try:
analyse(self.senpy, input='nothing', algorithm='MOCK')
assert False
except Error as ex:
assert 'error in analysis' in ex['message']
assert ex['status'] == 500
ex = Exception('generic exception on analysis')
mm.analyse.side_effect = ex
mm.analyse_entries.side_effect = ex
try:
analyse(self.senpy, input='nothing', algorithm='MOCK')
assert False
except Exception as ex:
assert 'generic exception on analysis' in ex['message']
assert ex['status'] == 500
def test_filtering(self):
""" Filtering plugins """
assert len(self.senpy.plugins(name="Dummy")) > 0
assert not len(self.senpy.plugins(name="NotDummy"))
assert self.senpy.plugins(name="Dummy", is_activated=True)
self.senpy.deactivate_plugin("Dummy", sync=True)
assert not len(self.senpy.plugins(name="Dummy",
is_activated=True))
def test_load_default_plugins(self):
senpy = Senpy(plugin_folder=self.examples_dir, default_plugins=True)
assert len(senpy.plugins()) > 1
def test_convert_emotions(self):
self.senpy.activate_all(sync=True)
plugin = Plugin({
'id': 'imaginary',
'onyx:usesEmotionModel': 'emoml:fsre-dimensions'
})
eSet1 = EmotionSet()
eSet1.prov__wasGeneratedBy = plugin['@id']
eSet1['onyx:hasEmotion'].append(Emotion({
'emoml:arousal': 1,
'emoml:potency': 0,
'emoml:valence': 0
}))
response = Results({
'analysis': [{'plugin': plugin}],
'entries': [Entry({
'nif:isString': 'much ado about nothing',
'emotions': [eSet1]
})]
})
params = {'emotionModel': 'emoml:big6',
'conversion': 'full'}
r1 = deepcopy(response)
r1.parameters = params
self.senpy.convert_emotions(r1)
assert len(r1.entries[0].emotions) == 2
params['conversion'] = 'nested'
r2 = deepcopy(response)
r2.parameters = params
self.senpy.convert_emotions(r2)
assert len(r2.entries[0].emotions) == 1
assert r2.entries[0].emotions[0]['prov:wasDerivedFrom'] == eSet1
params['conversion'] = 'filtered'
r3 = deepcopy(response)
r3.parameters = params
self.senpy.convert_emotions(r3)
assert len(r3.entries[0].emotions) == 1
r3.jsonld()