How to select only FUV IRIS level 1 data using JSOC

I’m trying to download only the FUV level 1 IRIS data using the JSOC interface.

It’s pretty easy to generate a response that contains all the data (SJI, NUV, FUV) using the following code:

response = sunpy.net.Fido.search(
    sunpy.net.attrs.Time("2014-01-01T00:00", "2014-01-01T00:05"),
    sunpy.net.attrs.jsoc.Series("iris.lev1"),
    sunpy.net.attrs.jsoc.Notify("roytsmart@gmail.com")
)
response

Which outputs:

<sunpy.net.fido_factory.UnifiedResponse object at 0x0000016B0036D8D0>
Results from 1 Provider:

22 Results from the JSOCClient:
Source: http://jsoc.stanford.edu

TELESCOP INSTRUME
-------- --------
    IRIS      NUV
    IRIS      FUV
    IRIS      SJI
    IRIS      NUV
    IRIS      SJI
    IRIS      NUV
    IRIS      SJI
    IRIS      NUV
    IRIS      FUV
    IRIS      SJI
    IRIS      NUV
    IRIS      FUV
    IRIS      NUV
    IRIS      FUV
    IRIS      SJI
    IRIS      NUV
    IRIS      FUV
    IRIS      SJI
    IRIS      NUV
    IRIS      FUV
    IRIS      SJI
    IRIS      NUV

However, when I try to use the following code which I felt should work:

response = sunpy.net.Fido.search(
    sunpy.net.attrs.Time("2014-01-01T00:00", "2014-01-01T00:05"),
    sunpy.net.attrs.jsoc.Series("iris.lev1"),
    sunpy.net.attrs.jsoc.Notify("roytsmart@gmail.com"),
    sunpy.net.attrs.Instrument("FUV"),
)
response

I get an error

---------------------------------------------------------------------------
NoMatchError                              Traceback (most recent call last)
Cell In[43], line 1
----> 1 response = sunpy.net.Fido.search(
      2     sunpy.net.attrs.Time("2014-01-01T00:00", "2014-01-01T00:05"),
      3     
      4     sunpy.net.attrs.jsoc.Series("iris.lev1"),
      5     sunpy.net.attrs.jsoc.Notify("roytsmart@gmail.com"),
      6     sunpy.net.attrs.Instrument("FUV"),
      7     # sunpy.net.attrs.jsoc.Keyword("INSTRUME") == "FUV",
      8 )
      9 response

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\fido_factory.py:315, in UnifiedDownloaderFactory.search(self, *query)
    269 """
    270 Query for data in form of multiple parameters.
    271 
   (...)
    312 parts individually.
    313 """
    314 query = attr.and_(*query)
--> 315 results = query_walker.create(query, self)
    317 # If we have searched the VSO but no results were returned, but another
    318 # client generated results, we drop the empty VSO results for tidiness.
    319 # This is because the VSO _can_handle_query is very broad because we
    320 # don't know the full list of supported values we can search for (yet).
    321 results = [r for r in results if not isinstance(r, vso.VSOQueryResponseTable) or len(r) > 0]

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\attr.py:613, in AttrWalker.create(self, *args, **kwargs)
    609 def create(self, *args, **kwargs):
    610     """
    611     Call the create function(s) matching the arguments to this method.
    612     """
--> 613     return self.createmm(self, *args, **kwargs)

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\util\functools.py:18, in seconddispatch.<locals>.wrapper(*args, **kwargs)
     17 def wrapper(*args, **kwargs):
---> 18     return dispatcher.dispatch(args[1].__class__)(*args, **kwargs)

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\fido_factory.py:244, in _create_and(walker, query, factory)
    242 @query_walker.add_creator(attr.AttrAnd)
    243 def _create_and(walker, query, factory):
--> 244     return factory._make_query_to_client(*query.attrs)

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\fido_factory.py:478, in UnifiedDownloaderFactory._make_query_to_client(self, *query)
    464 def _make_query_to_client(self, *query):
    465     """
    466     Given a query, look up the client and perform the query.
    467 
   (...)
    476         Instance of client class
    477     """
--> 478     candidate_widget_types = self._check_registered_widgets(*query)
    479     results = []
    480     for client in candidate_widget_types:

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\fido_factory.py:460, in UnifiedDownloaderFactory._check_registered_widgets(self, *args)
    457 n_matches = len(candidate_widget_types)
    458 if n_matches == 0:
    459     # There is no default client
--> 460     raise NoMatchError("This query was not understood by any clients. Did you miss an OR?")
    462 return candidate_widget_types

NoMatchError: This query was not understood by any clients. Did you miss an OR?

And when I used a slightly different code that was also suggested by the docs:

response = sunpy.net.Fido.search(
    sunpy.net.attrs.Time("2014-01-01T00:00", "2014-01-01T00:05"),
    sunpy.net.attrs.jsoc.Series("iris.lev1"),
    sunpy.net.attrs.jsoc.Notify("roytsmart@gmail.com"),
    # sunpy.net.attrs.Instrument("FUV"),
    sunpy.net.attrs.jsoc.Keyword("INSTRUME") == "FUV",
)
response

I get a different error that is hard to understand

---------------------------------------------------------------------------
DrmsQueryError                            Traceback (most recent call last)
Cell In[44], line 1
----> 1 response = sunpy.net.Fido.search(
      2     sunpy.net.attrs.Time("2014-01-01T00:00", "2014-01-01T00:05"),
      3     sunpy.net.attrs.jsoc.Series("iris.lev1"),
      4     sunpy.net.attrs.jsoc.Notify("roytsmart@gmail.com"),
      5     # sunpy.net.attrs.Instrument("FUV"),
      6     sunpy.net.attrs.jsoc.Keyword("INSTRUME") == "FUV",
      7 )
      8 response

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\fido_factory.py:315, in UnifiedDownloaderFactory.search(self, *query)
    269 """
    270 Query for data in form of multiple parameters.
    271 
   (...)
    312 parts individually.
    313 """
    314 query = attr.and_(*query)
--> 315 results = query_walker.create(query, self)
    317 # If we have searched the VSO but no results were returned, but another
    318 # client generated results, we drop the empty VSO results for tidiness.
    319 # This is because the VSO _can_handle_query is very broad because we
    320 # don't know the full list of supported values we can search for (yet).
    321 results = [r for r in results if not isinstance(r, vso.VSOQueryResponseTable) or len(r) > 0]

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\attr.py:613, in AttrWalker.create(self, *args, **kwargs)
    609 def create(self, *args, **kwargs):
    610     """
    611     Call the create function(s) matching the arguments to this method.
    612     """
--> 613     return self.createmm(self, *args, **kwargs)

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\util\functools.py:18, in seconddispatch.<locals>.wrapper(*args, **kwargs)
     17 def wrapper(*args, **kwargs):
---> 18     return dispatcher.dispatch(args[1].__class__)(*args, **kwargs)

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\fido_factory.py:244, in _create_and(walker, query, factory)
    242 @query_walker.add_creator(attr.AttrAnd)
    243 def _create_and(walker, query, factory):
--> 244     return factory._make_query_to_client(*query.attrs)

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\fido_factory.py:486, in UnifiedDownloaderFactory._make_query_to_client(self, *query)
    484     if isinstance(tmpclient, vso.VSOClient):
    485         kwargs = dict(response_format="table")
--> 486     results.append(tmpclient.search(*query, **kwargs))
    488 # This method is called by `search` and the results are fed into a
    489 # UnifiedResponse object.
    490 return results

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\jsoc\jsoc.py:307, in JSOCClient.search(self, *query, **kwargs)
    305     # Update blocks with deep copy of iargs because in _make_recordset we use .pop() on element from iargs
    306     blocks.append(copy.deepcopy(iargs))
--> 307     return_results = astropy.table.vstack([return_results, self._lookup_records(iargs)])
    308 return_results.query_args = blocks
    309 return_results._original_num_rows = len(return_results)

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\sunpy\net\jsoc\jsoc.py:768, in JSOCClient._lookup_records(self, iargs)
    766 log.debug(f"Running following query: {ds}")
    767 log.debug(f"Requesting following keywords: {key}")
--> 768 result = client.query(ds, key=key, rec_index=isMeta)
    769 if result is None or result.empty:
    770     return astropy.table.Table()

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\drms\client.py:1061, in Client.query(self, ds, key, seg, link, convert_numeric, skip_conversion, pkeys, rec_index, n)
   1059 status = lres.get("status")
   1060 if status != 0:
-> 1061     self._raise_query_error(lres)
   1063 res = []
   1064 if key is not None:

File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\drms\client.py:669, in Client._raise_query_error(d, status)
    667     msg = "DRMS Query failed."
    668 msg += f" [status={status}]"
--> 669 raise DrmsQueryError(msg)

DrmsQueryError: query failed: ERROR:  column "fuv" does not exist at character 3328
Error at /home/jsoc/cvs/Development/waystation/JSOC-orig/base/libs/db/db_postgresql.c, line 451: Query 'SELECT T1.recnum, T1.sunum, T1.slotnum, T1.sessionid, T1.sessionns, T1.cparms_sg000, T1.image_lev1_bzero, T1.image_lev1_bscale, T1.bld_vers, T1.date, T1.date__obs, T1.t_obs, T1.imgfpt, T1.fsn, T1.isysn, T1.fid, T1.instrume, T1.img_path, T1.img_type, T1.camera, T1.sumsptrl, T1.sumspat, T1.exptime, T1.expsdev, T1.int_time, T1.quality, T1.quallev0, T1.cropid, T1.lutid, T1.totvals, T1.datavals, T1.missvals, T1.percentd, T1.datamin, T1.datamax, T1.datamedn, T1.datamean, T1.datarms, T1.dataskew, T1.datakurt, T1.datap01, T1.datap10, T1.datap25, T1.datap75, T1.datap90, T1.datap95, T1.datap98, T1.datap99, T1.nsatpix, T1.iicrsid, T1.crs_desc, T1.crs_type, T1.crs_nreg, T1.win_flip, T1.tsr1, T1.ter1, T1.tsc1, T1.tec1, T1.tsr2, T1.ter2, T1.tsc2, T1.tec2, T1.tsr3, T1.ter3, T1.tsc3, T1.tec3, T1.tsr4, T1.ter4, T1.tsc4, T1.tec4, T1.tsr5, T1.ter5, T1.tsc5, T1.tec5, T1.tsr6, T1.ter6, T1.tsc6, T1.tec6, T1.tsr7, T1.ter7, T1.tsc7, T1.tec7, T1.tsr8, T1.ter8, T1.tsc8, T1.tec8, T1.wcsdbver, T1.wcsaxes, T1.xcen, T1.ycen, T1.crpix1, T1.crpix2, T1.crval1, T1.crval2, T1.crval3, T1.cdelt1, T1.cdelt2, T1.cdelt3, T1.ctype1, T1.ctype2, T1.ctype3, T1.cunit1, T1.cunit2, T1.cunit3, T1.pc1_1, T1.pc1_2, T1.pc2_1, T1.pc2_2, T1.pc3_1, T1.pc3_2, T1.crpix1a, T1.crpix2a, T1.crval1a, T1.crval2a, T1.crval3a, T1.cdelt1a, T1.cdelt2a, T1.cdelt3a, T1.ctype1a, T1.ctype2a, T1.ctype3a, T1.cunit1a, T1.cunit2a, T1.cunit3a, T1.pc1_1a, T1.pc1_2a, T1.pc2_1a, T1.pc2_2a, T1.pc3_1a, T1.pc3_2a, T1.pointrec, T1.time_qbi, T1.aeulrbrx, T1.aeulrbry, T1.aeulrbrz, T1.acg_roll, T1.ophase, T1.sat_rot, T1.flat_rec, T1.orb_rec, T1.rsun_obs, T1.dsun_obs, T1.geix_obs, T1.geiy_obs, T1.geiz_obs, T1.heix_obs, T1.heiy_obs, T1.heiz_obs, T1.obs_vr, T1.hlz, T1.saa, T1.temp_rec, T1.itf1ccd1, T1.itf2ccd2, T1.itnuccd3, T1.itsjccd4, T1.bt06cbpx, T1.bt07cbnx, T1.bt15ieb, T1.it08gtwm, T1.it14sppx, T1.it16spnx, T1.ispsname, T1.isppktim, T1.isppktvn, T1.isqisysn, T1.isqfsn, T1.iifrmtyp, T1.iiobslid, T1.iifrmlid, T1.isqoltid, T1.isqfltid, T1.iifdbid, T1.iifuvfdb, T1.iinuvfdb, T1.iisjifdb, T1.iiolrpt, T1.iiolnrpt, T1.iiflrpt, T1.iiflnrpt, T1.isqoltdx, T1.isqoltnx, T1.isqfltdx, T1.isqfltnx, T1.iissloop, T1.iissdiod, T1.iissoffr, T1.iiss_src, T1.iissctrl, T1.ifmcpos, T1.ifmpos, T1.ifwctgt, T1.ifwenc, T1.ifwpos, T1.iwm1cpos, T1.iwm1ctgt, T1.iwm1enc, T1.iwm2cpos, T1.iwm2ctgt, T1.iwm2enc, T1.iimgshce, T1.iimgcfd1, T1.iimgcfd2, T1.iimgcfd3, T1.iimgcfd4, T1.ifuvcexp, T1.inuvcexp, T1.isjicexp, T1.iimgots, T1.isqorbpd, T1.isqorbse, T1.isqorbsu, T1.isqowtid, T1.isqsrtid, T1.isqpzta, T1.isqpztb, T1.isqpztc, T1.iisspzta, T1.iisspztb, T1.iisspztc, T1.irtpzta, T1.irtpztb, T1.irtpztc, T1.iwbpzta, T1.iwbpztb, T1.iwbpztc, T1.isxer, T1.isxeravg, T1.isxermax, T1.isxermin, T1.isyer, T1.isyeravg, T1.isyermax, T1.isyermin, T1.igtpoffx, T1.igtpoffy, T1.igtpsvx, T1.igtpsvy, T1.itacssts, T1.iaectid, T1.iaecenam, T1.iaecevfl, T1.iaecflag, T1.iaecflfl, T1.iaecltim, T1.iaecevlt, T1.iihis1, T1.iihis2, T1.iihis3, T1.iihis4, T1.iihis5, T1.iihisfsn, T1.history, T1.comment, T1.sg_000_file, T1.sg_000_axis000, T1.sg_000_axis001 FROM iris.lev1 AS T1, (SELECT q2.max1 AS max FROM (SELECT max(recnum) AS max1, min(q1.max) AS max2 FROM iris.lev1, (SELECT iris.lev1.T_OBS, iris.lev1.FSN, max(recnum) FROM iris.lev1 WHERE ( ( 1167609635.000000<=T_OBS AND T_OBS<=1167609935.000000 ) ) AND (  INSTRUME=FUV  ) GROUP BY iris.lev1.T_OBS, iris.lev1.FSN) AS q1 WHERE iris.lev1.T_OBS = q1.T_OBS AND iris.lev1.FSN = q1.FSN GROUP BY iris.lev1.T_OBS, iris.lev1.FSN) AS q2 WHERE max1 = max2) AS q3 WHERE T1.recnum = q3.max ORDER BY T1.T_OBS, T1.FSN LIMIT 75000' failed.
Failed in drms_retrieve_records, query = 'SELECT T1.recnum, T1.sunum, T1.slotnum, T1.sessionid, T1.sessionns, T1.cparms_sg000, T1.image_lev1_bzero, T1.image_lev1_bscale, T1.bld_vers, T1.date, T1.date__obs, T1.t_obs, T1.imgfpt, T1.fsn, T1.isysn, T1.fid, T1.instrume, T1.img_path, T1.img_type, T1.camera, T1.sumsptrl, T1.sumspat, T1.exptime, T1.expsdev, T1.int_time, T1.quality, T1.quallev0, T1.cropid, T1.lutid, T1.totvals, T1.datavals, T1.missvals, T1.percentd, T1.datamin, T1.datamax, T1.datamedn, T1.datamean, T1.datarms, T1.dataskew, T1.datakurt, T1.datap01, T1.datap10, T1.datap25, T1.datap75, T1.datap90, T1.datap95, T1.datap98, T1.datap99, T1.nsatpix, T1.iicrsid, T1.crs_desc, T1.crs_type, T1.crs_nreg, T1.win_flip, T1.tsr1, T1.ter1, T1.tsc1, T1.tec1, T1.tsr2, T1.ter2, T1.tsc2, T1.tec2, T1.tsr3, T1.ter3, T1.tsc3, T1.tec3, T1.tsr4, T1.ter4, T1.tsc4, T1.tec4, T1.tsr5, T1.ter5, T1.tsc5, T1.tec5, T1.tsr6, T1.ter6, T1.tsc6, T1.tec6, T1.tsr7, T1.ter7, T1.tsc7, T1.tec7, T1.tsr8, T1.ter8, T1.tsc8, T1.tec8, T1.wcsdbver, T1.wcsaxes, T1.xcen, T1.ycen, T1.crpix1, T1.crpix2, T1.crval1, T1.crval2, T1.crval3, T1.cdelt1, T1.cdelt2, T1.cdelt3, T1.ctype1, T1.ctype2, T1.ctype3, T1.cunit1, T1.cunit2, T1.cunit3, T1.pc1_1, T1.pc1_2, T1.pc2_1, T1.pc2_2, T1.pc3_1, T1.pc3_2, T1.crpix1a, T1.crpix2a, T1.crval1a, T1.crval2a, T1.crval3a, T1.cdelt1a, T1.cdelt2a, T1.cdelt3a, T1.ctype1a, T1.ctype2a, T1.ctype3a, T1.cunit1a, T1.cunit2a, T1.cunit3a, T1.pc1_1a, T1.pc1_2a, T1.pc2_1a, T1.pc2_2a, T1.pc3_1a, T1.pc3_2a, T1.pointrec, T1.time_qbi, T1.aeulrbrx, T1.aeulrbry, T1.aeulrbrz, T1.acg_roll, T1.ophase, T1.sat_rot, T1.flat_rec, T1.orb_rec, T1.rsun_obs, T1.dsun_obs, T1.geix_obs, T1.geiy_obs, T1.geiz_obs, T1.heix_obs, T1.heiy_obs, T1.heiz_obs, T1.obs_vr, T1.hlz, T1.saa, T1.temp_rec, T1.itf1ccd1, T1.itf2ccd2, T1.itnuccd3, T1.itsjccd4, T1.bt06cbpx, T1.bt07cbnx, T1.bt15ieb, T1.it08gtwm, T1.it14sppx, T1.it16spnx, T1.ispsname, T1.isppktim, T1.isppktvn, T1.isqisysn, T1.isqfsn, T1.iifrmtyp, T1.iiobslid, T1.iifrmlid, T1.isqoltid, T1.isqfltid, T1.iifdbid, T1.iifuvfdb, T1.iinuvfdb, T1.iisjifdb, T1.iiolrpt, T1.iiolnrpt, T1.iiflrpt, T1.iiflnrpt, T1.isqoltdx, T1.isqoltnx, T1.isqfltdx, T1.isqfltnx, T1.iissloop, T1.iissdiod, T1.iissoffr, T1.iiss_src, T1.iissctrl, T1.ifmcpos, T1.ifmpos, T1.ifwctgt, T1.ifwenc, T1.ifwpos, T1.iwm1cpos, T1.iwm1ctgt, T1.iwm1enc, T1.iwm2cpos, T1.iwm2ctgt, T1.iwm2enc, T1.iimgshce, T1.iimgcfd1, T1.iimgcfd2, T1.iimgcfd3, T1.iimgcfd4, T1.ifuvcexp, T1.inuvcexp, T1.isjicexp, T1.iimgots, T1.isqorbpd, T1.isqorbse, T1.isqorbsu, T1.isqowtid, T1.isqsrtid, T1.isqpzta, T1.isqpztb, T1.isqpztc, T1.iisspzta, T1.iisspztb, T1.iisspztc, T1.irtpzta, T1.irtpztb, T1.irtpztc, T1.iwbpzta, T1.iwbpztb, T1.iwbpztc, T1.isxer, T1.isxeravg, T1.isxermax, T1.isxermin, T1.isyer, T1.isyeravg, T1.isyermax, T1.isyermin, T1.igtpoffx, T1.igtpoffy, T1.igtpsvx, T1.igtpsvy, T1.itacssts, T1.iaectid, T1.iaecenam, T1.iaecevfl, T1.iaecflag, T1.iaecflfl, T1.iaecltim, T1.iaecevlt, T1.iihis1, T1.iihis2, T1.iihis3, T1.iihis4, T1.iihis5, T1.iihisfsn, T1.history, T1.comment, T1.sg_000_file, T1.sg_000_axis000, T1.sg_000_axis001 FROM iris.lev1 AS T1, (SELECT q2.max1 AS max FROM (SELECT max(recnum) AS max1, min(q1.max) AS max2 FROM iris.lev1, (SELECT iris.lev1.T_OBS, iris.lev1.FSN, max(recnum) FROM iris.lev1 WHERE ( ( 1167609635.000000<=T_OBS AND T_OBS<=1167609935.000000 ) ) AND (  INSTRUME=FUV  ) GROUP BY iris.lev1.T_OBS, iris.lev1.FSN) AS q1 WHERE iris.lev1.T_OBS = q1.T_OBS AND iris.lev1.FSN = q1.FSN GROUP BY iris.lev1.T_OBS, iris.lev1.FSN) AS q2 WHERE max1 = max2) AS q3 WHERE T1.recnum = q3.max ORDER BY T1.T_OBS, T1.FSN LIMIT 75000'
 [status=6]

Does anyone know where I might be going wrong?

Hi @byrdie,

So the first error comes from the fact that JSOCClient does not support the normal wavelength attribute. The error message unfortunately is pretty gibberish and needs to be improved in the future.

The second error I have the same issue and I am unsure if its a JSOC software issue or the query we send to the JSOC.

Can you see if you can filter on that keyword on the web UI? If so, I would imagine its a sunpy problem, but if not, we might need to reach out the jSOC.

Cheers,
Nabil

HI Nabil,

Thanks for your response, I’m glad I’m not missing something obvious in the docs.

Just out of curiosity, do you know if there is any other way to acquire IRIS level 1 data? I was using JSOC since I am trying to port an IDL script, but I am willing to use anything that can get the job done.

Can you see if you can filter on that keyword on the web UI? If so, I would imagine its a sunpy problem, but if not, we might need to reach out the jSOC.

It seems like filtering that keyword does work on the web UI, here is a screenshot of my attempt.

I would be willing to open a PR to try and fix this if you don’t think it’ll be too difficult.

Thanks,
Roy

Hi Roy,

In that case, I would at first glance assume the query we construct to the JSOC is incorrect. Finding what that query is and the difference to the website query hopefully will tell us what is broken.

In the meantime, I assume that you want a searchable interface and not just a directory of files? The SDAC has a mirror of level 1 files (Index of /iris/iris_data/level1) but it is not searchable by an API. You could scrape the server but its more work.

Thanks,
Nabil

Hi Nabil,

In that case, I would at first glance assume the query we construct to the JSOC is incorrect. Finding what that query is and the difference to the website query hopefully will tell us what is broken.

I lazily stuck a print statement into drms.client.Client.query() and I found that the generated query was

ds='iris.lev1[2014.01.01_00:00:35_TAI-2014.01.01_00:05:35_TAI][? INSTRUME=FUV ?]'

which incorrectly doesn’t have quotes around the FUV.

So, a temporary workaround is just to manually insert the quotes

response = sunpy.net.Fido.search(
    sunpy.net.attrs.Time("2014-01-01T00:00", "2014-01-01T00:05"),
    sunpy.net.attrs.jsoc.Series("iris.lev1"),
    sunpy.net.attrs.jsoc.Notify("roytsmart@gmail.com"),
    sunpy.net.attrs.jsoc.Keyword("INSTRUME") == "'FUV'",
)
response

which outputs

<sunpy.net.fido_factory.UnifiedResponse object at 0x000002B250727610>
Results from 1 Provider:

6 Results from the JSOCClient:
Source: http://jsoc.stanford.edu

TELESCOP INSTRUME
-------- --------
    IRIS      FUV
    IRIS      FUV
    IRIS      FUV
    IRIS      FUV
    IRIS      FUV
    IRIS      FUV

I’m not sure if this is a bug in drms or Sunpy, but maybe it wouldn’t be too hard to open a PR to fix this.

Thanks for helping me to figure out the problem!

Roy

That will need to be fixed in sunpy. I can work on that and get that patched this week.

A fix has been opened here: Fix jsoc keyword not escaping a string for the query by nabobalis · Pull Request #7440 · sunpy/sunpy · GitHub