swh:1:snp:7ce5f1105410d5ee1ad6abfdc873986c25b579e5
Raw File
Tip revision: 92d03dc470a217b73f890212332e07feeebe4a3a authored by Dirk Roorda on 10 January 2019, 19:18:54 UTC
tutorials moved
Tip revision: 92d03dc
serve.py
import pickle
import markdown
from flask import jsonify, redirect, render_template, make_response

from ..core.helpers import console, wrapMessages
from ..applib.helpers import RESULT
from .wrap import (
    pageLinks,
    passageLinks,
    getValues,
    wrapOptions,
    wrapCondense,
    wrapFormats,
    wrapProvenance,
)
from .servelib import getAbout, getFormData, zipData

TIMEOUT = 180


def serveTable(setup, kind, getx=None, asDict=False):
  form = getFormData(setup.config)
  textFormat = form['textformat'] or None
  task = form[kind].strip()
  openedKey = f'{kind}Opened'
  openedSet = {int(n) for n in form[openedKey].split(',')} if form[openedKey] else set()

  optionSpecs = setup.config.OPTIONS
  options = getValues(optionSpecs, form)

  method = dict if asDict else jsonify

  kernelApi = setup.TF.connect()

  messages = ''
  table = None
  if task:
    (
        table,
        messages,
    ) = kernelApi.table(
        kind,
        task,
        form['features'],
        opened=openedSet,
        fmt=textFormat,
        withNodes=form['withNodes'],
        getx=int(getx) if getx else None,
        **options,
    )

    if messages:
      messages = wrapMessages(messages)

  return method(
      table=table,
      messages=messages,
  )


def serveQuery(setup, getx, asDict=False):
  kind = 'query'
  form = getFormData(setup.config)
  task = form[kind]
  condenseType = form['condenseTp'] or None
  resultKind = condenseType if form['condensed'] else RESULT
  textFormat = form['textformat'] or None
  openedKey = f'{kind}Opened'
  openedSet = {int(n) for n in form[openedKey].split(',')} if form[openedKey] else set()

  optionSpecs = setup.config.OPTIONS
  options = getValues(optionSpecs, form)

  pages = ''
  features = ''

  kernelApi = setup.TF.connect()
  method = dict if asDict else jsonify

  if task:
    messages = ''
    table = None
    if task in setup.wildQueries:
      messages = (
          f'Aborted because query is known to take longer than {TIMEOUT} second'
          + ('' if TIMEOUT == 1 else 's')
      )
    else:
      try:
        (
            table,
            messages,
            features,
            start,
            total,
        ) = kernelApi.search(
            task,
            form['batch'],
            position=form['position'],
            opened=openedSet,
            condensed=form['condensed'],
            condenseType=condenseType,
            fmt=textFormat,
            withNodes=form['withNodes'],
            linked=form['linked'],
            getx=int(getx) if getx else None,
            **options,
        )
      except TimeoutError:
        messages = (
            f'Aborted because query takes longer than {TIMEOUT} second'
            + ('' if TIMEOUT == 1 else 's')
        )
        console(f'{task}\n{messages}', error=True)
        setup.wildQueries.add(task)

    if table is not None:
      pages = pageLinks(total, form['position'])
    # messages have already been shaped by search
    # if messages:
    #  messages = wrapMessages(messages)
  else:
    table = f'no {resultKind}s'
    messages = ''

  return method(
      pages=pages,
      table=table,
      messages=messages,
      features=features,
  )


def servePassage(setup, getx):
  form = getFormData(setup.config)
  textFormat = form['textformat'] or None

  optionSpecs = setup.config.OPTIONS
  options = getValues(optionSpecs, form)

  passages = ''

  kernelApi = setup.TF.connect()

  openedKey = 'passageOpened'
  openedSet = set(form[openedKey].split(',')) if form[openedKey] else set()

  sec0 = form['sec0']
  sec1 = form['sec1']
  sec2 = form['sec2']
  (
      table,
      sec0Type,
      passages,
      browseNavLevel,
  ) = kernelApi.passage(
      form['features'],
      form['query'],
      sec0,
      sec1=sec1,
      sec2=sec2,
      opened=openedSet,
      fmt=textFormat,
      withNodes=form['withNodes'],
      getx=getx,
      **options,
  )
  passages = pickle.loads(passages)
  passages = passageLinks(passages, sec0Type, sec0, sec1, browseNavLevel)
  return jsonify(
      table=table,
      passages=passages,
  )


def serveExport(setup):
  sectionsData = serveTable(setup, 'sections', None, asDict=True)
  tuplesData = serveTable(setup, 'tuples', None, asDict=True)
  queryData = serveQuery(setup, None, asDict=True)

  form = getFormData(setup.config)

  kernelApi = setup.TF.connect()
  (header, appLogo, tfLogo) = kernelApi.header()
  css = kernelApi.css()
  provenance = kernelApi.provenance()
  setNames = kernelApi.setNames()
  setNamesRep = ', '.join(setNames)
  setNameHtml = f'''
<p class="setnames">Sets:
<span class="setnames">{setNamesRep}</span>
</p>''' if setNames else ''
  (provenanceHtml, provenanceMd) = wrapProvenance(form, provenance, setNames)

  descriptionMd = markdown.markdown(
      form['description'], extensions=[
          'markdown.extensions.tables',
          'markdown.extensions.fenced_code',
      ]
  )

  sectionsMessages = sectionsData['messages']
  sectionsTable = sectionsData['table']
  tuplesMessages = tuplesData['messages']
  tuplesTable = tuplesData['table']
  queryMessages = queryData['messages']
  queryTable = queryData['table']

  return render_template(
      'export.html',
      dataSource=setup.dataSource,
      css=css,
      descriptionMd=descriptionMd,
      sectionsTable=(
          sectionsMessages if sectionsMessages or sectionsTable is None else sectionsTable
      ),
      tuplesTable=(
          tuplesMessages if tuplesMessages or tuplesTable is None else tuplesTable
      ),
      queryTable=(
          queryMessages if queryMessages or queryTable is None else queryTable
      ),
      colofon=f'{appLogo}{header}{tfLogo}',
      provenance=provenanceHtml,
      setNames=setNameHtml,
      **form,
  )


def serveDownload(setup):
  form = getFormData(setup.config)
  kernelApi = setup.TF.connect()

  task = form['query']
  condenseType = form['condenseTp'] or None
  textFormat = form['textformat'] or None
  csvs = None
  resultsX = None
  messages = ''
  if task in setup.wildQueries:
    messages = (
        f'Aborted because query is known to take longer than {TIMEOUT} second'
        + ('' if TIMEOUT == 1 else 's')
    )
  else:
    try:
      (queryMessages, csvs, resultsX) = kernelApi.csvs(
          task,
          form['tuples'],
          form['sections'],
          condensed=form['condensed'],
          condenseType=condenseType,
          fmt=textFormat,
      )
    except TimeoutError:
      messages = (
          f'Aborted because query takes longer than {TIMEOUT} second'
          + ('' if TIMEOUT == 1 else 's')
      )
      console(f'{task}\n{messages}', error=True)
      setup.wildQueries.add(task)
      return jsonify(messages=messages)

  if queryMessages:
    redirect('/')
    return jsonify(messages=queryMessages)

  (header, appLogo, tfLogo) = kernelApi.header()
  provenance = kernelApi.provenance()
  setNames = kernelApi.setNames()
  (provenanceHtml, provenanceMd) = wrapProvenance(form, provenance, setNames)

  csvs = pickle.loads(csvs)
  resultsX = pickle.loads(resultsX)
  about = getAbout(header, provenanceMd, form)
  (fileName, zipBuffer) = zipData(csvs, resultsX, about, form)

  headers = {
      'Expires': '0',
      'Cache-Control': 'no-cache, no-store, must-revalidate',
      'Content-Type': 'application/octet-stream',
      'Content-Disposition': f'attachment; filename="{fileName}"',
      'Content-Encoding': 'identity',
  }
  return make_response(zipBuffer, headers)


def serveAll(setup, anything):
  form = getFormData(setup.config)
  condensedAtt = ' checked ' if form['condensed'] else ''
  withNodesAtt = ' checked ' if form['withNodes'] else ''

  optionSpecs = setup.config.OPTIONS
  options = getValues(optionSpecs, form)

  pages = ''
  passages = ''

  kernelApi = setup.TF.connect()

  (header, appLogo, tfLogo) = kernelApi.header()
  css = kernelApi.css()
  provenance = kernelApi.provenance()
  setNames = kernelApi.setNames()
  setNamesRep = ', '.join(setNames)
  setNameHtml = f'''
<p class="setnames">Sets:
<span class="setnames">{setNamesRep}</span>
</p>''' if setNames else ''
  (provenanceHtml, provenanceMd) = wrapProvenance(form, provenance, setNames)

  (
      defaultCondenseType,
      exampleSection,
      exampleSectionText,
      condenseTypes,
      defaultTextFormat,
      textFormats,
  ) = kernelApi.condenseTypes()
  condenseType = form['condenseTp'] or defaultCondenseType
  condenseOpts = wrapCondense(condenseTypes, condenseType)
  textFormat = form['textformat'] or defaultTextFormat
  textFormatOpts = wrapFormats(textFormats, textFormat)

  return render_template(
      'index.html',
      dataSource=setup.dataSource,
      css=css,
      header=f'{appLogo}{header}{tfLogo}',
      setNames=setNameHtml,
      options=wrapOptions(optionSpecs, options),
      condensedAtt=condensedAtt,
      condenseOpts=condenseOpts,
      defaultCondenseType=defaultCondenseType,
      textFormatOpts=textFormatOpts,
      defaultTextFormat=defaultTextFormat,
      exampleSection=exampleSection,
      exampleSectionText=exampleSectionText,
      withNodesAtt=withNodesAtt,
      pages=pages,
      passages=passages,
      **form,
  )
back to top