AttributeError: 'BuilderKeyResponse' object has no attribute 'tt'

Hello,

I’m hoping someone could help point me in the right direction here. I designed an experiment that has two tasks running simultaneously and am trying to capture the output of both tasks in a csv file. One task was made in builder and I overlaid the other in the coder. I mimicked the code for logging the button presses from the task made in the builder and applied that to the second task. The code for this is here

t = 0
    trialClock.reset()  # clock
    frameN = -1
    continueRoutine = True
    routineTimer.add(2.500000)
    # update component parameters for each repeat
    TargetNumber.setText(stim)
    TargetResponse = event.BuilderKeyResponse()
    PMtask = event.BuilderKeyResponse()
    # keep track of which components have finished
    trialComponents = [TargetNumber, TargetResponse]
    for thisComponent in trialComponents:
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED
    
    # -------Start Routine "trial"-------
    while continueRoutine and routineTimer.getTime() > 0:
        # get current time
        t = trialClock.getTime()
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
        
#this is supposed to make the clock
        if countDown.getTime() > -1:
            secPos = countDown.getTime() * 6  
            second.ori = secPos
        stopwatch.setAutoDraw(True)
        second.setAutoDraw(True)
        if countDown.getTime() < PM_time - 3:
            second.setAutoDraw(False)
        win.flip()
        press_space = event.getKeys(keyList=['space'])
        if 'space' in press_space:
            second_hand_clock.reset()
            #record second_hand_clock time as a variable via get time
            while second_hand_clock.getTime() < 1:
                stopwatch.setAutoDraw(True)
                second.setAutoDraw(True)
                win.flip()
            if second_hand_clock.getTime()>1:
                second.setAutoDraw(False)
                #circle.setAutoDraw(False)
                win.flip()
        PMKeys = event.getKeys(keyList=['space', 'right'])
            # check for quit:
        
        if len(PMKeys) > 0:  # at least one key was pressed
            PMtask.keys = PMKeys[-1]  # just the last key pressed
            PMtask.tt = clock.getTime()
            
        # *TargetNumber* updates
        if t >= 0.5 and TargetNumber.status == NOT_STARTED:
            # keep track of start time/frame for later
            TargetNumber.tStart = t
            TargetNumber.frameNStart = frameN  # exact frame index
            TargetNumber.setAutoDraw(True)
        frameRemains = 0.5 + 2- win.monitorFramePeriod * 0.75  # most of one frame period left
        if TargetNumber.status == STARTED and t >= frameRemains:
            TargetNumber.setAutoDraw(False)
        
        # *TargetResponse* updates
        if t >= 0.5 and TargetResponse.status == NOT_STARTED:
            # keep track of start time/frame for later
            TargetResponse.tStart = t
            TargetResponse.frameNStart = frameN  # exact frame index
            TargetResponse.status = STARTED
            # keyboard checking is just starting
            win.callOnFlip(TargetResponse.clock.reset)  # t=0 on next screen flip
            event.clearEvents(eventType='keyboard')
        frameRemains = 0.5 + 1- win.monitorFramePeriod * 0.75  # most of one frame period left
        if TargetResponse.status == STARTED and t >= frameRemains:
            TargetResponse.status = STOPPED
        if TargetResponse.status == STARTED:
            theseKeys = event.getKeys(keyList=['left', 'down'])
            
            # check for quit:
            if "escape" in theseKeys:
                endExpNow = True
            if len(theseKeys) > 0:  # at least one key was pressed
                TargetResponse.keys = theseKeys[-1]  # just the last key pressed
                TargetResponse.rt = TargetResponse.clock.getTime()
                TargetResponse.tt = clock.getTime()
                # was this 'correct'?
                if (TargetResponse.keys == str(corrAns)) or (TargetResponse.keys == corrAns):
                    TargetResponse.corr = 1
                else:
                    TargetResponse.corr = 0
                    
        # check if all components have finished
        if not continueRoutine:  # a component has requested a forced-end of Routine
            break
        continueRoutine = False  # will revert to True if at least one component still running
        for thisComponent in trialComponents:
            if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
                continueRoutine = True
                break  # at least one component has not yet finished
        
        # check for quit (the Esc key)
        if endExpNow or event.getKeys(keyList=["escape"]):
            core.quit()
        
        # refresh the screen
        if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
            win.flip()
        
    # -------Ending Routine "trial"-------
    for thisComponent in trialComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)
    # check responses
    if TargetResponse.keys in ['', [], None]:  # No response was made
        TargetResponse.keys=None
        # was no response the correct answer?!
        if str(corrAns).lower() == 'none':
           TargetResponse.corr = 1  # correct non-response
        else:
           TargetResponse.corr = 0  # failed to respond (incorrectly)
    # store data for nbacktrials (TrialHandler)
    nbacktrials.addData('TargetResponse.keys',TargetResponse.keys)
    nbacktrials.addData('TargetResponse.corr', TargetResponse.corr)
    if TargetResponse.keys != None:  # we had a response
        nbacktrials.addData('TargetResponse.rt', TargetResponse.rt)
        nbacktrials.addData('TargetResponse.tt', TargetResponse.tt)
    if PMtask.keys != None:  # at least one key was pressed
        nbacktrials.addData('PMtask.keys', PMtask.keys)
        nbacktrials.addData('PMtask.tt', PMtask.tt)
    thisExp.nextEntry()

Unfortunately, I get this error (below) and I’m not sure how to correct it. Any assistance would be most appreciated.

AttributeError: 'BuilderKeyResponse' object has no attribute 'tt'```

Unlike R, you can’t use . in variable names in Python - the period tells python to look for a function/attribute within an object. If you remove the periods (e.g. PMtasktt, or PMtask_tt) it should would.

BW

Oli

Thank you for the quick response. Unfortunately, this didn’t solve the issue. In the code I have

PMtask = event.BuilderKeyResponse()

and I add an attribute to this that’s intended to capture the time the button press occurred via

        PMKeys = event.getKeys(keyList=['space', 'right'])
            # check for quit:
        
        if len(PMKeys) > 0:  # at least one key was pressed
            PMtask.keys = PMKeys[-1]  # just the last key pressed
            PMtask.tt = clock.getTime()

Of course, tt is not one of the original attributes of BuilderKeyResponse. This process works seamlessly for the TargetResponse:

            if len(theseKeys) > 0:  # at least one key was pressed
                TargetResponse.keys = theseKeys[-1]  # just the last key pressed
                TargetResponse.rt = TargetResponse.clock.getTime()
                TargetResponse.tt = clock.getTime()

The error I receive refers to the PMtask.tt line within this section:

    # store data for nbacktrials (TrialHandler)
    nbacktrials.addData('TargetResponse.keys',TargetResponse.keys)
    nbacktrials.addData('TargetResponse.corr', TargetResponse.corr)
    if TargetResponse.keys != None:  # we had a response
        nbacktrials.addData('TargetResponse.rt', TargetResponse.rt)
        nbacktrials.addData('TargetResponse.tt', TargetResponse.tt)
    if PMtask.keys != None:  # at least one key was pressed
        nbacktrials.addData('PMtask.keys', PMtask.keys)
        nbacktrials.addData('PMtask.tt', PMtask.tt)
    thisExp.nextEntry()

If I remove the PMtask.tt lines, the program runs and I get output columns in the excel file for TargetResponse.tt and PMtask.keys. I’m new to coding so, I wouldn’t be shocked to learn that I’m missing something trivial. The goal is to get the time for each of the PMtask.keys presses and I’d be happy to learn of possible alternatives.

Thanks again for your time. This forum has been tremendously helpful for me.

-Scott

The error is very likely due to you assigning conditionally to PMtask.tt. i.e. that attribute doesn’t necessarily exist when it comes time to save the data. You need to debug the logic of your code.

You could test that by initially (i.e. unconditionally) assigning a default value like:

PMtask.tt = 'Not set'

If that value appears in your data, you know the source of the problem.

Quite possible, a part of your problem is that you are making multiple calls to event.getKeys() within a single screen refresh. This will get really unstable and unpredictable. A better strategy here is just to make one check per refresh and store it in a variable. Then check the value of that repeatedly in your code (taking into account time in the trial, etc), as required. Otherwise things get very unpredictable, depending on the exact time at which someone might press a key.

I’d advise using code components within Builder here rather than munging the code in Coder: it will impose some disciplines with regard to the event cycle.