From d07b73781f9a7de3ffaa53b4631f659120543049 Mon Sep 17 00:00:00 2001 From: Patrick Jentsch Date: Sun, 29 Mar 2020 19:40:29 +0200 Subject: [PATCH] Update --- app/corpora/cqi/api/client.py | 49 +----- app/corpora/cqi/errors.py | 156 +++++++++++++----- app/corpora/pj_events.py | 72 ++++---- app/static/js/nopaque.CorpusAnalysisClient.js | 36 ++-- .../corpora/pj_analyse_corpus.html.j2 | 16 +- 5 files changed, 188 insertions(+), 141 deletions(-) diff --git a/app/corpora/cqi/api/client.py b/app/corpora/cqi/api/client.py index 7df30997..d0f328c9 100644 --- a/app/corpora/cqi/api/client.py +++ b/app/corpora/cqi/api/client.py @@ -1,5 +1,6 @@ from time import sleep -from .. import errors, specification +from .. import specification +from ..errors import cl_error_lookup, error_lookup, cqp_error_lookup import socket import struct @@ -434,58 +435,18 @@ class APIClient: byte_data = self.__recv_WORD() response_type = byte_data >> 8 if response_type == specification.CL_ERROR: - raise self.__create_cl_error(byte_data) + raise cl_error_lookup[byte_data]() elif response_type == specification.CQP_ERROR: - raise self.__create_cqp_error(byte_data) + raise cqp_error_lookup[byte_data]() elif response_type == specification.DATA: return self.__recv_DATA(byte_data) elif response_type == specification.ERROR: - raise self.__create_error(byte_data) + raise error_lookup[byte_data]() elif response_type == specification.STATUS: return {'code': byte_data, 'msg': specification.lookup[byte_data]} else: raise Exception('Unknown response type: {}'.format(response_type)) - def __create_cl_error(self, error_type): - if error_type == specification.CL_ERROR_NO_SUCH_ATTRIBUTE: - return errors.CLErrorNoSuchAttribute() - elif error_type == specification.CL_ERROR_WRONG_ATTRIBUTE_TYPE: - return errors.CLErrorWrongAttributeType() - elif error_type == specification.CL_ERROR_OUT_OF_RANGE: - return errors.CLErrorOutOfRange() - elif error_type == specification.CL_ERROR_REGEX: - return errors.CLErrorRegex() - elif error_type == specification.CL_ERROR_CORPUS_ACCESS: - return errors.CLErrorCorpusAccess() - elif error_type == specification.CL_ERROR_OUT_OF_MEMORY: - return errors.CLErrorOutOfMemory() - elif error_type == specification.CL_ERROR_INTERNAL: - return errors.CLErrorInternal() - else: - return errors.CLError(error_type) - - def __create_cqp_error(self, error_type): - if error_type == specification.CQP_ERROR_GENERAL: - return errors.CQPErrorGeneral() - elif error_type == specification.CQP_ERROR_INVALID_FIELD: - return errors.CQPErrorInvalidField() - elif error_type == specification.CQP_ERROR_OUT_OF_RANGE: - return errors.CQPErrorOutOfRange() - else: - return errors.CQPError(error_type) - - def __create_error(self, error_type): - if error_type == specification.ERROR_GENERAL_ERROR: - return errors.ErrorGeneralError() - elif error_type == specification.ERROR_CONNECT_REFUSED: - return errors.ErrorConnectRefused() - elif error_type == specification.ERROR_USER_ABORT: - return errors.ErrorUserAbort() - elif error_type == specification.ERROR_SYNTAX_ERROR: - return errors.ErrorSyntaxError() - else: - return errors.Error(error_type) - def __recv_DATA(self, data_type): if data_type == specification.DATA_BYTE: data = self.__recv_DATA_BYTE() diff --git a/app/corpora/cqi/errors.py b/app/corpora/cqi/errors.py index 086f4981..fa0d33a0 100644 --- a/app/corpora/cqi/errors.py +++ b/app/corpora/cqi/errors.py @@ -1,3 +1,6 @@ +from . import specification + + class CQiException(Exception): """ A base class from which all other exceptions inherit. @@ -5,100 +8,173 @@ class CQiException(Exception): catch this base exception. """ + def __init__(self, *args, **kwargs): + super(CQiException, self).__init__(*args, **kwargs) + self.code = None + self.name = None + self.description = None + class Error(CQiException): - # ERROR = 0x02 - pass + def __init__(self, *args, **kwargs): + super(Error, self).__init__(*args, **kwargs) + self.code = specification.ERROR class ErrorGeneralError(Error): - # ERROR_GENERAL_ERROR = 0x0201 - pass + def __init__(self, *args, **kwargs): + super(ErrorGeneralError, self).__init__(*args, **kwargs) + self.code = specification.ERROR_GENERAL_ERROR + self.name = specification.lookup[self.code] class ErrorConnectRefused(Error): - # ERROR_CONNECT_REFUSED = 0x0202 - pass + def __init__(self, *args, **kwargs): + super(ErrorConnectRefused, self).__init__(*args, **kwargs) + self.code = specification.ERROR_CONNECT_REFUSED + self.name = specification.lookup[self.code] class ErrorUserAbort(Error): - # ERROR_USER_ABORT = 0x0203 - pass + def __init__(self, *args, **kwargs): + super(ErrorUserAbort, self).__init__(*args, **kwargs) + self.code = specification.ERROR_USER_ABORT + self.name = specification.lookup[self.code] class ErrorSyntaxError(Error): - # ERROR_SYNTAX_ERROR = 0x0204 - pass + def __init__(self, *args, **kwargs): + super(ErrorSyntaxError, self).__init__(*args, **kwargs) + self.code = specification.ERROR_SYNTAX_ERROR + self.name = specification.lookup[self.code] class CLError(CQiException): - # CL_ERROR = 0x04 - pass + def __init__(self, *args, **kwargs): + super(CLError, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR class CLErrorNoSuchAttribute(CLError): - # CL_ERROR_NO_SUCH_ATTRIBUTE = 0x0401 - # returned if CQi server couldn't open attribute - pass + def __init__(self, *args, **kwargs): + super(CLErrorNoSuchAttribute, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR_NO_SUCH_ATTRIBUTE + self.name = specification.lookup[self.code] + self.description = "CQi server couldn't open attribute" class CLErrorWrongAttributeType(CLError): - # CL_ERROR_WRONG_ATTRIBUTE_TYPE = 0x0402 # CDA_EATTTYPE - pass + def __init__(self, *args, **kwargs): + super(CLErrorWrongAttributeType, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR_WRONG_ATTRIBUTE_TYPE + self.name = specification.lookup[self.code] class CLErrorOutOfRange(CLError): - # CL_ERROR_OUT_OF_RANGE = 0x0403 # CDA_EIDORNG, CDA_EIDXORNG, CDA_EPOSORNG - pass + def __init__(self, *args, **kwargs): + super(CLErrorOutOfRange, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR_OUT_OF_RANGE + self.name = specification.lookup[self.code] class CLErrorRegex(CLError): - # CL_ERROR_REGEX = 0x0404 # CDA_EPATTERN (not used), CDA_EBADREGEX - pass + def __init__(self, *args, **kwargs): + super(CLErrorRegex, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR_REGEX + self.name = specification.lookup[self.code] class CLErrorCorpusAccess(CLError): - # CL_ERROR_CORPUS_ACCESS = 0x0405 # CDA_ENODATA - pass + def __init__(self, *args, **kwargs): + super(CLErrorCorpusAccess, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR_CORPUS_ACCESS + self.name = specification.lookup[self.code] class CLErrorOutOfMemory(CLError): - # CL_ERROR_OUT_OF_MEMORY = 0x0406 # CDA_ENOMEM - # this means the CQi server has run out of memory; - # try discarding some other corpora and/or subcorpora - pass + def __init__(self, *args, **kwargs): + super(CLErrorOutOfMemory, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR_OUT_OF_MEMORY + self.name = specification.lookup[self.code] + self.description = ('CQi server has run out of memory; try discarding ' + 'some other corpora and/or subcorpora') class CLErrorInternal(CLError): - # CL_ERROR_INTERNAL = 0x0407 # CDA_EOTHER, CDA_ENYI - # this is the classical 'please contact technical support' error - pass + def __init__(self, *args, **kwargs): + super(CLErrorInternal, self).__init__(*args, **kwargs) + self.code = specification.CL_ERROR_INTERNAL + self.name = specification.lookup[self.code] + self.description = "Classical 'please contact technical support' error" class CQPError(CQiException): - # CQP_ERROR = 0x05 # CQP error messages yet to be defined - pass + def __init__(self, *args, **kwargs): + super(CQPError, self).__init__(*args, **kwargs) + self.code = specification.CQP_ERROR class CQPErrorGeneral(CQPError): - # CQP_ERROR_GENERAL = 0x0501 - pass - # CQP_ERROR_NO_SUCH_CORPUS = 0x0502 + def __init__(self, *args, **kwargs): + super(CQPErrorGeneral, self).__init__(*args, **kwargs) + self.code = specification.CQP_ERROR_GENERAL + self.name = specification.lookup[self.code] + + +class CQPErrorNoSuchCorpus(CQPError): + def __init__(self, *args, **kwargs): + super(CQPErrorNoSuchCorpus, self).__init__(*args, **kwargs) + self.code = specification.CQP_ERROR_NO_SUCH_CORPUS + self.name = specification.lookup[self.code] class CQPErrorInvalidField(CQPError): - # CQP_ERROR_INVALID_FIELD = 0x0503 - pass + def __init__(self, *args, **kwargs): + super(CQPErrorInvalidField, self).__init__(*args, **kwargs) + self.code = specification.CQP_ERROR_INVALID_FIELD + self.name = specification.lookup[self.code] class CQPErrorOutOfRange(CQPError): - # CQP_ERROR_OUT_OF_RANGE = 0x0504 - # various cases where a number is out of range - pass + def __init__(self, *args, **kwargs): + super(CQPErrorOutOfRange, self).__init__(*args, **kwargs) + self.code = specification.CQP_ERROR_OUT_OF_RANGE + self.name = specification.lookup[self.code] + self.description = 'A number is out of range' + + +error_lookup = { + specification.ERROR: Error, + specification.ERROR_GENERAL_ERROR: ErrorGeneralError, + specification.ERROR_CONNECT_REFUSED: ErrorConnectRefused, + specification.ERROR_USER_ABORT: ErrorUserAbort, + specification.ERROR_SYNTAX_ERROR: ErrorSyntaxError +} + + +cl_error_lookup = { + specification.CL_ERROR: CLError, + specification.CL_ERROR_NO_SUCH_ATTRIBUTE: CLErrorNoSuchAttribute, + specification.CL_ERROR_WRONG_ATTRIBUTE_TYPE: CLErrorWrongAttributeType, + specification.CL_ERROR_OUT_OF_RANGE: CLErrorOutOfRange, + specification.CL_ERROR_REGEX: CLErrorRegex, + specification.CL_ERROR_CORPUS_ACCESS: CLErrorCorpusAccess, + specification.CL_ERROR_OUT_OF_MEMORY: CLErrorOutOfMemory, + specification.CL_ERROR_INTERNAL: CLErrorInternal +} + + +cqp_error_lookup = { + specification.CQP_ERROR: CQPError, + specification.CQP_ERROR_GENERAL: CQPErrorGeneral, + specification.CQP_ERROR_NO_SUCH_CORPUS: CQPErrorNoSuchCorpus, + specification.CQP_ERROR_INVALID_FIELD: CQPErrorInvalidField, + specification.CQP_ERROR_OUT_OF_RANGE: CQPErrorOutOfRange +} diff --git a/app/corpora/pj_events.py b/app/corpora/pj_events.py index 0a5d2ca7..0d9feb1b 100644 --- a/app/corpora/pj_events.py +++ b/app/corpora/pj_events.py @@ -33,37 +33,46 @@ def pj_init_corpus_analysis(corpus_id): def pj_corpus_analysis_query(query): client = pj_corpus_analysis_clients.get(request.sid) if client is None: - response = {'code': 404, 'msg': 'Failed Dependency'} + response = {'code': 404, 'desc': 'No client found for this session', + 'msg': 'Failed Dependency'} + socketio.emit('pj_corpus_analysis_query', response, room=request.sid) + return + try: + corpus = client.corpora.get('CORPUS') + except cqi.errors.CQiException as e: + response = {'code': 500, 'desc': None, 'msg': 'Internal Server Error', + 'payload': {'code': e.code, 'desc': e.description, + 'msg': e.name}} socketio.emit('pj_corpus_analysis_query', response, room=request.sid) return - corpus = client.corpora.get('CORPUS') try: results = corpus.query(query) except cqi.errors.CQiException as e: - response = {'code': 1, 'msg': str(e)} + response = {'code': 500, 'desc': None, 'msg': 'Internal Server Error', + 'payload': {'code': e.code, 'desc': e.description, + 'msg': e.name}} socketio.emit('pj_corpus_analysis_query', response, room=request.sid) - else: - response = {'code': 200, 'msg': 'OK', - 'data': {'num_matches': results.size}} - socketio.emit('pj_corpus_analysis_query', response, room=request.sid) - chunk_size = 100 - chunk_start = 0 - context = 100 - progress = 0 - while chunk_start <= results.size: - chunk = results.export(context=context, offset=chunk_start, - cutoff=chunk_size) - if (results.size == 0): - progress = 100 - else: - progress = ((chunk_start + chunk_size) / results.size) * 100 - progress = min(100, int(math.ceil(progress))) - socketio.emit('pj_corpus_analysis_query_results', - {'chunk': chunk, - 'progress': progress}, - room=request.sid) - chunk_start += chunk_size - chunk_size = 250 + return + response = {'code': 200, 'desc': None, 'msg': 'OK', + 'payload': {'num_matches': results.size}} + socketio.emit('pj_corpus_analysis_query', response, room=request.sid) + chunk_size = 100 + chunk_start = 0 + context = 100 + progress = 0 + while chunk_start <= results.size: + chunk = results.export(context=context, cutoff=chunk_size, + offset=chunk_start) + if (results.size == 0): + progress = 100 + else: + progress = ((chunk_start + chunk_size) / results.size) * 100 + progress = min(100, int(math.ceil(progress))) + response = {'code': 200, 'desc': None, 'msg': 'OK', + 'payload': {'chunk': chunk, 'progress': progress}} + socketio.emit('pj_corpus_analysis_query_results', response, + room=request.sid) + chunk_start += chunk_size def pj_corpus_analysis_session_handler(app, corpus_id, user_id, session_id): @@ -72,11 +81,11 @@ def pj_corpus_analysis_session_handler(app, corpus_id, user_id, session_id): corpus = Corpus.query.get(corpus_id) user = User.query.get(user_id) if corpus is None: - response = {'code': 404, 'msg': 'Not Found'} + response = {'code': 404, 'desc': None, 'msg': 'Not Found'} socketio.emit('pj_corpus_analysis_init', response, room=session_id) return elif not (corpus.creator == user or user.is_administrator()): - response = {'code': 403, 'msg': 'Forbidden'} + response = {'code': 403, 'desc': None, 'msg': 'Forbidden'} socketio.emit('pj_corpus_analysis_init', response, room=session_id) return while corpus.status != 'analysing': @@ -85,8 +94,11 @@ def pj_corpus_analysis_session_handler(app, corpus_id, user_id, session_id): client = cqi.CQiClient('corpus_{}_analysis'.format(corpus_id)) try: client.connect() - except cqi.errors.CQiException: - response = {'code': 500, 'msg': 'Internal Server Error'} + except cqi.errors.CQiException as e: + response = {'code': 500, 'desc': None, + 'msg': 'Internal Server Error', + 'payload': {'code': e.code, 'desc': e.description, + 'msg': e.name}} socketio.emit('pj_corpus_analysis_init', response, room=session_id) return pj_corpus_analysis_clients[session_id] = client @@ -94,7 +106,7 @@ def pj_corpus_analysis_session_handler(app, corpus_id, user_id, session_id): pj_corpus_analysis_sessions[corpus_id] = [session_id] else: pj_corpus_analysis_sessions[corpus_id].append(session_id) - response = {'code': 200, 'msg': 'OK'} + response = {'code': 200, 'desc': None, 'msg': 'OK'} socketio.emit('pj_corpus_analysis_init', response, room=session_id) ''' Observe analysis session ''' while session_id in connected_sessions: diff --git a/app/static/js/nopaque.CorpusAnalysisClient.js b/app/static/js/nopaque.CorpusAnalysisClient.js index 59f6e14d..abde67b4 100644 --- a/app/static/js/nopaque.CorpusAnalysisClient.js +++ b/app/static/js/nopaque.CorpusAnalysisClient.js @@ -8,48 +8,46 @@ class CorpusAnalysisClient { socket.on("pj_corpus_analysis_init", (response) => { if (response.code === 200) { console.log(`pj_corpus_analysis_init: ${response.code} - ${response.msg}`); - if (this.callbacks.init != undefined) {this.callbacks.init(response.msg);} + if (this.callbacks.init != undefined) {this.callbacks.init(response.payload);} if (this.displays.init != undefined) {this.displays.init.setVisibilityByStatus("success");} } else { - if (this.displays.init != undefined) { - if (this.displays.init.errorContainer != undefined) {this.displays.init.errorContainer.innerHTML = `

error Error ${response.code}: ${response.msg}

`;} - this.displays.init.setVisibilityByStatus("error"); - } - console.error(`pj_corpus_analysis_init: ${response.code} - ${response.msg}`); + errorText = `Error ${response.payload.code} - ${response.payload.msg}`; + if (this.displays.init.errorContainer != undefined) {this.displays.init.errorContainer.innerHTML = `

error ${errorText}

`;} + if (this.displays.init != undefined) {this.displays.init.setVisibilityByStatus("error");} + console.error(`pj_corpus_analysis_init: ${errorText}`); } }); socket.on("pj_corpus_analysis_query", (response) => { + var errorText; + if (response.code === 200) { console.log(`pj_corpus_analysis_query: ${response.code} - ${response.msg}`); - if (this.callbacks.query != undefined) {this.callbacks.query(response.data);} + if (this.callbacks.query != undefined) {this.callbacks.query(response.payload);} if (this.displays.query != undefined) {this.displays.query.setVisibilityByStatus("success");} } else { - nopaque.flash("error", `Error ${response.code}: ${response.msg}`); - if (this.displays.query.errorContainer != undefined) {this.displays.query.errorContainer.innerHTML = `

error Error ${response.code}: ${response.msg}

`;} + errorText = `Error ${response.payload.code} - ${response.payload.msg}`; + nopaque.flash("error", errorText); + if (this.displays.query.errorContainer != undefined) {this.displays.query.errorContainer.innerHTML = `

error ${errorText}

`;} if (this.displays.query != undefined) {this.displays.query.setVisibilityByStatus("error");} - console.error(`pj_corpus_analysis_query: ${response.code} - ${response.msg}`) + console.error(`pj_corpus_analysis_query: ${errorText}`); } }); socket.on("pj_corpus_analysis_query_results", (response) => { - if (this.callbacks.query_results != undefined) {this.callbacks.query_results(response);} + if (this.callbacks.query_results != undefined) {this.callbacks.query_results(response.payload);} }); } init() { - if (this.displays.init) { - if (this.displays.init.errorContainer != undefined) {this.displays.init.errorContainer.innerHTML == "";} - this.displays.init.setVisibilityByStatus("waiting"); - } + if (this.displays.init.errorContainer != undefined) {this.displays.init.errorContainer.innerHTML == "";} + if (this.displays.init != undefined) {this.displays.init.setVisibilityByStatus("waiting");} this.socket.emit("pj_corpus_analysis_init", this.corpusId); } query(query) { - if (this.displays.query) { - if (this.displays.query.errorContainer != undefined) {this.displays.query.errorContainer.innerHTML == "";} - this.displays.query.setVisibilityByStatus("waiting"); - } + if (this.displays.query.errorContainer != undefined) {this.displays.query.errorContainer.innerHTML == "";} + if (this.displays.query != undefined) {this.displays.query.setVisibilityByStatus("waiting");} nopaque.socket.emit("pj_corpus_analysis_query", query); } diff --git a/app/templates/corpora/pj_analyse_corpus.html.j2 b/app/templates/corpora/pj_analyse_corpus.html.j2 index 3f306ffb..3c389bbf 100644 --- a/app/templates/corpora/pj_analyse_corpus.html.j2 +++ b/app/templates/corpora/pj_analyse_corpus.html.j2 @@ -131,24 +131,24 @@ client.setDisplay("init", initDisplay); client.setCallback("init", () => {initModal.close();}); client.setDisplay("query", queryDisplay); - client.setCallback("query", (response) => { + client.setCallback("query", (payload) => { // This is called when a query was successfull results = {matches: [], cpos_lookup: {}, text_lookup: {}}; queryResultsDeterminateElement.style.width = "0%"; receivedMatchNumElement.innerText = "0"; textLookupNumElement.innerText = "0"; - matchNumElement.innerText = response.num_matches; + matchNumElement.innerText = payload.num_matches; }); - client.setCallback("query_results", (response) => { + client.setCallback("query_results", (payload) => { // This is called when results are transmitted. - if (response.progress === 100) { + if (payload.progress === 100) { queryResultsProgressElement.classList.add("hide"); } - queryResultsDeterminateElement.style.width = `${response.progress}%`; - results.matches.push(...response.chunk.matches); + queryResultsDeterminateElement.style.width = `${payload.progress}%`; + results.matches.push(...payload.chunk.matches); receivedMatchNumElement.innerText = `${results.matches.length}`; - Object.assign(results.cpos_lookup, response.chunk.cpos_lookup); - Object.assign(results.text_lookup, response.chunk.text_lookup); + Object.assign(results.cpos_lookup, payload.chunk.cpos_lookup); + Object.assign(results.text_lookup, payload.chunk.text_lookup); textLookupNumElement.innerText = `${Object.keys(results.text_lookup).length}`; });