mirror of
https://github.com/gsi-upm/senpy
synced 2024-11-22 00:02:28 +00:00
Pre-0.8.6
* Improved debugging (back to using Flask's built-in mechanisms) * Recursive model loading from json * Added DEVPORT to Makefile * Accept json-ld input. Closes #16 * Improved Exception handling in client * Modified default plugin selection to only include analysis plugins * More tests
This commit is contained in:
parent
cc298742ec
commit
0c8f98d466
5
Makefile
5
Makefile
@ -6,6 +6,7 @@ VERSION=$(shell git describe --tags --dirty 2>/dev/null)
|
||||
TARNAME=$(NAME)-$(VERSION).tar.gz
|
||||
IMAGENAME=$(REPO)/$(NAME)
|
||||
IMAGEWTAG=$(IMAGENAME):$(VERSION)
|
||||
DEVPORT=5000
|
||||
action="test-${PYMAIN}"
|
||||
|
||||
all: build run
|
||||
@ -43,7 +44,7 @@ quick_test: $(addprefix test-,$(PYMAIN))
|
||||
dev-%:
|
||||
@docker start $(NAME)-dev$* || (\
|
||||
$(MAKE) build-$*; \
|
||||
docker run -d -w /usr/src/app/ -v $$PWD:/usr/src/app --entrypoint=/bin/bash -ti --name $(NAME)-dev$* '$(IMAGEWTAG)-python$*'; \
|
||||
docker run -d -w /usr/src/app/ -p $(DEVPORT):5000 -v $$PWD:/usr/src/app --entrypoint=/bin/bash -ti --name $(NAME)-dev$* '$(IMAGEWTAG)-python$*'; \
|
||||
)\
|
||||
|
||||
docker exec -ti $(NAME)-dev$* bash
|
||||
@ -86,7 +87,7 @@ pip_upload:
|
||||
python setup.py sdist upload ;
|
||||
|
||||
run-%: build-%
|
||||
docker run --rm -p 5000:5000 -ti '$(IMAGEWTAG)-python$(PYMAIN)' --default-plugins
|
||||
docker run --rm -p $(DEVPORT):5000 -ti '$(IMAGEWTAG)-python$(PYMAIN)' --default-plugins
|
||||
|
||||
run: run-$(PYMAIN)
|
||||
|
||||
|
@ -26,7 +26,6 @@ from gevent.wsgi import WSGIServer
|
||||
from gevent.monkey import patch_all
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import senpy
|
||||
|
||||
@ -35,22 +34,6 @@ patch_all(thread=False)
|
||||
SERVER_PORT = os.environ.get("PORT", 5000)
|
||||
|
||||
|
||||
def info(type, value, tb):
|
||||
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
|
||||
# we are in interactive mode or we don't have a tty-like
|
||||
# device, so we call the default hook
|
||||
sys.__excepthook__(type, value, tb)
|
||||
else:
|
||||
import traceback
|
||||
import pdb
|
||||
# we are NOT in interactive mode, print the exception...
|
||||
traceback.print_exception(type, value, tb)
|
||||
print
|
||||
# ...then start the debugger in post-mortem mode.
|
||||
# pdb.pm() # deprecated
|
||||
pdb.post_mortem(tb) # more "modern"
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Run a Senpy server')
|
||||
parser.add_argument(
|
||||
@ -100,22 +83,25 @@ def main():
|
||||
rl.setLevel(getattr(logging, args.level))
|
||||
app = Flask(__name__)
|
||||
app.debug = args.debug
|
||||
if args.debug:
|
||||
sys.excepthook = info
|
||||
sp = Senpy(app, args.plugins_folder, default_plugins=args.default_plugins)
|
||||
if args.only_install:
|
||||
sp.install_deps()
|
||||
return
|
||||
sp.activate_all()
|
||||
http_server = WSGIServer((args.host, args.port), app)
|
||||
try:
|
||||
print('Senpy version {}'.format(senpy.__version__))
|
||||
print('Server running on port %s:%d. Ctrl+C to quit' % (args.host,
|
||||
args.port))
|
||||
if not app.debug:
|
||||
http_server = WSGIServer((args.host, args.port), app)
|
||||
try:
|
||||
http_server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print('Bye!')
|
||||
http_server.stop()
|
||||
else:
|
||||
app.run(args.host,
|
||||
args.port,
|
||||
debug=True)
|
||||
sp.deactivate_all()
|
||||
|
||||
|
||||
|
@ -70,7 +70,7 @@ NIF_PARAMS = {
|
||||
"aliases": ["f", "informat"],
|
||||
"required": False,
|
||||
"default": "text",
|
||||
"options": ["turtle", "text"],
|
||||
"options": ["turtle", "text", "json-ld"],
|
||||
},
|
||||
"intype": {
|
||||
"@id": "intype",
|
||||
|
@ -92,6 +92,9 @@ def basic_api(f):
|
||||
response = f(*args, **kwargs)
|
||||
except Error as ex:
|
||||
response = ex
|
||||
logger.error(ex)
|
||||
if current_app.debug:
|
||||
raise
|
||||
|
||||
in_headers = web_params['inHeaders'] != "0"
|
||||
expanded = api_params['expanded-jsonld']
|
||||
@ -113,11 +116,8 @@ def basic_api(f):
|
||||
@api_blueprint.route('/', methods=['POST', 'GET'])
|
||||
@basic_api
|
||||
def api():
|
||||
try:
|
||||
response = current_app.senpy.analyse(**request.params)
|
||||
return response
|
||||
except Error as ex:
|
||||
return ex
|
||||
|
||||
|
||||
@api_blueprint.route('/plugins/', methods=['POST', 'GET'])
|
||||
|
@ -7,7 +7,7 @@ standard_library.install_aliases()
|
||||
|
||||
from . import plugins
|
||||
from .plugins import SenpyPlugin
|
||||
from .models import Error, Entry, Results, from_dict
|
||||
from .models import Error, Entry, Results, from_string
|
||||
from .blueprints import api_blueprint, demo_blueprint, ns_blueprint
|
||||
from .api import API_PARAMS, NIF_PARAMS, parse_params
|
||||
|
||||
@ -128,7 +128,7 @@ class Senpy(object):
|
||||
entry = Entry(text=params['input'])
|
||||
results.entries.append(entry)
|
||||
elif params['informat'] == 'json-ld':
|
||||
results = from_dict(params['input'])
|
||||
results = from_string(params['input'], cls=Results)
|
||||
else:
|
||||
raise NotImplemented('Informat {} is not implemented'.format(params['informat']))
|
||||
return results
|
||||
@ -171,7 +171,7 @@ class Senpy(object):
|
||||
except (Error, Exception) as ex:
|
||||
if not isinstance(ex, Error):
|
||||
ex = Error(message=str(ex), status=500)
|
||||
logger.exception('Error returning analysis result')
|
||||
logger.error('Error returning analysis result')
|
||||
raise ex
|
||||
return resp
|
||||
|
||||
@ -236,7 +236,8 @@ class Senpy(object):
|
||||
def default_plugin(self):
|
||||
candidate = self._default
|
||||
if not candidate:
|
||||
candidates = self.filter_plugins(is_activated=True)
|
||||
candidates = self.filter_plugins(plugin_type='analysisPlugin',
|
||||
is_activated=True)
|
||||
if len(candidates) > 0:
|
||||
candidate = list(candidates.values())[0]
|
||||
logger.debug("Default: {}".format(candidate))
|
||||
|
@ -214,6 +214,7 @@ class BaseModel(SenpyMixin, dict):
|
||||
temp['@type'] = getattr(self, '@type')
|
||||
except AttributeError:
|
||||
logger.warn('Creating an instance of an unknown model')
|
||||
|
||||
super(BaseModel, self).__init__(temp)
|
||||
|
||||
def _get_key(self, key):
|
||||
@ -252,13 +253,32 @@ def register(rsubclass, rtype=None):
|
||||
_subtypes[rtype or rsubclass.__name__] = rsubclass
|
||||
|
||||
|
||||
def from_dict(indict):
|
||||
def from_dict(indict, cls=None):
|
||||
if not cls:
|
||||
target = indict.get('@type', None)
|
||||
try:
|
||||
if target and target in _subtypes:
|
||||
cls = _subtypes[target]
|
||||
else:
|
||||
cls = BaseModel
|
||||
return cls(**indict)
|
||||
except Exception:
|
||||
cls = BaseModel
|
||||
outdict = dict()
|
||||
for k, v in indict.items():
|
||||
if k == '@context':
|
||||
pass
|
||||
elif isinstance(v, dict):
|
||||
v = from_dict(indict[k])
|
||||
elif isinstance(v, list):
|
||||
for ix, v2 in enumerate(v):
|
||||
if isinstance(v2, dict):
|
||||
v[ix] = from_dict(v2)
|
||||
outdict[k] = v
|
||||
return cls(**outdict)
|
||||
|
||||
|
||||
def from_string(string, **kwargs):
|
||||
return from_dict(json.loads(string), **kwargs)
|
||||
|
||||
|
||||
def from_json(injson):
|
||||
@ -308,7 +328,7 @@ for i in [
|
||||
_ErrorModel = from_schema('error')
|
||||
|
||||
|
||||
class Error(SenpyMixin, BaseException):
|
||||
class Error(SenpyMixin, Exception):
|
||||
def __init__(self, message, *args, **kwargs):
|
||||
super(Error, self).__init__(self, message, message)
|
||||
self._error = _ErrorModel(message=message, *args, **kwargs)
|
||||
|
@ -19,6 +19,7 @@ def parse_resp(resp):
|
||||
class BlueprintsTest(TestCase):
|
||||
def setUp(self):
|
||||
self.app = Flask("test_extensions")
|
||||
self.app.debug = False
|
||||
self.client = self.app.test_client()
|
||||
self.senpy = Senpy()
|
||||
self.senpy.init_app(self.app)
|
||||
|
@ -96,6 +96,27 @@ class ExtensionsTest(TestCase):
|
||||
assert r2.analysis[0] == "plugins/Dummy_0.1"
|
||||
assert r1.entries[0].text == 'input'
|
||||
|
||||
def test_analyse_jsonld(self):
|
||||
""" Using a plugin with JSON-LD input"""
|
||||
js_input = '''{
|
||||
"@id": "prueba",
|
||||
"@type": "results",
|
||||
"entries": [
|
||||
{"@id": "entry1",
|
||||
"text": "tupni",
|
||||
"@type": "entry"
|
||||
}
|
||||
]
|
||||
}'''
|
||||
r1 = self.senpy.analyse(algorithm="Dummy",
|
||||
input=js_input,
|
||||
informat="json-ld",
|
||||
output="tuptuo")
|
||||
r2 = self.senpy.analyse(input="tupni", output="tuptuo")
|
||||
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.id = 'magic_mock'
|
||||
|
@ -13,7 +13,9 @@ from senpy.models import (Emotion,
|
||||
Results,
|
||||
Sentiment,
|
||||
Plugins,
|
||||
Plugin)
|
||||
Plugin,
|
||||
from_string,
|
||||
from_dict)
|
||||
from senpy import plugins
|
||||
from pprint import pprint
|
||||
|
||||
@ -167,3 +169,22 @@ class ModelsTest(TestCase):
|
||||
assert isinstance(plugs.plugins, list)
|
||||
js = plugs.jsonld()
|
||||
assert isinstance(js['plugins'], list)
|
||||
|
||||
def test_from_string(self):
|
||||
results = {
|
||||
'@type': 'results',
|
||||
'@id': 'prueba',
|
||||
'entries': [{
|
||||
'@id': 'entry1',
|
||||
'@type': 'entry',
|
||||
'text': 'TEST'
|
||||
}]
|
||||
}
|
||||
recovered = from_dict(results)
|
||||
assert isinstance(recovered, Results)
|
||||
assert isinstance(recovered.entries[0], Entry)
|
||||
|
||||
string = json.dumps(results)
|
||||
recovered = from_string(string)
|
||||
assert isinstance(recovered, Results)
|
||||
assert isinstance(recovered.entries[0], Entry)
|
||||
|
Loading…
Reference in New Issue
Block a user