def print(status: int = 200, data: str = "") -> json:
        """
        Makes a json object to return to send.
        @param status (int): HTTP status code: https://nl.wikipedia.org/wiki/Lijst_van_HTTP-statuscodes. Default = 200
        @param data (json): object what has to be send back. Default = ""
        @return formatted json.

        input:
        @code
            Api.print(200, {
                "result": 1
            })
        @endcode

        Result:
        @code
            {
                "description": "Request was successful.",
                "status": 200,
                "data": {
                    "result": 1
                },
                "message": "OK"
            }
        @endcode

        """
        return {
            "status": Status(status).code,
            "message": Status(status).name,
            "description": Status(status).description,
            "data": data
        }
예제 #2
0
    def __call__(self, environ, start_response):
        url_params = None
        current_url_handler, url_params = self.get_handler(environ)

        response_text, status_code, extra_headers = current_url_handler(
            environ, url_params)

        status_code_message = '{} {}'.format(
            Status(status_code).code,
            Status(status_code).name,
        )
        headers = {
            'Content-Type': 'text/html',
        }
        headers.update(extra_headers)

        if isinstance(response_text, (list, dict)):
            response_text = json.dumps(response_text)
            headers['Content-Type'] = 'text/json'

        start_response(
            status_code_message,
            list(headers.items()),
        )
        return [response_text.encode('utf-8')]
예제 #3
0
def images(taxon=None, service=None, limit=None, offset=None):
    """Specimen link retrieval."""
    from ..elc import subreq

    desc_obj = dict()
    t0 = time()
    sub_query = 'Specimen images for {0:s} retrieved through {1:s}'.format(
        taxon.capitalize(), 'iDigBio' if service == 'idigbio' else 'ePANDDA')

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='images')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Call parse function to check for parameter errors

    try:
        payload = params.parse(req_args=connexion.request.args,
                               options=options,
                               db='pbdb',
                               endpoint='images')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Query media aggregators

    try:
        media = subreq.images_req(payload=payload,
                                  options=options)

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Build returned metadata object

    desc_obj.update(aux.build_meta(options))

    desc_obj.update(aux.build_meta_sub(source=sub_query,
                                       t0=t0,
                                       sub_tag='media_links',
                                       options=options,
                                       data=media))

    # Return data structure to client

    return jsonify(metadata=desc_obj, records=media)
예제 #4
0
def mobile(taxon=None, bbox=None):
    """Lightweight custom response."""
    from ..elc import config, subreq

    return_obj = list()

    # Set runtime options

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='occ')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # This query only applies to Neotoma and PBDB

    for db in ['neotoma', 'pbdb']:

        # Configure parameter payload for api subquery

        try:
            payload = params.parse(req_args=connexion.request.args,
                                   options=options,
                                   db=db,
                                   endpoint='occ')

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

        # Database API call

        url_path = ''.join([config.get('resource_api', db),
                            config.get('db_occ_endpt', db)])

        try:
            return_obj = subreq.mobile_req(return_obj=return_obj,
                                           url_path=url_path,
                                           payload=payload,
                                           db=db)

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

    # Return composite data structure to client

    return jsonify(return_obj)
예제 #5
0
 def test_undefined_code(self):
     HTTP_Status = Status(code=self.undefined_code)
     self.assertEqual(HTTP_Status.name, self.default_name_fail)
     self.assertEqual(HTTP_Status.name, HTTP_Status.name_fail)
     self.assertEqual(HTTP_Status.description,
                      self.default_description_fail)
     self.assertEqual(HTTP_Status.description, HTTP_Status.description_fail)
예제 #6
0
 def test_alt_name_description(self):
     HTTP_Status = Status(code=self.undefined_code,
                          name_fail=self.alt_name_fail,
                          description_fail=self.alt_description_fail)
     self.assertEqual(HTTP_Status.name, self.alt_name_fail)
     self.assertEqual(HTTP_Status.name, HTTP_Status.name_fail)
     self.assertEqual(HTTP_Status.description, self.alt_description_fail)
     self.assertEqual(HTTP_Status.description, HTTP_Status.description_fail)
예제 #7
0
 def _generate_error(error_message: str,
                     start_response: Callable) -> List[bytes]:
     """
     Generates an error.
     :param error_message: error message
     :param start_response: header handler
     :return: error body
     """
     start_response(_code_and_description(Status(400)), [])
     return [error_message.encode("utf-8")]
예제 #8
0
    def _endpoint(environment: Dict, start_response: Callable) -> List[bytes]:
        """
        Endpoint handler.
        :param environment: environment of call
        :param start_response: header handler
        :return: body
        """
        path = environment["PATH_INFO"][1:]
        try:
            raw_status = int(path)
        except ValueError:
            return Server._generate_error(f"Unknown status code: \"{path}\"",
                                          start_response)
        try:
            status_information = Status(raw_status)
        except InvalidHttpCode:
            return Server._generate_error(f"Invalid status code: {raw_status}",
                                          start_response)

        code_and_description = _code_and_description(status_information)
        start_response(code_and_description, [])
        return [f"{code_and_description}".encode("utf-8")]
예제 #9
0
def get_url(url, **kwargs):
    """Gets a url, handles all the icky requests stuff."""
    try:
        if 'timeout' not in kwargs:
            kwargs['timeout'] = 20
        r = requests.get(url, **kwargs)
        r.status = Status(r.status_code)

        if not r.ok:
            return 'HTTP Error - {code} {name} - {description}'.format(
                **{
                    'code': r.status.code,
                    'name': r.status.name,
                    'description': r.status.description
                })

    except requests.exceptions.Timeout:
        return 'Connection timed out'

    except requests.exceptions.RequestException as x:
        return '{}'.format(x.__class__.__name__)

    return r
예제 #10
0
def paleocoords(coords=None, age=None, ageunits=None):
    """
    Return paleocoordinates for a given age and modern lat/lon.

    :param coords: Comma separated latitude,longitude
    :type coords: str
    :param age: Numerical or geologic age
    :param age: str
    :param ageunits: Units of measure for the ages specified (and returned)
    :type ageunits: str ('ybp', 'ka' or 'ma')

    """
    t0 = time()
    desc_obj = dict()

    # Set runtime options

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='misc')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Call parse function to check for parameter errors

    try:
        params.parse(req_args=connexion.request.args,
                     options=options,
                     db='pbdb',
                     endpoint='paleocoords')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Determine paleocoordinates and resolve geologic age if necessary

    try:
        paleo, modern, geog_ref = geog.get_geog(coords=coords,
                                                age=age,
                                                options=options)

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Build returned metadata object

    desc_obj.update(aux.build_meta(options))

    desc_obj.update(aux.build_meta_sub(source=geog_ref,
                                       t0=t0,
                                       sub_tag='paleo_coord',
                                       options=options))

    # Return data structure to client

    return_obj = {'paleo_lat': paleo[1],
                  'paleo_lon': paleo[0],
                  'modern_lat': modern[0],
                  'modern_lon': modern[1],
                  'age': age}

    return jsonify(metadata=desc_obj, records=return_obj)
예제 #11
0
def subtaxa(taxon=None, synonyms=True):
    """
    Retrieve the related lower taxonomy for a given taxon name.

    :param taxon: taxonomic name
    :type taxon: str
    :param synonyms: optionally include synonymous names
    :type synonyms: bool (default true)

    """
    t0 = time()
    desc_obj = dict()
    sub_query = '{0:s} {1:s} synonyms (PBDB systematics)'.format(
        taxon.capitalize(), 'including' if synonyms else 'excluding')

    # Set runtime options

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='misc')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Call parse function to check for parameter errors

    try:
        params.parse(req_args=connexion.request.args,
                     options=options,
                     db='pbdb',
                     endpoint='subtaxa')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Retrieve lower taxa

    try:
        lower_taxa = taxa.get_subtaxa(taxon=taxon, inc_syn=synonyms)

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Build returned metadata object

    desc_obj.update(aux.build_meta(options))

    desc_obj.update(aux.build_meta_sub(source=sub_query,
                                       t0=t0,
                                       sub_tag='subtaxa',
                                       options=options,
                                       data=lower_taxa))

    # Return data structure to client

    return jsonify(metadata=desc_obj, records=lower_taxa)
예제 #12
0
 def test_code_match(self):
     HTTP_NoneStatus = NoneStatus(code=self.correct_code)
     HTTP_Status = Status(code=self.correct_code)
     self.assertEqual(HTTP_NoneStatus.code, HTTP_Status.code)
예제 #13
0
 def test__unicode__(self):
     HTTP_Status = Status(code=self.correct_code)
     self.assertEqual(HTTP_Status.__unicode__(verbose=True),
                      self.correct_unicode_verbose)
     self.assertEqual(HTTP_Status.__unicode__(verbose=False),
                      self.correct_unicode)
예제 #14
0
 def test_non_numeric_code(self):
     with self.assertRaises(Invalid):
         Status(code=self.non_numeric_code)
예제 #15
0
def ref(idlist=None, show=None, output=None, run=None):
    """
    Literature references/publications.

    Accepts the following dataset types: occ, col, dst, ref

    :param idlist: List of formatted ids [dbname]:[datasettype]:[number]
    :type idlist: str
    :param show: Return identifiers or stats (defult=full, idx, poll)
    :type show: str
    :param output: Response format (defult=bibjson, csv)
    :type output: str

    """
    return_obj = list()
    desc_obj = dict()

    # Set runtime options

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='ref')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    run_list = aux.get_run_list(connexion.request.args.get('run'))

    # Cycle through external databases

    for db in run_list:

        t0 = time()
        options.update(skip=False)

        # Configure parameter payload for api subquery

        try:
            payload = params.parse(req_args=connexion.request.args,
                                   options=options,
                                   db=db,
                                   endpoint='ref')

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

        # skip this database if no ids specified

        if options.get('skip'):
            continue

        # Database API call

        url_path = ''.join(
            [config.get('resource_api', db),
             config.get('db_ref_endpt', db)])

        try:
            resp_json, api_call = subreq.trigger(url_path, payload, db)

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

        # Parse database response

        return_obj = router.response_decode(resp_json=resp_json,
                                            return_obj=return_obj,
                                            options=options,
                                            db=db,
                                            endpoint='ref')

        # Build returned metadata object

        desc_obj.update(aux.build_meta(options))

        desc_obj.update(
            aux.build_meta_sub(data=return_obj,
                               source=api_call,
                               t0=t0,
                               sub_tag=db,
                               options=options))

    # Return composite data structure to client

    if options.get('output') in ['json', 'bibjson']:
        if options.get('show') == 'poll':
            return jsonify(desc_obj)
        if options.get('show') == 'idx':
            return jsonify(aux.get_id_numbers(data=return_obj, endpoint='ref'))
        else:
            if options.get('output') == 'bibjson':
                return jsonify(metadata=desc_obj,
                               records=formatter.type_bibjson(return_obj))
            else:
                return jsonify(metadata=desc_obj, records=return_obj)

    elif options.get('output') == 'json':
        if options.get('show') == 'poll':
            return jsonify(desc_obj)
        if options.get('show') == 'idx':
            return jsonify(aux.get_id_numbers(data=return_obj, endpoint='ref'))
        else:
            return jsonify(metadata=desc_obj, records=return_obj)

    elif options.get('output') == 'csv':
        if return_obj:
            filename = aux.build_filename(endpoint='ref', data=return_obj)
            return flask_csv.send_csv(return_obj, filename,
                                      return_obj[0].keys())
        else:
            msg = 'Unable to generate CSV file. Search returned no records.'
            return jsonify(status=204,
                           title=Status(204).name,
                           detail=msg,
                           type='about:blank')
예제 #16
0
 def test_exceeds_max_code(self):
     with self.assertRaises(Invalid):
         Status(code=self.exceeds_max_code)
예제 #17
0
 def test__unicode__(self):
     HTTP_Status = Status(code=self.correct_code)
     self.assertEqual(HTTP_Status.__unicode__(verbose=True), self.correct_unicode_verbose)
     self.assertEqual(HTTP_Status.__unicode__(verbose=False), self.correct_unicode)
예제 #18
0
 def test_correct_code(self):
     HTTP_Status = Status(code=self.correct_code)
     self.assertEqual(HTTP_Status.name, self.correct_name)
     self.assertEqual(HTTP_Status.description, self.correct_description)
예제 #19
0
 def test_default_code(self):
     HTTP_Status = Status()
     self.assertEqual(HTTP_Status.code, self.default_code)
예제 #20
0
def loc(idlist=None,
        bbox=None,
        agerange=None,
        ageunits=None,
        timerule=None,
        coordtype=None,
        limit=None,
        offset=None,
        show=None,
        output=None,
        run=None):
    """Return locale identifiers: collections, datasets etc."""
    return_obj = list()
    desc_obj = dict()

    # Set runtime options

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='loc')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    run_list = aux.get_run_list(connexion.request.args.get('run'))

    # Cycle through external databases

    for db in run_list:

        t0 = time()
        options.update(skip=False)

        # Configure parameter payload for api subquery

        try:
            payload = params.parse(req_args=connexion.request.args,
                                   options=options,
                                   db=db,
                                   endpoint='loc')

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

        # skip this database if no ids specified

        if options.get('skip'):
            continue

        # Database API call

        url_path = ''.join(
            [config.get('resource_api', db),
             config.get('db_loc_endpt', db)])

        try:
            resp_json, api_call = subreq.trigger(url_path, payload, db)

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

        # Parse database response

        return_obj = router.response_decode(resp_json=resp_json,
                                            return_obj=return_obj,
                                            options=options,
                                            db=db,
                                            endpoint='loc')

        # Build returned metadata object

        desc_obj.update(aux.build_meta(options))

        desc_obj.update(
            aux.build_meta_sub(data=return_obj,
                               source=api_call,
                               t0=t0,
                               sub_tag=db,
                               options=options))

    # Return composite data structure to client

    if options.get('output') == 'json':
        if options.get('show') == 'poll':
            return jsonify(desc_obj)
        if options.get('show') == 'idx':
            return jsonify(
                aux.get_id_numbers(data=return_obj, endpoint='locale'))
        else:
            return jsonify(metadata=desc_obj, records=return_obj)

    elif options.get('output') == 'csv':
        if return_obj:
            tab_data = formatter.type_csv(return_obj)
            return Response((x for x in tab_data), mimetype='text/csv')
        else:
            msg = 'Unable to generate CSV file. Search returned no records.'
            return jsonify(status=204,
                           title=Status(204).name,
                           detail=msg,
                           type='about:blank')

    elif options.get('output') == 'file':
        import flask_csv
        if return_obj:
            filename = aux.build_filename(endpoint='loc', data=return_obj)
            return flask_csv.send_csv(return_obj, filename,
                                      return_obj[0].keys())
        else:
            msg = 'Unable to generate CSV file. Search returned no records.'
            return jsonify(status=204,
                           title=Status(204).name,
                           detail=msg,
                           type='about:blank')
예제 #21
0
def timebound(agerange=None, ageunits=None):
    """
    Return min and max ages given a specified bound and units.

    :param agerange: Comma separated numerical or textual geologic ages
    :type agerange: str
    :param ageunits: Units of measure for the ages specified (and returned)
    :type ageunits: str ('ybp', 'ka' or 'ma')

    """
    t0 = time()
    desc_obj = dict()

    # Set runtime options

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='misc')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Call parse function to check for parameter errors

    try:
        params.parse(req_args=connexion.request.args,
                     options=options,
                     db='pbdb',
                     endpoint='timebound')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Determine time bounds and resolve geologic age if necessary

    try:
        early_age, late_age, \
            col_hex, age_ref = ages.get_age(age_range=agerange,
                                            options=options)

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    # Build returned metadata object

    desc_obj.update(aux.build_meta(options))

    desc_obj.update(aux.build_meta_sub(source=age_ref,
                                       t0=t0,
                                       sub_tag='geo_age',
                                       options=options))

    # Return data structure to client

    return_obj = {'early_age': early_age,
                  'late_age': late_age,
                  'ics_color': col_hex}

    return jsonify(metadata=desc_obj, records=return_obj)
예제 #22
0
def occ(bbox=None,
        agerange=None,
        ageuits=None,
        timerule=None,
        taxon=None,
        includelower=None,
        coordtype=None,
        limit=None,
        offset=None,
        show=None,
        output=None,
        run=None):
    """Paleobiological occurrences in a specific place and time."""
    return_obj = list()
    desc_obj = dict()

    # Set runtime options

    try:
        options = params.set_options(req_args=connexion.request.args,
                                     endpoint='occ')

    except ValueError as err:
        return connexion.problem(status=err.args[0],
                                 title=Status(err.args[0]).name,
                                 detail=err.args[1],
                                 type='about:blank')

    run_list = aux.get_run_list(connexion.request.args.get('run'))

    # Cycle through external databases

    for db in run_list:

        t0 = time()

        # Configure parameter payload for api subquery

        try:
            payload = params.parse(req_args=connexion.request.args,
                                   options=options,
                                   db=db,
                                   endpoint='occ')

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

        url_path = ''.join(
            [config.get('resource_api', db),
             config.get('db_occ_endpt', db)])

        # Database API call

        try:
            resp_json, api_call = subreq.trigger(url_path, payload, db)

        except ValueError as err:
            return connexion.problem(status=err.args[0],
                                     title=Status(err.args[0]).name,
                                     detail=err.args[1],
                                     type='about:blank')

        # Parse database response

        return_obj = router.response_decode(resp_json=resp_json,
                                            return_obj=return_obj,
                                            options=options,
                                            db=db,
                                            endpoint='occ')

        # Build returned metadata object

        desc_obj.update(aux.build_meta(options))

        desc_obj.update(
            aux.build_meta_sub(data=return_obj,
                               source=api_call,
                               t0=t0,
                               sub_tag=db,
                               options=options))

    # Return composite data structure to client

    if options.get('output') == 'json':
        if options.get('show') == 'poll':
            return jsonify(desc_obj)
        if options.get('show') == 'idx':
            return jsonify(aux.get_id_numbers(data=return_obj, endpoint='occ'))
        else:
            return jsonify(metadata=desc_obj, records=return_obj)

    elif options.get('output') == 'csv':
        if return_obj:
            filename = aux.build_filename(endpoint='occ', data=return_obj)
            return flask_csv.send_csv(return_obj, filename,
                                      return_obj[0].keys())
        else:
            msg = 'Unable to generate CSV file. Search returned no records.'
            return jsonify(status=204,
                           title=Status(204).name,
                           detail=msg,
                           type='about:blank')
예제 #23
0
 def test_below_min_code(self):
     with self.assertRaises(Invalid):
         Status(code=self.below_min_code)