Pull request Compare This branch is 2 commits ahead of develop.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
..
Failed to load latest commit information.
README.md
__init__.py
context.py
main.py
parser.py
test_context.py
test_odmadapter.py
test_parser.py

README.md

audit_event

audit_event is a simple way to consume the ODMAdapter Clinical Audit Records service

audit_event takes the approach of converting the ODM dataset provided by the clinical audit record service into a set of events. This is the same approach that SAX parsers take to parsing XML files.

Capturing Events

To use the library you must first create a class that registers the events you want to capture. For instance, if you want to count the number of subjects created you might write:

class SubjectCounter(object):

    def __init__(self):
        self.count = 0
        
    def SubjectCreated(self, context):
        self.count += 1
        
    def default(self, context):
        """You can use the default event to capture all events that you have not defined a handler for
           the default handler is also optional, you do not have to define it.
        """
        pass

Events raised are named after the audit subcategory for each reported audit in the ODM stream. See a full list of event names

The context object passed contains all the data pulled from the audit record.

Context:
    study_oid
    subcategory
    metadata_version
    subject
        key
        name
        status
        transaction_type          
    event
        oid
        repeat_key
        transaction_type
        instance_name
        instance_overdue
        instance_id
    form
        oid
        repeat_key
        transaction_type
        datapage_name
        datapage_id
    itemgroup
        oid
        repeat_key
        transaction_type
        record_id  
    item
        oid 
        value
        freeze
        verify
        lock
        transaction_type     
    audit_record
        user_oid
        location_oid
        datetimestamp
        reason_for_change
        source_id
    query
        repeat_key
        status
        response
        recipient
        value
    protocol_deviation
        repeat_key 
        code
        klass
        status 
        value
        transaction_type      
    comment
        repeat_key 
        value 
        transaction_type         
    review
        group_name
        reviewed
    signature
        oid 
        user_oid 
        location_oid 
        datetimestamp                 

What you look for in the context object depends on the audit subcategory type. For instance in the case of the SubjectCreated event there will be no value for event, item, review, signature etc. In the case of a signature event of some kind the signature attribute will be populated with a context.Signature object.

The purpose of this scheme is to cope with the many different types of audit events that can be reported via the clinical audits dataset.

Using ODMAdapter

ODMAdapter is a class that takes a RWSConnection, the name of the study and environment you want to process for events and an instance of your eventer class.

the run() method starts ODMAadpter using the RWSConnection credentials to pull audits from the study, passing them to your event capturing class for reporting.

#Define a counting class
class SubjectCounter(object):

    def __init__(self):
        self.count = 0
        
    def SubjectCreated(self, context):
        self.count += 1
        
#Create one
counter = SubjectCounter()

#Make a connection
c = RWSConnection("ravedemo7","myusername","**mypassword**")

#Pass connection and counter to the ODMAdapter along with the study name/environment we want to process
o = ODMAdapter(c, "MEDICILLIN-RD7","DEMO", counter )

#Run the adapter
o.run()

#get the count
print counter.count

The ODMAdapter run() method takes a number of optional arguments. By default it will start with audit id 0 and keep requesting pages of data (with audit 1000 records per page, the minimum) until the Clinical Audit Records webservice says that there is no more data.

The options to run() are:

start_id=0     #Which audit id to start ar (great for daily/hourly incremental pulls from the service)
max_pages=-1   #How many pages of data to pull (-1 means all pages)
per_page=1000  #The size (in audit records) of each request - 1,000 is min, higher takes more memory/time

Working out which id to start on

If we planned to run our Subject Counter on a regular basis, we wouldn't want to start from the beginning of the "audit tape" each time, that would be inefficient. Instead we could change our SubjectCounter class to track the last id it saw and ask for this value +1 the next time.

class SubjectCounter(object):

    def __init__(self):
        self.count = 0
        self.max_id = 0
        
    def SubjectCreated(self, context):
        self.count += 1
        self.max_id = context.audit_record.source_id
        
    def default(self, context):
        self.max_id = context.audit_record.source_id

Now at the end of a run we can ask for the max_id and feed that back into the ODMAdapter .run(start_id=max_id+1) method.