From 9bbea592edaf1400f06245e1d346032ab191b1d0 Mon Sep 17 00:00:00 2001 From: "ESAAD\\jsaiz" Date: Tue, 30 Sep 2025 17:17:35 +0200 Subject: [PATCH 1/9] EUCLIDSWRQ-215: Add get_datalinks_metadata & options to get_datalinks --- astroquery/esa/euclid/core.py | 30 ++++++++++++++++++++++++++++-- astroquery/utils/tap/core.py | 22 +++++++++++++--------- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/astroquery/esa/euclid/core.py b/astroquery/esa/euclid/core.py index 768d2288f6..d46dd20ebd 100644 --- a/astroquery/esa/euclid/core.py +++ b/astroquery/esa/euclid/core.py @@ -1418,7 +1418,7 @@ def get_spectrum(self, *, source_id, schema='sedm', retrieval_type="ALL", output return files - def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', verbose=False): + def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', options=None, verbose=False): """Gets datalinks associated to the provided identifiers TAP+ only @@ -1428,6 +1428,8 @@ def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', verbose=False): list of identifiers linking_parameter : str, optional, default SOURCE_ID, valid values: SOURCE_ID By default, all the identifiers are considered as source_id + options : str, optional, default None + To let customize the server behaviour verbose : bool, optional, default 'False' flag to display information about the process @@ -1437,7 +1439,31 @@ def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', verbose=False): """ - return self.__eucliddata.get_datalinks(ids=ids, linking_parameter=linking_parameter, verbose=verbose) + return self.__eucliddata.get_datalinks(ids=ids, + linking_parameter=linking_parameter, + options=options, + verbose=verbose) + + def get_datalinks_metadata(self, ids, *, linking_parameter='SOURCE_ID', verbose=False): + """Gets datalinks associated to the provided identifiers, including additional metadata (the datalabs_path) + TAP+ only + + Parameters + ---------- + ids : str, int, list of str or list of int, mandatory + List of identifiers + linking_parameter : str, optional, default SOURCE_ID, valid values: SOURCE_ID + By default, all the identifiers are considered as source_id + verbose : bool, optional, default 'False' + Flag to display information about the process + + Returns + ------- + A table object + + """ + + return self.get_datalinks(ids=ids, linking_parameter=linking_parameter, options='METADATA', verbose=verbose) def get_scientific_product_list(self, *, observation_id=None, tile_index=None, category=None, group=None, product_type=None, dataset_release='REGREPROC1_R2', verbose=False): diff --git a/astroquery/utils/tap/core.py b/astroquery/utils/tap/core.py index c137b10a56..97b3971199 100755 --- a/astroquery/utils/tap/core.py +++ b/astroquery/utils/tap/core.py @@ -1247,20 +1247,22 @@ def is_valid_user(self, *, user_id=None, verbose=False): print(f"USER response = {user}") return user.startswith(f"{user_id}:") and user.count("\\n") == 0 - def get_datalinks(self, ids, *, linking_parameter=None, verbose=False): + def get_datalinks(self, ids, *, linking_parameter=None, options=None, verbose=False): """Gets datalinks associated to the provided identifiers Parameters ---------- ids : str list, mandatory - list of identifiers + List of identifiers linking_parameter : str, optional, default SOURCE_ID, valid values: SOURCE_ID, TRANSIT_ID, IMAGE_ID By default, all the identifiers are considered as source_id SOURCE_ID: the identifiers are considered as source_id TRANSIT_ID: the identifiers are considered as transit_id IMAGE_ID: the identifiers are considered as sif_observation_id + options : str, optional, default None + If present, an extra parameter OPTIONS will be added to the call, to be interpreted by the TAP service verbose : bool, optional, default 'False' - flag to display information about the process + Flag to display information about the process Returns ------- @@ -1282,15 +1284,17 @@ def get_datalinks(self, ids, *, linking_parameter=None, verbose=False): if linking_parameter is not None: ids_arg = f'{ids_arg}&LINKING_PARAMETER={linking_parameter}' + if options is not None: + ids_arg = f'{ids_arg}&OPTIONS={options}' + if verbose: - print(f"Datalink request: {ids_arg}") - connHandler = self.__getconnhandler() - response = connHandler.execute_datalinkpost(subcontext="links", - data=ids_arg, - verbose=verbose) + print(f"Datalink request: ID={ids_arg}") + + conn_handler = self.__getconnhandler() + response = conn_handler.execute_datalinkpost(subcontext="links", data=ids_arg, verbose=verbose) if verbose: print(response.status, response.reason) - connHandler.check_launch_response_status(response, verbose, 200) + conn_handler.check_launch_response_status(response, verbose, 200) if verbose: print("Done.") results = utils.read_http_response(response, "votable", use_names_over_ids=self.use_names_over_ids) From 91ea0079590ea1292e5886662c26df90d933c584 Mon Sep 17 00:00:00 2001 From: "ESAAD\\jsaiz" Date: Wed, 1 Oct 2025 11:34:57 +0200 Subject: [PATCH 2/9] EUCLIDSWRQ-215: Add test_get_datalinks_metadata --- astroquery/esa/euclid/tests/test_euclidtap.py | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/astroquery/esa/euclid/tests/test_euclidtap.py b/astroquery/esa/euclid/tests/test_euclidtap.py index 40eaadd8a2..0d3e6241ee 100644 --- a/astroquery/esa/euclid/tests/test_euclidtap.py +++ b/astroquery/esa/euclid/tests/test_euclidtap.py @@ -1220,12 +1220,12 @@ def test_logout(mock_logout): def test_get_datalinks(monkeypatch): - def get_datalinks_monkeypatched(self, ids, linking_parameter, verbose): + def get_datalinks_monkeypatched(self, ids, linking_parameter, options, verbose): return Table() # `EuclidClass` is a subclass of `TapPlus`, but it does not inherit # `get_datalinks()`, it replaces it with a call to the `get_datalinks()` - # of its `__gaiadata`. + # of its `__eucliddata`. monkeypatch.setattr(TapPlus, "get_datalinks", get_datalinks_monkeypatched) euclid = EuclidClass(show_server_messages=False) @@ -1233,6 +1233,24 @@ def get_datalinks_monkeypatched(self, ids, linking_parameter, verbose): assert isinstance(result, Table) +def test_get_datalinks_metadata(monkeypatch): + def get_datalinks_monkeypatched(self, ids, linking_parameter, options, verbose): + table = TapTableMeta() + table.name = options + return table + + # `EuclidClass` is a subclass of `TapPlus`, but it does not inherit + # `get_datalinks()`, it replaces it with a call to the `get_datalinks()` + # of its `__eucliddata`. get_datalinks_metadata delegates to get_datalinks, + # which in turn delegates to TapPlus' get_datalinks + monkeypatch.setattr(TapPlus, "get_datalinks", get_datalinks_monkeypatched) + euclid = EuclidClass(show_server_messages=False) + + result = euclid.get_datalinks_metadata(ids=[12345678], verbose=True) + assert isinstance(result, TapTableMeta) + assert result.name is "METADATA" + + @pytest.mark.parametrize("background", [False, True]) def test_cross_match_basic(monkeypatch, background, cross_match_basic_kwargs, mock_querier_async): def load_table_monkeypatched(self, table, verbose): From e11f753a83cddf71508aa8e68b146cbc2c814c8c Mon Sep 17 00:00:00 2001 From: "ESAAD\\jsaiz" Date: Wed, 1 Oct 2025 13:06:39 +0200 Subject: [PATCH 3/9] EUCLIDSWRQ-215: Correct assertion --- astroquery/esa/euclid/tests/test_euclidtap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astroquery/esa/euclid/tests/test_euclidtap.py b/astroquery/esa/euclid/tests/test_euclidtap.py index 0d3e6241ee..f5d055d498 100644 --- a/astroquery/esa/euclid/tests/test_euclidtap.py +++ b/astroquery/esa/euclid/tests/test_euclidtap.py @@ -1248,7 +1248,7 @@ def get_datalinks_monkeypatched(self, ids, linking_parameter, options, verbose): result = euclid.get_datalinks_metadata(ids=[12345678], verbose=True) assert isinstance(result, TapTableMeta) - assert result.name is "METADATA" + assert result.name == "METADATA" @pytest.mark.parametrize("background", [False, True]) From fa21e76723c28fb8098e3b9d085c8f1f5cf7857b Mon Sep 17 00:00:00 2001 From: Jaime Saiz Santos Date: Wed, 1 Oct 2025 16:36:02 +0200 Subject: [PATCH 4/9] EUCLIDSWRQ-215: Add documentation for get_datalinks_metadata --- docs/esa/euclid/euclid.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/esa/euclid/euclid.rst b/docs/esa/euclid/euclid.rst index 43d6b7c3b5..08d795e9dd 100644 --- a/docs/esa/euclid/euclid.rst +++ b/docs/esa/euclid/euclid.rst @@ -1215,6 +1215,20 @@ To find out the resources associated with a given source: sedm 2707008224650763513 SOURCE_ID https://eas.esac.esa.int/sas-dd/data?ID=sedm+2707008224650763513&RETRIEVAL_TYPE=SPECTRA_BGS #this Spectra Blue Source -- +Euclid also provides a way to execute a similar call by getting the datalabs_path as an additional column: + +.. Skipping authentication requiring examples +.. doctest-skip:: + + >>> from astroquery.esa.euclid import Euclid + >>> Euclid.login() + >>> result = Euclid.get_datalinks_metadata(ids=2707008224650763513) + >>> print(result) + ID linking_parameter access_url service_def ... content_type content_length datalabs_path + ... byte + ------------------------ ----------------- ------------------------------------------------------------------------------------------------------- ----------- ... ------------ -------------- ----------------------------------- + sedm 2707008224650763513 SOURCE_ID https://eas.esac.esa.int/sas-dd/datalink/data?ID=sedm+2707008224650763513&RETRIEVAL_TYPE=SPECTRA_RGS ... -- /data/euclid_q1/Q1_R1/SIR/102158586 + sedm 2707008224650763513 SOURCE_ID https://eas.esac.esa.int/sas-dd/datalink/data?ID=sedm+2707008224650763513&RETRIEVAL_TYPE=SPECTRA_BGS ... -- /data/euclid_q1/Q1_R1/SIR/102158586 The query below retrieves a random sample of Euclid sources having spectra. From 671956f043bc75bec2419c65883adb2ffe432451 Mon Sep 17 00:00:00 2001 From: Jaime Saiz Santos Date: Wed, 8 Oct 2025 16:26:44 +0200 Subject: [PATCH 5/9] Change for PR #3438 added to CHANGES.rst --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 1879f11851..ff0a3f9549 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -66,6 +66,9 @@ esa.euclid - New cross-match method [#3386] +- New method, ``get_datalinks_metadata``, to retrieve additional columns + from the datalinks metadata. [#3438] + esa.hubble ^^^^^^^^^^ From 06c897d22e7fa104f035754f216c48af03261af6 Mon Sep 17 00:00:00 2001 From: Jaime Saiz Santos Date: Mon, 20 Oct 2025 11:24:52 +0200 Subject: [PATCH 6/9] EUCLIDSWRQ-215: Rename options to extra_options and update changelog --- CHANGES.rst | 14 +++++++++++--- astroquery/esa/euclid/core.py | 10 +++++----- astroquery/esa/euclid/tests/test_euclidtap.py | 6 +++--- astroquery/utils/tap/core.py | 5 +++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index ff0a3f9549..f2a8824016 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -9,11 +9,22 @@ New Tools and Services API changes ----------- +esa.euclid +^^^^^^^^^^ + +- Method ``get_datalinks`` has a new argument, extra_options, to customize + the results to be got from the server. [#3438] + Service fixes and enhancements ------------------------------ +esa.euclid +^^^^^^^^^^ + +- New method, ``get_datalinks_metadata``, to retrieve additional columns + from the datalinks metadata. [#3438] Infrastructure, Utility and Other Changes and Additions @@ -66,9 +77,6 @@ esa.euclid - New cross-match method [#3386] -- New method, ``get_datalinks_metadata``, to retrieve additional columns - from the datalinks metadata. [#3438] - esa.hubble ^^^^^^^^^^ diff --git a/astroquery/esa/euclid/core.py b/astroquery/esa/euclid/core.py index d46dd20ebd..aab9d687a1 100644 --- a/astroquery/esa/euclid/core.py +++ b/astroquery/esa/euclid/core.py @@ -1418,7 +1418,7 @@ def get_spectrum(self, *, source_id, schema='sedm', retrieval_type="ALL", output return files - def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', options=None, verbose=False): + def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', extra_options=None, verbose=False): """Gets datalinks associated to the provided identifiers TAP+ only @@ -1428,8 +1428,8 @@ def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', options=None, ver list of identifiers linking_parameter : str, optional, default SOURCE_ID, valid values: SOURCE_ID By default, all the identifiers are considered as source_id - options : str, optional, default None - To let customize the server behaviour + extra_options : str, optional, default None, valid values: METADATA + To let customize the server behaviour, if present verbose : bool, optional, default 'False' flag to display information about the process @@ -1441,7 +1441,7 @@ def get_datalinks(self, ids, *, linking_parameter='SOURCE_ID', options=None, ver return self.__eucliddata.get_datalinks(ids=ids, linking_parameter=linking_parameter, - options=options, + extra_options=extra_options, verbose=verbose) def get_datalinks_metadata(self, ids, *, linking_parameter='SOURCE_ID', verbose=False): @@ -1463,7 +1463,7 @@ def get_datalinks_metadata(self, ids, *, linking_parameter='SOURCE_ID', verbose= """ - return self.get_datalinks(ids=ids, linking_parameter=linking_parameter, options='METADATA', verbose=verbose) + return self.get_datalinks(ids=ids, linking_parameter=linking_parameter, extra_options='METADATA', verbose=verbose) def get_scientific_product_list(self, *, observation_id=None, tile_index=None, category=None, group=None, product_type=None, dataset_release='REGREPROC1_R2', verbose=False): diff --git a/astroquery/esa/euclid/tests/test_euclidtap.py b/astroquery/esa/euclid/tests/test_euclidtap.py index f5d055d498..9b4a86630d 100644 --- a/astroquery/esa/euclid/tests/test_euclidtap.py +++ b/astroquery/esa/euclid/tests/test_euclidtap.py @@ -1220,7 +1220,7 @@ def test_logout(mock_logout): def test_get_datalinks(monkeypatch): - def get_datalinks_monkeypatched(self, ids, linking_parameter, options, verbose): + def get_datalinks_monkeypatched(self, ids, linking_parameter, extra_options, verbose): return Table() # `EuclidClass` is a subclass of `TapPlus`, but it does not inherit @@ -1234,9 +1234,9 @@ def get_datalinks_monkeypatched(self, ids, linking_parameter, options, verbose): def test_get_datalinks_metadata(monkeypatch): - def get_datalinks_monkeypatched(self, ids, linking_parameter, options, verbose): + def get_datalinks_monkeypatched(self, ids, linking_parameter, extra_options, verbose): table = TapTableMeta() - table.name = options + table.name = extra_options return table # `EuclidClass` is a subclass of `TapPlus`, but it does not inherit diff --git a/astroquery/utils/tap/core.py b/astroquery/utils/tap/core.py index 97b3971199..315d0ef84b 100755 --- a/astroquery/utils/tap/core.py +++ b/astroquery/utils/tap/core.py @@ -1247,7 +1247,7 @@ def is_valid_user(self, *, user_id=None, verbose=False): print(f"USER response = {user}") return user.startswith(f"{user_id}:") and user.count("\\n") == 0 - def get_datalinks(self, ids, *, linking_parameter=None, options=None, verbose=False): + def get_datalinks(self, ids, *, linking_parameter=None, extra_options=None, verbose=False): """Gets datalinks associated to the provided identifiers Parameters @@ -1259,8 +1259,9 @@ def get_datalinks(self, ids, *, linking_parameter=None, options=None, verbose=Fa SOURCE_ID: the identifiers are considered as source_id TRANSIT_ID: the identifiers are considered as transit_id IMAGE_ID: the identifiers are considered as sif_observation_id - options : str, optional, default None + extra_options : str, optional, default None, valid values: METADATA If present, an extra parameter OPTIONS will be added to the call, to be interpreted by the TAP service + METADATA: to retrieve extra metadata columns (currently supported by the Euclid archive) verbose : bool, optional, default 'False' Flag to display information about the process From a2fb3a19558b02bacb553e7c1f12455f346858ff Mon Sep 17 00:00:00 2001 From: Jaime Saiz Santos Date: Mon, 20 Oct 2025 11:28:01 +0200 Subject: [PATCH 7/9] EUCLIDSWRQ-215: Correct blank lines --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5e778fbba4..8d3ba6df6c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,7 +16,6 @@ esa.euclid the results to be got from the server. [#3438] - Service fixes and enhancements ------------------------------ @@ -25,6 +24,7 @@ esa.euclid - New method, ``get_datalinks_metadata``, to retrieve additional columns from the datalinks metadata. [#3438] + esa.hubble ^^^^^^^^^^ From 0638e445183e3e4ba4417b4ec0de8d8d78d3b16a Mon Sep 17 00:00:00 2001 From: Jaime Saiz Santos Date: Mon, 20 Oct 2025 11:35:53 +0200 Subject: [PATCH 8/9] EUCLIDSWRQ-215: Correct usage of extra_options in TapPlus class --- astroquery/utils/tap/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astroquery/utils/tap/core.py b/astroquery/utils/tap/core.py index db139f8197..6301db4f1c 100755 --- a/astroquery/utils/tap/core.py +++ b/astroquery/utils/tap/core.py @@ -1285,8 +1285,8 @@ def get_datalinks(self, ids, *, linking_parameter=None, extra_options=None, verb if linking_parameter is not None: ids_arg = f'{ids_arg}&LINKING_PARAMETER={linking_parameter}' - if options is not None: - ids_arg = f'{ids_arg}&OPTIONS={options}' + if extra_options is not None: + ids_arg = f'{ids_arg}&OPTIONS={extra_options}' if verbose: print(f"Datalink request: ID={ids_arg}") From 8c8dc07bc864be36ea4804ed133cda20cb21f098 Mon Sep 17 00:00:00 2001 From: Jaime Saiz Santos Date: Mon, 20 Oct 2025 11:54:40 +0200 Subject: [PATCH 9/9] EUCLIDSWRQ-215: Break line too long --- astroquery/esa/euclid/core.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/astroquery/esa/euclid/core.py b/astroquery/esa/euclid/core.py index aab9d687a1..4488696309 100644 --- a/astroquery/esa/euclid/core.py +++ b/astroquery/esa/euclid/core.py @@ -1463,7 +1463,10 @@ def get_datalinks_metadata(self, ids, *, linking_parameter='SOURCE_ID', verbose= """ - return self.get_datalinks(ids=ids, linking_parameter=linking_parameter, extra_options='METADATA', verbose=verbose) + return self.get_datalinks(ids=ids, + linking_parameter=linking_parameter, + extra_options='METADATA', + verbose=verbose) def get_scientific_product_list(self, *, observation_id=None, tile_index=None, category=None, group=None, product_type=None, dataset_release='REGREPROC1_R2', verbose=False):