Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ff002c818a | ||
|
79d6b6f67f | ||
|
b8993f7d64 | ||
|
bd2e0f0d5c | ||
|
7de5b41340 | ||
|
a63e9209fd | ||
|
b0eb2e0628 | ||
|
60415f8217 | ||
|
724eac38d8 | ||
|
8fa372de15 | ||
|
a1ffe04a30 | ||
|
74b0cf868e | ||
|
50e8e2730b | ||
|
b484b453e0 | ||
|
7c2e0ddec7 | ||
|
384aba4654 | ||
|
a857dd3042 | ||
|
b1b672f66d | ||
|
09d9143a82 | ||
|
c1a6b57ac5 | ||
|
6b78b7ccc7 | ||
|
f0b1cfcba6 | ||
|
4bcd046016 | ||
|
ae09f609c2 |
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*.pyc
|
||||
.*
|
||||
*egg-info
|
||||
dist
|
||||
README.html
|
6
.travis.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
install: "pip install -r requirements.txt"
|
||||
# run nosetests - Tests
|
||||
script: nosetests
|
3
Dockerfile
Normal file
@@ -0,0 +1,3 @@
|
||||
from python:2.7-onbuild
|
||||
|
||||
ENTRYPOINT ["python", "-m", "senpy"]
|
@@ -1,4 +1,5 @@
|
||||
include requirements.txt
|
||||
include test-requirements.txt
|
||||
include README.md
|
||||
include senpy/context.jsonld
|
||||
recursive-include *.senpy
|
||||
graft senpy/plugins
|
||||
|
19
README.md
@@ -1,19 +0,0 @@
|
||||

|
||||
[Senpy](http://senpy.herokuapp.com)
|
||||
=========================================
|
||||
Example endpoint that yields results compatible with the EUROSENTIMENT format and exposes the NIF API.
|
||||
It can be used as a template to adapt existing services to EUROSENTIMENT or to create new services.
|
||||
|
||||
[DEMO on Heroku](http://eurosentiment-endpoint.herokuapp.com)
|
||||
|
||||
This endpoint serves as bootcampt for any developer wishing to build applications that use the EUROSENTIMENT services.
|
||||
|
||||
Acknowledgement
|
||||
---------------
|
||||
EUROSENTIMENT PROJECT
|
||||
Grant Agreement no: 296277
|
||||
Starting date: 01/09/2012
|
||||
Project duration: 24 months
|
||||
|
||||

|
||||

|
91
README.rst
Normal file
@@ -0,0 +1,91 @@
|
||||
.. image:: img/header.png
|
||||
:height: 6em
|
||||
:target: http://demos.gsi.dit.upm.es/senpy
|
||||
|
||||
.. image:: https://travis-ci.org/gsi-upm/senpy.svg?branch=master
|
||||
:target: https://travis-ci.org/gsi-upm/senpy
|
||||
|
||||
Senpy lets you create sentiment analysis web services easily, fast and using a well known API.
|
||||
As a bonus, senpy services use semantic vocabularies (e.g. `NIF <http://persistence.uni-leipzig.org/nlp2rdf/>`_, `Marl <http://www.gsi.dit.upm.es/ontologies/marl>`_, `Onyx <http://www.gsi.dit.upm.es/ontologies/onyx>`_) and formats (turtle, JSON-LD, xml-rdf).
|
||||
|
||||
Have you ever wanted to turn your sentiment analysis algorithms into a service?
|
||||
With senpy, now you can.
|
||||
It provides all the tools so you just have to worry about improving your algorithms:
|
||||
|
||||
`See it in action. <http://demos.gsi.dit.upm.es/senpy>`_
|
||||
|
||||
Installation
|
||||
------------
|
||||
The stable version can be installed in three ways.
|
||||
|
||||
Through PIP
|
||||
***********
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pip install --user senpy
|
||||
|
||||
|
||||
Alternatively, you can use the development version:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git clone git@github.com:gsi-upm/senpy
|
||||
cd senpy
|
||||
pip install --user .
|
||||
|
||||
If you want to install senpy globally, use sudo instead of the ``--user`` flag.
|
||||
|
||||
Docker Image
|
||||
************
|
||||
Build the image or use the pre-built one: ``docker run -ti -p 5000:5000 balkian/senpy --host 0.0.0.0 --default-plugins``.
|
||||
|
||||
To add custom plugins, add a volume and tell senpy where to find the plugins: ``docker run -ti -p 5000:5000 -v <PATH OF PLUGINS>:/plugins balkian/senpy --host 0.0.0.0 --default-plugins -f /plugins``
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
However, the easiest and recommended way is to just use the command-line tool to load your plugins and launch the server.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
senpy
|
||||
|
||||
or, alternatively:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
python -m senpy
|
||||
|
||||
|
||||
This will create a server with any modules found in the current path.
|
||||
For more options, see the `--help` page.
|
||||
|
||||
Alternatively, you can use the modules included in senpy to build your own application.
|
||||
|
||||
Deploying on Heroku
|
||||
-------------------
|
||||
Use a free heroku instance to share your service with the world.
|
||||
Just use the example Procfile in this repository, or build your own.
|
||||
|
||||
|
||||
`DEMO on heroku <http://senpy.herokuapp.com>`_
|
||||
|
||||
|
||||
For more information, check out the `documentation <http://senpy.readthedocs.org>`_.
|
||||
------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Acknowledgement
|
||||
---------------
|
||||
This development has been partially funded by the European Union through the MixedEmotions Project (project number H2020 655632), as part of the `RIA ICT 15 Big data and Open Data Innovation and take-up` programme.
|
||||
|
||||
|
||||
.. image:: img/me.png
|
||||
:target: http://mixedemotions-project.eu
|
||||
:height: 100px
|
||||
:alt: MixedEmotions Logo
|
||||
|
||||
.. image:: img/eu-flag.jpg
|
||||
:height: 100px
|
||||
:target: http://ec.europa.eu/research/participants/portal/desktop/en/opportunities/index.html
|
4
app.py
@@ -19,7 +19,7 @@ This is a helper for development. If you want to run Senpy use:
|
||||
|
||||
python -m senpy
|
||||
"""
|
||||
from gevent.monkey import patch_all patch_all()
|
||||
from gevent.monkey import patch_all; patch_all()
|
||||
import gevent
|
||||
import config
|
||||
from flask import Flask
|
||||
@@ -32,7 +32,7 @@ logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
app = Flask(__name__)
|
||||
mypath = os.path.dirname(os.path.realpath(__file__))
|
||||
sp = Senpy(app, os.path.join(mypath, "plugins"))
|
||||
sp = Senpy(app, os.path.join(mypath, "plugins"), default_plugins=True)
|
||||
sp.activate_all()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
1
docs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_build
|
177
docs/Makefile
Normal file
@@ -0,0 +1,177 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Senpy.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Senpy.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Senpy"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Senpy"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
208
docs/api.rst
Normal file
@@ -0,0 +1,208 @@
|
||||
NIF API
|
||||
=======
|
||||
.. http:get:: /api
|
||||
|
||||
Basic endpoint for sentiment/emotion analysis.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api?input=I%20love%20GSI HTTP/1.1
|
||||
Host: localhost
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: text/javascript
|
||||
|
||||
{
|
||||
"@context": [
|
||||
"http://127.0.0.1/static/context.jsonld",
|
||||
],
|
||||
"analysis": [
|
||||
{
|
||||
"@id": "SentimentAnalysisExample",
|
||||
"@type": "marl:SentimentAnalysis",
|
||||
"dc:language": "en",
|
||||
"marl:maxPolarityValue": 10.0,
|
||||
"marl:minPolarityValue": 0.0
|
||||
}
|
||||
],
|
||||
"domain": "wndomains:electronics",
|
||||
"entries": [
|
||||
{
|
||||
"opinions": [
|
||||
{
|
||||
"prov:generatedBy": "SentimentAnalysisExample",
|
||||
"marl:polarityValue": 7.8,
|
||||
"marl:hasPolarity": "marl:Positive",
|
||||
"marl:describesObject": "http://www.gsi.dit.upm.es",
|
||||
}
|
||||
],
|
||||
"nif:isString": "I love GSI",
|
||||
"strings": [
|
||||
{
|
||||
"nif:anchorOf": "GSI",
|
||||
"nif:taIdentRef": "http://www.gsi.dit.upm.es"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query i input: No default. Depends on informat and intype
|
||||
:query f informat: one of `turtle` (default), `text`, `json-ld`
|
||||
:query t intype: one of `direct` (default), `url`
|
||||
:query o outformat: one of `turtle` (default), `text`, `json-ld`
|
||||
:query p prefix: prefix for the URIs
|
||||
:query algo algorithm: algorithm/plugin to use for the analysis. For a list of options, see :http:get:`/api/plugins`. If not provided, the default plugin will be used (:http:get:`/api/plugins/default`).
|
||||
|
||||
:reqheader Accept: the response content type depends on
|
||||
:mailheader:`Accept` header
|
||||
:resheader Content-Type: this depends on :mailheader:`Accept`
|
||||
header of request
|
||||
:statuscode 200: no error
|
||||
:statuscode 404: service not found
|
||||
|
||||
.. http:post:: /api
|
||||
|
||||
The same as :http:get:`/api`.
|
||||
|
||||
.. http:get:: /api/plugins
|
||||
|
||||
Returns a list of installed plugins.
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/plugins HTTP/1.1
|
||||
Host: localhost
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
{
|
||||
"@context": {
|
||||
...
|
||||
},
|
||||
"sentiment140": {
|
||||
"name": "sentiment140",
|
||||
"is_activated": true,
|
||||
"version": "0.1",
|
||||
"extra_params": {
|
||||
"@id": "extra_params_sentiment140_0.1",
|
||||
"language": {
|
||||
"required": false,
|
||||
"@id": "lang_sentiment140",
|
||||
"options": [
|
||||
"es",
|
||||
"en",
|
||||
"auto"
|
||||
],
|
||||
"aliases": [
|
||||
"language",
|
||||
"l"
|
||||
]
|
||||
}
|
||||
},
|
||||
"@id": "sentiment140_0.1"
|
||||
},
|
||||
"rand": {
|
||||
"name": "rand",
|
||||
"is_activated": true,
|
||||
"version": "0.1",
|
||||
"extra_params": {
|
||||
"@id": "extra_params_rand_0.1",
|
||||
"language": {
|
||||
"required": false,
|
||||
"@id": "lang_rand",
|
||||
"options": [
|
||||
"es",
|
||||
"en",
|
||||
"auto"
|
||||
],
|
||||
"aliases": [
|
||||
"language",
|
||||
"l"
|
||||
]
|
||||
}
|
||||
},
|
||||
"@id": "rand_0.1"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. http:get:: /api/plugins/<pluginname>
|
||||
|
||||
Returns the information of a specific plugin.
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/plugins/rand HTTP/1.1
|
||||
Host: localhost
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
{
|
||||
"@id": "rand_0.1",
|
||||
"extra_params": {
|
||||
"@id": "extra_params_rand_0.1",
|
||||
"language": {
|
||||
"@id": "lang_rand",
|
||||
"aliases": [
|
||||
"language",
|
||||
"l"
|
||||
],
|
||||
"options": [
|
||||
"es",
|
||||
"en",
|
||||
"auto"
|
||||
],
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"is_activated": true,
|
||||
"name": "rand",
|
||||
"version": "0.1"
|
||||
}
|
||||
|
||||
|
||||
.. http:get:: /api/plugins/default
|
||||
|
||||
Return the information about the default plugin.
|
||||
|
||||
.. http:get:: /api/plugins/<pluginname>/{de}activate
|
||||
|
||||
{De}activate a plugin.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/plugins/rand/deactivate HTTP/1.1
|
||||
Host: localhost
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
{
|
||||
"@context": {},
|
||||
"message": "Ok"
|
||||
}
|
272
docs/conf.py
Normal file
@@ -0,0 +1,272 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Senpy documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Feb 24 08:57:32 2015.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.todo',
|
||||
'sphinxcontrib.httpdomain',
|
||||
'sphinx.ext.coverage',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Senpy'
|
||||
copyright = u'2015, J. Fernando Sánchez'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.4'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.4'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
else:
|
||||
html_theme = 'default'
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Senpydoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
('index', 'Senpy.tex', u'Senpy Documentation',
|
||||
u'J. Fernando Sánchez', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'senpy', u'Senpy Documentation',
|
||||
[u'J. Fernando Sánchez'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'Senpy', u'Senpy Documentation',
|
||||
u'J. Fernando Sánchez', 'Senpy', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
16
docs/index.rst
Normal file
@@ -0,0 +1,16 @@
|
||||
.. Senpy documentation master file, created by
|
||||
sphinx-quickstart on Tue Feb 24 08:57:32 2015.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Senpy's documentation!
|
||||
=================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
installation
|
||||
usage
|
||||
api
|
||||
plugins
|
||||
:maxdepth: 2
|
27
docs/installation.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
Installation
|
||||
------------
|
||||
The stable version can be installed in three ways.
|
||||
|
||||
Through PIP
|
||||
***********
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pip install --user senpy
|
||||
|
||||
|
||||
Alternatively, you can use the development version:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git clone git@github.com:gsi-upm/senpy
|
||||
cd senpy
|
||||
pip install --user .
|
||||
|
||||
If you want to install senpy globally, use sudo instead of the ``--user`` flag.
|
||||
|
||||
Docker Image
|
||||
************
|
||||
Build the image or use the pre-built one: ``docker run -ti -p 5000:5000 balkian/senpy --host 0.0.0.0 --default-plugins``.
|
||||
|
||||
To add custom plugins, add a volume and tell senpy where to find the plugins: ``docker run -ti -p 5000:5000 -v <PATH OF PLUGINS>:/plugins balkian/senpy --host 0.0.0.0 --default-plugins -f /plugins``
|
48
docs/plugins.rst
Normal file
@@ -0,0 +1,48 @@
|
||||
Developing new plugins
|
||||
----------------------
|
||||
|
||||
Plugins Interface
|
||||
=================
|
||||
|
||||
The basic methods in a plugin are:
|
||||
|
||||
* __init__
|
||||
* activate: used to load memory-hungry resources
|
||||
* deactivate: used to free up resources
|
||||
|
||||
Plugins are loaded asynchronously, so don't worry if the activate method takes too long. The plugin will be marked as activated once it is finished executing the method.
|
||||
|
||||
F.A.Q.
|
||||
======
|
||||
If I'm using a classifier, where should I train the classifier?
|
||||
???????????????????????????????????????????????????????????????
|
||||
|
||||
Training a classifier can be time time consuming. To avoid running the training unnecessarily, you can use ShelfMixin to store the classifier. For instance:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from senpy.plugins import ShelfMixin, SenpyPlugin
|
||||
|
||||
class MyPlugin(ShelfMixin, SenpyPlugin):
|
||||
def train(self):
|
||||
''' Code to train the classifier
|
||||
'''
|
||||
# Here goes the code
|
||||
# ...
|
||||
return classifier
|
||||
|
||||
def activate(self):
|
||||
if 'classifier' not in self.sh:
|
||||
classifier = self.train()
|
||||
self.sh['classifier'] = classifier
|
||||
self.classifier = self.sh['classifier']
|
||||
|
||||
def deactivate(self):
|
||||
self.close()
|
||||
|
||||
You can speficy a 'shelf_file' in your .senpy file. By default the ShelfMixin creates a file based on the plugin name and stores it in that plugin's folder.
|
||||
|
||||
Where can I find more code examples?
|
||||
????????????????????????????????????
|
||||
|
||||
See: `<http://github.com/gsi-upm/senpy-plugins-community>`_.
|
1
docs/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
sphinxcontrib-httpdomain>=1.4
|
20
docs/usage.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
Usage
|
||||
-----
|
||||
|
||||
The easiest and recommended way is to just use the command-line tool to load your plugins and launch the server.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
senpy
|
||||
|
||||
Or, alternatively:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
python -m senpy
|
||||
|
||||
|
||||
This will create a server with any modules found in the current path.
|
||||
For more options, see the `--help` page.
|
||||
|
||||
Alternatively, you can use the modules included in senpy to build your own application.
|
BIN
img/eu-flag.jpg
Normal file
After Width: | Height: | Size: 5.6 KiB |
828
img/final-logo.svg
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
img/gsi.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
img/header.png
Normal file
After Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
2728
img/logo.svg
Normal file
After Width: | Height: | Size: 180 KiB |
BIN
img/logo_grande.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
img/me.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
logo_fp7.gif
Normal file
After Width: | Height: | Size: 5.1 KiB |
@@ -1,7 +1,7 @@
|
||||
Flask==0.10.1
|
||||
gunicorn==19.0.0
|
||||
requests==2.4.1
|
||||
GitPython==0.3.2.RC1
|
||||
Yapsy>=1.10.423
|
||||
Flask>=0.10.1
|
||||
gunicorn>=19.0.0
|
||||
requests>=2.4.1
|
||||
GitPython>=0.3.2.RC1
|
||||
gevent>=1.0.1
|
||||
PyLD>=0.6.5
|
||||
Flask-Testing>=0.4.2
|
||||
|
@@ -17,7 +17,3 @@
|
||||
"""
|
||||
Sentiment analysis server in Python
|
||||
"""
|
||||
|
||||
import extensions
|
||||
import blueprints
|
||||
import plugins
|
||||
|
@@ -31,7 +31,7 @@ import argparse
|
||||
|
||||
patch_all(thread=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Run a Senpy server')
|
||||
parser.add_argument('--level',
|
||||
"-l",
|
||||
@@ -44,6 +44,10 @@ if __name__ == '__main__':
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Run the application in debug mode')
|
||||
parser.add_argument('--default-plugins',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Load the default plugins')
|
||||
parser.add_argument('--host',
|
||||
type=str,
|
||||
default="127.0.0.1",
|
||||
@@ -62,14 +66,16 @@ if __name__ == '__main__':
|
||||
logging.basicConfig(level=getattr(logging, args.level))
|
||||
app = Flask(__name__)
|
||||
app.debug = args.debug
|
||||
sp = Senpy(app, args.plugins_folder)
|
||||
sp = Senpy(app, args.plugins_folder, default_plugins=args.default_plugins)
|
||||
sp.activate_all()
|
||||
import logging
|
||||
http_server = WSGIServer((args.host, args.port), app)
|
||||
try:
|
||||
print "Server running on port %s:%d. Ctrl+C to quit" % (args.host,
|
||||
args.port)
|
||||
print("Server running on port %s:%d. Ctrl+C to quit" % (args.host,
|
||||
args.port))
|
||||
http_server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
http_server.stop()
|
||||
print "Bye!"
|
||||
print("Bye!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@@ -18,7 +18,7 @@
|
||||
Blueprints for Senpy
|
||||
"""
|
||||
from flask import Blueprint, request, current_app
|
||||
from .models import Error, Response
|
||||
from .models import Error, Response, Leaf
|
||||
|
||||
import json
|
||||
import logging
|
||||
@@ -158,9 +158,9 @@ def plugins(plugin=None, action="list"):
|
||||
method = "{}_plugin".format(action)
|
||||
if(hasattr(sp, method)):
|
||||
getattr(sp, method)(plugin)
|
||||
return "Ok"
|
||||
return Leaf(message="Ok").flask()
|
||||
else:
|
||||
return "action '{}' not allowed".format(action), 400
|
||||
return Error("action '{}' not allowed".format(action)).flask()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@@ -1,5 +1,9 @@
|
||||
"""
|
||||
"""
|
||||
import gevent
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
|
||||
from .plugins import SenpyPlugin, SentimentPlugin, EmotionPlugin
|
||||
from .models import Error
|
||||
from .blueprints import nif_blueprint
|
||||
@@ -13,6 +17,7 @@ import inspect
|
||||
import sys
|
||||
import imp
|
||||
import logging
|
||||
import traceback
|
||||
import gevent
|
||||
import json
|
||||
|
||||
@@ -23,15 +28,16 @@ class Senpy(object):
|
||||
|
||||
""" Default Senpy extension for Flask """
|
||||
|
||||
def __init__(self, app=None, plugin_folder="plugins"):
|
||||
def __init__(self, app=None, plugin_folder="plugins", default_plugins=False):
|
||||
self.app = app
|
||||
base_folder = os.path.join(os.path.dirname(__file__), "plugins")
|
||||
|
||||
self._search_folders = set()
|
||||
self._outdated = True
|
||||
|
||||
for folder in (base_folder, plugin_folder):
|
||||
self.add_folder(folder)
|
||||
self.add_folder(plugin_folder)
|
||||
if default_plugins:
|
||||
base_folder = os.path.join(os.path.dirname(__file__), "plugins")
|
||||
self.add_folder(base_folder)
|
||||
|
||||
if app is not None:
|
||||
self.init_app(app)
|
||||
@@ -88,7 +94,7 @@ class Senpy(object):
|
||||
logger.debug(("The algorithm '{}' is not valid\n"
|
||||
"Valid algorithms: {}").format(algo,
|
||||
self.plugins.keys()))
|
||||
return Error(status=400,
|
||||
return Error(status=404,
|
||||
message="The algorithm '{}' is not valid"
|
||||
.format(algo))
|
||||
|
||||
@@ -124,7 +130,14 @@ class Senpy(object):
|
||||
|
||||
def activate_plugin(self, plugin_name, sync=False):
|
||||
plugin = self.plugins[plugin_name]
|
||||
th = gevent.spawn(plugin.activate)
|
||||
def act():
|
||||
try:
|
||||
plugin.activate()
|
||||
except Exception as ex:
|
||||
logger.error("Error activating plugin {}: {}".format(plugin.name,
|
||||
ex))
|
||||
logger.error("Trace: {}".format(traceback.format_exc()))
|
||||
th = gevent.spawn(act)
|
||||
th.link_value(partial(self._set_active_plugin, plugin_name, True))
|
||||
if sync:
|
||||
th.join()
|
||||
@@ -179,7 +192,8 @@ class Senpy(object):
|
||||
except InvalidGitRepositoryError:
|
||||
module._repo = None
|
||||
except Exception as ex:
|
||||
logger.debug("Exception importing {}: {}".format(filename, ex))
|
||||
logger.error("Exception importing {}: {}".format(filename, ex))
|
||||
logger.error("Trace: {}".format(traceback.format_exc()))
|
||||
return None, None
|
||||
return name, module
|
||||
|
||||
|
@@ -71,7 +71,10 @@ class Leaf(dict):
|
||||
return id
|
||||
|
||||
def __delattr__(self, key):
|
||||
return super(Leaf, self).__delitem__(self._get_key(key))
|
||||
if key in self.__dict__:
|
||||
del self.__dict__[key]
|
||||
else:
|
||||
super(Leaf, self).__delitem__(self._get_key(key))
|
||||
|
||||
def _get_key(self, key):
|
||||
if key[0] == "_":
|
||||
@@ -154,7 +157,7 @@ class Leaf(dict):
|
||||
' type="application/ld+json"' % url)
|
||||
}
|
||||
del js["@context"]
|
||||
return FlaskResponse(json.dumps(js),
|
||||
return FlaskResponse(json.dumps(js, indent=4),
|
||||
status=self.get("status", 200),
|
||||
headers=headers,
|
||||
mimetype="application/json")
|
||||
@@ -239,7 +242,7 @@ class Emotion(Leaf):
|
||||
_context = {}
|
||||
|
||||
|
||||
class Error(Response):
|
||||
class Error(Leaf):
|
||||
# A better pattern would be this:
|
||||
# http://flask.pocoo.org/docs/0.10/patterns/apierrors/
|
||||
_frame = {}
|
||||
|
@@ -1,4 +1,7 @@
|
||||
|
||||
import inspect
|
||||
import os.path
|
||||
import shelve
|
||||
import logging
|
||||
import ConfigParser
|
||||
from .models import Response, Leaf
|
||||
@@ -85,6 +88,9 @@ class SenpyPlugin(Leaf):
|
||||
self.is_activated = False
|
||||
self._info = info
|
||||
|
||||
def get_folder(self):
|
||||
return os.path.dirname(inspect.getfile(self.__class__))
|
||||
|
||||
def analyse(self, *args, **kwargs):
|
||||
logger.debug("Analysing with: {} {}".format(self.name, self.version))
|
||||
pass
|
||||
@@ -121,3 +127,29 @@ class EmotionPlugin(SenpyPlugin):
|
||||
resp = super(EmotionPlugin, self).__init__(info, *args, **kwargs)
|
||||
self.minEmotionValue = float(info.get("minEmotionValue", 0))
|
||||
self.maxEmotionValue = float(info.get("maxEmotionValue", 0))
|
||||
|
||||
|
||||
class ShelfMixin(object):
|
||||
|
||||
@property
|
||||
def sh(self):
|
||||
if not hasattr(self, '_sh') or not self._sh:
|
||||
self._sh = shelve.open(self.shelf_file, writeback=True)
|
||||
return self._sh
|
||||
|
||||
@sh.deleter
|
||||
def sh(self):
|
||||
if hasattr(self, '_sh'):
|
||||
del(self._sh)
|
||||
|
||||
@property
|
||||
def shelf_file(self):
|
||||
if not hasattr(self, '_shelf_file') or not self._shelf_file:
|
||||
if hasattr(self, '_info') and 'shelf_file' in self._info:
|
||||
self._shelf_file = self._info['shelf_file']
|
||||
else:
|
||||
self._shelf_file = os.path.join(self.get_folder(), self.name + '.db')
|
||||
return self._shelf_file
|
||||
|
||||
def close(self):
|
||||
del(self._sh)
|
||||
|
@@ -20,9 +20,10 @@ class Sentiment140Plugin(SentimentPlugin):
|
||||
polarity_value = self.maxPolarityValue*int(res.json()["data"][0]
|
||||
["polarity"]) * 0.25
|
||||
polarity = "marl:Neutral"
|
||||
if polarity_value > 50:
|
||||
neutral_value = self.maxPolarityValue / 2.0
|
||||
if polarity_value > neutral_value:
|
||||
polarity = "marl:Positive"
|
||||
elif polarity_value < 50:
|
||||
elif polarity_value < neutral_value:
|
||||
polarity = "marl:Negative"
|
||||
entry = Entry(id="Entry0",
|
||||
text=params["input"],
|
@@ -1,2 +1,2 @@
|
||||
[metadata]
|
||||
description-file = README.md
|
||||
description-file = README.rst
|
||||
|
26
setup.py
@@ -1,16 +1,21 @@
|
||||
import pip
|
||||
from setuptools import setup
|
||||
from pip.req import parse_requirements
|
||||
|
||||
# parse_requirements() returns generator of pip.req.InstallRequirement objects
|
||||
install_reqs = parse_requirements("requirements.txt")
|
||||
|
||||
try:
|
||||
install_reqs = parse_requirements("requirements.txt", session=pip.download.PipSession())
|
||||
test_reqs = parse_requirements("test-requirements.txt", session=pip.download.PipSession())
|
||||
except AttributeError:
|
||||
install_reqs = parse_requirements("requirements.txt")
|
||||
test_reqs = parse_requirements("test-requirements.txt")
|
||||
|
||||
# reqs is a list of requirement
|
||||
# e.g. ['django==1.5.1', 'mezzanine==1.4.6']
|
||||
reqs = [str(ir.req) for ir in install_reqs]
|
||||
install_reqs = [str(ir.req) for ir in install_reqs]
|
||||
test_reqs = [str(ir.req) for ir in test_reqs]
|
||||
|
||||
VERSION = "0.4.0"
|
||||
|
||||
print(reqs)
|
||||
VERSION = "0.4.10"
|
||||
|
||||
setup(
|
||||
name='senpy',
|
||||
@@ -27,6 +32,13 @@ extendable, so new algorithms and sources can be used.
|
||||
.format(VERSION),
|
||||
keywords=['eurosentiment', 'sentiment', 'emotions', 'nif'],
|
||||
classifiers=[],
|
||||
install_requires=reqs,
|
||||
install_requires=install_reqs,
|
||||
tests_require=test_reqs,
|
||||
test_suite="nose.collector",
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'senpy = senpy.__main__:main'
|
||||
]
|
||||
}
|
||||
)
|
||||
|
3
test-requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
nose
|
||||
mock
|
||||
pbr
|
@@ -15,7 +15,7 @@ class ExtensionsTest(TestCase):
|
||||
def create_app(self):
|
||||
self.app = Flask("test_extensions")
|
||||
self.dir = os.path.join(os.path.dirname(__file__), "..")
|
||||
self.senpy = Senpy(plugin_folder=self.dir)
|
||||
self.senpy = Senpy(plugin_folder=self.dir, default_plugins=False)
|
||||
self.senpy.init_app(self.app)
|
||||
self.senpy.activate_plugin("Dummy", sync=True)
|
||||
return self.app
|
||||
@@ -76,6 +76,7 @@ class ExtensionsTest(TestCase):
|
||||
logging.debug("Response: {}".format(resp))
|
||||
assert resp["status"] == 404
|
||||
|
||||
|
||||
def test_filtering(self):
|
||||
""" Filtering plugins """
|
||||
assert len(self.senpy.filter_plugins(name="Dummy")) > 0
|
||||
|
41
tests/plugins_test/__init__.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import os
|
||||
import logging
|
||||
import shelve
|
||||
|
||||
try:
|
||||
import unittest.mock as mock
|
||||
except ImportError:
|
||||
import mock
|
||||
import json
|
||||
import os
|
||||
from unittest import TestCase
|
||||
from senpy.models import Response, Entry
|
||||
from senpy.plugins import SenpyPlugin, ShelfMixin
|
||||
|
||||
|
||||
class ModelsTest(TestCase):
|
||||
|
||||
# def test_shelf(self):
|
||||
# class ShelfTest(ShelfMixin):
|
||||
# pass
|
||||
# a = ShelfTest()
|
||||
# print(type(a.sh))
|
||||
# assert(False)
|
||||
|
||||
def test_shelf(self):
|
||||
class ShelfTest(ShelfMixin, SenpyPlugin):
|
||||
pass
|
||||
a = ShelfTest({'name': 'shelve', 'version': 'test'})
|
||||
print(type(a.sh))
|
||||
a.context = "ohno"
|
||||
del a.context
|
||||
print(a)
|
||||
a.sh['classifier'] = {'name': 'ohno'}
|
||||
assert a.name == 'shelve'
|
||||
assert isinstance(a.sh, shelve.Shelf)
|
||||
a.close()
|
||||
b = ShelfTest({'name': 'shelve', 'version': 'test'})
|
||||
assert b.name == 'shelve'
|
||||
assert b.sh['classifier']
|
||||
assert b.sh['classifier']['name'] == 'ohno'
|
||||
assert isinstance(b.sh, shelve.Shelf)
|
@@ -13,4 +13,5 @@ class SleepPlugin(SenpyPlugin):
|
||||
sleep(self.timeout)
|
||||
|
||||
def analyse(self, *args, **kwargs):
|
||||
sleep(float(kwargs.get("timeout", self.timeout)))
|
||||
return Response()
|
||||
|
@@ -4,5 +4,13 @@
|
||||
"description": "I am dummy",
|
||||
"author": "@balkian",
|
||||
"version": "0.1",
|
||||
"timeout": "2"
|
||||
"timeout": "2",
|
||||
"extra_params": {
|
||||
"timeout": {
|
||||
"@id": "timeout_sleep",
|
||||
"aliases": ["timeout", "to"],
|
||||
"required": false,
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|