Module tf.browser.ner.request

Auxiliary functions for managing request data.

To see how this fits among all the modules of this package, see tf.browser.ner.annotate .

Expand source code Browse git
"""Auxiliary functions for managing request data.

To see how this fits among all the modules of this package, see
`tf.browser.ner.annotate` .
"""


from ...core.generic import AttrDict
from .settings import TOOLKEY, EMPTY, NONE, SORTKEY_DEFAULT, SORTDIR_DEFAULT, SC_ALL
from .form import Form
from .helpers import findCompile


class Request(Form):
    def __init__(self):
        """Calculate important values based on form data.

        We define specifications as to how to read form values and which defaults
        should be supplied.

        We categorize the keys in the request form into categories based on their
        interpreted type and organization.

        We provide appropriate empty values as defaults, but it is possible to specify
        other defaults.

        The categories are:

        *   `Str` values are strings;
        *   `Bool` values are booleans (2 possible values);
        *   `Tri` values are booleans (3 possible values, a none value is included);
        *   `Int` values are positive integers;
        *   `Tup` values are tuples of strings;
        *   `SetInt` values are sets of integers;
        *   `Json` values are arbitrary structures encoded in JSON strings;

        We also define a few composed values, where we store the values of
        several related keys in the form as a dictionary value under a new key.
        """
        annotate = self.annotate
        settings = annotate.settings
        features = settings.features

        keysStr = """
            resetForm
            submitter
            sec0
            sec1
            sec2
            annoset
            duannoset
            rannoset
            dannoset
            sortkey
            sortdir
            bfind
            bfinderror
            freestate
            efind
            scope
            reportdel
            reportadd
            modwidgetstate
        """.strip().split()

        keysBool = """
            formattingdo
            bfindc
        """.strip().split()

        keysTri = """
            anyent
        """.strip().split()

        keysInt = """
            tokenstart
            tokenend
        """.strip().split()

        keysTup = """
            activeentity
        """.strip().split()

        keysSetInt = """
            excludedtokens
        """.strip().split()

        keysJson = """
            adddata
            deldata
        """.strip().split()

        defaults = dict(
            sortkey=SORTKEY_DEFAULT,
            sortdir=SORTDIR_DEFAULT,
            freestate="all",
            scope=SC_ALL,
            modwidgetstate="add",
        )

        formattingState = {
            feat: f"{feat}_appearance" for feat in features + ("_stat_", "_entity_")
        }
        self.formattingState = formattingState

        for feat, featStr in formattingState.items():
            keysBool.append(featStr)
            defaults[featStr] = "v"

        activeVal = {feat: f"{feat}_active" for feat in features}
        self.activeVal = activeVal

        for feat, featStr in activeVal.items():
            keysStr.append(featStr)

        valSelectProto = {feat: f"{feat}_select" for feat in features}
        self.valSelectProto = valSelectProto

        for feat, featStr in valSelectProto.items():
            keysStr.append(featStr)

        super().__init__(
            features,
            defaults,
            keysStr=keysStr,
            keysBool=keysBool,
            keysTri=keysTri,
            keysInt=keysInt,
            keysTup=keysTup,
            keysSetInt=keysSetInt,
            keysJson=keysJson,
        )

    def getFormData(self):
        """Get form data.

        The TF browser user interacts with the app by clicking and typing,
        as a result of which a HTML form gets filled in.
        This form as regularly submitted to the server with a request
        for a new incarnation of the page: a response.

        The values that come with a request, must be peeled out of the form,
        and stored as logical values.

        Additionally, some business logic is carried out:
        we set values for the entity features, based on the form, especially the
        keys ending in `_active`. We build a value under key `valselect`
        based on the value for key `submitter`.
        Depending on which button caused the submit, the NONE value is added
        to each feature.

        The idea is that when the user is still engaged in filtering buckets,
        and there is an occurrence selected, the user should have the option
        to sub-select occurrences that do not yet have an entity assigned.
        """
        annotate = self.annotate
        settings = annotate.settings
        features = settings.features
        formattingState = self.formattingState
        activeVal = self.activeVal
        valSelectProto = self.valSelectProto

        form = self.fill()

        form["formattingstate"] = {
            feat: self.fget2(featStr) for (feat, featStr) in formattingState.items()
        }

        form["activeval"] = {
            feat: self.fgets(featStr) for (feat, featStr) in activeVal.items()
        }

        valSelectProto = {
            feat: self.fgets(featStr) for (feat, featStr) in valSelectProto.items()
        }

        submitter = form["submitter"]

        valSelect = {}

        startSearch = submitter in {"lookupq", "lookupn", "freebutton"}

        for feat in features:
            valProto = valSelectProto[feat]
            valSelect[feat] = (
                set("" if x == EMPTY else x for x in valProto.split(","))
                if valProto
                else set()
            )
            if startSearch:
                valSelect[feat].add(NONE)

        form["valselect"] = valSelect

        return form

    def initVars(self):
        """Initializes the computation of the new page.

        It collects the request data, gleans some info from the configuration
        settings and the TF app, and initializes some data structures that
        will collect further information for the page.

        All bits and pieces that are needed during processing
        the request and filling in the final HTML template find a place under
        some key in the `v` dict which is stored in `self`.

        So, this function makes the transition from information that is in the
        `form` dictionary to values that are stored in the `v` dictionary.
        """
        annotate = self.annotate
        settings = annotate.settings
        bucketType = settings.bucketType
        features = settings.features

        appName = annotate.appName
        appName = appName.replace("/", " / ")
        slotType = annotate.slotType

        form = self.getFormData()
        resetForm = form["resetForm"]

        v = AttrDict()
        v.toolkey = TOOLKEY
        v.buckettype = bucketType
        v.featurelist = ",".join(features)

        for k, vl in form.items():
            if not resetForm or k not in v:
                v[k] = vl

        v.appname = appName
        v.slottype = slotType
        v.resetform = ""

        self.v = v

    def adaptValSelect(self):
        """Adapts the values contained in `valSelect` after a modification action.

        After the addition or deletion of an entity, the values contained in `valSelect`
        may have become obsolete or inconvenient for further actions.

        This function adapts those values before having them rendered on the page.

        Parameters
        ----------
        v: dict
            Contains the intermediate results of computing the new page.
        """
        v = self.v
        annotate = self.annotate
        settings = annotate.settings
        features = settings.features

        submitter = v.submitter
        valSelect = v.valselect

        if submitter == "addgo":
            addData = v.adddata
            additions = addData.additions
            freeVals = addData.freeVals

            freeState = v.freestate

            for i, (feat, values) in enumerate(zip(features, additions)):
                for val in values:
                    valSelect.setdefault(feat, set()).add(val)
                    if val == freeVals[i]:
                        freeVals[i] = None

            if freeState == "free":
                v.freestate = "all"

        elif submitter == "delgo":
            for feat in features:
                valSelect.setdefault(feat, set()).add(NONE)

        v.submitter = ""

    def findSetup(self):
        """Compiles the filter pattern into a regular expression.

        When the user enters a search pattern in the box meant to filter the buckets,
        the pattern will be interpreted as a regular expression.

        We do the compilation here.
        If there are errors in the pattern they will be reported.
        Whether or not the search is case sensitive or not is under user control,
        and it will influence the compilation of the pattern.

        All input and output data is in `v` .
        """
        v = self.v
        bFind = v.bfind
        bFindC = v.bfindc

        (bFind, bFindRe, errorMsg) = findCompile(bFind, bFindC)

        v.bfind = bFind
        v.bfindre = bFindRe
        v.errormsg = errorMsg

Classes

class Request

Calculate important values based on form data.

We define specifications as to how to read form values and which defaults should be supplied.

We categorize the keys in the request form into categories based on their interpreted type and organization.

We provide appropriate empty values as defaults, but it is possible to specify other defaults.

The categories are:

  • Str values are strings;
  • Bool values are booleans (2 possible values);
  • Tri values are booleans (3 possible values, a none value is included);
  • Int values are positive integers;
  • Tup values are tuples of strings;
  • SetInt values are sets of integers;
  • Json values are arbitrary structures encoded in JSON strings;

We also define a few composed values, where we store the values of several related keys in the form as a dictionary value under a new key.

Expand source code Browse git
class Request(Form):
    def __init__(self):
        """Calculate important values based on form data.

        We define specifications as to how to read form values and which defaults
        should be supplied.

        We categorize the keys in the request form into categories based on their
        interpreted type and organization.

        We provide appropriate empty values as defaults, but it is possible to specify
        other defaults.

        The categories are:

        *   `Str` values are strings;
        *   `Bool` values are booleans (2 possible values);
        *   `Tri` values are booleans (3 possible values, a none value is included);
        *   `Int` values are positive integers;
        *   `Tup` values are tuples of strings;
        *   `SetInt` values are sets of integers;
        *   `Json` values are arbitrary structures encoded in JSON strings;

        We also define a few composed values, where we store the values of
        several related keys in the form as a dictionary value under a new key.
        """
        annotate = self.annotate
        settings = annotate.settings
        features = settings.features

        keysStr = """
            resetForm
            submitter
            sec0
            sec1
            sec2
            annoset
            duannoset
            rannoset
            dannoset
            sortkey
            sortdir
            bfind
            bfinderror
            freestate
            efind
            scope
            reportdel
            reportadd
            modwidgetstate
        """.strip().split()

        keysBool = """
            formattingdo
            bfindc
        """.strip().split()

        keysTri = """
            anyent
        """.strip().split()

        keysInt = """
            tokenstart
            tokenend
        """.strip().split()

        keysTup = """
            activeentity
        """.strip().split()

        keysSetInt = """
            excludedtokens
        """.strip().split()

        keysJson = """
            adddata
            deldata
        """.strip().split()

        defaults = dict(
            sortkey=SORTKEY_DEFAULT,
            sortdir=SORTDIR_DEFAULT,
            freestate="all",
            scope=SC_ALL,
            modwidgetstate="add",
        )

        formattingState = {
            feat: f"{feat}_appearance" for feat in features + ("_stat_", "_entity_")
        }
        self.formattingState = formattingState

        for feat, featStr in formattingState.items():
            keysBool.append(featStr)
            defaults[featStr] = "v"

        activeVal = {feat: f"{feat}_active" for feat in features}
        self.activeVal = activeVal

        for feat, featStr in activeVal.items():
            keysStr.append(featStr)

        valSelectProto = {feat: f"{feat}_select" for feat in features}
        self.valSelectProto = valSelectProto

        for feat, featStr in valSelectProto.items():
            keysStr.append(featStr)

        super().__init__(
            features,
            defaults,
            keysStr=keysStr,
            keysBool=keysBool,
            keysTri=keysTri,
            keysInt=keysInt,
            keysTup=keysTup,
            keysSetInt=keysSetInt,
            keysJson=keysJson,
        )

    def getFormData(self):
        """Get form data.

        The TF browser user interacts with the app by clicking and typing,
        as a result of which a HTML form gets filled in.
        This form as regularly submitted to the server with a request
        for a new incarnation of the page: a response.

        The values that come with a request, must be peeled out of the form,
        and stored as logical values.

        Additionally, some business logic is carried out:
        we set values for the entity features, based on the form, especially the
        keys ending in `_active`. We build a value under key `valselect`
        based on the value for key `submitter`.
        Depending on which button caused the submit, the NONE value is added
        to each feature.

        The idea is that when the user is still engaged in filtering buckets,
        and there is an occurrence selected, the user should have the option
        to sub-select occurrences that do not yet have an entity assigned.
        """
        annotate = self.annotate
        settings = annotate.settings
        features = settings.features
        formattingState = self.formattingState
        activeVal = self.activeVal
        valSelectProto = self.valSelectProto

        form = self.fill()

        form["formattingstate"] = {
            feat: self.fget2(featStr) for (feat, featStr) in formattingState.items()
        }

        form["activeval"] = {
            feat: self.fgets(featStr) for (feat, featStr) in activeVal.items()
        }

        valSelectProto = {
            feat: self.fgets(featStr) for (feat, featStr) in valSelectProto.items()
        }

        submitter = form["submitter"]

        valSelect = {}

        startSearch = submitter in {"lookupq", "lookupn", "freebutton"}

        for feat in features:
            valProto = valSelectProto[feat]
            valSelect[feat] = (
                set("" if x == EMPTY else x for x in valProto.split(","))
                if valProto
                else set()
            )
            if startSearch:
                valSelect[feat].add(NONE)

        form["valselect"] = valSelect

        return form

    def initVars(self):
        """Initializes the computation of the new page.

        It collects the request data, gleans some info from the configuration
        settings and the TF app, and initializes some data structures that
        will collect further information for the page.

        All bits and pieces that are needed during processing
        the request and filling in the final HTML template find a place under
        some key in the `v` dict which is stored in `self`.

        So, this function makes the transition from information that is in the
        `form` dictionary to values that are stored in the `v` dictionary.
        """
        annotate = self.annotate
        settings = annotate.settings
        bucketType = settings.bucketType
        features = settings.features

        appName = annotate.appName
        appName = appName.replace("/", " / ")
        slotType = annotate.slotType

        form = self.getFormData()
        resetForm = form["resetForm"]

        v = AttrDict()
        v.toolkey = TOOLKEY
        v.buckettype = bucketType
        v.featurelist = ",".join(features)

        for k, vl in form.items():
            if not resetForm or k not in v:
                v[k] = vl

        v.appname = appName
        v.slottype = slotType
        v.resetform = ""

        self.v = v

    def adaptValSelect(self):
        """Adapts the values contained in `valSelect` after a modification action.

        After the addition or deletion of an entity, the values contained in `valSelect`
        may have become obsolete or inconvenient for further actions.

        This function adapts those values before having them rendered on the page.

        Parameters
        ----------
        v: dict
            Contains the intermediate results of computing the new page.
        """
        v = self.v
        annotate = self.annotate
        settings = annotate.settings
        features = settings.features

        submitter = v.submitter
        valSelect = v.valselect

        if submitter == "addgo":
            addData = v.adddata
            additions = addData.additions
            freeVals = addData.freeVals

            freeState = v.freestate

            for i, (feat, values) in enumerate(zip(features, additions)):
                for val in values:
                    valSelect.setdefault(feat, set()).add(val)
                    if val == freeVals[i]:
                        freeVals[i] = None

            if freeState == "free":
                v.freestate = "all"

        elif submitter == "delgo":
            for feat in features:
                valSelect.setdefault(feat, set()).add(NONE)

        v.submitter = ""

    def findSetup(self):
        """Compiles the filter pattern into a regular expression.

        When the user enters a search pattern in the box meant to filter the buckets,
        the pattern will be interpreted as a regular expression.

        We do the compilation here.
        If there are errors in the pattern they will be reported.
        Whether or not the search is case sensitive or not is under user control,
        and it will influence the compilation of the pattern.

        All input and output data is in `v` .
        """
        v = self.v
        bFind = v.bfind
        bFindC = v.bfindc

        (bFind, bFindRe, errorMsg) = findCompile(bFind, bFindC)

        v.bfind = bFind
        v.bfindre = bFindRe
        v.errormsg = errorMsg

Ancestors

Subclasses

Methods

def adaptValSelect(self)

Adapts the values contained in valSelect after a modification action.

After the addition or deletion of an entity, the values contained in valSelect may have become obsolete or inconvenient for further actions.

This function adapts those values before having them rendered on the page.

Parameters

v : dict
Contains the intermediate results of computing the new page.
Expand source code Browse git
def adaptValSelect(self):
    """Adapts the values contained in `valSelect` after a modification action.

    After the addition or deletion of an entity, the values contained in `valSelect`
    may have become obsolete or inconvenient for further actions.

    This function adapts those values before having them rendered on the page.

    Parameters
    ----------
    v: dict
        Contains the intermediate results of computing the new page.
    """
    v = self.v
    annotate = self.annotate
    settings = annotate.settings
    features = settings.features

    submitter = v.submitter
    valSelect = v.valselect

    if submitter == "addgo":
        addData = v.adddata
        additions = addData.additions
        freeVals = addData.freeVals

        freeState = v.freestate

        for i, (feat, values) in enumerate(zip(features, additions)):
            for val in values:
                valSelect.setdefault(feat, set()).add(val)
                if val == freeVals[i]:
                    freeVals[i] = None

        if freeState == "free":
            v.freestate = "all"

    elif submitter == "delgo":
        for feat in features:
            valSelect.setdefault(feat, set()).add(NONE)

    v.submitter = ""
def findSetup(self)

Compiles the filter pattern into a regular expression.

When the user enters a search pattern in the box meant to filter the buckets, the pattern will be interpreted as a regular expression.

We do the compilation here. If there are errors in the pattern they will be reported. Whether or not the search is case sensitive or not is under user control, and it will influence the compilation of the pattern.

All input and output data is in v .

Expand source code Browse git
def findSetup(self):
    """Compiles the filter pattern into a regular expression.

    When the user enters a search pattern in the box meant to filter the buckets,
    the pattern will be interpreted as a regular expression.

    We do the compilation here.
    If there are errors in the pattern they will be reported.
    Whether or not the search is case sensitive or not is under user control,
    and it will influence the compilation of the pattern.

    All input and output data is in `v` .
    """
    v = self.v
    bFind = v.bfind
    bFindC = v.bfindc

    (bFind, bFindRe, errorMsg) = findCompile(bFind, bFindC)

    v.bfind = bFind
    v.bfindre = bFindRe
    v.errormsg = errorMsg
def getFormData(self)

Get form data.

The TF browser user interacts with the app by clicking and typing, as a result of which a HTML form gets filled in. This form as regularly submitted to the server with a request for a new incarnation of the page: a response.

The values that come with a request, must be peeled out of the form, and stored as logical values.

Additionally, some business logic is carried out: we set values for the entity features, based on the form, especially the keys ending in _active. We build a value under key valselect based on the value for key submitter. Depending on which button caused the submit, the NONE value is added to each feature.

The idea is that when the user is still engaged in filtering buckets, and there is an occurrence selected, the user should have the option to sub-select occurrences that do not yet have an entity assigned.

Expand source code Browse git
def getFormData(self):
    """Get form data.

    The TF browser user interacts with the app by clicking and typing,
    as a result of which a HTML form gets filled in.
    This form as regularly submitted to the server with a request
    for a new incarnation of the page: a response.

    The values that come with a request, must be peeled out of the form,
    and stored as logical values.

    Additionally, some business logic is carried out:
    we set values for the entity features, based on the form, especially the
    keys ending in `_active`. We build a value under key `valselect`
    based on the value for key `submitter`.
    Depending on which button caused the submit, the NONE value is added
    to each feature.

    The idea is that when the user is still engaged in filtering buckets,
    and there is an occurrence selected, the user should have the option
    to sub-select occurrences that do not yet have an entity assigned.
    """
    annotate = self.annotate
    settings = annotate.settings
    features = settings.features
    formattingState = self.formattingState
    activeVal = self.activeVal
    valSelectProto = self.valSelectProto

    form = self.fill()

    form["formattingstate"] = {
        feat: self.fget2(featStr) for (feat, featStr) in formattingState.items()
    }

    form["activeval"] = {
        feat: self.fgets(featStr) for (feat, featStr) in activeVal.items()
    }

    valSelectProto = {
        feat: self.fgets(featStr) for (feat, featStr) in valSelectProto.items()
    }

    submitter = form["submitter"]

    valSelect = {}

    startSearch = submitter in {"lookupq", "lookupn", "freebutton"}

    for feat in features:
        valProto = valSelectProto[feat]
        valSelect[feat] = (
            set("" if x == EMPTY else x for x in valProto.split(","))
            if valProto
            else set()
        )
        if startSearch:
            valSelect[feat].add(NONE)

    form["valselect"] = valSelect

    return form
def initVars(self)

Initializes the computation of the new page.

It collects the request data, gleans some info from the configuration settings and the TF app, and initializes some data structures that will collect further information for the page.

All bits and pieces that are needed during processing the request and filling in the final HTML template find a place under some key in the v dict which is stored in self.

So, this function makes the transition from information that is in the form dictionary to values that are stored in the v dictionary.

Expand source code Browse git
def initVars(self):
    """Initializes the computation of the new page.

    It collects the request data, gleans some info from the configuration
    settings and the TF app, and initializes some data structures that
    will collect further information for the page.

    All bits and pieces that are needed during processing
    the request and filling in the final HTML template find a place under
    some key in the `v` dict which is stored in `self`.

    So, this function makes the transition from information that is in the
    `form` dictionary to values that are stored in the `v` dictionary.
    """
    annotate = self.annotate
    settings = annotate.settings
    bucketType = settings.bucketType
    features = settings.features

    appName = annotate.appName
    appName = appName.replace("/", " / ")
    slotType = annotate.slotType

    form = self.getFormData()
    resetForm = form["resetForm"]

    v = AttrDict()
    v.toolkey = TOOLKEY
    v.buckettype = bucketType
    v.featurelist = ",".join(features)

    for k, vl in form.items():
        if not resetForm or k not in v:
            v[k] = vl

    v.appname = appName
    v.slottype = slotType
    v.resetform = ""

    self.v = v

Inherited members