1
0
mirror of https://github.com/gsi-upm/senpy synced 2025-09-17 03:52:22 +00:00

Compare commits

..

10 Commits

Author SHA1 Message Date
J. Fernando Sánchez
e5662d482e Allow activation fails 2018-06-20 11:51:06 +02:00
J. Fernando Sánchez
61181db199 Fix sentiment140 plugin 2018-06-18 17:43:10 +02:00
J. Fernando Sánchez
a1663a3f31 Upload latest with version 2018-06-18 17:36:30 +02:00
J. Fernando Sánchez
83b23dbdf4 UI improvements
* Add option to add multiple plugins
* Improve UI hints for collapsed parameters
* Refactored plugins without requirements
* Hide evaluation tab for the moment. You can see it by adding "?evaluation" to
  the URL.
2018-06-18 16:46:49 +02:00
J. Fernando Sánchez
4675d9acf1 Avoid testing tags twice 2018-06-15 16:59:00 +02:00
J. Fernando Sánchez
6832a2816d Change data loading logic. Bugs senpy.testing 2018-06-15 16:47:48 +02:00
J. Fernando Sánchez
7a8abf1823 Update makefiles 2018-06-15 11:45:49 +02:00
J. Fernando Sánchez
a21ce0d90e Squashed '.makefiles/' changes from a75ba69..6c47840
6c47840 Updated makefiles from senpy
625549c Do not push image tag for latest
b3318c0 Updated makefiles from senpy
8453e8b Fix problems with echo and newlines
083c8c9 Updated makefiles from senpy-plugins-community

git-subtree-dir: .makefiles
git-subtree-split: 6c47840f216bb641886da57e1e98ccf5df0285d7
2018-06-15 11:45:49 +02:00
J. Fernando Sánchez
a964e586d7 Rename senpy.test to senpy.testing to avoid conflicts 2018-06-15 11:45:40 +02:00
J. Fernando Sánchez
bce42b5bb4 Updated makefiles from senpy 2018-06-15 10:57:26 +02:00
24 changed files with 343 additions and 137 deletions

View File

@@ -18,6 +18,8 @@ before_script:
stage: test
script:
- make -e test-$PYTHON_VERSION
except:
- tags # Avoid unnecessary double testing
test-3.5:
<<: *test_definition

View File

@@ -1,5 +1,14 @@
IMAGENAME?=$(NAME)
ifndef IMAGENAME
ifdef CI_REGISTRY_IMAGE
IMAGENAME=$(CI_REGISTRY_IMAGE)
else
IMAGENAME=$(NAME)
endif
endif
IMAGEWTAG?=$(IMAGENAME):$(VERSION)
DOCKER_FLAGS?=$(-ti)
DOCKER_CMD?=
docker-login: ## Log in to the registry. It will only be used in the server, or when running a CI task locally (if CI_BUILD_TOKEN is set).
ifeq ($(CI_BUILD_TOKEN),)
@@ -19,6 +28,19 @@ else
@docker logout
endif
docker-run: ## Build a generic docker image
docker run $(DOCKER_FLAGS) $(IMAGEWTAG) $(DOCKER_CMD)
docker-build: ## Build a generic docker image
docker build . -t $(IMAGEWTAG)
docker-push: docker-login ## Push a generic docker image
docker push $(IMAGEWTAG)
docker-latest-push: docker-login ## Push the latest image
docker tag $(IMAGEWTAG) $(IMAGENAME)
docker push $(IMAGENAME)
login:: docker-login
clean:: docker-clean

View File

@@ -14,7 +14,7 @@ push-github: ## Push the code to github. You need to set up GITHUB_DEPLOY_KEY
ifeq ($(GITHUB_DEPLOY_KEY),)
else
$(eval KEY_FILE := "$(shell mktemp)")
@echo "$(GITHUB_DEPLOY_KEY)" > $(KEY_FILE)
@printf '%b' '$(GITHUB_DEPLOY_KEY)' > $(KEY_FILE)
@git remote rm github-deploy || true
git remote add github-deploy $(GITHUB_REPO)
-@GIT_SSH_COMMAND="ssh -i $(KEY_FILE)" git fetch github-deploy $(CI_COMMIT_REF_NAME)

View File

@@ -13,7 +13,7 @@
KUBE_CA_TEMP=false
ifndef KUBE_CA_PEM_FILE
KUBE_CA_PEM_FILE:=$$PWD/.ca.crt
CREATED:=$(shell echo -e "$(KUBE_CA_BUNDLE)" > $(KUBE_CA_PEM_FILE))
CREATED:=$(shell printf '%b\n' '$(KUBE_CA_BUNDLE)' > $(KUBE_CA_PEM_FILE))
endif
KUBE_TOKEN?=""
KUBE_NAMESPACE?=$(NAME)

View File

@@ -26,6 +26,7 @@ Dockerfile-%: Dockerfile.template ## Generate a specific dockerfile (e.g. Docke
quick_build: $(addprefix build-, $(PYMAIN))
build: $(addprefix build-, $(PYVERSIONS)) ## Build all images / python versions
docker tag $(IMAGEWTAG)-python$(PYMAIN) $(IMAGEWTAG)
build-%: version Dockerfile-% ## Build a specific version (e.g. build-2.7)
docker build -t '$(IMAGEWTAG)-python$*' -f Dockerfile-$* .;
@@ -75,8 +76,9 @@ pip_upload: pip_test ## Upload package to pip
push-latest: $(addprefix push-latest-,$(PYVERSIONS)) ## Push the "latest" tag to dockerhub
docker tag '$(IMAGEWTAG)-python$(PYMAIN)' '$(IMAGEWTAG)'
docker tag '$(IMAGEWTAG)-python$(PYMAIN)' '$(IMAGENAME)'
docker tag '$(IMAGEWTAG)-python$(PYMAIN)' '$(IMAGENAME):latest'
docker push '$(IMAGENAME):latest'
docker push '$(IMAGEWTAG)'
push-latest-%: build-% ## Push the latest image for a specific python version
docker tag $(IMAGENAME):$(VERSION)-python$* $(IMAGENAME):python$*

10
docker-compose.dev.yml Normal file
View File

@@ -0,0 +1,10 @@
version: '3'
services:
senpy:
image: "${IMAGENAME-gsiupm/senpy}:${VERSION-latest}"
entrypoint: ["/bin/bash"]
working_dir: "/senpy-plugins"
ports:
- 5000:5000
volumes:
- ".:/usr/src/app/"

9
docker-compose.test.yml Normal file
View File

@@ -0,0 +1,9 @@
version: '3'
services:
test:
image: "${IMAGENAME-gsiupm/senpy}:${VERSION-dev}"
entrypoint: ["py.test"]
volumes:
- ".:/usr/src/app/"
command:
[]

11
docker-compose.yml Normal file
View File

@@ -0,0 +1,11 @@
version: '3'
services:
senpy:
image: "${IMAGENAME-gsiupm/senpy}:${VERSION-dev}"
build:
context: .
dockerfile: Dockerfile${PYVERSION--2.7}
ports:
- 5001:5000
volumes:
- "./data:/data"

View File

@@ -43,7 +43,6 @@ class Dictionary(plugins.SentimentPlugin):
class EmojiOnly(Dictionary):
'''Sentiment annotation with a basic lexicon of emojis'''
description = 'A plugin'
dictionaries = [basic.emojis]
test_cases = [{

View File

@@ -105,6 +105,12 @@ def main():
action='store_true',
default=False,
help='Output the senpy version and exit')
parser.add_argument(
'--allow-fail',
'--fail',
action='store_true',
default=False,
help='Do not exit if some plugins fail to activate')
args = parser.parse_args()
if args.version:
print('Senpy version {}'.format(senpy.__version__))
@@ -128,7 +134,7 @@ def main():
sp.install_deps()
if args.only_install:
return
sp.activate_all()
sp.activate_all(allow_fail=args.allow_fail)
if args.only_test:
easy_test(sp.plugins(), debug=args.debug)
return

View File

@@ -47,7 +47,12 @@ def get_params(req):
@demo_blueprint.route('/')
def index():
return render_template("index.html", version=__version__)
ev = str(get_params(request).get('evaluation', False))
evaluation_enabled = ev.lower() not in ['false', 'no', 'none']
return render_template("index.html",
evaluation=evaluation_enabled,
version=__version__)
@api_blueprint.route('/contexts/<entity>.jsonld')

View File

@@ -318,10 +318,15 @@ class Senpy(object):
else:
self._default = self._plugins[value.lower()]
def activate_all(self, sync=True):
def activate_all(self, sync=True, allow_fail=False):
ps = []
for plug in self._plugins.keys():
ps.append(self.activate_plugin(plug, sync=sync))
try:
self.activate_plugin(plug, sync=sync)
except Exception as ex:
if not allow_fail:
raise
logger.error('Could not activate {}: {}'.format(plug, ex))
return ps
def deactivate_all(self, sync=True):

View File

@@ -95,12 +95,22 @@ class Plugin(with_metaclass(PluginMeta, models.Plugin)):
self.id = 'plugins/{}_{}'.format(self['name'], self['version'])
self.is_activated = False
self._lock = threading.Lock()
self.data_folder = data_folder or os.getcwd()
self._directory = os.path.abspath(os.path.dirname(inspect.getfile(self.__class__)))
self._data_paths = ['',
self._directory,
os.path.join(self._directory, 'data'),
self.data_folder]
data_folder = data_folder or os.getcwd()
subdir = os.path.join(data_folder, self.name)
self._data_paths = [
data_folder,
subdir,
self._directory,
os.path.join(self._directory, 'data'),
]
if os.path.exists(subdir):
data_folder = subdir
self.data_folder = data_folder
self._log = logging.getLogger('{}.{}'.format(__name__, self.name))
@property
@@ -499,7 +509,7 @@ def install_deps(*plugins):
exitcode = process.wait()
installed = True
if exitcode != 0:
raise models.Error("Dependencies not properly installed")
raise models.Error("Dependencies not properly installed: {}".format(pip_args))
nltk_resources |= set(info.get('nltk_resources', []))
installed |= nltk.download(list(nltk_resources))

View File

@@ -1,19 +0,0 @@
---
name: split
module: senpy.plugins.misc.split
description: A sample plugin that chunks input text
author: "@militarpancho"
version: '0.2'
url: "https://github.com/gsi-upm/senpy"
requirements:
- nltk
extra_params:
delimiter:
aliases:
- type
- t
required: false
default: sentence
options:
- sentence
- paragraph

View File

@@ -5,13 +5,27 @@ from nltk.tokenize.simple import LineTokenizer
import nltk
class SplitPlugin(AnalysisPlugin):
class Split(AnalysisPlugin):
'''description: A sample plugin that chunks input text'''
author = ["@militarpancho", '@balkian']
version = '0.2'
url = "https://github.com/gsi-upm/senpy"
extra_params = {
'delimiter': {
'aliases': ['type', 't'],
'required': False,
'default': 'sentence',
'options': ['sentence', 'paragraph']
},
}
def activate(self):
nltk.download('punkt')
def analyse_entry(self, entry, params):
yield entry
chunker_type = params["delimiter"]
original_text = entry['nif:isString']
if chunker_type == "sentence":

View File

@@ -1,22 +0,0 @@
---
name: sentiment140
module: sentiment140
description: "Connects to the sentiment140 free API: http://sentiment140.com"
author: "@balkian"
version: '0.2'
url: "https://github.com/gsi-upm/senpy-plugins-community"
extra_params:
language:
"@id": lang_sentiment140
aliases:
- language
- l
required: false
options:
- es
- en
- auto
default: auto
requirements: {}
maxPolarityValue: 1
minPolarityValue: 0

View File

@@ -5,8 +5,25 @@ from senpy.plugins import SentimentPlugin
from senpy.models import Sentiment
class Sentiment140Plugin(SentimentPlugin):
class Sentiment140(SentimentPlugin):
'''Connects to the sentiment140 free API: http://sentiment140.com'''
author = "@balkian"
version = '0.2'
url = "https://github.com/gsi-upm/senpy-plugins-community"
extra_params = {
'language': {
"@id": 'lang_sentiment140',
'aliases': ['language', 'l'],
'required': False,
'default': 'auto',
'options': ['es', 'en', 'auto']
}
}
maxPolarityValue = 1
minPolarityValue = 0
def analyse_entry(self, entry, params):
lang = params["language"]
res = requests.post("http://www.sentiment140.com/api/bulkClassifyJson",
@@ -31,7 +48,6 @@ class Sentiment140Plugin(SentimentPlugin):
marl__hasPolarity=polarity,
marl__polarityValue=polarity_value)
sentiment.prov__wasGeneratedBy = self.id
entry.sentiments = []
entry.sentiments.append(sentiment)
entry.language = lang
yield entry
@@ -41,10 +57,10 @@ class Sentiment140Plugin(SentimentPlugin):
To avoid calling the sentiment140 API, we will mock the results
from requests.
'''
from senpy.test import patch_requests
from senpy.testing import patch_requests
expected = {"data": [{"polarity": 4}]}
with patch_requests(expected) as (request, response):
super(Sentiment140Plugin, self).test(*args, **kwargs)
super(Sentiment140, self).test(*args, **kwargs)
assert request.called
assert response.json.called

View File

@@ -167,3 +167,36 @@ textarea{
color: inherit;
text-decoration: inherit;
}
.collapsed .collapseicon {
display: none !important;
}
.collapsed .expandicon {
display: inline-block !important;
}
.expandicon {
display: none !important;
}
.collapseicon {
display: inline-block !important;
}
.loader {
border: 6px solid #f3f3f3; /* Light grey */
border-top: 6px solid blue;
border-bottom: 6px solid blue;
border-radius: 50%;
width: 3em;
height: 3em;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

View File

@@ -4,6 +4,7 @@ var plugins_params = default_params = {};
var plugins = [];
var defaultPlugin = {};
var gplugins = {};
var pipeline = [];
function replaceURLWithHTMLLinks(text) {
console.log('Text: ' + text);
@@ -30,7 +31,10 @@ function hashchanged(){
function get_plugins(response){
plugins = response.plugins;
for(ix in response.plugins){
plug = response.plugins[ix];
plugins[plug.name] = plug;
}
}
function get_datasets(response){
@@ -83,10 +87,32 @@ function draw_plugins_selection(){
html += "</optgroup>"
// Two elements with plugin class
// One from the evaluate tab and another one from the analyse tab
document.getElementsByClassName('plugin')[0].innerHTML = html;
document.getElementsByClassName('plugin')[1].innerHTML = html;
plugin_lists = document.getElementsByClassName('plugin')
for (element in plugin_lists){
plugin_lists[element].innerHTML = html;
}
draw_plugin_pipeline();
}
function draw_plugin_pipeline(){
var pipeHTML = "";
console.log("Drawing pipeline: ", pipeline);
for (ix in pipeline){
plug = pipeline[ix];
pipeHTML += '<span onclick="remove_plugin_pipeline(\'' + plug + '\')" class="btn btn-primary"><span ><i class="fa fa-minus"></i></span> ' + plug + '</span> <i class="fa fa-arrow-right"></i> ';
}
console.log(pipeHTML);
$("#pipeline").html(pipeHTML);
}
function remove_plugin_pipeline(name){
console.log("Removing plugin: ", name);
var index = pipeline.indexOf(name);
pipeline.splice(index, 1);
draw_plugin_pipeline();
}
function draw_plugins_list(){
var availablePlugins = document.getElementById('availablePlugins');
@@ -105,6 +131,13 @@ function draw_plugins_list(){
}
}
function add_plugin_pipeline(){
var selected = get_selected_plugin();
pipeline.push(selected);
console.log("Adding ", selected);
draw_plugin_pipeline();
}
function draw_datasets(){
html = "";
repeated_html = "<input class=\"checks-datasets\" type=\"checkbox\" value=\"";
@@ -118,16 +151,20 @@ function draw_datasets(){
$(document).ready(function() {
var response = JSON.parse($.ajax({type: "GET", url: "/api/plugins/" , async: false}).responseText);
defaultPlugin= JSON.parse($.ajax({type: "GET", url: "/api/plugins/default" , async: false}).responseText);
var response2 = JSON.parse($.ajax({type: "GET", url: "/api/datasets/" , async: false}).responseText);
get_plugins(response);
get_default_parameters();
get_datasets(response2);
draw_plugins_list();
draw_plugins_selection();
draw_parameters();
draw_datasets();
draw_plugin_description();
if (evaluation_enabled) {
var response2 = JSON.parse($.ajax({type: "GET", url: "/api/datasets/" , async: false}).responseText);
get_datasets(response2);
draw_datasets();
}
$(window).on('hashchange', hashchanged);
hashchanged();
@@ -144,17 +181,34 @@ function get_default_parameters(){
}
function get_selected_plugin(){
return document.getElementsByClassName('plugin')[0].options[document.getElementsByClassName('plugin')[0].selectedIndex].value;
}
function draw_default_parameters(){
var basic_params = document.getElementById("basic_params");
basic_params.innerHTML = params_div(default_params);
}
function update_params(params, plug){
ep = plugins_params[plug];
for(k in ep){
params[k] = ep[k];
}
return params
}
function draw_extra_parameters(){
var plugin = document.getElementsByClassName('plugin')[0].options[document.getElementsByClassName('plugin')[0].selectedIndex].value;
var plugin = get_selected_plugin();
get_parameters();
var extra_params = document.getElementById("extra_params");
extra_params.innerHTML = params_div(plugins_params[plugin]);
var params = {};
for (sel in pipeline){
update_params(params, pipeline[sel]);
}
update_params(params, plugin);
extra_params.innerHTML = params_div(params);
}
function draw_parameters(){
@@ -261,6 +315,15 @@ function add_param(key, value){
return "&"+key+"="+value;
}
function get_pipeline_arg(){
arg = "";
for (ix in pipeline){
arg = arg + pipeline[ix] + ",";
}
arg = arg + get_selected_plugin();
return arg;
}
function load_JSON(){
url = "/api";
@@ -269,7 +332,9 @@ function load_JSON(){
rawcontainer.innerHTML = '';
container.innerHTML = '';
var plugin = document.getElementsByClassName("plugin")[0].options[document.getElementsByClassName("plugin")[0].selectedIndex].value;
var plugin = get_pipeline_arg();
$(".loading").addClass("loader");
$("#preview").hide();
var input = encodeURIComponent(document.getElementById("input").value);
url += "?algo="+plugin+"&i="+input
@@ -280,27 +345,27 @@ function load_JSON(){
url += add_param(key, params[key]);
}
var response = $.ajax({type: "GET", url: url , async: false}).responseText;
rawcontainer.innerHTML = replaceURLWithHTMLLinks(response);
$.ajax({type: "GET", url: url}).always(function(response){
document.getElementById("results-div").style.display = 'block';
if(typeof response=="object") {
var options = {
mode: 'view'
};
var editor = new JSONEditor(container, options, response);
editor.expandAll();
$('#results-div a[href="#viewer"]').click();
response = JSON.stringify(response, null, 4);
} else {
console.log("Got turtle?");
$('#results-div a[href="#raw"]').click();
}
document.getElementById("input_request").innerHTML = "<a href='"+url+"'>"+url+"</a>"
document.getElementById("results-div").style.display = 'block';
try {
response = JSON.parse(response);
var options = {
mode: 'view'
};
var editor = new JSONEditor(container, options, response);
editor.expandAll();
// $('#results-div a[href="#viewer"]').tab('show');
$('#results-div a[href="#viewer"]').click();
// location.hash = 'raw';
}
catch(err){
console.log("Error decoding JSON (got turtle?)");
$('#results-div a[href="#raw"]').click();
// location.hash = 'raw';
}
rawcontainer.innerHTML = replaceURLWithHTMLLinks(response);
document.getElementById("input_request").innerHTML = "<a href='"+url+"'>"+url+"</a>"
$(".loading").removeClass("loader");
$("#preview").show();
});
}
function get_datasets_from_checkbox(){
@@ -347,40 +412,53 @@ function evaluate_JSON(){
url += "?algo="+plugin+"&dataset="+datasets
var response = $.ajax({type: "GET", url: url , async: false, dataType: 'json'}).responseText;
rawcontainer.innerHTML = replaceURLWithHTMLLinks(response);
$('#doevaluate').attr("disabled", true);
$.ajax({type: "GET", url: url, dataType: 'json'}).done(function(resp) {
$('#doevaluate').attr("disabled", false);
response = resp.responseText;
rawcontainer.innerHTML = replaceURLWithHTMLLinks(response);
document.getElementById("input_request_eval").innerHTML = "<a href='"+url+"'>"+url+"</a>"
document.getElementById("evaluate-div").style.display = 'block';
try {
response = JSON.parse(response);
var options = {
mode: 'view'
};
//Control the single response results
if (!(Array.isArray(response.evaluations))){
response.evaluations = [response.evaluations]
}
new_tbody = create_body_metrics(response.evaluations)
table.replaceChild(new_tbody, table.lastElementChild)
var editor = new JSONEditor(container, options, response);
editor.expandAll();
// $('#results-div a[href="#viewer"]').tab('show');
$('#evaluate-div a[href="#evaluate-table"]').click();
// location.hash = 'raw';
document.getElementById("input_request_eval").innerHTML = "<a href='"+url+"'>"+url+"</a>"
document.getElementById("evaluate-div").style.display = 'block';
try {
response = JSON.parse(response);
var options = {
mode: 'view'
};
//Control the single response results
if (!(Array.isArray(response.evaluations))){
response.evaluations = [response.evaluations]
}
catch(err){
console.log("Error decoding JSON (got turtle?)");
$('#evaluate-div a[href="#evaluate-raw"]').click();
// location.hash = 'raw';
}
})
}
new_tbody = create_body_metrics(response.evaluations)
table.replaceChild(new_tbody, table.lastElementChild)
function draw_plugin_description(){
var plugin = plugins[get_selected_plugin()];
$("#plugdescription").text(plugin.description);
console.log(plugin);
}
var editor = new JSONEditor(container, options, response);
editor.expandAll();
// $('#results-div a[href="#viewer"]').tab('show');
$('#evaluate-div a[href="#evaluate-table"]').click();
// location.hash = 'raw';
}
catch(err){
console.log("Error decoding JSON (got turtle?)");
$('#evaluate-div a[href="#evaluate-raw"]').click();
// location.hash = 'raw';
}
}
function plugin_selected(){
draw_extra_parameters();
draw_plugin_description();
}

View File

@@ -5,6 +5,9 @@
<title>Playground {{version}}</title>
</head>
<script>
this.evaluation_enabled = {% if evaluation %}true{%else %}false{%endif%};
</script>
<script src="static/js/jquery-2.1.1.min.js" ></script>
<!--<script src="jquery.autosize.min.js"></script>-->
<link rel="stylesheet" href="static/css/bootstrap.min.css">
@@ -32,7 +35,9 @@
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" ><a class="active" href="#about">About</a></li>
<li role="presentation"class="active"><a class="active" href="#test">Test it</a></li>
{% if evaluation %}
<li role="presentation"><a class="active" href="#evaluate">Evaluate Plugins</a></li>
{% endif %}
</ul>
@@ -61,6 +66,14 @@
</ul>
</p>
<p>Senpy is a research project. If you use it in your research, please cite:
<pre>
Senpy: A Pragmatic Linked Sentiment Analysis Framework.
Sánchez-Rada, J. F., Iglesias, C. A., Corcuera, I., & Araque, Ó.
In Data Science and Advanced Analytics (DSAA),
2016 IEEE International Conference on (pp. 735-742). IEEE.
</pre>
</p>
</div>
<div class="col-lg-6 ">
@@ -70,8 +83,6 @@
</div>
<div class="panel-body"><ul id=availablePlugins></ul></div>
</div>
</div>
<div class="col-lg-6 ">
<a href="http://senpy.readthedocs.io">
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-book"></i> If you are new to senpy, you might want to read senpy's documentation</div>
@@ -82,9 +93,6 @@
<div class="panel-heading"><i class="fa fa-sign-in"></i> Feel free to follow us on GitHub</div>
</div>
</a>
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-child"></i> Enjoy.</div>
</div>
</div>
</div>
</div>
@@ -96,17 +104,28 @@
whilst this text makes me happy and surprised at the same time.
I cannot believe it!</textarea>
</div>
<div>
<label>Select the plugin:</label>
<select id="plugins" name="plugins" class=plugin onchange="draw_extra_parameters()">
</select>
</div>
<!-- PARAMETERS -->
<div class="panel-group" id="parameters">
<div class="panel panel-default">
<a data-toggle="collapse" class="deco-none" href="#basic_params">
<div class="panel-heading">
<h4 class="panel-title">
Select the plugin.
</h4>
</div>
<div id="plugin_selection" class="panel-collapse panel-body">
<span id="pipeline"></span>
<select name="plugins" class="plugin" onchange="plugin_selected()">
</select>
<span onclick="add_plugin_pipeline()"><span class="btn"><i class="fa fa-plus" title="Add more plugins to the pipeline. Processing order is left to right. i.e. the results of the leftmost plugin will be used as input for the second leftmost, and so on."></i></span></span>
<label class="help-block " id="plugdescription"></label>
</div>
</div>
<div class="panel panel-default">
<a data-toggle="collapse" class="deco-none collapsed" href="#basic_params">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fa fa-chevron-right pull-left expandicon"></i>
<i class="fa fa-chevron-down pull-left collapseicon"></i>
Basic API parameters
</h4>
</div>
@@ -118,6 +137,8 @@ I cannot believe it!</textarea>
<a data-toggle="collapse" class="deco-none" href="#extra_params">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fa fa-chevron-right pull-left expandicon"></i>
<i class="fa fa-chevron-down pull-left collapseicon"></i>
Plugin extra parameters
</h4>
</div>
@@ -129,6 +150,7 @@ I cannot believe it!</textarea>
<!-- END PARAMETERS -->
<a id="preview" class="btn btn-lg btn-primary" onclick="load_JSON()">Analyse!</a>
<div id="loading-results" class="loading"></div>
<!--<button id="visualise" name="type" type="button">Visualise!</button>-->
</form>
</div>
@@ -155,6 +177,8 @@ I cannot believe it!</textarea>
</div>
</div>
{% if evaluation %}
<div class="tab-pane" id="evaluate">
<div class="well">
<form id="form" class="container" onsubmit="return getPlugins();" accept-charset="utf-8">
@@ -169,7 +193,7 @@ I cannot believe it!</textarea>
</select>
</div>
<a id="preview" class="btn btn-lg btn-primary" onclick="evaluate_JSON()">Evaluate Plugin!</a>
<a id="doevaluate" class="btn btn-lg btn-primary" onclick="evaluate_JSON()">Evaluate Plugin!</a>
<!--<button id="visualise" name="type" type="button">Visualise!</button>-->
</form>
</div>
@@ -216,6 +240,7 @@ I cannot believe it!</textarea>
</div>
</div>
</div>
{% endif %}
</div>
<a href="http://www.gsi.dit.upm.es" target="_blank"><img class="center-block" src="static/img/gsi.png"/> </a>

View File

@@ -36,7 +36,7 @@ class BlueprintsTest(TestCase):
def test_playground(self):
resp = self.client.get("/")
assert "main.js" in resp.data.decode()
assert "main.js" in resp.get_data(as_text=True)
def test_home(self):
"""

View File

@@ -1,6 +1,6 @@
from unittest import TestCase
from senpy.test import patch_requests
from senpy.testing import patch_requests
from senpy.client import Client
from senpy.models import Results, Plugins, Error
from senpy.plugins import AnalysisPlugin

View File

@@ -2,7 +2,7 @@ from unittest import TestCase
import requests
import json
from senpy.test import patch_requests
from senpy.testing import patch_requests
from senpy.models import Results