示例#1
0
    def search(self):
        """Return the list of keyboard resources matching the input
        JSON query.

        :URL: ``SEARCH /keyboards``
          (or ``POST /keyboards/search``)
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        """
        try:
            json_search_params = unicode(request.body, request.charset)
            python_search_params = json.loads(json_search_params)
            query = self.query_builder.get_SQLA_query(
                python_search_params.get('query'))
            return h.add_pagination(query,
                                    python_search_params.get('paginator'))
        except h.JSONDecodeError:
            response.status_int = 400
            return h.JSONDecodeErrorResponse
        except (OLDSearchParseError, Invalid), e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#2
0
    def search(self):
        """Return the list of form search resources matching the input JSON query.

        :URL: ``SEARCH /formsearches`` (or ``POST /formsearches/search``)
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        .. note::
        
            Yes, that's right, you can search form searches.  (No, you can't
            search searches of form searches :)

        """
        try:
            json_search_params = unicode(request.body, request.charset)
            python_search_params = json.loads(json_search_params)
            query = h.eagerload_form_search(
                self.query_builder.get_SQLA_query(python_search_params.get('query')))
            return h.add_pagination(query, python_search_params.get('paginator'))
        except h.JSONDecodeError:
            response.status_int = 400
            return h.JSONDecodeErrorResponse
        except (OLDSearchParseError, Invalid), e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#3
0
    def search_corpora(self):
        """Return the list of corpora that match the input JSON query.

        :URL: ``SEARCH/POST /corpora/searchcorpora``
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        .. note::

            This action *does* result in a search across corpora resources.
            Contrast this with the `search` method below which allows one to
            search across the forms in a specified corpus.

        """

        try:
            json_search_params = unicode(request.body, request.charset)
            python_search_params = json.loads(json_search_params)
            SQLAQuery = self.query_builder_for_ordering.get_SQLA_query(
                python_search_params.get('query'))
            return h.add_pagination(SQLAQuery,
                                    python_search_params.get('paginator'))
        except h.JSONDecodeError:
            response.status_int = 400
            return h.JSONDecodeErrorResponse
        except (OLDSearchParseError, Invalid), e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#4
0
    def search(self, id):
        """Return the remembered forms of a user that match the input JSON query.

        :URL: ``SEARCH /rememberedforms/id`` (or ``POST /rememberedforms/id/search``).
        :param str id: the ``id`` value of the user whose remembered forms are searched.
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        """
        user = Session.query(User).get(id)
        if user:
            try:
                json_search_params = unicode(request.body, request.charset)
                python_search_params = json.loads(json_search_params)
                query = h.eagerload_form(
                    self.query_builder.get_SQLA_query(
                        python_search_params.get('query')))
                query = query.filter(Form.memorizers.contains(user))
                query = h.filter_restricted_models('Form', query)
                return h.add_pagination(query,
                                        python_search_params.get('paginator'))
            except h.JSONDecodeError:
                response.status_int = 400
                return h.JSONDecodeErrorResponse
            except (OLDSearchParseError, Invalid), e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
            except:
示例#5
0
    def search(self):
        """Return the list of morpheme language model resources matching the
        input JSON query.

        :URL: ``SEARCH /morphemelanguagemodels`` (or ``POST
            /morphemelanguagemodels/search``)
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        """
        try:
            json_search_params = unicode(request.body, request.charset)
            python_search_params = json.loads(json_search_params)
            query = self.query_builder.get_SQLA_query(python_search_params.get('query'))
            return h.add_pagination(query, python_search_params.get('paginator'))
        except h.JSONDecodeError:
            response.status_int = 400
            return h.JSONDecodeErrorResponse
        except (OLDSearchParseError, Invalid), e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#6
0
    def index(self):
        """Get all collection resources.

        :URL: ``GET /collections`` with optional query string parameters for
            ordering and pagination.
        :returns: a list of all collection resources.

        .. note::

           See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the
           query string parameters that effect ordering and pagination.

        .. note::
        
            ``GET /collections`` does not return the forms of the collections
            returned.  For that, a second request is required, i.e., to
            ``GET /collections/id`` with the relevant ``id`` value.

        """
        try:
            query = h.eagerload_collection(Session.query(Collection))
            query = h.add_order_by(query, dict(request.GET),
                                   self.query_builder)
            query = h.filter_restricted_models('Collection', query)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#7
0
    def search(self):
        """Return the list of collection resources matching the input JSON query.

        :URL: ``SEARCH /collections`` (or ``POST /collections/search``)
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        .. note::
        
            Search does not return the forms of all collections that match the
            search.  For that, a second request is required, i.e., to
            ``GET /collections/id``.

        """
        try:
            json_search_params = unicode(request.body, request.charset)
            python_search_params = json.loads(json_search_params)
            SQLAQuery = h.eagerload_collection(
                self.query_builder.get_SQLA_query(
                    python_search_params.get('query')))
            query = h.filter_restricted_models('Collection', SQLAQuery)
            return h.add_pagination(query,
                                    python_search_params.get('paginator'))
        except h.JSONDecodeError:
            response.status_int = 400
            return h.JSONDecodeErrorResponse
        except (OLDSearchParseError, Invalid), e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#8
0
    def index(self):
        """Get all collection resources.

        :URL: ``GET /collections`` with optional query string parameters for
            ordering and pagination.
        :returns: a list of all collection resources.

        .. note::

           See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the
           query string parameters that effect ordering and pagination.

        .. note::
        
            ``GET /collections`` does not return the forms of the collections
            returned.  For that, a second request is required, i.e., to
            ``GET /collections/id`` with the relevant ``id`` value.

        """
        try:
            query = h.eagerload_collection(Session.query(Collection))
            query = h.add_order_by(query, dict(request.GET), self.query_builder)
            query = h.filter_restricted_models('Collection', query)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#9
0
    def search(self):
        """Return the list of collection resources matching the input JSON query.

        :URL: ``SEARCH /collections`` (or ``POST /collections/search``)
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        .. note::
        
            Search does not return the forms of all collections that match the
            search.  For that, a second request is required, i.e., to
            ``GET /collections/id``.

        """
        try:
            json_search_params = unicode(request.body, request.charset)
            python_search_params = json.loads(json_search_params)
            SQLAQuery = h.eagerload_collection(
                self.query_builder.get_SQLA_query(python_search_params.get('query')))
            query = h.filter_restricted_models('Collection', SQLAQuery)
            return h.add_pagination(query, python_search_params.get('paginator'))
        except h.JSONDecodeError:
            response.status_int = 400
            return h.JSONDecodeErrorResponse
        except (OLDSearchParseError, Invalid), e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#10
0
    def search(self, id):
        """Return the remembered forms of a user that match the input JSON query.

        :URL: ``SEARCH /rememberedforms/id`` (or ``POST /rememberedforms/id/search``).
        :param str id: the ``id`` value of the user whose remembered forms are searched.
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        """
        user = Session.query(User).get(id)
        if user:
            try:
                json_search_params = unicode(request.body, request.charset)
                python_search_params = json.loads(json_search_params)
                query = h.eagerload_form(
                    self.query_builder.get_SQLA_query(python_search_params.get('query')))
                query = query.filter(Form.memorizers.contains(user))
                query = h.filter_restricted_models('Form', query)
                return h.add_pagination(query, python_search_params.get('paginator'))
            except h.JSONDecodeError:
                response.status_int = 400
                return h.JSONDecodeErrorResponse
            except (OLDSearchParseError, Invalid), e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
            except:
示例#11
0
    def show(self, id):
        """Return a user's remembered forms.
        
        :URL: ``GET /rememberedforms/id`` with optional query string parameters
            for ordering and pagination.
        :param str id: the ``id`` value of a user model.
        :returns: a list form models.

        .. note::

            Any authenticated user is authorized to access this resource.
            Restricted forms are filtered from the array on a per-user basis.

        .. note::

           See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the
           query string parameters that effect ordering and pagination.

        """
        user = Session.query(User).get(id)
        if user:
            try:
                query = h.eagerload_form(Session.query(Form))\
                            .filter(Form.memorizers.contains(user))
                query = h.add_order_by(query, dict(request.GET),
                                       self.query_builder)
                query = h.filter_restricted_models('Form', query)
                return h.add_pagination(query, dict(request.GET))
            except Invalid, e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
示例#12
0
文件: corpora.py 项目: jrwdunham/old
    def search_corpora(self):
        """Return the list of corpora that match the input JSON query.

        :URL: ``SEARCH/POST /corpora/searchcorpora``
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        .. note::

            This action *does* result in a search across corpora resources.
            Contrast this with the `search` method below which allows one to
            search across the forms in a specified corpus.

        """

        try:
            json_search_params = unicode(request.body, request.charset)
            python_search_params = json.loads(json_search_params)
            SQLAQuery = self.query_builder_for_ordering.get_SQLA_query(
                python_search_params.get('query'))
            return h.add_pagination(SQLAQuery,
                python_search_params.get('paginator'))
        except h.JSONDecodeError:
            response.status_int = 400
            return h.JSONDecodeErrorResponse
        except (OLDSearchParseError, Invalid), e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#13
0
    def show(self, id):
        """Return a user's remembered forms.
        
        :URL: ``GET /rememberedforms/id`` with optional query string parameters
            for ordering and pagination.
        :param str id: the ``id`` value of a user model.
        :returns: a list form models.

        .. note::

            Any authenticated user is authorized to access this resource.
            Restricted forms are filtered from the array on a per-user basis.

        .. note::

           See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the
           query string parameters that effect ordering and pagination.

        """
        user = Session.query(User).get(id)
        if user:
            try:
                query = h.eagerload_form(Session.query(Form))\
                            .filter(Form.memorizers.contains(user))
                query = h.add_order_by(query, dict(request.GET), self.query_builder)
                query = h.filter_restricted_models('Form', query)
                return h.add_pagination(query, dict(request.GET))
            except Invalid, e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
示例#14
0
    def index(self):
        """Get all morphology backup resources.

        :URL: ``GET /morphologybackups`` 
        :returns: a list of all morphology backup resources.

        """
        try:
            query = Session.query(MorphologyBackup)
            query = h.add_order_by(query, dict(request.GET), self.query_builder)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#15
0
    def index(self):
        """Get all language resources.

        :URL: ``GET /languages`` 
        :returns: a list of all language resources.

        """
        try:
            query = Session.query(Language)
            query = h.add_order_by(query, dict(request.GET), self.query_builder, 'Id')
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#16
0
    def index(self):
        """Get all language resources.

        :URL: ``GET /languages`` 
        :returns: a list of all language resources.

        """
        try:
            query = Session.query(Language)
            query = h.add_order_by(query, dict(request.GET),
                                   self.query_builder, 'Id')
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#17
0
    def index(self):
        """Get all corpus backup resources.

        :URL: ``GET /corpusbackups`` 
        :returns: a list of all corpus backup resources.

        """
        try:
            query = Session.query(CorpusBackup)
            query = h.add_order_by(query, dict(request.GET),
                                   self.query_builder)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#18
0
    def index(self):
        """Get all form backup resources.

        :URL: ``GET /formbackups`` 
        :returns: a list of all form backup resources.

        """
        try:
            query = Session.query(FormBackup)
            query = h.add_order_by(query, dict(request.GET), self.query_builder)
            query = h.filter_restricted_models(u'FormBackup', query)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#19
0
    def index(self):
        """Get all form backup resources.

        :URL: ``GET /formbackups`` 
        :returns: a list of all form backup resources.

        """
        try:
            query = Session.query(FormBackup)
            query = h.add_order_by(query, dict(request.GET),
                                   self.query_builder)
            query = h.filter_restricted_models(u'FormBackup', query)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#20
0
    def search(self, id):
        """Return the forms from corpus ``id`` that match the input JSON query.

        :param str id: the id value of the corpus to be searched.
        :URL: ``SEARCH /corpora/id` (or ``POST /corpora/id/search``)
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        .. note::

            The corpora search action is different from typical search actions
            in that it does not return an array of corpora but of forms that
            are in the corpus whose ``id`` value matches ``id``.  This action
            resembles the search action of the ``RememberedformsController``.

        """
        corpus = Session.query(Corpus).get(id)
        if corpus:
            try:
                json_search_params = unicode(request.body, request.charset)
                python_search_params = json.loads(json_search_params)
                query = h.eagerload_form(
                    self.query_builder.get_SQLA_query(
                        python_search_params.get('query')))
                query = query.filter(Form.corpora.contains(corpus))
                query = h.filter_restricted_models('Form', query)
                return h.add_pagination(query,
                                        python_search_params.get('paginator'))
            except h.JSONDecodeError:
                response.status_int = 400
                return h.JSONDecodeErrorResponse
            except (OLDSearchParseError, Invalid), e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
            except Exception, e:
                log.warn(
                    "%s's filter expression (%s) raised an unexpected exception: %s."
                    % (h.get_user_full_name(session['user']), request.body, e))
                response.status_int = 400
                return {
                    'error':
                    u'The specified search parameters generated an invalid database query'
                }
示例#21
0
    def index(self):
        """Get all phonology resources.

        :URL: ``GET /phonologies`` with optional query string parameters for
            ordering and pagination.
        :returns: a list of all phonology resources.

        .. note::

           See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the
           query string parameters that effect ordering and pagination.

        """
        try:
            query = h.eagerload_phonology(Session.query(Phonology))
            query = h.add_order_by(query, dict(request.GET), self.query_builder)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#22
0
文件: users.py 项目: jrwdunham/old
    def index(self):
        """Get all user resources.

        :URL: ``GET /users`` with optional query string parameters for
            ordering and pagination.
        :returns: a list of all user resources.

        .. note::

           See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the
           query string parameters that effect ordering and pagination.

        """
        try:
            query = Session.query(User)
            query = h.add_order_by(query, dict(request.GET), self.query_builder)
            return h.add_pagination(query, dict(request.GET))
        except Invalid, e:
            response.status_int = 400
            return {'errors': e.unpack_errors()}
示例#23
0
文件: corpora.py 项目: jrwdunham/old
    def search(self, id):
        """Return the forms from corpus ``id`` that match the input JSON query.

        :param str id: the id value of the corpus to be searched.
        :URL: ``SEARCH /corpora/id` (or ``POST /corpora/id/search``)
        :request body: A JSON object of the form::

                {"query": {"filter": [ ... ], "order_by": [ ... ]},
                 "paginator": { ... }}

            where the ``order_by`` and ``paginator`` attributes are optional.

        .. note::

            The corpora search action is different from typical search actions
            in that it does not return an array of corpora but of forms that
            are in the corpus whose ``id`` value matches ``id``.  This action
            resembles the search action of the ``RememberedformsController``.

        """
        corpus = Session.query(Corpus).get(id)
        if corpus:
            try:
                json_search_params = unicode(request.body, request.charset)
                python_search_params = json.loads(json_search_params)
                query = h.eagerload_form(
                    self.query_builder.get_SQLA_query(python_search_params.get('query')))
                query = query.filter(Form.corpora.contains(corpus))
                query = h.filter_restricted_models('Form', query)
                return h.add_pagination(query, python_search_params.get('paginator'))
            except h.JSONDecodeError:
                response.status_int = 400
                return h.JSONDecodeErrorResponse
            except (OLDSearchParseError, Invalid), e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
            except Exception, e:
                log.warn("%s's filter expression (%s) raised an unexpected exception: %s." % (
                    h.get_user_full_name(session['user']), request.body, e))
                response.status_int = 400
                return {'error': u'The specified search parameters generated an invalid database query'}
示例#24
0
文件: corpora.py 项目: jrwdunham/old
    def tgrep2(self, id):
        """Search the corpus-as-treebank using Tgrep2.

        :URL: ``SEARCH/POST /corpora/id/tgrep2``.
        :Request body: JSON object with obligatory 'tgrep2pattern' attribute and
            optional 'paginator' and 'order_by' attributes.
        :param str id: the ``id`` value of the corpus.
        :returns: an array of forms as JSON objects

        """
        if not h.command_line_program_installed('tgrep2'):
            response.status_int = 400
            return {'error': 'TGrep2 is not installed.'}
        corpus = Session.query(Corpus).get(id)
        if corpus:
            try:
                treebank_corpus_file_object = filter(lambda cf: cf.format == u'treebank',
                        corpus.files)[0]
                corpus_dir_path = get_corpus_dir_path(corpus)
                tgrep2_corpus_file_path = os.path.join(corpus_dir_path,
                        '%s.t2c' % treebank_corpus_file_object.filename)
            except Exception:
                response.status_int = 400
                return {'error': 'Corpus %d has not been written to file as a treebank.'}
            if not os.path.exists(tgrep2_corpus_file_path):
                response.status_int = 400
                return {'error': 'Corpus %d has not been written to file as a treebank.'}
            #if not authorized_to_access_corpus_file(session['user'], treebank_corpus_file_object):
            #    response.status_int = 403
            #    return h.unauthorized_msg
            try:
                request_params = json.loads(unicode(request.body, request.charset))
                try:
                    tgrep2pattern = request_params['tgrep2pattern']
                    assert isinstance(tgrep2pattern, basestring)
                except Exception:
                    response.status_int = 400
                    return {'errors': {'tgrep2pattern':
                        'A tgrep2pattern attribute must be supplied and must have a unicode/string value'}}
                tmp_path = os.path.join(corpus_dir_path, '%s%s.txt' % (session['user'].username, h.generate_salt()))
                with open(os.devnull, "w") as fnull:
                    with open(tmp_path, 'w') as stdout:
                        # The -wu option causes TGrep2 to print only the root symbol of each matching tree
                        process = Popen(['tgrep2', '-c', tgrep2_corpus_file_path, '-wu', tgrep2pattern],
                            stdout=stdout, stderr=fnull)
                        process.communicate()
                match_ids = filter(None, map(get_form_ids_from_tgrep2_output_line, open(tmp_path, 'r')))
                os.remove(tmp_path)
                if match_ids:
                    query = h.eagerload_form(Session.query(Form)).filter(Form.id.in_(match_ids))
                    query = h.filter_restricted_models('Form', query)
                    query = h.add_order_by(query, request_params.get('order_by'), self.query_builder)
                    result = h.add_pagination(query, request_params.get('paginator'))
                elif request_params.get('paginator'):
                    paginator = request_params['paginator']
                    paginator['count'] = 0
                    result = {'paginator': paginator, 'items': []}
                else:
                    result = []
                return result
            except h.JSONDecodeError:
                response.status_int = 400
                return h.JSONDecodeErrorResponse
            except Invalid, e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
            except Exception, e:
                response.status_int = 400
                return {'error': 'Unable to perform TGrep2 search: %s.' % e}
示例#25
0
    def tgrep2(self, id):
        """Search the corpus-as-treebank using Tgrep2.

        :URL: ``SEARCH/POST /corpora/id/tgrep2``.
        :Request body: JSON object with obligatory 'tgrep2pattern' attribute and
            optional 'paginator' and 'order_by' attributes.
        :param str id: the ``id`` value of the corpus.
        :returns: an array of forms as JSON objects

        """
        if not h.command_line_program_installed('tgrep2'):
            response.status_int = 400
            return {'error': 'TGrep2 is not installed.'}
        corpus = Session.query(Corpus).get(id)
        if corpus:
            try:
                treebank_corpus_file_object = filter(
                    lambda cf: cf.format == u'treebank', corpus.files)[0]
                corpus_dir_path = get_corpus_dir_path(corpus)
                tgrep2_corpus_file_path = os.path.join(
                    corpus_dir_path,
                    '%s.t2c' % treebank_corpus_file_object.filename)
            except Exception:
                response.status_int = 400
                return {
                    'error':
                    'Corpus %d has not been written to file as a treebank.'
                }
            if not os.path.exists(tgrep2_corpus_file_path):
                response.status_int = 400
                return {
                    'error':
                    'Corpus %d has not been written to file as a treebank.'
                }
            #if not authorized_to_access_corpus_file(session['user'], treebank_corpus_file_object):
            #    response.status_int = 403
            #    return h.unauthorized_msg
            try:
                request_params = json.loads(
                    unicode(request.body, request.charset))
                try:
                    tgrep2pattern = request_params['tgrep2pattern']
                    assert isinstance(tgrep2pattern, basestring)
                except Exception:
                    response.status_int = 400
                    return {
                        'errors': {
                            'tgrep2pattern':
                            'A tgrep2pattern attribute must be supplied and must have a unicode/string value'
                        }
                    }
                tmp_path = os.path.join(
                    corpus_dir_path,
                    '%s%s.txt' % (session['user'].username, h.generate_salt()))
                with open(os.devnull, "w") as fnull:
                    with open(tmp_path, 'w') as stdout:
                        # The -wu option causes TGrep2 to print only the root symbol of each matching tree
                        process = Popen([
                            'tgrep2', '-c', tgrep2_corpus_file_path, '-wu',
                            tgrep2pattern
                        ],
                                        stdout=stdout,
                                        stderr=fnull)
                        process.communicate()
                match_ids = filter(
                    None,
                    map(get_form_ids_from_tgrep2_output_line,
                        open(tmp_path, 'r')))
                os.remove(tmp_path)
                if match_ids:
                    query = h.eagerload_form(Session.query(Form)).filter(
                        Form.id.in_(match_ids))
                    query = h.filter_restricted_models('Form', query)
                    query = h.add_order_by(query,
                                           request_params.get('order_by'),
                                           self.query_builder)
                    result = h.add_pagination(query,
                                              request_params.get('paginator'))
                elif request_params.get('paginator'):
                    paginator = request_params['paginator']
                    paginator['count'] = 0
                    result = {'paginator': paginator, 'items': []}
                else:
                    result = []
                return result
            except h.JSONDecodeError:
                response.status_int = 400
                return h.JSONDecodeErrorResponse
            except Invalid, e:
                response.status_int = 400
                return {'errors': e.unpack_errors()}
            except Exception, e:
                response.status_int = 400
                return {'error': 'Unable to perform TGrep2 search: %s.' % e}