Sorry for posting this twice. It seems better to track progress with this in this thread.
........
I used XNATpy 0.5.2 (I think 0.5.1 will also work
without issues but I didn't test this) and used Hakim's suggestion to
get past the "*** TypeError: 'NoneType' object is not iterable"
exception that was thrown when trying to query on an XNAT class. This
is a hack and I'm sure that with the next iteration of XNATpy this will
be fixed. To make that change:
1. Quick hack for searching on 0.5.2
Find module `search.py` on your python path for example `lib/python3.9/site-packages/xnat/search.py` (there is another search,py at /xnat/client/search.py that you dont want). In the definition for Class Query change fields=None to fields = ()
so before looks like this:
class Query(object):
def __init__(self, queried_class, xnat_session, fields=None, constraints=None):
self.queried_class = queried_class
after looks like this:
class Query(object):
def __init__(self, queried_class, xnat_session, fields=(), constraints=None):
self.queried_class = queried_class
2. What can I search on?
XNATpy's documentation on searching is really comprehensive and explains much
https://xnat.readthedocs.io/en/latest/static/tutorial.html#searching.
To inspect what fields are available in a connection class e.g
SubjectData - we can use the vars() method as shown below - I have
highlighted the Custom Fields that I created using the Custom Form
import xnat
from pprint import pprint
connection = xnat.connect(server="http://127.0.0.1",user='admin',password='admin')
SubjectData = connection.classes.SubjectData pprint(vars(SubjectData))
This is a trunctated output showing custom fields and standard fields:
mappingproxy({'ADD_IDS': <SearchField xnat:subjectData/ADD_IDS>,
'AGE': <SearchField xnat:subjectData/AGE>,
'AGE_BRACKET': <SearchField xnat:subjectData/AGE_BRACKET>,
'DOB': <SearchField xnat:subjectData/DOB>,
'EDUC': <SearchField xnat:subjectData/EDUC>,
'ETHNICITY': <SearchField xnat:subjectData/ETHNICITY>,
'GENDER_TEXT': <SearchField xnat:subjectData/GENDER_TEXT>,
'HANDEDNESS_TEXT': <SearchField xnat:subjectData/HANDEDNESS_TEXT>,
'INSERT_DATE': <SearchField xnat:subjectData/INSERT_DATE>,
'INSERT_USER': <SearchField xnat:subjectData/INSERT_USER>,
'INVEST_CSV': <SearchField xnat:subjectData/INVEST_CSV>,
'PROJECT': <SearchField xnat:subjectData/PROJECT>,
'PROJECTS': <SearchField xnat:subjectData/PROJECTS>,
'RACE': <SearchField xnat:subjectData/RACE>,
'SES': <SearchField xnat:subjectData/SES>,
'SUB_GROUP': <SearchField xnat:subjectData/SUB_GROUP>,
'XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGDOSE':
<SearchField
xnat:subjectData/XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGDOSE>,
'XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGTYPE':
<SearchField
xnat:subjectData/XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGTYPE>,
3. Constructing a search using custom fields (from custom form) and standard fields?
because
of the format of the custom fields we will access them using the
getattr() method instead. So for a combined search on gender and drug
dose for example we can do this:
sublist
= SubjectData.query().filter((SubjectData.GENDER_TEXT == "M") &
(getattr(SubjectData,"XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGDOSE")
> 20))
sublist.all()
[<SubjectData SUB001 (XNAT_S00001)>, <SubjectData SUB004 (XNAT_S00004)>]