@@ -180,6 +180,7 @@ def getEfdData(
180180 event : TMAEvent | None = None ,
181181 expRecord : dafButler .DimensionRecord | None = None ,
182182 warn : bool = True ,
183+ raiseIfTopicNotInSchema : bool = True ,
183184) -> pd .DataFrame :
184185 """Get one or more EFD topics over a time range, synchronously.
185186
@@ -194,6 +195,15 @@ def getEfdData(
194195
195196 The results from all topics are merged into a single dataframe.
196197
198+ `raiseIfTopicNotInSchema` should only be set to `False` when running on the
199+ summit or in utility code for topics which might have had no data taken
200+ within the last <data_retention_period> (nominally 30 days). Once a topic
201+ is in the schema at USDF it will always be there, and thus users there
202+ never need worry about this, always using `False` will be fine. However, at
203+ the summit things are a little less predictable, so something missing from
204+ the schema doesn't necessarily mean a typo, and utility code shouldn't
205+ raise when data has been expunged.
206+
197207 Parameters
198208 ----------
199209 client : `lsst_efd_client.efd_helper.EfdClient`
@@ -230,6 +240,8 @@ def getEfdData(
230240 If ``True``, warn when no data is found. Exists so that utility code
231241 can disable warnings when checking for data, and therefore defaults to
232242 ``True``.
243+ raiseIfTopicNotInSchema : `bool`, optional
244+ Whether to raise an error if the topic is not in the EFD schema.
233245
234246 Returns
235247 -------
@@ -263,14 +275,22 @@ def getEfdData(
263275 nest_asyncio .apply ()
264276 loop = asyncio .get_event_loop ()
265277 ret = loop .run_until_complete (
266- _getEfdData (client = client , topic = topic , begin = begin , end = end , columns = columns )
278+ _getEfdData (
279+ client = client ,
280+ topic = topic ,
281+ begin = begin ,
282+ end = end ,
283+ columns = columns ,
284+ raiseIfTopicNotInSchema = raiseIfTopicNotInSchema ,
285+ )
267286 )
268287 if ret .empty and warn :
269288 log = logging .getLogger (__name__ )
270- log .warning (
271- f"Topic { topic } is in the schema, but no data was returned by the query for the specified"
272- " time range"
273- )
289+ msg = ""
290+ if raiseIfTopicNotInSchema :
291+ f"Topic { topic } is in the schema, but "
292+ msg += "no data was returned by the query for the specified time range"
293+ log .warning (msg )
274294 return ret
275295
276296
@@ -280,6 +300,7 @@ async def _getEfdData(
280300 begin : astropy .Time ,
281301 end : astropy .Time ,
282302 columns : list [str ] | None = None ,
303+ raiseIfTopicNotInSchema : bool = True ,
283304) -> pd .DataFrame :
284305 """Get data for a topic from the EFD over the specified time range.
285306
@@ -295,6 +316,8 @@ async def _getEfdData(
295316 The end time for the query.
296317 columns : `list` of `str`, optional
297318 The columns to query. If not specified, all columns are returned.
319+ raiseIfTopicNotInSchema : `bool`, optional
320+ Whether to raise an error if the topic is not in the EFD schema.
298321
299322 Returns
300323 -------
@@ -308,7 +331,12 @@ async def _getEfdData(
308331 availableTopics = await client .get_topics ()
309332
310333 if topic not in availableTopics :
311- raise ValueError (f"Topic { topic } not in EFD schema" )
334+ if raiseIfTopicNotInSchema :
335+ raise ValueError (f"Topic { topic } not in EFD schema" )
336+ else :
337+ log = logging .getLogger (__name__ )
338+ log .debug (f"Topic { topic } not in EFD schema, returning empty DataFrame" )
339+ return pd .DataFrame ()
312340
313341 data = await client .select_time_series (topic , columns , begin .utc , end .utc )
314342
@@ -322,6 +350,7 @@ def getMostRecentRowWithDataBefore(
322350 warnStaleAfterNMinutes : float | int = 60 * 12 ,
323351 maxSearchNMinutes : float | int | None = None ,
324352 where : Callable [[pd .DataFrame ], list [bool ]] | None = None ,
353+ raiseIfTopicNotInSchema : bool = True ,
325354) -> pd .Series :
326355 """Get the most recent row of data for a topic before a given time.
327356
@@ -341,6 +370,8 @@ def getMostRecentRowWithDataBefore(
341370 where: `Callable` or None, optional
342371 A callable taking a single pd.Dataframe argument and returning a
343372 boolean list indicating rows to consider.
373+ raiseIfTopicNotInSchema : `bool`, optional
374+ Whether to raise an error if the topic is not in the EFD schema.
344375
345376 Returns
346377 -------
@@ -366,7 +397,14 @@ def getMostRecentRowWithDataBefore(
366397 df = pd .DataFrame ()
367398 beginTime = timeToLookBefore
368399 while df .empty and beginTime > earliest :
369- df = getEfdData (client , topic , begin = beginTime , timespan = - TIME_CHUNKING , warn = False )
400+ df = getEfdData (
401+ client ,
402+ topic ,
403+ begin = beginTime ,
404+ timespan = - TIME_CHUNKING ,
405+ warn = False ,
406+ raiseIfTopicNotInSchema = raiseIfTopicNotInSchema ,
407+ )
370408 beginTime -= TIME_CHUNKING
371409 if where is not None and not df .empty :
372410 df = df [where (df )]
@@ -776,6 +814,7 @@ def getCommands(
776814 prePadding = prePadding ,
777815 postPadding = postPadding ,
778816 warn = False , # most commands will not be issue so we expect many empty queries
817+ raiseIfTopicNotInSchema = False ,
779818 )
780819 for time , _ in data .iterrows ():
781820 # this is much the most simple data structure, and the chance
0 commit comments