From 1eac524f2d904414a53a443ddc690f59cd0f8142 Mon Sep 17 00:00:00 2001 From: AmandaWasserman Date: Wed, 13 Mar 2024 15:50:19 -0700 Subject: [PATCH] add tom_client class to access TOM --- resspect/fit_lightcurves.py | 12 ++- resspect/request_webservice_elasticc.py | 59 --------------- resspect/tom_client.py | 97 +++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 61 deletions(-) delete mode 100644 resspect/request_webservice_elasticc.py create mode 100644 resspect/tom_client.py diff --git a/resspect/fit_lightcurves.py b/resspect/fit_lightcurves.py index 071e6363..9e8f627b 100644 --- a/resspect/fit_lightcurves.py +++ b/resspect/fit_lightcurves.py @@ -38,8 +38,9 @@ from resspect.lightcurves_utils import find_available_key_name_in_header from resspect.lightcurves_utils import PLASTICC_TARGET_TYPES from resspect.lightcurves_utils import PLASTICC_RESSPECT_FEATURES_HEADER +from resspect.tom_client import TomClient -__all__ = ["fit_snpcc", "fit_plasticc", "fit_TOM"] +__all__ = ["fit_snpcc", "fit_plasticc", "fit_TOM", "request_TOM_data"] FEATURE_EXTRACTOR_MAPPING = { @@ -296,7 +297,14 @@ def fit_TOM(data_dic: dict, features_file: str, write_features_to_output_file( light_curve_data, snpcc_features_file) logging.info("Features have been saved to: %s", features_file) - + +def request_TOM_data(url: str = "https://desc-tom-2.lbl.gov", username: str = None, + passwordfile: str = None, password: str = None): + tom = TomClient(url = url, username = username, passwordfile = passwordfile, + password = password) + res = tom.request( 'POST', 'elasticc2/gethotsne/10/' ) + data_dic = res.json() + return data_dic def main(): diff --git a/resspect/request_webservice_elasticc.py b/resspect/request_webservice_elasticc.py deleted file mode 100644 index f5729f8b..00000000 --- a/resspect/request_webservice_elasticc.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2020 resspect software -# Author: Amanda Wasserman -# -# created on 12 March 2024 -# -# Licensed GNU General Public License v3.0; -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.gnu.org/licenses/gpl-3.0.en.html -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import requests - -class TomClient: - def __init__(self, url='https://desc-tom.lbl.gov', username=None, - password=None, passwordfile = None, connect=True): - self._url = url - self._username = username - self._password = password - self._rqs=None - if self._password is None: - if passwordfile is None: - raise RuntimeError('No password or passwordfile provided') - with open(passwordfile) as ifp: - self._password = ifp.readline().strip() - - if connect: - self.connect() - - def connect(self): - self._rqs = requests.session() #should this be capitalized S? - res = self._rqs.get(f'{self._url}/acounts/login/') - if res.status_code != 200: - raise RuntimeError(f'Failed to connect to {self._url}') - res = self._rqs.post(f'{self._url}/accounts/login/', - data={'username':self._username, - 'password':self._password, - 'csrfmiddlewaretoken': self._rqs.cookies['csrftoken']}) - if res.status_code != 200: - raise RuntimeError(f'Failed to login.') - if 'Please enter a correct' in res.text: - raise RuntimeError("failed to log in.") - self._rqs.headers.update({'X-CSRFToken': self._rqs.cookies['csrftoken']}) - - def request(self, method="GET", page=None, **kwargs): - - return self._rqs.request(method=method, url=f"{self._url}/{page}", **kwargs) - -#def request(website: str): -# r = requests.get(website) -# status = r.status_code -# text = r.text -# return text \ No newline at end of file diff --git a/resspect/tom_client.py b/resspect/tom_client.py new file mode 100644 index 00000000..24e3f3c8 --- /dev/null +++ b/resspect/tom_client.py @@ -0,0 +1,97 @@ +# Copyright 2020 resspect software +# Author: Rob Knop +# +# created on 12 March 2024 +# +# Licensed GNU General Public License v3.0; +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.gnu.org/licenses/gpl-3.0.en.html +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import requests + +class TomClient: + """A thin class that supports sending requests via "requests" to the DESC tom. + + Usage: initialize one of these, giving it the url, your TOM + username, and either your TOM password, or a file that has your TOM + password in it: + + tc = TomClient( username='rknop', passwordfile='/home/raknop/secrets/tom_rknop_passwd' ) + + (You can give it a url with url=; it defaults to https://desc-tom.lbl.gov.) + + Thereafter, just do something like + + res = tc.request( "POST", "elasticc2/ppdbdiaobject/55772173" ) + + and res will come back with a string that you can load into JSON + that will have all the fun data about PPDBDiaObject number 55772173. + + tc.request is just a thin front-end to python requests.request. The + only reason to use this client rather than the python requests + module directly is that this class takes care of the stupid fiddly + bits of getting some headers that django demands set up right in the + request object when you log in. + + """ + + def __init__( self, url="https://desc-tom.lbl.gov", username=None, password=None, passwordfile=None, connect=True ): + self._url = url + self._username = username + self._password = password + self._rqs = None + if self._password is None: + if passwordfile is None: + raise RuntimeError( "Must give either password or passwordfile. " ) + with open( passwordfile ) as ifp: + self._password = ifp.readline().strip() + + if connect: + self.connect() + + def connect( self ): + self._rqs = requests.session() + res = self._rqs.get( f'{self._url}/accounts/login/' ) + if res.status_code != 200: + raise RuntimeError( f"Got status {res.status_code} from first attempt to connect to {self._url}" ) + res = self._rqs.post( f'{self._url}/accounts/login/', + data={ 'username': self._username, + 'password': self._password, + 'csrfmiddlewaretoken': self._rqs.cookies['csrftoken'] } ) + if res.status_code != 200: + raise RuntimeError( f"Failed to log in; http status: {res.status_code}" ) + if 'Please enter a correct' in res.text: + # This is a very cheesy attempt at checking if the login failed. + # I haven't found clean documentation on how to log into a django site + # from an app like this using standard authentication stuff. So, for + # now, I'm counting on the HTML that happened to come back when + # I ran it with a failed login one time. One of these days I'll actually + # figure out how Django auth works and make a version of /accounts/login/ + # designed for use in API scripts like this one, rather than desgined + # for interactive users. + raise RuntimeError( "Failed to log in. I think. Put in a debug break and look at res.text" ) + self._rqs.headers.update( { 'X-CSRFToken': self._rqs.cookies['csrftoken'] } ) + + def request( self, method="GET", page=None, **kwargs ): + """Send a request to the TOM + + method : a string with the HTTP method ("GET", "POST", etc.) + + page : the page to get; this is the URL but with the url you + passed to the constructor removed. So, if you wanted to get + https://desc-tom.lbl.gov/elasticc, you'd pass just "elasticc" + here. + + **kwargs : additional keyword arguments are passed on to + requests.request + + """ + return self._rqs.request( method=method, url=f"{self._url}/{page}", **kwargs )