Skip to content

Commit

Permalink
Merge pull request #6 from terraref/call-season-impl
Browse files Browse the repository at this point in the history
helper function + implementation of different endpoints
  • Loading branch information
robkooper authored Oct 2, 2018
2 parents 392c331 + ee9d801 commit f1f5e71
Show file tree
Hide file tree
Showing 20 changed files with 117,541 additions and 61 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ target/

#Ipython Notebook
.ipynb_checkpoints

# pycharm
.idea
206 changes: 206 additions & 0 deletions README.html

Large diffs are not rendered by default.

34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Python 3.5.2+
To run, first start an intance of the BETY database:

```
docker run -h betydb -d -p 5432:5432 terraref/bety-postgis
docker run --name betydb -d -p 5431:5432 terraref/bety-postgis
```

Install the python requirements and start the Flask server:
Expand All @@ -30,3 +30,35 @@ http://localhost:8080/brapi/v1/ui/

The only call implemented is the `GET phenotypes-search` with a very very
preliminary mapping of BETY fields to BRAPI objects.


## Mappings from BETY to BRAPI models

| BRAPI | BETY | Notes |
|------------|-------------|-------|
| /calls | generated | |
| /locations | sitegroups | lat/lon computed from sites part of sitegroup |
| /seasons | experiments | season = month of start_date, year of start_date |
| /germplasm | cultivars. | |
| /observations | traits | |


## How to add an endpoint

Example: see controllers/crops_controller.py and CropsController_impl.py

## Showing data in BETY database

You can use the following command to start a docker container that is connected to the database
allowing you to browse the database.

```
docker run -ti --rm -p 8000:8000 --link betydb:postgres pecan/bety
```

To enable the guest user you can run the following sql query when connected to the database:

```
INSERT INTO users (login, name, email, crypted_password, salt, city, state_prov, postal_code, country, area, access_level, page_access_level, created_at, updated_at, apikey, remember_token, remember_token_expires_at)
VALUES ('guestuser', 'guestuser', '[email protected]', '994363a949b6486fc7ea54bf40335127f5413318', 'bety', 'Urbana', 'IL', '61801', 'USA', '', 4, 4, NOW(), NOW(), NULL, NULL, NULL);
```
6 changes: 0 additions & 6 deletions bety_brapi/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ def main():
app = connexion.App(__name__, specification_dir='./swagger/')
app.app.json_encoder = encoder.JSONEncoder
app.add_api('swagger.yaml', arguments={'title': 'BrAPI'})
app.run(port=8080)

handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)

app.app.logger.addHandler(handler)
app.app.logger.setLevel(logging.DEBUG)

app.run(port=8080)
Expand Down
5 changes: 2 additions & 3 deletions bety_brapi/controllers/calls_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import connexion
import six
#from bety_brapi.controllers_impl import CallsController_impl
from bety_brapi.controllers_impl import CallsController_impl

from bety_brapi.models.calls_response import CallsResponse # noqa: E501
from bety_brapi import util
Expand All @@ -21,6 +21,5 @@ def calls_get(datatype=None, pageSize=None, page=None): # noqa: E501
:rtype: CallsResponse
"""

# return CallsController_impl.calls_get(datatype=None, pageSize=None, page=None)
return "Not implemented"
return CallsController_impl.calls_get(datatype, pageSize, page)

8 changes: 3 additions & 5 deletions bety_brapi/controllers/crops_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import connexion
import six
#from bety_brapi.controllers_impl import CropsController_impl
from bety_brapi.controllers_impl import CropsController_impl

from bety_brapi.models.common_crop_names_response import CommonCropNamesResponse # noqa: E501
from bety_brapi import util
Expand All @@ -19,8 +19,7 @@ def common_crop_names_get(pageSize=None, page=None): # noqa: E501
:rtype: CommonCropNamesResponse
"""

# return CropsController_impl.common_crop_names_get(pageSize=None, page=None)
return "Not implemented"
return CropsController_impl.common_crop_names_get(pageSize, page)


def crops_get(pageSize=None, page=None): # noqa: E501
Expand All @@ -36,6 +35,5 @@ def crops_get(pageSize=None, page=None): # noqa: E501
:rtype: CommonCropNamesResponse
"""

# return CropsController_impl.crops_get(pageSize=None, page=None)
return "Not implemented"
return CropsController_impl.crops_get(pageSize, page)

5 changes: 2 additions & 3 deletions bety_brapi/controllers/germplasm_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import connexion
import six
#from bety_brapi.controllers_impl import GermplasmController_impl
from bety_brapi.controllers_impl import GermplasmController_impl

from bety_brapi.models.breeding_method_response import BreedingMethodResponse # noqa: E501
from bety_brapi.models.breeding_methods_response import BreedingMethodsResponse # noqa: E501
Expand Down Expand Up @@ -155,8 +155,7 @@ def germplasm_search_get(germplasmPUI=None, germplasmDbId=None, germplasmName=No
:rtype: GermplasmResponse
"""

# return GermplasmController_impl.germplasm_search_get(germplasmPUI=None, germplasmDbId=None, germplasmName=None, commonCropName=None, pageSize=None, page=None)
return "Not implemented"
return GermplasmController_impl.germplasm_search_get(germplasmPUI, germplasmDbId, germplasmName, commonCropName, pageSize, page)


def germplasm_search_post(body=None): # noqa: E501
Expand Down
8 changes: 3 additions & 5 deletions bety_brapi/controllers/locations_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import connexion
import six
#from bety_brapi.controllers_impl import LocationsController_impl
from bety_brapi.controllers_impl import LocationsController_impl

from bety_brapi.models.location_response import LocationResponse # noqa: E501
from bety_brapi.models.locations_response import LocationsResponse # noqa: E501
Expand All @@ -22,8 +22,7 @@ def locations_get(locationType=None, pageSize=None, page=None): # noqa: E501
:rtype: LocationsResponse
"""

# return LocationsController_impl.locations_get(locationType=None, pageSize=None, page=None)
return "Not implemented"
return LocationsController_impl.locations_get(locationType, pageSize, page)


def locations_location_db_id_get(locationDbId): # noqa: E501
Expand All @@ -37,6 +36,5 @@ def locations_location_db_id_get(locationDbId): # noqa: E501
:rtype: LocationResponse
"""

# return LocationsController_impl.locations_location_db_id_get(locationDbId)
return "Not implemented"
return LocationsController_impl.locations_location_db_id_get(locationDbId)

5 changes: 2 additions & 3 deletions bety_brapi/controllers/studies_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import connexion
import six
#from bety_brapi.controllers_impl import StudiesController_impl
from bety_brapi.controllers_impl import StudiesController_impl

from bety_brapi.models.germplasm_summary_list_response import GermplasmSummaryListResponse # noqa: E501
from bety_brapi.models.new_observation_db_ids_response import NewObservationDbIdsResponse # noqa: E501
Expand Down Expand Up @@ -38,8 +38,7 @@ def seasons_get(year=None, pageSize=None, page=None): # noqa: E501
:rtype: SeasonsResponse
"""

# return StudiesController_impl.seasons_get(year=None, pageSize=None, page=None)
return "Not implemented"
return StudiesController_impl.seasons_get(year, pageSize, page)


def studies_search_get(studyType=None, programDbId=None, locationDbId=None, seasonDbId=None, trialDbId=None, studyDbId=None, germplasmDbIds=None, observationVariableDbIds=None, pageSize=None, page=None, active=None, sortBy=None, sortOrder=None): # noqa: E501
Expand Down
57 changes: 57 additions & 0 deletions bety_brapi/controllers_impl/CallsController_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from bety_brapi import helper

VERSIONS_ALL = ["1.0", "1.1", "1.2"]
VERSIONS_LATEST = ["1.2"]


def calls_get(datatype, pageSize, page):
"""
Return a list of all calls that are implemented
"""

# create the full list of all calls implemented.
data = [
calls_get_helper('calls'),
calls_get_helper('commonCropNames', versions=['1.2']),
calls_get_helper('crops'),
calls_get_helper('germplasm-search'),
calls_get_helper('locations'),
calls_get_helper('locations/{locationDbId}'),
calls_get_helper('phenotypes-search'),
calls_get_helper('seasons')
]

# filter on datatype
if datatype:
data = [d for d in data if datatype in d['datatypes']]

# total number of rows
count = len(data)

# add a limit
if not pageSize:
pageSize = len(data)
if not page:
page = 0
data = data[page * pageSize:(page+1) * pageSize]

# return the resulting data
return helper.create_result({"data": data}, count, pageSize, page)


def calls_get_helper(api_call, datatypes=None, methods=None, versions=None):
"""
Helper function to return a brapi call information.
"""
if not datatypes:
datatypes = ["json"]
if not methods:
methods = ['GET']
if not versions:
versions = VERSIONS_ALL
return {
"call": api_call,
"datatypes": datatypes,
"methods": methods,
"versions": versions
}
15 changes: 15 additions & 0 deletions bety_brapi/controllers_impl/CropsController_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from bety_brapi import helper

def common_crop_names_get(pageSize=None, page=None):

query = "SELECT DISTINCT commonname FROM species ORDER BY commonname"
count = helper.query_count(query)
res = helper.query_result(query, [], pageSize, page)

data = [r[0] for r in res]

return helper.create_result({"data": data}, count, pageSize, page)

def crops_get(pageSize=None, page=None):
# deprecated function name
return common_crop_names_get(pageSize, page)
41 changes: 41 additions & 0 deletions bety_brapi/controllers_impl/GermplasmController_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import json

from bety_brapi import helper

def germplasm_search_get(germplasmPUI, germplasmDbId, germplasmName, commonCropName, pageSize, page):
"""
Search for a specific germplasm. Right now this will use an external file to get all the information.
:param germplasmPUI:
:param germplasmDbId:
:param germplasmName:
:param commonCropName:
:param pageSize:
:param page:
:return:
"""

# load all the data
# TODO this does not work if pakcage is installed, need to use pkgutil
file = 'data/germplasm.json'
data = json.load(open(file, 'r'))

# filter the data
if germplasmPUI:
data = [x for x in data if x.get('germplasmPUI', '') == germplasmPUI]
if germplasmDbId:
data = [x for x in data if x.get('germplasmDbId', '') == int(germplasmDbId)]
if germplasmName:
data = [x for x in data if x.get('germplasmName', '') == germplasmName]
if commonCropName:
data = [x for x in data if x.get('commonCropName', '') == commonCropName]

# split data if needed, remembering total number
count = len(data)
if not pageSize:
pageSize = helper.DEFAULT_PAGE_SIZE
if not page:
page = 0
data = data[page * pageSize:(page+1) * pageSize]

# return the resulting data
return helper.create_result({"data": data}, count, pageSize, page)
102 changes: 102 additions & 0 deletions bety_brapi/controllers_impl/LocationsController_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from bety_brapi import helper


def locations_get(locationType, pageSize, page):
"""
:param locationType:
:param pageSize: number of elements to return
:param page: which page to return
:return: all locations in the page
"""

# TODO map locationType to something
params = list()

# get all sitegroups and sites
query = "SELECT sitegroups.id AS locationDbId, " \
" sitegroups.name AS name, " \
" sites.geometry AS geometry " \
"FROM sites, sitegroups, sitegroups_sites " \
"WHERE sitegroups_sites.site_id = sites.id " \
" AND sitegroups_sites.sitegroup_id = sitegroups.id "
# compute the bounding box
query = "SELECT locationDbId, " \
" name, " \
" ST_Extent(geometry) AS geometry " \
"FROM (" + query + ") ss1 " \
"GROUP BY locationDbId, name "
# compute center point
query = "SELECT locationDbId::text, " \
" name, " \
" ST_X(ST_CENTROID(geometry)) AS longitude, " \
" ST_Y(ST_CENTROID(geometry)) AS latitude " \
"FROM (" + query + ") ss2"

# order query
query += " ORDER BY locationDbId"

# TODO add a filter on the locationType
# if locationType:
# # wrap query in a sub select to allow us to use locationType in WHERE clause
# query = "SELECT * FROM (" + query + ") locations WHERE locationType = %s "
# params.append(locationType)

# count first
count = helper.query_count(query, params)

# execute query
results = helper.query_result(query, params, pageSize, page)

# wrap result
data = []
for row in results:
data.append({k: v for k, v in row.items() if v})
return helper.create_result({"data": data}, count, pageSize, page)


def locations_location_db_id_get(locationDbId):
"""
:param locationDbId:
:return:
"""

params = list()

# get all sitegroups and sites
query = "SELECT sitegroups.id AS locationDbId, " \
" sitegroups.name AS name, " \
" sites.geometry AS geometry " \
"FROM sites, sitegroups, sitegroups_sites " \
"WHERE sitegroups.id = %s " \
" AND sitegroups_sites.site_id = sites.id " \
" AND sitegroups_sites.sitegroup_id = sitegroups.id "
params.append(int(locationDbId))
# compute the bounding box
query = "SELECT locationDbId, " \
" name, " \
" ST_Extent(geometry) AS geometry " \
"FROM (" + query + ") ss1 " \
"GROUP BY locationDbId, name "
# compute center point
query = "SELECT locationDbId::text, " \
" name, " \
" ST_X(ST_CENTROID(geometry)) AS longitude, " \
" ST_Y(ST_CENTROID(geometry)) AS latitude " \
"FROM (" + query + ") ss2"

# order query
query += " ORDER BY locationDbId"

# count first
count = helper.query_count(query, params)

# execute query
results = helper.query_result(query, params)

# wrap result
data = []
for row in results:
data.append({k: v for k, v in row.items() if v})
return helper.create_result({"location": data}, count)
Loading

0 comments on commit f1f5e71

Please sign in to comment.