Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Special treatment empty POSIXPath parameters #731

Merged
merged 14 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions cdci_data_analysis/analysis/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from urllib.parse import urlencode

from cdci_data_analysis.analysis.queries import _check_is_base_query
from .parameters import POSIXPath
from ..analysis import tokenHelper, parameters
from .catalog import BasicCatalog
from .products import QueryOutput
Expand Down Expand Up @@ -167,14 +168,16 @@ def set_pars_from_dic(self, arg_dic, verbose=False):
for par in param_list:
self.logger.info("before normalizing, set_pars_from_dic>> par: %s par.name: %s par.value: %s par_dic[par.name]: %s",
par, par.name, par.value, arg_dic.get(par.name, None))

# this is required because in some cases a parameter is set without a name (eg UserCatalog),
# or they don't have to set (eg scw_list)
if par.name is not None and par.name not in params_not_to_be_included:
if isinstance(par, POSIXPath) and par.name + '_type' in arg_dic and arg_dic[par.name + '_type'] == 'file'\
and par.name not in arg_dic:
par.value = None

# set the value for par to a default format,
# or to a default value if this is not included within the request
updated_arg_dic[par.name] = par.set_value_from_form(arg_dic, verbose=verbose)

if par.units_name is not None:
if par.default_units is not None:
updated_arg_dic[par.units_name] = par.default_units
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ instruments:
- empty_development_instrument
- empty_async_return_progress_instrument
- empty_instrument_with_conf
- empty_instrument_with_posix_path
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""
Overview
--------

general info about this module


Classes and Inheritance Structure
----------------------------------------------
.. inheritance-diagram::

Summary
---------
.. autosummary::
list of the module you want

Module API
----------
"""

from __future__ import absolute_import, division, print_function

__author__ = "Andrea Tramacere"

# Standard library
# eg copy
# absolute import rg:from copy import deepcopy

# Dependencies
# eg numpy
# absolute import eg: import numpy as np

# Project
# relative import eg: from .mod import f


from cdci_data_analysis.analysis.instrument import Instrument
from cdci_data_analysis.analysis.queries import SourceQuery, InstrumentQuery, Float

from .data_server_dispatcher import (EmptyProductQuery,
DataServerNumericQuery,
FailingProductQuery,
DataServerParametricQuery,
EchoProductQuery,
DefaultEchoProductQuery,
FileParameterQuery)

# duplicated with jemx, but this staticmethod makes it complex.
# this all should be done commonly, for all parameters - limits are common thing
from ...analysis.exceptions import RequestNotUnderstood
from ...analysis.parameters import (SpectralBoundary,
Angle,
Energy,
Integer,
Float,
String,
StructuredParameter,
POSIXPath)



class BoundaryFloat(Float):
def check_value(self):
super().check_value()
if self.value > 800:
raise RequestNotUnderstood('p value is restricted to 800 W')


def my_instr_factory():
src_query = SourceQuery('src_query')

# empty query
instr_query = InstrumentQuery(name='empty_instrument_query',
input_prod_list_name='p_list',
catalog=None,
catalog_name='user_catalog')

empty_query = EmptyProductQuery('empty_with_posix_path_parameters_dummy_query',)
failing_query = FailingProductQuery('failing_parameters_dummy_query',)
# let's build a simple parameter to its list
p = BoundaryFloat(value=10., name='p', units='W',)
numerical_query = DataServerNumericQuery('numerical_parameters_dummy_query',
parameters_list=[p])

f = POSIXPath(value=None, name='dummy_POSIX_file', is_optional=True)
burnout87 marked this conversation as resolved.
Show resolved Hide resolved
file_query = FileParameterQuery('file_parameters_dummy_query',
parameters_list=[p, f])

# let's build a simple parameter to its list
sb = SpectralBoundary(value=10., name='sb')
parametrical_query = DataServerParametricQuery('parametrical_parameters_dummy_query',
parameters_list=[sb])

ang = Angle(value=1., units='arcsec', default_units='arcsec', name='ang')
ang_deg = Angle(value=1., units='deg', default_units='arcsec', name='ang_deg')
energ = Energy(value=1., E_units='MeV', name='energ', units_name='energy_units')
echo_param_query = EchoProductQuery('echo_parameters_dummy_query',
parameters_list=[ang, ang_deg, energ])

bounded_int_param = Integer(5, name = 'bounded_int_par', min_value = 2, max_value = 8)
bounded_float_param = Float(5., name = 'bounded_float_par', min_value = 2.2, max_value = 7.7)
string_select_param = String('spam', name='string_select_par', allowed_values=('spam', 'eggs', 'ham'))
restricted_param_query = EchoProductQuery('restricted_parameters_dummy_query',
parameters_list=[bounded_int_param,
bounded_float_param,
string_select_param])

struct_par = StructuredParameter({'a': [1, 2]}, name='struct')
structured_echo_query = DefaultEchoProductQuery('structured_param_dummy_query', parameters_list=[struct_par])

optional_par0 = Float(5., name = 'optional_def_float', is_optional=True)
optional_par1 = Float(None, name = 'optional_def_none', is_optional=True)
optional_echo_query = DefaultEchoProductQuery('optional_param_dummy_query', parameters_list=[optional_par0, optional_par1])

# this dicts binds the product query name to the product name from frontend
# eg my_instr_image is the parameter passed by the fronted to access the
# the MyInstrMosaicQuery, and the dictionary will bind
# query_dictionary['my_instr_image'] = 'my_instr_image_query'
query_dictionary = {}
# the empty instrument does not effectively do anything and therefore support any particular query
# nor product, only a simple query that does not return anything
query_dictionary['dummy'] = 'empty_with_posix_path_parameters_dummy_query'
query_dictionary['numerical'] = 'numerical_parameters_dummy_query'
query_dictionary['file_dummy'] = 'file_parameters_dummy_query'
query_dictionary['failing'] = 'failing_parameters_dummy_query'
query_dictionary['parametrical'] = 'parametrical_parameters_dummy_query'
query_dictionary['echo'] = 'echo_parameters_dummy_query'
query_dictionary['restricted'] = 'restricted_parameters_dummy_query'
query_dictionary['structured'] = 'structured_param_dummy_query'
query_dictionary['optional'] = 'optional_param_dummy_query'

return Instrument('empty-with-posix-path',
src_query=src_query,
instrumet_query=instr_query,
product_queries_list=[empty_query,
numerical_query,
file_query,
failing_query,
parametrical_query,
echo_param_query,
restricted_param_query,
structured_echo_query,
optional_echo_query],
query_dictionary=query_dictionary)
1 change: 1 addition & 0 deletions cdci_data_analysis/plugins/dummy_plugin/exposer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from . import empty_development_instrument
from . import empty_async_return_progress_instrument
from . import empty_instrument_with_conf
from . import empty_instrument_with_posix_path

Check notice

Code scanning / CodeQL

Unused import Note

Import of 'empty_instrument_with_posix_path' is not used.
from . import conf_file
import yaml

Expand Down
53 changes: 53 additions & 0 deletions tests/test_server_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1988,6 +1988,59 @@
assert ownerships['user_roles'] == []


@pytest.mark.parametrize("include_file_arg", [True, False])
def test_default_value_empty_posix_path(dispatcher_live_fixture, include_file_arg):
DispatcherJobState.remove_scratch_folders()
DispatcherJobState.empty_request_files_folders()
server = dispatcher_live_fixture
logger.info("constructed server: %s", server)

# let's generate a valid token
token_payload = {
**default_token_payload,
"roles": "unige-hpc-full, general",
}
encoded_token = jwt.encode(token_payload, secret_key, algorithm='HS256')

params = {
**default_params,
'product_type': 'file_dummy',
'query_type': "Dummy",
'instrument': 'empty-with-posix-path',
'dummy_POSIX_file_type': 'file',
'p': 6.,
'token': encoded_token
}

p_file_path = DispatcherJobState.create_p_value_file(p_value=6)
list_file = open(p_file_path)

Check warning

Code scanning / CodeQL

File is not always closed Warning test

File may not be closed if an exception is raised.

expected_query_status = 'done'
expected_job_status = 'done'
expected_status_code = 200

files = None
if include_file_arg:
files = {'dummy_POSIX_file': list_file.read()}

jdata = ask(server,
params,
expected_query_status=expected_query_status,
expected_job_status=expected_job_status,
expected_status_code=expected_status_code,
max_time_s=150,
method='post',
files=files
)

list_file.close()
assert 'dummy_POSIX_file' in jdata['products']['analysis_parameters']
if include_file_arg:
assert jdata['products']['analysis_parameters']['dummy_POSIX_file'] is not None
else:
assert jdata['products']['analysis_parameters']['dummy_POSIX_file'] is None


def test_scws_list_file(dispatcher_live_fixture):

server = dispatcher_live_fixture
Expand Down
Loading