Skip to content

Commit b498f56

Browse files
authored
Merge pull request #1370 from TOMToolkit/feature/basic_antares_dataservice_and_docs
Feature/basic antares dataservice and docs
2 parents 3d9313f + 467c54d commit b498f56

14 files changed

Lines changed: 295 additions & 35 deletions

File tree

docs/api/modules.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ API Documentation
1414
tom_catalogs/index
1515
tom_common/index
1616
tom_dataproducts/index
17+
tom_dataservices/index
1718
tom_observations/index
1819
tom_targets/index
1920
management_commands
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Data Servces
2+
============
3+
4+
**********************
5+
Base DataService Class
6+
**********************
7+
8+
.. automodule:: tom_dataservices.dataservices
9+
:members:
10+
11+
***
12+
TNS
13+
***
14+
15+
.. automodule:: tom_dataservices.data_services.tns
16+
:members:
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Exceptions
2+
==========
3+
4+
********************
5+
MissingDataException
6+
********************
7+
.. automodule:: tom_dataservices.dataservices.MissingDataException
8+
:members:
9+
10+
******************
11+
NotConfiguredError
12+
******************
13+
.. automodule:: tom_dataservices.dataservices.NotConfiguredError
14+
:members:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Data Services
2+
=============
3+
4+
.. toctree::
5+
:maxdepth: 2
6+
7+
data_services
8+
exceptions
9+
models
10+
views
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Models
2+
======
3+
4+
.. automodule:: tom_dataservices.models
5+
:members:
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Views
2+
=====
3+
4+
.. automodule:: tom_dataservices.views
5+
:members:
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
Adding a Data Service Module for the TOM Toolkit
2+
------------------------------------------------
3+
4+
This guide is to walk you step by step through the process of creating a Data Service.
5+
This assumes that you want a user interface for querying your data service via a form.
6+
Many of these steps can be skipped if your service is only intended to be accessed internally.
7+
8+
Setting up the Basic Data Service:
9+
**********************************
10+
11+
First we will build the bare bones of our data service. This is the bare minimum to get the service to show up in the
12+
TOM. We'll start with three peices of code:
13+
14+
First the actual query class:
15+
+++++++++++++++++++++++++++++
16+
17+
18+
.. code-block:: python
19+
:caption: my_dataservice.py
20+
:linenos:
21+
22+
from tom_dataservices.dataservices import BaseDataService
23+
from my_dataservice.forms import MyServiceForm
24+
25+
class MyDataService(BaseDataService):
26+
"""
27+
This is an Example Data Service with the minimum required
28+
functionality.
29+
"""
30+
name = 'MyService'
31+
32+
@classmethod
33+
def get_form_class(cls):
34+
"""
35+
Points to the form class discussed below.
36+
"""
37+
return MyServiceForm
38+
39+
def build_query_parameters(self, parameters, **kwargs):
40+
"""
41+
Use this function to convert the form results into the query parameters understood
42+
by the Data Service.
43+
"""
44+
return self.query_parameters
45+
46+
def query_service(self, data, **kwargs):
47+
"""
48+
This is where you actually make the call to the Data Service.
49+
Return the results.
50+
"""
51+
return self.query_results
52+
53+
54+
Your Data Service needs a form:
55+
+++++++++++++++++++++++++++++++
56+
57+
.. code-block:: python
58+
:caption: forms.py
59+
:linenos:
60+
61+
from django import forms
62+
from tom_dataservices.forms import BaseQueryForm
63+
64+
class MyServiceForm(BaseQueryForm):
65+
first_field = forms.CharField(required=False,
66+
label='An Example Field',
67+
help_text='Put important info here.')
68+
69+
70+
Adding the integration point:
71+
+++++++++++++++++++++++++++++
72+
73+
.. code-block:: python
74+
:caption: apps.py
75+
:linenos:
76+
77+
from django.apps import AppConfig
78+
79+
80+
class MyAppConfig(AppConfig):
81+
default_auto_field = 'django.db.models.BigAutoField'
82+
name = 'my_app'
83+
84+
def data_services(self):
85+
"""
86+
integration point for including data services in the TOM
87+
This method should return a list of dictionaries containing dot separated DataService classes
88+
"""
89+
return [{'class': f'{self.name}.my_dataservice.MyDataService'}]
90+
91+
92+
Customizing your Data Service:
93+
******************************
94+
95+
The next step is to update our code to have all specific features relevent for our data service. Here we will focus on
96+
extending several methods of `BaseDataService` to be relevent for your data service.
97+
98+
99+
`BaseDataService.build_query_parameters`
100+
++++++++++++++++++++++++++++++++++++++++
101+
102+
For starters, let's make our `build_query_parameters` function inside of `MyDataService` actually do something.
103+
This code is to convert all of the form fields into a data dictionary or set of query parameters that is understood by
104+
the data service (or more specifically our `query_service` method.)
105+
106+
.. code-block:: python
107+
:caption: my_dataservice.MyDataService
108+
:linenos:
109+
110+
def build_query_parameters(self, parameters, **kwargs):
111+
"""
112+
Use this function to convert the form results into the query parameters understood
113+
by the Data Service.
114+
"""
115+
data = {
116+
'example_field': parameters.get('first_field')
117+
}
118+
119+
self.query_parameters = data
120+
return data
121+
122+
In some cases, this can be very straightforward, while in others this can involve complex constructions of query
123+
commands. Ultimately this is based on the API or client of your Data Service, and how you chose to name your form
124+
fields.
125+
126+
`BaseDataService.query_service`
127+
+++++++++++++++++++++++++++++++
128+
129+
Next we will need to fill out our `query_service` module. This is the function that actualy goes and calls the query
130+
service using the parameters created by `build_query_parameters`. This function produces query results that can then be
131+
interpreted by `query_targets`, `query_photometry`, or other functions to produce specific kinds of results that can be
132+
interpreted by your TOM.
133+
134+
.. code-block:: python
135+
:caption: my_dataservice.MyDataService
136+
:linenos:
137+
138+
def query_service(self, data, **kwargs):
139+
"""
140+
This is where you actually make the call to the Data Service.
141+
Return the results.
142+
"""
143+
if self.get_urls(url_type='search'):
144+
results = requests.post(self.get_urls(url_type='search'), data, headers=self.build_headers())
145+
else:
146+
results = data_service_client.search(data)
147+
self.query_results = results
148+
return self.query_results
149+
150+
Again, depending on the nature of your data service, the `query_service` function could take many different forms.
151+
This may also require you to create a `build_headers` method, or make use of the `urls`, `get_configuration`, or
152+
`get_credentials`methods. Saving the results to `self.query_results` could save time in other methods by not requireing
153+
you to redo the query.
154+
155+
`BaseDataService.query_target`
156+
++++++++++++++++++++++++++++++
157+
158+
We will just use `query_target` as an example. The same ideas apply to any of the individual query functions.
159+
This is the function that pulls useful data from the query results in a way that the TOM understands. In this case, we
160+
will be extracting Target data from the query results and creating a dictionary.
161+
162+
.. code-block:: python
163+
:caption: my_dataservice.MyDataService
164+
:linenos:
165+
166+
def query_target(self, data, **kwargs):
167+
"""
168+
This code calls `query_dataservice` and returns a dictionary of results.
169+
This call and the results should be tailroed towards describing targets.
170+
"""
171+
query_results = super().query_targets(data)
172+
targets = []
173+
for result in query_results:
174+
result['name'] = f"MyService:{result['ra']},{result['dec']}"
175+
targets.append(result)
176+
return targets
177+
178+
In this example, we create or modify the name of a query result so we will have something to enter into the TOM.
179+
Line 6 calls the super which will either retrieve `self.query_results` if it exists or run `query_service`.
180+
The final output should be a dictionary of results.
181+
182+
`BaseDataService.create_target_from_query`
183+
++++++++++++++++++++++++++++++++++++++++++
184+
185+
Continuing with our `target` example, we need to be able to `create_target_from_query` in order to actually save the
186+
target object resulting from a succesful result for `query_target` above. This function expects a single instance with
187+
the same format as the list of dictionaries created by `query_targets` and converts that dictionary into a Target Object
188+
returning that object.
189+
190+
.. code-block:: python
191+
:caption: my_dataservice.MyDataService
192+
:linenos:
193+
194+
def create_target_from_query(self, target_result, **kwargs):
195+
"""Create a new target from the query results
196+
:returns: target object
197+
:rtype: `Target`
198+
"""
199+
200+
target = Target(
201+
name=target_result['name'],
202+
type='SIDEREAL',
203+
ra=target_result['ra'],
204+
dec=target_result['dec']
205+
)
206+
return target

docs/brokers/index.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Brokers
99
create_dash_broker
1010
../api/tom_alerts/brokers
1111
../api/tom_alerts/views
12+
create_dataservice
1213

1314

1415
What is an Alert Broker Module?
@@ -24,3 +25,5 @@ A TOM Toolkit Alert Broker Module is an object which contains the logic for quer
2425
:doc:`Broker Modules <../api/tom_alerts/brokers>` - Take a look at the supported brokers.
2526

2627
:doc:`Broker Views <../api/tom_alerts/views>` - Familiarize yourself with the available Broker Views.
28+
29+
:doc:`Create Data Service <create_dataservice>` - Walk through the creation of your own Data Service.

tom_dataservices/data_services/tns.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -178,37 +178,32 @@ def query_service(self, data, **kwargs):
178178

179179
def query_targets(self, query_parameters):
180180
"""Set up and run a specialized query for retrieving targets from a DataService."""
181+
results = super().query_targets(query_parameters, url=self.get_urls('search_url'))
181182
targets = []
182-
results = self.query_service(query_parameters, url=self.get_urls('search_url'))
183+
# results = self.query_service(query_parameters, url=self.get_urls('search_url'))
183184
for result in results:
184185
target_parameters = self.build_query_parameters(result)
185186
target_data = self.query_service(target_parameters, url=self.get_urls('object_url'))
186187
targets.append(target_data)
188+
self.target_results = targets
187189
return targets
188190

189191
@classmethod
190192
def get_form_class(cls):
191193
return TNSForm
192194

193-
def create_target_from_query(self, query_results, **kwargs):
195+
def create_target_from_query(self, target_results, **kwargs):
194196
"""
195-
Returns a Target instance for an object defined by a query result, as well as
196-
any TargetExtra or additional TargetNames.
197+
Returns a Target instance for an object defined by a query result,
197198
198199
:returns: target object
199200
:rtype: `Target`
200-
201-
:returns: dict of extras to be added to the new Target
202-
:rtype: `dict`
203-
204-
:returns: list of aliases to be added to the new Target
205-
:rtype: `list`
206201
"""
207202

208203
target = Target(
209-
name=query_results['name_prefix'] + query_results['objname'],
204+
name=target_results['name_prefix'] + target_results['objname'],
210205
type='SIDEREAL',
211-
ra=query_results['radeg'],
212-
dec=query_results['decdeg']
206+
ra=target_results['radeg'],
207+
dec=target_results['decdeg']
213208
)
214209
return target

0 commit comments

Comments
 (0)