Skip to content

Commit e2282ec

Browse files
[Rubin] update schema endpoint (#135)
* Add versioning of Fink fields * Expose fields * Fix bug * Fix syntax to get all nights * Migrate schema for stats in the schema endpoint * Add schema for all bands * Fix doc * Update sso schema * Add schemas for datatransfer * Fix name * Add root for lsst * Add in_tns * Prefix tag table with tag_ * Update requirements * Update schema -- lc missing * Bump requirements * Bump requirements * Update requirements * Add new added value * Fix legacy taxonomy * Fix legacy taxonomy * Update schema for statistics * Add test suite for schema
1 parent 2901679 commit e2282ec

7 files changed

Lines changed: 573 additions & 51 deletions

File tree

apps/routes/v1/lsst/schema/api.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
required=True,
3333
),
3434
"major_version": fields.Integer(
35-
description="Major version. Default is latest.",
36-
example=9,
35+
description="LSST major version. Default is latest.",
36+
example=10,
3737
required=False,
3838
),
3939
"minor_version": fields.Integer(
40-
description="Minor version. Default is latest.",
40+
description="LSST minor version. Default is latest.",
4141
example=0,
4242
required=False,
4343
),
@@ -55,6 +55,7 @@ def get(self):
5555
# POST from query URL
5656
return self.post()
5757
else:
58+
# FIXME: return the list of endpoints?
5859
return Response(ns.description, 200)
5960

6061
@ns.expect(ARGS, location="json", as_dict=True)

apps/routes/v1/lsst/schema/test.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Copyright 2026 AstroLab Software
2+
# Author: Julien Peloton
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
import requests
16+
import numpy as np
17+
import logging
18+
19+
import sys
20+
21+
APIURL = sys.argv[1]
22+
_LOG = logging.getLogger(__name__)
23+
24+
25+
def get_fields_per_family():
26+
"""Get fields exposed in /api/v1/schema"""
27+
r = requests.post(
28+
"{}/api/v1/schema".format(APIURL), json={"endpoint": "/api/v1/sources"}
29+
)
30+
31+
assert r.status_code == 200, r.content
32+
33+
schema = r.json()
34+
35+
categories = schema.keys()
36+
37+
dic = {}
38+
for i in ["r:", "f:"]:
39+
for category in categories:
40+
if i in category:
41+
dic[i] = list(schema[category].keys())
42+
43+
return dic
44+
45+
46+
def get_fields_from_schema(schema_dic):
47+
"""Get fields exposed in /api/v1/schema"""
48+
categories = schema_dic.keys()
49+
50+
out = []
51+
for i in ["r:", "f:"]:
52+
for category in categories:
53+
if i in category:
54+
tmp = [i + k for k in list(schema_dic[category].keys())]
55+
out.append(tmp)
56+
if len(out) > 1:
57+
return np.concatenate(out)
58+
else:
59+
return out[0]
60+
61+
62+
def check_schema_endpoint():
63+
"""Check there is not holes in the schema
64+
65+
Examples
66+
--------
67+
>>> check_schema_endpoint()
68+
"""
69+
diaobjectid = "313875415113400364"
70+
endpoints = {
71+
"/api/v1/sources": {"diaObjectId": diaobjectid},
72+
"/api/v1/objects": {"diaObjectId": diaobjectid},
73+
# "/api/v1/sso": {"name_or_d": ""},
74+
"/api/v1/conesearch": {
75+
"ra": "10 02 38.65",
76+
"dec": "+00 51 02.6",
77+
"radius": "5",
78+
},
79+
"/api/v1/tags": {"tag": "in_tns"},
80+
"/api/v1/statistics": {"date": "20260129"},
81+
}
82+
83+
for endpoint, payload in endpoints.items():
84+
_LOG.warning(endpoint)
85+
r_schema = requests.post(
86+
"{}/api/v1/schema".format(APIURL), json={"endpoint": endpoint}
87+
)
88+
r_data = requests.post("{}{}".format(APIURL, endpoint), json=payload)
89+
90+
if r_data.status_code != 200:
91+
_LOG.error(r_data.content)
92+
raise r_data.raise_for_status()
93+
if r_schema.status_code != 200:
94+
_LOG.error(r_schema.content)
95+
raise r_schema.raise_for_status()
96+
schema_fields = get_fields_from_schema(r_schema.json())
97+
98+
if len(r_data.json()) == 0:
99+
_LOG.error(
100+
"Data is empty for endpoint {} with payload {}".format(
101+
endpoint, payload
102+
)
103+
)
104+
raise ValueError
105+
data_fields = list(r_data.json()[0].keys())
106+
107+
# Expected non-null as not all alerts have all fields
108+
# not_in_alert = [i for i in schema_fields if i not in data_fields]
109+
110+
# Should be empty!
111+
not_in_schema = [i for i in data_fields if i not in schema_fields]
112+
113+
if len(not_in_schema) >= 1:
114+
allowed_fields = ["f:pixel1024", "v:separation_degree", "r:salt"]
115+
is_allowed = [i in allowed_fields for i in not_in_schema]
116+
assert np.sum(is_allowed) == len(not_in_schema), (endpoint, not_in_schema)
117+
118+
119+
if __name__ == "__main__":
120+
""" Execute the test suite """
121+
import sys
122+
import doctest
123+
124+
sys.exit(doctest.testmod()[0])

0 commit comments

Comments
 (0)