Skip to content

Commit 1eb28a7

Browse files
committed
Backend type argument
1 parent 2492ce6 commit 1eb28a7

File tree

4 files changed

+109
-12
lines changed

4 files changed

+109
-12
lines changed

servicex/servicex.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def __init__(
175175
self,
176176
dataset: DatasetType,
177177
backend_name: Optional[str] = None,
178+
backend_type: Optional[str] = None,
178179
codegen: Optional[str] = None,
179180
image: Optional[str] = None,
180181
max_workers: int = 20,
@@ -202,8 +203,13 @@ def __init__(
202203
will default to xaod, unless you have any endpoint listed
203204
in your servicex file. It will default to best match there,
204205
or fail if a name has been given.
206+
backend_type The type of backend. Overrides the `type` in the `yaml`
207+
config file.
205208
codegen The type of code generator passed to the backend to
206209
generate the code that powers the requested transform.
210+
Don't use unless you know what you are doing - sometimes
211+
the return filetype is also needed. Better to use
212+
`backend_type`!
207213
image Name of transformer image to use to transform the data. If
208214
left as default, `None`, then the default image for the
209215
ServiceX backend will be used.
@@ -276,7 +282,9 @@ def __init__(
276282

277283
if not servicex_adaptor:
278284
# Given servicex adaptor is none, this should be ok. Fixes type checkers
279-
end_point, token = config.get_servicex_adaptor_config(backend_name)
285+
end_point, token = config.get_servicex_adaptor_config(
286+
backend_name, backend_type=backend_type
287+
)
280288
servicex_adaptor = ServiceXAdaptor(end_point, token)
281289
self._servicex_adaptor = servicex_adaptor
282290

@@ -296,7 +304,11 @@ def __init__(
296304
else default_client_session
297305
)
298306

299-
self._return_types = [config.get_default_returned_datatype(backend_name)]
307+
self._return_types = [
308+
config.get_default_returned_datatype(
309+
backend_name, backend_type=backend_type
310+
)
311+
]
300312
self._converter = (
301313
data_convert_adaptor
302314
if data_convert_adaptor is not None
@@ -306,7 +318,9 @@ def __init__(
306318
# TODO - this should not be in the ABC backend since we have to have some intelligence
307319
# in setting it, it turns out.
308320
if self._codegen is None:
309-
self._codegen = config.get_backend_info(backend_name, "codegen")
321+
self._codegen = config.get_backend_info(
322+
backend_name, "codegen", backend_type=backend_type
323+
)
310324

311325
def first_supported_datatype(
312326
self, datatypes: Union[List[str], str]

servicex/servicex_config.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ def settings(self) -> ConfigView:
3737
"""
3838
return self._settings
3939

40-
def get_default_returned_datatype(self, backend_name: Optional[str]) -> str:
40+
def get_default_returned_datatype(
41+
self, backend_name: Optional[str], backend_type: Optional[str] = None
42+
) -> str:
4143
"""Return the default return data type, given the backend is a certain type.
4244
4345
Args:
@@ -47,7 +49,9 @@ def get_default_returned_datatype(self, backend_name: Optional[str]) -> str:
4749
str: The backend datatype, like `root` or `parquet`.
4850
"""
4951
# Check to see if we know about the backend info
50-
r = self.get_backend_info(backend_name, "return_data")
52+
r = self.get_backend_info(
53+
backend_name, "return_data", backend_type=backend_type
54+
)
5155

5256
if r is None:
5357
raise ServiceXException(
@@ -57,22 +61,27 @@ def get_default_returned_datatype(self, backend_name: Optional[str]) -> str:
5761

5862
return r
5963

60-
def get_backend_info(self, backend_name: Optional[str], key: str) -> Optional[str]:
64+
def get_backend_info(
65+
self, backend_name: Optional[str], key: str, backend_type: Optional[str] = None
66+
) -> Optional[str]:
6167
"""Find an item in the backend info, searching first for the backend
6268
name/type and then the defaults with a given type.
6369
6470
Args:
6571
backend_name (str): Backend name
6672
key (str): The key for the info we are after
73+
backend_type (str): The backend type, if we are overriding normal lookup
6774
6875
Returns:
6976
Optional[str]: Return a string for the info we are after, or return None if we can't
7077
find it.
7178
"""
72-
config = self._get_backend_info(backend_name)
79+
config = self._get_backend_info(backend_name, backend_type)
7380
return config[key] if key in config else None
7481

75-
def _get_backend_info(self, backend_name: Optional[str]) -> Dict[str, str]:
82+
def _get_backend_info(
83+
self, backend_name: Optional[str], backend_type: Optional[str]
84+
) -> Dict[str, str]:
7685
"""Returns all the info for a backend name/type.
7786
7887
Search algorithm is non-trivial:
@@ -89,6 +98,8 @@ def _get_backend_info(self, backend_name: Optional[str]) -> Dict[str, str]:
8998
9099
Args:
91100
backend_name (str): Name or type of the api end point we are going to look up.
101+
backend_type (str): Override the backend type, if we are looking for a specific
102+
type behavior.
92103
93104
Returns:
94105
Dict[str, str]: Attributes for this backend's configuration
@@ -159,8 +170,14 @@ def _get_backend_info(self, backend_name: Optional[str]) -> Dict[str, str]:
159170
)
160171

161172
# Now, extract the type and see if we can figure out any defaults from the
162-
# `backend_types` info.
163-
type_lookup = config["type"] if "type" in config else backend_name
173+
# `backend_types` info. Skip this if we have a type we are passed in.
174+
type_lookup = (
175+
backend_type
176+
if backend_type is not None
177+
else config["type"]
178+
if "type" in config
179+
else backend_name
180+
)
164181
if type_lookup is None:
165182
return config
166183

@@ -181,7 +198,9 @@ def _get_backend_info(self, backend_name: Optional[str]) -> Dict[str, str]:
181198
return config
182199

183200
def get_servicex_adaptor_config(
184-
self, backend_name: Optional[str] = None
201+
self,
202+
backend_name: Optional[str] = None,
203+
backend_type: Optional[str] = None,
185204
) -> Tuple[str, Optional[str]]:
186205
"""Return the servicex (endpoint, token) from a given backend configuration.
187206
@@ -193,7 +212,7 @@ def get_servicex_adaptor_config(
193212
Tuple[str, str]: The tuple of info to create a `ServiceXAdaptor`: end point,
194213
token (optionally).
195214
"""
196-
config = self._get_backend_info(backend_name)
215+
config = self._get_backend_info(backend_name, backend_type)
197216

198217
endpoint = config["endpoint"]
199218
token = config["token"] if "token" in config else None

tests/test_servicex.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,30 @@ async def test_codegen_override(mocker, good_awkward_file_data):
13241324
assert called["codegen"] == "good_codegen"
13251325

13261326

1327+
@pytest.mark.asyncio
1328+
async def test_codegen_backend_type(mocker, good_awkward_file_data):
1329+
mock_cache = build_cache_mock(mocker)
1330+
mock_logger = mocker.MagicMock(spec=log_adaptor)
1331+
mock_servicex_adaptor = MockServiceXAdaptor(mocker, "123-456")
1332+
mock_minio_adaptor = MockMinioAdaptor(mocker, files=["one_minio_entry"])
1333+
data_adaptor = mocker.MagicMock(spec=DataConverterAdaptor)
1334+
1335+
ds = fe.ServiceXDataset(
1336+
"localds://mc16_tev:13",
1337+
servicex_adaptor=mock_servicex_adaptor, # type: ignore
1338+
minio_adaptor=mock_minio_adaptor, # type: ignore
1339+
cache_adaptor=mock_cache,
1340+
data_convert_adaptor=data_adaptor,
1341+
local_log=mock_logger,
1342+
max_workers=50,
1343+
backend_type="uproot",
1344+
)
1345+
await ds.get_data_rootfiles_async("(valid qastle string)")
1346+
1347+
called = mock_servicex_adaptor.query_json
1348+
assert called["codegen"] == "uproot"
1349+
1350+
13271351
@pytest.mark.asyncio
13281352
async def test_codegen_default_by_backend(mocker, good_awkward_file_data):
13291353
mock_cache = build_cache_mock(mocker)

tests/test_servicex_config.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,36 @@ def test_returned_datatype_from_endpoint():
6363
assert x.get_default_returned_datatype("forkit") == "spoons"
6464

6565

66+
def test_backend_info():
67+
c = ConfigSettings("servicex", "servicex")
68+
c.clear()
69+
c["backend_types"] = [{"type": "forkit", "silly": "spoon"}]
70+
c["api_endpoints"] = [{"type": "forkit", "return_data": "spoons"}]
71+
72+
x = ServiceXConfigAdaptor(c)
73+
assert x.get_backend_info("forkit", "silly") == "spoon"
74+
75+
76+
def test_backend_info_by_name():
77+
c = ConfigSettings("servicex", "servicex")
78+
c.clear()
79+
c["backend_types"] = [{"type": "forkit", "silly": "spoon"}]
80+
c["api_endpoints"] = [{"name": "dude", "type": "forkit", "return_data": "spoons"}]
81+
82+
x = ServiceXConfigAdaptor(c)
83+
assert x.get_backend_info("dude", "silly") == "spoon"
84+
85+
86+
def test_backend_info_specified_type():
87+
c = ConfigSettings("servicex", "servicex")
88+
c.clear()
89+
c["backend_types"] = [{"type": "forkit", "silly": "spoon"}]
90+
c["api_endpoints"] = [{"name": "dude", "type": "leftfoot", "return_data": "spoons"}]
91+
92+
x = ServiceXConfigAdaptor(c)
93+
assert x.get_backend_info("dude", "silly", backend_type="forkit") == "spoon"
94+
95+
6696
def test_default_config_has_default_return_datatype():
6797
"Test default settings - default_returned_datatype"
6898
c = ConfigSettings("servicex", "servicex")
@@ -80,6 +110,16 @@ def test_default_config_has_backend_types():
80110
assert count > 0
81111

82112

113+
def test_default_config_has_codegen():
114+
c = ConfigSettings("servicex", "servicex")
115+
assert c["backend_types"].exists()
116+
count = 0
117+
for info in c["backend_types"]:
118+
count += 1
119+
assert info["codegen"].exists()
120+
assert count > 0
121+
122+
83123
def test_sx_adaptor_settings(caplog):
84124
from confuse import Configuration
85125

0 commit comments

Comments
 (0)