Instruction:
Write a Python 3 function for
configuring the python logging system to log to a debug file and to stdout for warn and above.

Response:
def configureLogger(self):
        """
        Configures the python logging system to log to a debug file and to stdout for warn and above.
        :return: the base logger.
        """
        baseLogLevel = logging.DEBUG if self.isDebugLogging() else logging.INFO
        # create recorder app root logger
        logger = logging.getLogger(self._name)
        logger.setLevel(baseLogLevel)
        # file handler
        fh = handlers.RotatingFileHandler(path.join(self._getConfigPath(), self._name + '.log'),
                                          maxBytes=10 * 1024 * 1024, backupCount=10)
        fh.setLevel(baseLogLevel)
        # create console handler with a higher log level
        ch = logging.StreamHandler()
        ch.setLevel(logging.WARN)
        # create formatter and add it to the handlers
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(funcName)s - %(message)s')
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)
        # add the handlers to the logger
        logger.addHandler(fh)
        logger.addHandler(ch)
        return logger


Instruction:
Can you write a function in Python 3 where it
translates IBM - format floating point numbers to IEEE 754 - format floating point numbers.

Response:
def ibm_to_ieee(ibm):
    '''
    Translate IBM-format floating point numbers (as bytes) to IEEE 754
    64-bit floating point format (as Python float).
    '''
    # IBM mainframe:    sign * 0.mantissa * 16 ** (exponent - 64)
    # Python uses IEEE: sign * 1.mantissa * 2 ** (exponent - 1023)

    # Pad-out to 8 bytes if necessary. We expect 2 to 8 bytes, but
    # there's no need to check; bizarre sizes will cause a struct
    # module unpack error.
    ibm = ibm.ljust(8, b'\x00')

    # parse the 64 bits of IBM float as one 8-byte unsigned long long
    ulong, = struct.unpack('>Q', ibm)

    # IBM: 1-bit sign, 7-bits exponent, 56-bits mantissa
    sign = ulong & 0x8000000000000000
    exponent = (ulong & 0x7f00000000000000) >> 56
    mantissa = ulong & 0x00ffffffffffffff

    if mantissa == 0:
        if ibm[0:1] == b'\x00':
            return 0.0
        elif ibm[0:1] in b'_.ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            return float('nan')
        else:
            raise ValueError('Neither zero nor NaN: %r' % ibm)

    # IBM-format exponent is base 16, so the mantissa can have up to 3
    # leading zero-bits in the binary mantissa. IEEE format exponent
    # is base 2, so we don't need any leading zero-bits and will shift
    # accordingly. This is one of the criticisms of IBM-format, its
    # wobbling precision.
    if ulong & 0x0080000000000000:
        shift = 3
    elif ulong & 0x0040000000000000:
        shift = 2
    elif ulong & 0x0020000000000000:
        shift = 1
    else:
        shift = 0
    mantissa >>= shift

    # clear the 1 bit to the left of the binary point
    # this is implicit in IEEE specification
    mantissa &= 0xffefffffffffffff

    # IBM exponent is excess 64, but we subtract 65, because of the
    # implicit 1 left of the radix point for the IEEE mantissa
    exponent -= 65
    # IBM exponent is base 16, IEEE is base 2, so we multiply by 4
    exponent <<= 2
    # IEEE exponent is excess 1023, but we also increment for each
    # right-shift when aligning the mantissa's first 1-bit
    exponent += shift + 1023

    # IEEE: 1-bit sign, 11-bits exponent, 52-bits mantissa
    # We didn't shift the sign bit, so it's already in the right spot
    ieee = sign | (exponent << 52) | mantissa
    return struct.unpack(">d", struct.pack(">Q", ieee))[0]


Instruction:
Make a summary of the following Python 3 code
def ieee_to_ibm(ieee):
    '''
    Translate Python floating point numbers to IBM-format (as bytes).
    '''
    # Python uses IEEE: sign * 1.mantissa * 2 ** (exponent - 1023)
    # IBM mainframe:    sign * 0.mantissa * 16 ** (exponent - 64)

    if ieee == 0.0:
        return b'\x00' * 8
    if ieee is None or math.isnan(ieee):
        return b'_' + b'\x00' * 7
    if math.isinf(ieee):
        raise NotImplementedError('Cannot convert infinity')

    bits = struct.pack('>d', ieee)
    ulong, = struct.unpack('>Q', bits)

    sign = (ulong & (1 << 63)) >> 63                    # 1-bit     sign
    exponent = ((ulong & (0x7ff << 52)) >> 52) - 1023   # 11-bits   exponent
    mantissa = ulong & 0x000fffffffffffff               # 52-bits   mantissa/significand

    if exponent > 248:
        msg = 'Cannot store magnitude more than ~ 16 ** 63 as IBM-format'
        raise Overflow(msg)
    if exponent < -260:
        msg = 'Cannot store magnitude less than ~ 16 ** -65 as IBM-format'
        raise Underflow(msg)

    # IEEE mantissa has an implicit 1 left of the radix:    1.significand
    # IBM mantissa has an implicit 0 left of the radix:     0.significand
    # We must bitwise-or the implicit 1.mmm into the mantissa
    # later we will increment the exponent to account for this change
    mantissa = 0x0010000000000000 | mantissa

    # IEEE exponents are for base 2:    mantissa * 2 ** exponent
    # IBM exponents are for base 16:    mantissa * 16 ** exponent
    # We must divide the exponent by 4, since 16 ** x == 2 ** (4 * x)
    quotient, remainder = divmod(exponent, 4)
    exponent = quotient

    # We don't want to lose information;
    # the remainder from the divided exponent adjusts the mantissa
    mantissa <<= remainder

    # Increment exponent, because of earlier adjustment to mantissa
    # this corresponds to the 1.mantissa vs 0.mantissa implicit bit
    exponent += 1

    # IBM exponents are excess 64
    exponent += 64

    # IBM has 1-bit sign, 7-bits exponent, and 56-bits mantissa.
    # We must shift the sign and exponent into their places.
    sign <<= 63
    exponent <<= 56

    # We lose some precision, but who said floats were perfect?
    return struct.pack('>Q', sign | exponent | mantissa)

Response: Translate a Python floating point number to IBM - format.


Instruction:
Write a Python 3 script to
serialize columns to a JSON formatted bytes object.

Response:
def dumps(columns):
    '''
    Serialize ``columns`` to a JSON formatted ``bytes`` object.
    '''
    fp = BytesIO()
    dump(columns, fp)
    fp.seek(0)
    return fp.read()


Instruction:
Can you generate a brief explanation for the following Python 3 code
def match(header):
        '''
        Parse the 3-line (240-byte) header of a SAS XPORT file.
        '''
        mo = Library.header_re.match(header)
        if mo is None:
            raise ValueError(f'Not a SAS Version 5 or 6 XPORT file')
        return {
            'created': strptime(mo['created']),
            'modified': strptime(mo['modified']),
            'sas_version': float(mo['version']),
            'os_version': mo['os'].decode().strip(),
        }

Response: Parse the 3 - line header of a SAS XPORT file.


Instruction:
Here you have a function in Python 3, explain what it does
def header_match(cls, header):
        '''
        Parse the 4-line (320-byte) library member header.
        '''
        mo = cls.header_re.match(header)
        if mo is None:
            msg = f'Expected {cls.header_re.pattern!r}, got {header!r}'
            raise ValueError(msg)
        return {
            'name': mo['name'].decode().strip(),
            'label': mo['label'].decode().strip(),
            'type': mo['type'].decode().strip(),
            'created': strptime(mo['created']),
            'modified': strptime(mo['modified']),
            'sas_version': float(mo['version']),
            'os_version': mo['os'].decode().strip(),
            'namestr_size': mo['descriptor_size'],
        }

Response: Parse the 4 - line 370 - byte library member header.


Instruction:
Create a Python 3 function to
parse a member namestrs header line and return the number of variables that match.

Response:
def header_match(cls, data):
        '''
        Parse a member namestrs header (1 line, 80 bytes).
        '''
        mo = cls.header_re.match(data)
        return int(mo['n_variables'])


Instruction:
How would you code a function in Python 3 to
parse variable metadata for a XPORT file member.

Response:
def readall(cls, member, size):
        '''
        Parse variable metadata for a XPORT file member.
        '''
        fp = member.library.fp
        LINE = member.library.LINE

        n = cls.header_match(fp.read(LINE))
        namestrs = [fp.read(size) for i in range(n)]

        # Each namestr field is 140 bytes long, but the fields are
        # streamed together and broken in 80-byte pieces. If the last
        # byte of the last namestr field does not fall in the last byte
        # of the 80-byte record, the record is padded with ASCII blanks
        # to 80 bytes.

        remainder = n * size % LINE
        if remainder:
            padding = 80 - remainder
            fp.read(padding)

        info = [cls.unpack(s) for s in namestrs]
        for d in info:
            d['format'] = Format(**d['format'])
            d['iformat'] = InputFormat(**d['iformat'])
        return [Variable(**d) for d in info]


Instruction:
Here you have a function in Python 3, explain what it does
def to_jd(year, month, day):
    '''Determine Julian day count from Islamic date'''
    return (day + ceil(29.5 * (month - 1)) + (year - 1) * 354 + trunc((3 + (11 * year)) / 30) + EPOCH) - 1

Response: Determine Julian day count from Islamic date


Instruction:
Make a summary of the following Python 3 code
def from_jd(jd):
    '''Calculate Islamic date from Julian day'''

    jd = trunc(jd) + 0.5
    year = trunc(((30 * (jd - EPOCH)) + 10646) / 10631)
    month = min(12, ceil((jd - (29 + to_jd(year, 1, 1))) / 29.5) + 1)
    day = int(jd - to_jd(year, month, 1)) + 1
    return (year, month, day)

Response: Calculate Islamic date from Julian day


Instruction:
Write a Python 3 function for
checking all the widgets that have been edited and have any triggers that have been triggered by this entry.

Response:
def checkAllTriggers(self, action):
        """ Go over all widgets and let them know they have been edited
            recently and they need to check for any trigger actions.  This
            would be used right after all the widgets have their values
            set or forced (e.g. via setAllEntriesFromParList). """
        for entry in self.entryNo:
            entry.widgetEdited(action=action, skipDups=False)


Instruction:
Given the following Python 3 function, write the documentation
def freshenFocus(self):
        self.top.update_idletasks()
        self.top.after(10, self.setViewAtTop)

Response: Called when a new item is added to the top of the queue.


Instruction:
Can you generate the documentation for the following Python 3 function
def mwl(self, event):
        if event.num == 4: # up on Linux
            self.top.f.canvas.yview_scroll(-1*self._tmwm, 'units')
        elif event.num == 5: # down on Linux
            self.top.f.canvas.yview_scroll(1*self._tmwm, 'units')
        else: # assume event.delta has the direction, but reversed sign
            self.top.f.canvas.yview_scroll(-(event.delta)*self._tmwm, 'units')

Response: Mouse wheel - under tkinter we need Tk v8. 5 + for this


Instruction:
Write a Python 3 function that can
set focus to next item in sequence

Response:
def focusNext(self, event):
        """Set focus to next item in sequence"""
        try:
            event.widget.tk_focusNext().focus_set()
        except TypeError:
            # see tkinter equivalent code for tk_focusNext to see
            # commented original version
            name = event.widget.tk.call('tk_focusNext', event.widget._w)
            event.widget._nametowidget(str(name)).focus_set()


Instruction:
How would you explain what the following Python 3 function does
def focusPrev(self, event):
        try:
            event.widget.tk_focusPrev().focus_set()
        except TypeError:
            # see tkinter equivalent code for tk_focusPrev to see
            # commented original version
            name = event.widget.tk.call('tk_focusPrev', event.widget._w)
            event.widget._nametowidget(str(name)).focus_set()

Response: Set focus to previous item in sequence


Instruction:
Can you write a function in Python 3 where it
scrolls the panel down to ensure the widget with focus to be visible.

Response:
def doScroll(self, event):
        """Scroll the panel down to ensure widget with focus to be visible

        Tracks the last widget that doScroll was called for and ignores
        repeated calls.  That handles the case where the focus moves not
        between parameter entries but to someplace outside the hierarchy.
        In that case the scrolling is not expected.

        Returns false if the scroll is ignored, else true.
        """
        canvas = self.top.f.canvas
        widgetWithFocus = event.widget
        if widgetWithFocus is self.lastFocusWidget:
            return FALSE
        self.lastFocusWidget = widgetWithFocus
        if widgetWithFocus is None:
            return TRUE
        # determine distance of widget from top & bottom edges of canvas
        y1 = widgetWithFocus.winfo_rooty()
        y2 = y1 + widgetWithFocus.winfo_height()
        cy1 = canvas.winfo_rooty()
        cy2 = cy1 + canvas.winfo_height()
        yinc = self.yscrollincrement
        if y1<cy1:
            # this will continue to work when integer division goes away
            sdist = int((y1-cy1-yinc+1.)/yinc)
            canvas.yview_scroll(sdist, "units")
        elif cy2<y2:
            sdist = int((y2-cy2+yinc-1.)/yinc)
            canvas.yview_scroll(sdist, "units")
        return TRUE


Instruction:
Make a summary of the following Python 3 code
def _handleParListMismatch(self, probStr, extra=False):

        errmsg = 'ERROR: mismatch between default and current par lists ' + \
               'for task "'+self.taskName+'"'
        if probStr:
            errmsg += '\n\t'+probStr
        errmsg += '\n(try: "unlearn '+self.taskName+'")'
        print(errmsg)
        return False

Response: Handle the situation where two par lists do not match.


Instruction:
Can you write a function in Python 3 where it
toggles the active state of a section.

Response:
def _toggleSectionActiveState(self, sectionName, state, skipList):
        """ Make an entire section (minus skipList items) either active or
            inactive.  sectionName is the same as the param's scope. """

        # Get model data, the list of pars
        theParamList = self._taskParsObj.getParList()

        # Loop over their assoc. entries
        for i in range(self.numParams):
            if theParamList[i].scope == sectionName:
                if skipList and theParamList[i].name in skipList:
#                   self.entryNo[i].setActiveState(True) # these always active
                    pass # if it started active, we don't need to reactivate it
                else:
                    self.entryNo[i].setActiveState(state)


Instruction:
Make a summary of the following Python 3 code
def saveAs(self, event=None):

        self.debug('Clicked Save as...')
        # On Linux Pers..Dlg causes the cwd to change, so get a copy of current
        curdir = os.getcwd()

        # The user wishes to save to a different name
        writeProtChoice = self._writeProtectOnSaveAs
        if capable.OF_TKFD_IN_EPAR:
            # Prompt using native looking dialog
            fname = asksaveasfilename(parent=self.top,
                    title='Save Parameter File As',
                    defaultextension=self._defSaveAsExt,
                    initialdir=os.path.dirname(self._getSaveAsFilter()))
        else:
            # Prompt. (could use tkinter's FileDialog, but this one is prettier)
            # initWProtState is only used in the 1st call of a session
            from . import filedlg
            fd = filedlg.PersistSaveFileDialog(self.top,
                         "Save Parameter File As", self._getSaveAsFilter(),
                         initWProtState=writeProtChoice)
            if fd.Show() != 1:
                fd.DialogCleanup()
                os.chdir(curdir) # in case file dlg moved us
                return
            fname = fd.GetFileName()
            writeProtChoice = fd.GetWriteProtectChoice()
            fd.DialogCleanup()

        if not fname: return # canceled

        # First check the child parameters, aborting save if
        # invalid entries were encountered
        if self.checkSetSaveChildren():
            os.chdir(curdir) # in case file dlg moved us
            return

        # Run any subclass-specific steps right before the save
        self._saveAsPreSave_Hook(fname)

        # Verify all the entries (without save), keeping track of the invalid
        # entries which have been reset to their original input values
        self.badEntriesList = self.checkSetSaveEntries(doSave=False)

        # If there were invalid entries, prepare the message dialog
        if self.badEntriesList:
            ansOKCANCEL = self.processBadEntries(self.badEntriesList,
                          self.taskName)
            if not ansOKCANCEL:
                os.chdir(curdir) # in case file dlg moved us
                return

        # If there were no invalid entries or the user says OK, finally
        # save to their stated file.  Since we have already processed the
        # bad entries, there should be none returned.
        mstr = "TASKMETA: task="+self.taskName+" package="+self.pkgName
        if self.checkSetSaveEntries(doSave=True, filename=fname, comment=mstr,
                                    set_ro=writeProtChoice,
                                    overwriteRO=True):
            os.chdir(curdir) # in case file dlg moved us
            raise Exception("Unexpected bad entries for: "+self.taskName)

        # Run any subclass-specific steps right after the save
        self._saveAsPostSave_Hook(fname)

        os.chdir(curdir)

Response: Save the parameter settings to a user - specified file.


Instruction:
Can you tell what is the following Python 3 function doing
def htmlHelp(self, helpString=None, title=None, istask=False, tag=None):
        # Check the help string.  If it turns out to be a URL, launch that,
        # if not, dump it to a quick and dirty tmp html file to make it
        # presentable, and pass that file name as the URL.
        if not helpString:
            helpString = self.getHelpString(self.pkgName+'.'+self.taskName)
        if not title:
            title = self.taskName
        lwr = helpString.lower()
        if lwr.startswith("http:") or lwr.startswith("https:") or \
           lwr.startswith("file:"):
            url = helpString
            if tag and url.find('#') < 0:
                url += '#'+tag
#           print('LAUNCHING: '+url) # DBG
            irafutils.launchBrowser(url, subj=title)
        else:
            # Write it to a temp HTML file to display
            (fd, fname) = tempfile.mkstemp(suffix='.html', prefix='editpar_')
            os.close(fd)
            f = open(fname, 'w')
            if istask and self._knowTaskHelpIsHtml:
                f.write(helpString)
            else:
                f.write('<title>'+title+'</title>\n')
                f.write('
'+title+'
\n')
                f.write('
\n'+helpString+'\n
')
            f.close()
            irafutils.launchBrowser("file://"+fname, subj=title)

Response: Displays the help string for the current task.


Instruction:
Given the following Python 3 function, write the documentation
def _showAnyHelp(self, kind, tag=None):

        # sanity check
        assert kind in ('epar', 'task', 'log'), 'Unknown help kind: '+str(kind)

        #-----------------------------------------
        # See if they'd like to view in a browser
        #-----------------------------------------
        if self._showHelpInBrowser or (kind == 'task' and
                                       self._knowTaskHelpIsHtml):
            if kind == 'epar':
                self.htmlHelp(helpString=self._appHelpString,
                              title='Parameter Editor Help')
            if kind == 'task':
                self.htmlHelp(istask=True, tag=tag)
            if kind == 'log':
                self.htmlHelp(helpString='\n'.join(self._msgHistory),
                              title=self._appName+' Event Log')
            return

        #-----------------------------------------
        # Now try to pop up the regular Tk window
        #-----------------------------------------
        wins = {'epar':self.eparHelpWin,
                'task':self.irafHelpWin,
                'log': self.logHistWin, }
        window = wins[kind]
        try:
            if window.state() != NORMAL:
                window.deiconify()
            window.tkraise()
            return
        except (AttributeError, TclError):
            pass

        #---------------------------------------------------------
        # That didn't succeed (window is still None), so build it
        #---------------------------------------------------------
        if kind == 'epar':
            self.eparHelpWin = self.makeHelpWin(self._appHelpString,
                                                title='Parameter Editor Help')
        if kind == 'task':
            # Acquire the task help as a string
            # Need to include the package name for the task to
            # avoid name conflicts with tasks from other packages. WJH
            self.irafHelpWin = self.makeHelpWin(self.getHelpString(
                                                self.pkgName+'.'+self.taskName))
        if kind == 'log':
            self.logHistWin = self.makeHelpWin('\n'.join(self._msgHistory),
                                               title=self._appName+' Event Log')

Response: Invoke the task or epar help and put the page in a regular Tk window.


Instruction:
How would you explain what the following Python 3 function does
def setAllEntriesFromParList(self, aParList, updateModel=False):

        # Get model data, the list of pars
        theParamList = self._taskParsObj.getParList() # we may modify members

        if len(aParList) != len(theParamList):
            showwarning(message="Attempting to set parameter values from a "+ \
                        "list of different length ("+str(len(aParList))+ \
                        ") than the number shown here ("+ \
                        str(len(theParamList))+").  Be aware.",
                        title="Parameter List Length Mismatch")

        # LOOP THRU GUI PAR LIST
        for i in range(self.numParams):
            par = theParamList[i]
            if par.type == "pset":
                continue # skip PSET's for now
            gui_entry = self.entryNo[i]

            # Set the value in the paramList before setting it in the GUI
            # This may be in the form of a list, or an IrafParList (getValue)
            if isinstance(aParList, list):
                # Since "aParList" can have them in different order and number
                # than we do, we'll have to first find the matching param.
                found = False
                for newpar in aParList:
                    if newpar.name==par.name and newpar.scope==par.scope:
                        par.set(newpar.value) # same as .get(native=1,prompt=0)
                        found = True
                        break

                # Now see if newpar was found in our list
                if not found:
                    pnm = par.name
                    if len(par.scope): pnm = par.scope+'.'+par.name
                    raise UnfoundParamError('Error - Unfound Parameter! \n\n'+\
                      'Expected parameter "'+pnm+'" for task "'+ \
                      self.taskName+'". \nThere may be others...')

            else: # assume has getValue()
                par.set(aParList.getValue(par.name, native=1, prompt=0))

            # gui holds a str, but par.value is native; conversion occurs
            gui_entry.forceValue(par.value, noteEdited=False) # no triggers yet

        if updateModel:
            # Update the model values via checkSetSaveEntries
            self.badEntriesList = self.checkSetSaveEntries(doSave=False)

            # If there were invalid entries, prepare the message dialog
            if self.badEntriesList:
                self.processBadEntries(self.badEntriesList,
                                       self.taskName, canCancel=False)

Response: Set all the entries in the GUI to the values in the given list of parameters.


Instruction:
How would you explain what the following Python 3 function does
def getValue(self, name, scope=None, native=False):

        # Get model data, the list of pars
        theParamList = self._taskParsObj.getParList()

        # NOTE: If par scope is given, it will be used, otherwise it is
        # assumed to be unneeded and the first name-match is returned.
        fullName = basicpar.makeFullName(scope, name)

        # Loop over the parameters to find the requested par
        for i in range(self.numParams):
            par = theParamList[i] # IrafPar or subclass
            entry = self.entryNo[i] # EparOption or subclass
            if par.fullName() == fullName or \
               (scope is None and par.name == name):
                if native:
                    return entry.convertToNative(entry.choice.get())
                else:
                    return entry.choice.get()
        # We didn't find the requested par
        raise RuntimeError('Could not find par: "'+fullName+'"')

Response: Get the value of the current parameter from the GUI.


Instruction:
Here you have a function in Python 3, explain what it does
def checkSetSaveChildren(self, doSave=True):
        if self.isChild:
            return

        # Need to get all the entries and verify them.
        # Save the children in backwards order to coincide with the
        # display of the dialogs (LIFO)
        for n in range (len(self.top.childList)-1, -1, -1):
            self.badEntriesList = self.top.childList[n]. \
                                  checkSetSaveEntries(doSave=doSave)
            if self.badEntriesList:
                ansOKCANCEL = self.processBadEntries(self.badEntriesList,
                              self.top.childList[n].taskName)
                if not ansOKCANCEL:
                    return self.badEntriesList
            # If there were no invalid entries or the user says OK,
            # close down the child and increment to the next child
            self.top.childList[n].top.focus_set()
            self.top.childList[n].top.withdraw()
            del self.top.childList[n]
        # all windows saved successfully
        return

Response: Check set then save the parameter settings for all child windows.


Instruction:
Can you tell what is the following Python 3 function doing
def showStatus(self, msg, keep=0, cat=None):
        # prep it, space-wise
        msg = msg.strip()
        if len(msg) > 0:
            # right here is the ideal place to collect a history of messages
            forhist = msg
            if cat: forhist = '['+cat+'] '+msg
            forhist = time.strftime("%a %H:%M:%S")+': '+forhist
            self._msgHistory.append(forhist)
            # now set the spacing
            msg = '  '+msg

        # stop here if it is a category not shown in the GUI
        if cat == DBG:
            return

        # see if we can show it
        now = time.time()
        if now >= self._leaveStatusMsgUntil: # we are clear, can show a msg
            # first see if this msg is '' - if so we will show an important
            # waiting msg instead of the '', and then pop it off our list
            if len(msg) < 1 and len(self._statusMsgsToShow) > 0:
                msg, keep = self._statusMsgsToShow[0] # overwrite both args
                del self._statusMsgsToShow[0]
            # now actuall print the status out to the status widget
            self.top.status.config(text = msg)
            # reset our delay flag
            self._leaveStatusMsgUntil = 0
            if keep > 0:
                self._leaveStatusMsgUntil = now + keep
        else:
            # there is a previous message still up, is this one important?
            if len(msg) > 0 and keep > 0:
                # Uh-oh, this is an important message that we don't want to
                # simply skip, but on the other hand we can't show it yet...
                # So we add it to _statusMsgsToShow and show it later (asap)
                if (msg,keep) not in self._statusMsgsToShow:
                    if len(self._statusMsgsToShow) < 7:
                        self._statusMsgsToShow.append( (msg,keep) ) # tuple
                        # kick off timer loop to get this one pushed through
                        if len(self._statusMsgsToShow) == 1:
                            self._pushMessages()
                    else:
                        # should never happen, but just in case
                        print("Lost message!: "+msg+" (too far behind...)")

Response: Show the given status string but not until any given delay from the previous message has expired.


Instruction:
Create a Python 3 function for
starting the GUI session or load a task s ConfigObj.

Response:
def teal(theTask, parent=None, loadOnly=False, returnAs="dict",
         canExecute=True, strict=False, errorsToTerm=False,
         autoClose=True, defaults=False):
#        overrides=None):
    """ Start the GUI session, or simply load a task's ConfigObj. """
    if loadOnly: # this forces returnAs="dict"
        obj = None
        try:
            obj = cfgpars.getObjectFromTaskArg(theTask, strict, defaults)
#           obj.strictUpdate(overrides) # ! would need to re-verify after this !
        except Exception as re: # catches RuntimeError and KeyError and ...
            # Since we are loadOnly, don't pop up the GUI for this
            if strict:
                raise
            else:
                print(re.message.replace('\n\n','\n'))
        return obj
    else:
        assert returnAs in ("dict", "status", None), \
               "Invalid value for returnAs arg: "+str(returnAs)
        dlg = None
        try:
            # if setting to all defaults, go ahead and load it here, pre-GUI
            if defaults:
                theTask = cfgpars.getObjectFromTaskArg(theTask, strict, True)
            # now create/run the dialog
            dlg = ConfigObjEparDialog(theTask, parent=parent,
                                      autoClose=autoClose,
                                      strict=strict,
                                      canExecute=canExecute)
#                                     overrides=overrides)
        except cfgpars.NoCfgFileError as ncf:
            log_last_error()
            if errorsToTerm:
                print(str(ncf).replace('\n\n','\n'))
            else:
                popUpErr(parent=parent,message=str(ncf),title="Unfound Task")
        except Exception as re: # catches RuntimeError and KeyError and ...
            log_last_error()
            if errorsToTerm:
                print(re.message.replace('\n\n','\n'))
            else:
                popUpErr(parent=parent, message=re.message,
                         title="Bad Parameters")

        # Return, depending on the mode in which we are operating
        if returnAs is None:
            return

        if returnAs == "dict":
            if dlg is None or dlg.canceled():
                return None
            else:
                return dlg.getTaskParsObj()

        # else, returnAs == "status"
        if dlg is None or dlg.canceled():
            return -1
        if dlg.executed():
            return 1
        return 0


Instruction:
Given the following Python 3 function, write the documentation
def load(theTask, canExecute=True, strict=True, defaults=False):
    return teal(theTask, parent=None, loadOnly=True, returnAs="dict",
                canExecute=canExecute, strict=strict, errorsToTerm=True,
                defaults=defaults)

Response:
Shortcut to load TEAL. cfg files for non - GUI access where
    loadOnly = True.


Instruction:
Create a Python 3 function for
unlearning the user - owned task from the system.

Response:
def unlearn(taskPkgName, deleteAll=False):
    """ Find the task named taskPkgName, and delete any/all user-owned
    .cfg files in the user's resource directory which apply to that task.
    Like a unix utility, this returns 0 on success (no files found or only
    1 found but deleted).  For multiple files found, this uses deleteAll,
    returning the file-name-list if deleteAll is False (to indicate the
    problem) and without deleting any files.  MUST check return value.
    This does not prompt the user or print to the screen. """

    # this WILL throw an exception if the taskPkgName isn't found
    flist = cfgpars.getUsrCfgFilesForPyPkg(taskPkgName) # can raise
    if flist is None or len(flist) == 0:
        return 0
    if len(flist) == 1:
        os.remove(flist[0])
        return 0
    # at this point, we know more than one matching file was found
    if deleteAll:
        for f in flist:
            os.remove(f)
        return 0
    else:
        return flist


Instruction:
Can you tell what is the following Python 3 function doing
def diffFromDefaults(theTask, report=False):
    # get the 2 dicts (trees: dicts of dicts)
    defaultTree = load(theTask, canExecute=False, strict=True, defaults=True)
    thisTree    = load(theTask, canExecute=False, strict=True, defaults=False)
    # they must be flattenable
    defaultFlat = cfgpars.flattenDictTree(defaultTree)
    thisFlat    = cfgpars.flattenDictTree(thisTree)
    # use the "set" operations till there is a dict.diff()
    # thanks to:  http://stackoverflow.com/questions/715234
    diffFlat = dict( set(thisFlat.items()) - \
                     set(defaultFlat.items()) )
    if report:
        defaults_of_diffs_only = {}
#       { k:defaultFlat[k] for k in diffFlat.keys() }
        for k in diffFlat:
            defaults_of_diffs_only[k] = defaultFlat[k]
        msg = 'Non-default values of "'+str(theTask)+'":\n'+ \
              _flat2str(diffFlat)+ \
              '\n\nDefault values:\n'+ \
              _flat2str(defaults_of_diffs_only)
        print(msg)
    return diffFlat

Response: Load the given file and return a dict containing the values which are different from the default values.


Instruction:
How would you implement a function in Python 3 that
returns True if the given file name is located in an analytical base area.

Response:
def _isInstalled(fullFname):
    """ Return True if the given file name is located in an
    installed area (versus a user-owned file) """
    if not fullFname: return False
    if not os.path.exists(fullFname): return False
    instAreas = []
    try:
        import site
        instAreas = site.getsitepackages()
    except:
        pass # python 2.6 and lower don't have site.getsitepackages()
    if len(instAreas) < 1:
        instAreas = [ os.path.dirname(os.__file__) ]
    for ia in instAreas:
        if fullFname.find(ia) >= 0:
            return True
    return False


Instruction:
Can you implement a function in Python 3 that
executes a string of embedded code in a specific scope.

Response:
def execEmbCode(SCOPE, NAME, VAL, TEAL, codeStr):
    """ .cfgspc embedded code execution is done here, in a relatively confined
        space.  The variables available to the code to be executed are:
              SCOPE, NAME, VAL, PARENT, TEAL
        The code string itself is expected to set a var named OUT
    """
    # This was all we needed in Python 2.x
#   OUT = None
#   exec codeStr
#   return OUT

    # In Python 3 (& 2.x) be more explicit:  http://bugs.python.org/issue4831
    PARENT = None
    if TEAL:
        PARENT = TEAL.top
    OUT = None
    ldict = locals() # will have OUT in it
    exec(codeStr, globals(), ldict)
    return ldict['OUT']


Instruction:
Can you tell what is the following Python 3 function doing
def print_tasknames(pkgName, aDir, term_width=80, always=False,
                    hidden=None):
    """ Print a message listing TEAL-enabled tasks available under a
        given installation directory (where pkgName resides).
        If always is True, this will always print when tasks are
        found; otherwise it will only print found tasks when in interactive
        mode.
        The parameter 'hidden' supports a list of input tasknames that should
        not be reported even though they still exist.
    """
    # See if we can bail out early
    if not always:
        # We can't use the sys.ps1 check if in PyRAF since it changes sys
        if 'pyraf' not in sys.modules:
           # sys.ps1 is only defined in interactive mode
           if not hasattr(sys, 'ps1'):
               return # leave here, we're in someone's script

    # Check for tasks
    taskDict = cfgpars.findAllCfgTasksUnderDir(aDir)
    tasks = [x for x in taskDict.values() if len(x) > 0]
    if hidden: # could even account for a single taskname as input here if needed
        for x in hidden:
            if x in tasks: tasks.remove(x)
    # only be verbose if there something found
    if len(tasks) > 0:
        sortedUniqTasks = sorted(set(tasks))
        if len(sortedUniqTasks) == 1:
            tlines = 'The following task in the '+pkgName+\
                     ' package can be run with TEAL:\n'
        else:
            tlines = 'The following tasks in the '+pkgName+\
                     ' package can be run with TEAL:\n'
        tlines += printColsAuto(sortedUniqTasks, term_width=term_width,
                                min_pad=2)
        print(tlines)

Response: Print a message listing TEAL - enabled tasks under a specific installation directory.


Instruction:
Here you have a function in Python 3, explain what it does
def getHelpFileAsString(taskname,taskpath):
    #get the local library directory where the code is stored
    pathsplit=os.path.split(taskpath) # taskpath should be task's __file__
    if taskname.find('.') > -1: # if taskname is given as package.taskname...
        helpname=taskname.split(".")[1]    # taskname should be __taskname__ from task's module
    else:
        helpname = taskname
    localdir = pathsplit[0]
    if localdir == '':
       localdir = '.'
    helpfile=rglob(localdir,helpname+".help")[0]

    if os.access(helpfile,os.R_OK):
        fh=open(helpfile,'r')
        ss=fh.readlines()
        fh.close()
        helpString=""
        for line in ss:
            helpString+=line
    else:
        helpString= ''

    return helpString

Response: This function returns useful help as a string read from a file in the task s installed directory called "<module. help>".


Instruction:
Given the following Python 3 function, write the documentation
def cfgGetBool(theObj, name, dflt):
    strval = theObj.get(name, None)
    if strval is None:
        return dflt
    return strval.lower().strip() == 'true'

Response: Get a stringified val from a ConfigObj obj and return it as bool


Instruction:
Given the following Python 3 function, write the documentation
def _overrideMasterSettings(self):
        # config-obj dict of defaults
        cod = self._getGuiSettings()

        # our own GUI setup
        self._appName              = APP_NAME
        self._appHelpString        = tealHelpString
        self._useSimpleAutoClose   = self._do_usac
        self._showExtraHelpButton  = False
        self._saveAndCloseOnExec   = cfgGetBool(cod, 'saveAndCloseOnExec', True)
        self._showHelpInBrowser    = cfgGetBool(cod, 'showHelpInBrowser', False)
        self._writeProtectOnSaveAs = cfgGetBool(cod, 'writeProtectOnSaveAsOpt', True)
        self._flagNonDefaultVals   = cfgGetBool(cod, 'flagNonDefaultVals', None)
        self._optFile              = APP_NAME.lower()+".optionDB"

        # our own colors
        # prmdrss teal: #00ffaa, pure cyan (teal) #00ffff (darker) #008080
        # "#aaaaee" is a darker but good blue, but "#bbbbff" pops
        ltblu = "#ccccff" # light blue
        drktl = "#008888" # darkish teal
        self._frmeColor = cod.get('frameColor', drktl)
        self._taskColor = cod.get('taskBoxColor', ltblu)
        self._bboxColor = cod.get('buttonBoxColor', ltblu)
        self._entsColor = cod.get('entriesColor', ltblu)
        self._flagColor = cod.get('flaggedColor', 'brown')

        # double check _canExecute, but only if it is still set to the default
        if self._canExecute and self._taskParsObj: # default _canExecute=True
            self._canExecute = self._taskParsObj.canExecute()
        self._showExecuteButton = self._canExecute

        # check on the help string - just to see if it is HTML
        # (could use HTMLParser here if need be, be quick and simple tho)
        hhh = self.getHelpString(self.pkgName+'.'+self.taskName)
        if hhh:
            hhh = hhh.lower()
            if hhh.find('<html') >= 0 or hhh.find('</html>') > 0:
                self._knowTaskHelpIsHtml = True
            elif hhh.startswith('http:') or hhh.startswith('https:'):
                self._knowTaskHelpIsHtml = True
            elif hhh.startswith('file:') and \
                 (hhh.endswith('.htm') or hhh.endswith('.html')):
                self._knowTaskHelpIsHtml = True

Response: Override so that we can run in a different mode.


Instruction:
Write a Python 3 script to
override this so we can handle case of file not writable overwriteRO and save the file if it exists.

Response:
def _doActualSave(self, fname, comment, set_ro=False, overwriteRO=False):
        """ Override this so we can handle case of file not writable, as
            well as to make our _lastSavedState copy. """
        self.debug('Saving, file name given: '+str(fname)+', set_ro: '+\
                   str(set_ro)+', overwriteRO: '+str(overwriteRO))
        cantWrite = False
        inInstArea = False
        if fname in (None, ''): fname = self._taskParsObj.getFilename()
        # now do some final checks then save
        try:
            if _isInstalled(fname): # check: may be installed but not read-only
                inInstArea = cantWrite = True
            else:
                # in case of save-as, allow overwrite of read-only file
                if overwriteRO and os.path.exists(fname):
                    setWritePrivs(fname, True, True) # try make writable
                # do the save
                rv=self._taskParsObj.saveParList(filename=fname,comment=comment)
        except IOError:
            cantWrite = True

        # User does not have privs to write to this file. Get name of local
        # choice and try to use that.
        if cantWrite:
            fname = self._taskParsObj.getDefaultSaveFilename()
            # Tell them the context is changing, and where we are saving
            msg = 'Read-only config file for task "'
            if inInstArea:
                msg = 'Installed config file for task "'
            msg += self._taskParsObj.getName()+'" is not to be overwritten.'+\
                  '  Values will be saved to: \n\n\t"'+fname+'".'
            showwarning(message=msg, title="Will not overwrite!")
            # Try saving to their local copy
            rv=self._taskParsObj.saveParList(filename=fname, comment=comment)

        # Treat like a save-as (update title for ALL save ops)
        self._saveAsPostSave_Hook(fname)

        # Limit write privs if requested (only if not in the rc dir)
        if set_ro and os.path.dirname(os.path.abspath(fname)) != \
                                      os.path.abspath(self._rcDir):
            cfgpars.checkSetReadOnly(fname)

        # Before returning, make a copy so we know what was last saved.
        # The dict() method returns a deep-copy dict of the keyvals.
        self._lastSavedState = self._taskParsObj.dict()
        return rv


Instruction:
Given the following Python 3 function, write the documentation
def hasUnsavedChanges(self):

        # Sanity check - this case shouldn't occur
        assert self._lastSavedState is not None, \
               "BUG: Please report this as it should never occur."

        # Force the current GUI values into our model in memory, but don't
        # change anything.  Don't save to file, don't even convert bad
        # values to their previous state in the gui.  Note that this can
        # leave the GUI in a half-saved state, but since we are about to exit
        # this is OK.  We only want prompting to occur if they decide to save.
        badList = self.checkSetSaveEntries(doSave=False, fleeOnBadVals=True,
                                           allowGuiChanges=False)
        if badList:
            return True

        # Then compare our data to the last known saved state.  MAKE SURE
        # the LHS is the actual dict (and not 'self') to invoke the dict
        # comparison only.
        return self._lastSavedState != self._taskParsObj

Response: Determine if there are any unsaved changes in the GUI.


Instruction:
Can you write a function in Python 3 where it
overrides to allow us to use an edited callback.

Response:
def _defineEditedCallbackObjectFor(self, parScope, parName):
        """ Override to allow us to use an edited callback. """

        # We know that the _taskParsObj is a ConfigObjPars
        triggerStrs = self._taskParsObj.getTriggerStrings(parScope, parName)

        # Some items will have a trigger, but likely most won't
        if triggerStrs and len(triggerStrs) > 0:
            return self
        else:
            return None


Instruction:
Create a Python 3 function to
override so we can append read - only status.

Response:
def updateTitle(self, atitle):
        """ Override so we can append read-only status. """
        if atitle and os.path.exists(atitle):
            if _isInstalled(atitle):
                atitle += '  [installed]'
            elif not os.access(atitle, os.W_OK):
                atitle += '  [read only]'
        super(ConfigObjEparDialog, self).updateTitle(atitle)


Instruction:
Here you have a function in Python 3, explain what it does
def findNextSection(self, scope, name):
        # first find index of starting point
        plist = self._taskParsObj.getParList()
        start = 0
        for i in range(len(plist)):
            if scope == plist[i].scope and name == plist[i].name:
                start = i
                break
        else:
            print('WARNING: could not find starting par: '+scope+'.'+name)
            return (None, None)

        # now find first different (non-null) scope in a par, after start
        for i in range(start, len(plist)):
            if len(plist[i].scope) > 0 and plist[i].scope != scope:
                return (plist[i].scope, plist[i].name)
        # else didn't find it
        return (None, None)

Response: Starts with given scope + name and returns the next section in the list of parameters.


Instruction:
Can you generate the documentation for the following Python 3 function
def _setTaskParsObj(self, theTask):
        # Create the ConfigObjPars obj
        self._taskParsObj = cfgpars.getObjectFromTaskArg(theTask,
                                    self._strict, False)
        # Tell it that we can be used for catching debug lines
        self._taskParsObj.setDebugLogger(self)

        # Immediately make a copy of it's un-tampered internal dict.
        # The dict() method returns a deep-copy dict of the keyvals.
        self._lastSavedState = self._taskParsObj.dict()

Response: Overridden version for ConfigObj. TheTask can be either a. cfg file name or a ConfigObjPars object.


Instruction:
Given the following Python 3 function, write the documentation
def _getSaveAsFilter(self):
        # figure the dir to use, start with the one from the file
        absRcDir = os.path.abspath(self._rcDir)
        thedir = os.path.abspath(os.path.dirname(self._taskParsObj.filename))
        # skip if not writeable, or if is _rcDir
        if thedir == absRcDir or not os.access(thedir, os.W_OK):
            thedir = os.path.abspath(os.path.curdir)
        # create save-as filter string
        filt = thedir+'/*.cfg'
        envVarName = APP_NAME.upper()+'_CFG'
        if envVarName in os.environ:
            upx = os.environ[envVarName]
            if len(upx) > 0:  filt = upx+"/*.cfg"
        # done
        return filt

Response:
Return a string to be used as the filter arg to the save file
            dialog during Save - As.


Instruction:
Create a Python 3 function to
go through all possible sites to find applicable. cfg files. Return as an iterable.

Response:
def _getOpenChoices(self):
        """ Go through all possible sites to find applicable .cfg files.
            Return as an iterable. """
        tsk = self._taskParsObj.getName()
        taskFiles = set()
        dirsSoFar = [] # this helps speed this up (skip unneeded globs)

        # last dir
        aDir = os.path.dirname(self._taskParsObj.filename)
        if len(aDir) < 1: aDir = os.curdir
        dirsSoFar.append(aDir)
        taskFiles.update(cfgpars.getCfgFilesInDirForTask(aDir, tsk))

        # current dir
        aDir = os.getcwd()
        if aDir not in dirsSoFar:
            dirsSoFar.append(aDir)
            taskFiles.update(cfgpars.getCfgFilesInDirForTask(aDir, tsk))

        # task's python pkg dir (if tsk == python pkg name)
        try:
            x, pkgf = cfgpars.findCfgFileForPkg(tsk, '.cfg', taskName=tsk,
                              pkgObj=self._taskParsObj.getAssocPkg())
            taskFiles.update( (pkgf,) )
        except cfgpars.NoCfgFileError:
            pass # no big deal - maybe there is no python package

        # user's own resourceDir
        aDir = self._rcDir
        if aDir not in dirsSoFar:
            dirsSoFar.append(aDir)
            taskFiles.update(cfgpars.getCfgFilesInDirForTask(aDir, tsk))

        # extra loc - see if they used the app's env. var
        aDir = dirsSoFar[0] # flag to skip this if no env var found
        envVarName = APP_NAME.upper()+'_CFG'
        if envVarName in os.environ: aDir = os.environ[envVarName]
        if aDir not in dirsSoFar:
            dirsSoFar.append(aDir)
            taskFiles.update(cfgpars.getCfgFilesInDirForTask(aDir, tsk))

        # At the very end, add an option which we will later interpret to mean
        # to open the file dialog.
        taskFiles = list(taskFiles) # so as to keep next item at end of seq
        taskFiles.sort()
        taskFiles.append("Other ...")

        return taskFiles


Instruction:
Create a Python 3 function for
loading the parameter settings from a user - specified file.

Response:
def pfopen(self, event=None):
        """ Load the parameter settings from a user-specified file. """

        # Get the selected file name
        fname = self._openMenuChoice.get()

        # Also allow them to simply find any file - do not check _task_name_...
        # (could use tkinter's FileDialog, but this one is prettier)
        if fname[-3:] == '...':
            if capable.OF_TKFD_IN_EPAR:
                fname = askopenfilename(title="Load Config File",
                                        parent=self.top)
            else:
                from . import filedlg
                fd = filedlg.PersistLoadFileDialog(self.top,
                                                   "Load Config File",
                                                   self._getSaveAsFilter())
                if fd.Show() != 1:
                    fd.DialogCleanup()
                    return
                fname = fd.GetFileName()
                fd.DialogCleanup()

        if not fname: return # canceled
        self.debug('Loading from: '+fname)

        # load it into a tmp object (use associatedPkg if we have one)
        try:
            tmpObj = cfgpars.ConfigObjPars(fname, associatedPkg=\
                                           self._taskParsObj.getAssocPkg(),
                                           strict=self._strict)
        except Exception as ex:
            showerror(message=ex.message, title='Error in '+os.path.basename(fname))
            self.debug('Error in '+os.path.basename(fname))
            self.debug(traceback.format_exc())
            return

        # check it to make sure it is a match
        if not self._taskParsObj.isSameTaskAs(tmpObj):
            msg = 'The current task is "'+self._taskParsObj.getName()+ \
                  '", but the selected file is for task "'+ \
                  str(tmpObj.getName())+'".  This file was not loaded.'
            showerror(message=msg, title="Error in "+os.path.basename(fname))
            self.debug(msg)
            self.debug(traceback.format_exc())
            return

        # Set the GUI entries to these values (let the user Save after)
        newParList = tmpObj.getParList()
        try:
            self.setAllEntriesFromParList(newParList, updateModel=True)
                # go ahead and updateModel, even though it will take longer,
                # we need it updated for the copy of the dict we make below
        except editpar.UnfoundParamError as pe:
            showwarning(message=str(pe), title="Error in "+os.path.basename(fname))
        # trip any triggers
        self.checkAllTriggers('fopen')

        # This new fname is our current context
        self.updateTitle(fname)
        self._taskParsObj.filename = fname # !! maybe try setCurrentContext() ?
        self.freshenFocus()
        self.showStatus("Loaded values from: "+fname, keep=2)

        # Since we are in a new context (and have made no changes yet), make
        # a copy so we know what the last state was.
        # The dict() method returns a deep-copy dict of the keyvals.
        self._lastSavedState = self._taskParsObj.dict()


Instruction:
Create a Python 3 function to
override to include ConfigObj filename and specific errors.

Response:
def _handleParListMismatch(self, probStr, extra=False):
        """ Override to include ConfigObj filename and specific errors.
        Note that this only handles "missing" pars and "extra" pars, not
        wrong-type pars.  So it isn't that big of a deal. """

        # keep down the duplicate errors
        if extra:
            return True # the base class is already stating it will be ignored

        # find the actual errors, and then add that to the generic message
        errmsg = 'Warning: '
        if self._strict:
            errmsg = 'ERROR: '
        errmsg = errmsg+'mismatch between default and current par lists ' + \
                 'for task "'+self.taskName+'".'
        if probStr:
            errmsg += '\n\t'+probStr
        errmsg += '\nTry editing/deleting: "' + \
                  self._taskParsObj.filename+'" (or, if in PyRAF: "unlearn ' + \
                  self.taskName+'").'
        print(errmsg)
        return True


Instruction:
Create a Python 3 function for
loading the default parameter settings into the GUI.

Response:
def _setToDefaults(self):
        """ Load the default parameter settings into the GUI. """

        # Create an empty object, where every item is set to it's default value
        try:
            tmpObj = cfgpars.ConfigObjPars(self._taskParsObj.filename,
                                           associatedPkg=\
                                           self._taskParsObj.getAssocPkg(),
                                           setAllToDefaults=self.taskName,
                                           strict=False)
        except Exception as ex:
            msg = "Error Determining Defaults"
            showerror(message=msg+'\n\n'+ex.message, title="Error Determining Defaults")
            return

        # Set the GUI entries to these values (let the user Save after)
        tmpObj.filename = self._taskParsObj.filename = '' # name it later
        newParList = tmpObj.getParList()
        try:
            self.setAllEntriesFromParList(newParList) # needn't updateModel yet
            self.checkAllTriggers('defaults')
            self.updateTitle('')
            self.showStatus("Loaded default "+self.taskName+" values via: "+ \
                 os.path.basename(tmpObj._original_configspec), keep=1)
        except editpar.UnfoundParamError as pe:
            showerror(message=str(pe), title="Error Setting to Default Values")


Instruction:
Implement a Python 3 function for
retrieving the current parameter settings from the GUI.

Response:
def getDict(self):
        """ Retrieve the current parameter settings from the GUI."""
        # We are going to have to return the dict so let's
        # first make sure all of our models are up to date with the values in
        # the GUI right now.
        badList = self.checkSetSaveEntries(doSave=False)
        if badList:
            self.processBadEntries(badList, self.taskName, canCancel=False)
        return self._taskParsObj.dict()


Instruction:
Create a Python 3 function to
load the parameter settings from a given dictionary into the GUI.

Response:
def loadDict(self, theDict):
        """ Load the parameter settings from a given dict into the GUI. """
        # We are going to have to merge this info into ourselves so let's
        # first make sure all of our models are up to date with the values in
        # the GUI right now.
        badList = self.checkSetSaveEntries(doSave=False)
        if badList:
            if not self.processBadEntries(badList, self.taskName):
                return
        # now, self._taskParsObj is up-to-date
        # So now we update _taskParsObj with the input dict
        cfgpars.mergeConfigObj(self._taskParsObj, theDict)
        # now sync the _taskParsObj dict with its par list model
        #    '\n'.join([str(jj) for jj in self._taskParsObj.getParList()])
        self._taskParsObj.syncParamList(False)

        # Set the GUI entries to these values (let the user Save after)
        try:
            self.setAllEntriesFromParList(self._taskParsObj.getParList(),
                                          updateModel=True)
            self.checkAllTriggers('fopen')
            self.freshenFocus()
            self.showStatus('Loaded '+str(len(theDict))+ \
                ' user par values for: '+self.taskName, keep=1)
        except Exception as ex:
            showerror(message=ex.message, title="Error Setting to Loaded Values")


Instruction:
Can you generate the documentation for the following Python 3 function
def _getGuiSettings(self):
        # Put the settings into a ConfigObj dict (don't use a config-spec)
        rcFile = self._rcDir+os.sep+APP_NAME.lower()+'.cfg'
        if os.path.exists(rcFile):
            try:
                return configobj.ConfigObj(rcFile)
            except:
                raise RuntimeError('Error parsing: '+os.path.realpath(rcFile))

            # tho, for simple types, unrepr=True eliminates need for .cfgspc
            # also, if we turn unrepr on, we don't need cfgGetBool
        else:
            return {}

Response: Return a dict of all user settings found in rcFile.


Instruction:
How would you explain what the following Python 3 function does
def _saveGuiSettings(self):
        # Put the settings into a ConfigObj dict (don't use a config-spec)
        rcFile = self._rcDir+os.sep+APP_NAME.lower()+'.cfg'
        #
        if os.path.exists(rcFile): os.remove(rcFile)
        co = configobj.ConfigObj(rcFile) # can skip try-block, won't read file

        co['showHelpInBrowser']       = self._showHelpInBrowser
        co['saveAndCloseOnExec']      = self._saveAndCloseOnExec
        co['writeProtectOnSaveAsOpt'] = self._writeProtectOnSaveAs
        co['flagNonDefaultVals']      = self._flagNonDefaultVals
        co['frameColor']              = self._frmeColor
        co['taskBoxColor']            = self._taskColor
        co['buttonBoxColor']          = self._bboxColor
        co['entriesColor']            = self._entsColor
        co['flaggedColor']            = self._flagColor

        co.initial_comment = ['Automatically generated by '+\
            APP_NAME+'.  All edits will eventually be overwritten.']
        co.initial_comment.append('To use platform default colors, delete each color line below.')
        co.final_comment = [''] # ensure \n at EOF
        co.write()

Response: Save the settings of the current object to a file.


Instruction:
Can you create a Python 3 function that
reads an association table from a FITS file and returns a dictionary that can be used by pydrizzle and multidrizzle.

Response:
def readASNTable(fname, output=None, prodonly=False):
    """
    Given a fits filename repesenting an association table reads in the table as a
    dictionary which can be used by pydrizzle and multidrizzle.

    An association table is a FITS binary table with 2 required columns: 'MEMNAME',
    'MEMTYPE'. It checks 'MEMPRSNT' column and removes all files for which its value is 'no'.

    Parameters
    ----------
    fname : str
        name of association table
    output : str
        name of output product - if not specified by the user,
        the first PROD-DTH name is used if present,
        if not, the first PROD-RPT name is used if present,
        if not, the rootname of the input association table is used.
    prodonly : bool
        what files should be considered as input
        if True - select only MEMTYPE=PROD* as input
        if False - select only MEMTYPE=EXP as input

    Returns
    -------
    asndict : dict
        A dictionary-like object with all the association information.

    Examples
    --------
    An association table can be read from a file using the following commands::

    >>> from stsci.tools import asnutil
    >>> asntab = asnutil.readASNTable('j8bt06010_shifts_asn.fits', prodonly=False)  # doctest: +SKIP

    The `asntab` object can now be passed to other code to provide relationships
    between input and output images defined by the association table.

    """

    try:
        f = fits.open(fu.osfn(fname))
    except:
        raise IOError("Can't open file %s\n" % fname)

    colnames = f[1].data.names
    try:
        colunits = f[1].data.units
    except AttributeError: pass

    hdr = f[0].header

    if 'MEMNAME' not in colnames or 'MEMTYPE' not in colnames:
        msg = 'Association table incomplete: required column(s) MEMNAME/MEMTYPE NOT found!'
        raise ValueError(msg)

    d = {}
    for n in colnames:
        d[n]=f[1].data.field(n)
    f.close()

    valid_input = d['MEMPRSNT'].copy()
    memtype = d['MEMTYPE'].copy()
    prod_dth = (memtype.find('PROD-DTH')==0).nonzero()[0]
    prod_rpt = (memtype.find('PROD-RPT')==0).nonzero()[0]
    prod_crj = (memtype.find('PROD-CRJ')==0).nonzero()[0]

    # set output name
    if output is None:
        if prod_dth:
            output = d['MEMNAME'][prod_dth[0]]
        elif prod_rpt:
            output = d['MEMNAME'][prod_rpt[0]]
        elif prod_crj:
            output = d['MEMNAME'][prod_crj[0]]
        else:
            output = fname.split('_')[0]

    if prodonly:
        input = d['MEMTYPE'].find('PROD')==0
        if prod_dth:
            input[prod_dth] = False
    else:
        input = (d['MEMTYPE'].find('EXP')==0)
    valid_input *= input

    for k in d:
        d[k] = d[k][valid_input]

    infiles = list(d['MEMNAME'].lower())
    if not infiles:
        print("No valid input specified")
        return None

    if ('XOFFSET' in colnames and d['XOFFSET'].any()) or ('YOFFSET' in colnames and d['YOFFSET'].any()):
        abshift = True
        dshift = False
        try:
            units=colunits[colnames.index('XOFFSET')]
        except: units='pixels'
        xshifts = list(d['XOFFSET'])
        yshifts = list(d['YOFFSET'])
    elif ('XDELTA' in colnames and d['XDELTA'].any()) or  ('YDELTA' in colnames and d['YDELTA'].any()):
        abshift = False
        dshift = True
        try:
            units=colunits[colnames.index('XDELTA')]
        except: units='pixels'
        xshifts = list(d['XDELTA'])
        yshifts = list(d['YDELTA'])
    else:
        abshift = False
        dshift = False
    members = {}

    if not abshift and not dshift:
        asndict = ASNTable(infiles,output=output)
        asndict.create()
        return asndict
    else:
        try:
            refimage = hdr['refimage']
        except KeyError: refimage = None
        try:
            frame = hdr['shframe']
        except KeyError: frame = 'input'
        if 'ROTATION' in colnames:
            rots = list(d['ROTATION'])
        if 'SCALE' in colnames:
            scales = list(d['SCALE'])

        for r in range(len(infiles)):
            row = r
            xshift = xshifts[r]
            yshift = yshifts[r]
            if rots: rot = rots[r]
            if scales: scale = scales[r]
            members[infiles[r]] = ASNMember(row=row, dshift=dshift, abshift=abshift, rot=rot, xshift=xshift,
                                      yshift=yshift, scale=scale, refimage=refimage, shift_frame=frame,
                                      shift_units=units)

        asndict= ASNTable(infiles, output=output)
        asndict.create()
        asndict['members'].update(members)
        return asndict


Instruction:
Write a Python 3 function that can
write the association table to a FITS file.

Response:
def write(self, output=None):
        """
        Write association table to a file.

        """
        if not output:
            outfile = self['output']+'_asn.fits'
            output = self['output']
        else:
            outfile = output

        # Delete the file if it exists.
        if os.path.exists(outfile):
            warningmsg =  "\n#########################################\n"
            warningmsg += "#                                       #\n"
            warningmsg += "# WARNING:                              #\n"
            warningmsg += "#  The existing association table,      #\n"
            warningmsg += "           " + str(outfile) + '\n'
            warningmsg += "#  is being replaced.                   #\n"
            warningmsg += "#                                       #\n"
            warningmsg += "#########################################\n\n"
        fasn = fits.HDUList()

        # Compute maximum length of MEMNAME for table column definition
        _maxlen = 0
        for _fname in self['order']:
            if len(_fname) > _maxlen: _maxlen = len(_fname)
        # Enforce a mimimum size of 24
        if _maxlen < 24: _maxlen = 24
        namelen_str = str(_maxlen+2)+'A'
        self.buildPrimary(fasn, output=output)

        mname = self['order'][:]
        mname.append(output)
        mtype = ['EXP-DTH' for l in self['order']]
        mtype.append('PROD-DTH')
        mprsn = [True for l in self['order']]
        mprsn.append(False)
        xoff = [self['members'][l]['xoff'] for l in self['order']]
        xoff.append(0.0)
        yoff = [self['members'][l]['yoff'] for l in self['order']]
        yoff.append(0.0)
        xsh = [self['members'][l]['xshift'] for l in self['order']]
        xsh.append(0.0)
        ysh = [self['members'][l]['yshift'] for l in self['order']]
        ysh.append(0.0)
        rot = [self['members'][l]['rot'] for l in self['order']]
        rot.append(0.0)
        scl = [self['members'][l]['scale'] for l in self['order']]
        scl.append(1.0)

        memname = fits.Column(name='MEMNAME',format=namelen_str,array=N.char.array(mname))
        memtype = fits.Column(name='MEMTYPE',format='14A',array=N.char.array(mtype))
        memprsn = fits.Column(name='MEMPRSNT', format='L', array=N.array(mprsn).astype(N.uint8))
        xoffset = fits.Column(name='XOFFSET', format='E', array=N.array(xoff))
        yoffset = fits.Column(name='YOFFSET', format='E', array=N.array(yoff))
        xdelta = fits.Column(name='XDELTA', format='E', array=N.array(xsh))
        ydelta = fits.Column(name='YDELTA', format='E', array=N.array(ysh))
        rotation = fits.Column(name='ROTATION', format='E', array=N.array(rot))
        scale = fits.Column(name='SCALE', format='E', array=N.array(scl))
        cols = fits.ColDefs([memname,memtype,memprsn,xoffset,yoffset,xdelta,ydelta,rotation,scale])
        hdu = fits.BinTableHDU.from_columns(cols)
        fasn.append(hdu)
        if ASTROPY_VER_GE13:
            fasn.writeto(outfile, overwrite=True)
        else:
            fasn.writeto(outfile, clobber=True)
        fasn.close()
        mem0 = self['order'][0]
        refimg = self['members'][mem0]['refimage']
        if refimg is not None:
            whdu = wcsutil.WCSObject(refimg)
            whdu.createReferenceWCS(outfile,overwrite=False)
            ftab = fits.open(outfile)
            ftab['primary'].header['refimage'] = outfile+"[wcs]"
            ftab.close()
        del whdu


Instruction:
Make a summary of the following Python 3 code
def readShiftFile(self, filename):
        order = []
        fshift = open(filename,'r')
        flines = fshift.readlines()
        fshift.close()

        common = [f.strip('#').strip() for f in flines if f.startswith('#')]
        c=[line.split(': ') for line in common]

        # Remove any line comments in the shift file - lines starting with '#'
        # but not part of the common block.
        for l in c:
            if l[0] not in ['frame', 'refimage', 'form', 'units']:
                c.remove(l)

        for line in c: line[1]=line[1].strip()
        self.update(c)

        files = [f.strip().split(' ',1) for f in flines if not (f.startswith('#') or f.strip() == '')]
        for f in files:
            order.append(f[0])

        self['order'] = order

        for f in files:
            # Check to see if filename provided is a full filename that corresponds
            # to a file on the path.  If not, try to convert given rootname into
            # a valid filename based on available files.  This may or may not
            # define the correct filename, which is why it prints out what it is
            # doing, so that the user can verify and edit the shiftfile if needed.
            #NOTE:
            # Supporting the specification of only rootnames in the shiftfile with this
            # filename expansion is NOT to be documented, but provided solely as
            # an undocumented, dangerous and not fully supported helper function for
            # some backwards compatibility.
            if not os.path.exists(f[0]):
                f[0] = fu.buildRootname(f[0])
                print('Defining filename in shiftfile as: ', f[0])

            f[1] = f[1].split()
            try:
                f[1] = [float(s) for s in f[1]]
            except:
                msg = 'Cannot read in ', s, ' from shiftfile ', filename, ' as a float number'
                raise ValueError(msg)
            msg = "At least 2 and at most 4 shift values should be provided in a shiftfile"
            if len(f[1]) < 2:
                raise ValueError(msg)
            elif len(f[1]) == 3:
                f[1].append(1.0)
            elif len(f[1]) == 2:
                f[1].extend([0.0, 1.0])
            elif len(f[1]) > 4:
                raise ValueError(msg)

        fdict = dict(files)
        self.update(fdict)

Response: Reads a shift file from disk and populates the internal dictionary with the information from that file.


Instruction:
Can you create a Python 3 function that
writes a shift file object to a file on disk using the convention for shift file format.

Response:
def writeShiftFile(self, filename="shifts.txt"):
        """
        Writes a shift file object to a file on disk using the convention for shift file format.
        """
        lines = ['# frame: ', self['frame'], '\n',
                 '# refimage: ', self['refimage'], '\n',
                 '# form: ', self['form'], '\n',
                 '# units: ', self['units'], '\n']

        for o in self['order']:
            ss = " "
            for shift in self[o]:
                ss += str(shift) + " "
            line = str(o) + ss + "\n"
            lines.append(line)

        fshifts= open(filename, 'w')
        fshifts.writelines(lines)
        fshifts.close()


Instruction:
Given the following Python 3 function, write the documentation
def weave(target, aspects, **options):
    if not callable(aspects):
        if not hasattr(aspects, '__iter__'):
            raise ExpectedAdvice('%s must be an `Aspect` instance, a callable or an iterable of.' % aspects)
        for obj in aspects:
            if not callable(obj):
                raise ExpectedAdvice('%s must be an `Aspect` instance or a callable.' % obj)
    assert target, "Can't weave falsy value %r." % target
    logdebug("weave (target=%s, aspects=%s, **options=%s)", target, aspects, options)

    bag = options.setdefault('bag', ObjectBag())

    if isinstance(target, (list, tuple)):
        return Rollback([
            weave(item, aspects, **options) for item in target
        ])
    elif isinstance(target, basestring):
        parts = target.split('.')
        for part in parts:
            _check_name(part)

        if len(parts) == 1:
            return weave_module(_import_module(part), aspects, **options)

        for pos in reversed(range(1, len(parts))):
            owner, name = '.'.join(parts[:pos]), '.'.join(parts[pos:])
            try:
                owner = _import_module(owner)
            except ImportError:
                continue
            else:
                break
        else:
            raise ImportError("Could not import %r. Last try was for %s" % (target, owner))

        if '.' in name:
            path, name = name.rsplit('.', 1)
            path = deque(path.split('.'))
            while path:
                owner = getattr(owner, path.popleft())

        logdebug("@ patching %s from %s ...", name, owner)
        obj = getattr(owner, name)

        if isinstance(obj, (type, ClassType)):
            logdebug("   .. as a class %r.", obj)
            return weave_class(
                obj, aspects,
                owner=owner, name=name, **options
            )
        elif callable(obj):  # or isinstance(obj, FunctionType) ??
            logdebug("   .. as a callable %r.", obj)
            if bag.has(obj):
                return Nothing
            return patch_module_function(owner, obj, aspects, force_name=name, **options)
        else:
            return weave(obj, aspects, **options)

    name = getattr(target, '__name__', None)
    if name and getattr(__builtin__, name, None) is target:
        if bag.has(target):
            return Nothing
        return patch_module_function(__builtin__, target, aspects, **options)
    elif PY3 and ismethod(target):
        if bag.has(target):
            return Nothing
        inst = target.__self__
        name = target.__name__
        logdebug("@ patching %r (%s) as instance method.", target, name)
        func = target.__func__
        setattr(inst, name, _checked_apply(aspects, func).__get__(inst, type(inst)))
        return Rollback(lambda: delattr(inst, name))
    elif PY3 and isfunction(target):
        if bag.has(target):
            return Nothing
        owner = _import_module(target.__module__)
        path = deque(target.__qualname__.split('.')[:-1])
        while path:
            owner = getattr(owner, path.popleft())
        name = target.__name__
        logdebug("@ patching %r (%s) as a property.", target, name)
        func = owner.__dict__[name]
        return patch_module(owner, name, _checked_apply(aspects, func), func, **options)
    elif PY2 and isfunction(target):
        if bag.has(target):
            return Nothing
        return patch_module_function(_import_module(target.__module__), target, aspects, **options)
    elif PY2 and ismethod(target):
        if target.im_self:
            if bag.has(target):
                return Nothing
            inst = target.im_self
            name = target.__name__
            logdebug("@ patching %r (%s) as instance method.", target, name)
            func = target.im_func
            setattr(inst, name, _checked_apply(aspects, func).__get__(inst, type(inst)))
            return Rollback(lambda: delattr(inst, name))
        else:
            klass = target.im_class
            name = target.__name__
            return weave(klass, aspects, methods='%s$' % name, **options)
    elif isclass(target):
        return weave_class(target, aspects, **options)
    elif ismodule(target):
        return weave_module(target, aspects, **options)
    elif type(target).__module__ not in ('builtins', '__builtin__') or InstanceType and isinstance(target, InstanceType):
        return weave_instance(target, aspects, **options)
    else:
        raise UnsupportedType("Can't weave object %s of type %s" % (target, type(target)))

Response: Send a message to a recipient that weave the target object.


Instruction:
Given the following Python 3 function, write the documentation
def weave_instance(instance, aspect, methods=NORMAL_METHODS, lazy=False, bag=BrokenBag, **options):
    if bag.has(instance):
        return Nothing

    entanglement = Rollback()
    method_matches = make_method_matcher(methods)
    logdebug("weave_instance (module=%r, aspect=%s, methods=%s, lazy=%s, **options=%s)",
             instance, aspect, methods, lazy, options)

    def fixup(func):
        return func.__get__(instance, type(instance))
    fixed_aspect = aspect + [fixup] if isinstance(aspect, (list, tuple)) else [aspect, fixup]

    for attr in dir(instance):
        func = getattr(instance, attr)
        if method_matches(attr):
            if ismethod(func):
                if hasattr(func, '__func__'):
                    realfunc = func.__func__
                else:
                    realfunc = func.im_func
                entanglement.merge(
                    patch_module(instance, attr, _checked_apply(fixed_aspect, realfunc, module=None), **options)
                )
    return entanglement

Response:
Low-level weaver for instances.

    .. warning:: You should not use this directly.

    :returns: An :obj:`aspectlib.Rollback` object.


Instruction:
Can you generate the documentation for the following Python 3 function
def weave_module(module, aspect, methods=NORMAL_METHODS, lazy=False, bag=BrokenBag, **options):
    if bag.has(module):
        return Nothing

    entanglement = Rollback()
    method_matches = make_method_matcher(methods)
    logdebug("weave_module (module=%r, aspect=%s, methods=%s, lazy=%s, **options=%s)",
             module, aspect, methods, lazy, options)

    for attr in dir(module):
        func = getattr(module, attr)
        if method_matches(attr):
            if isroutine(func):
                entanglement.merge(patch_module_function(module, func, aspect, force_name=attr, **options))
            elif isclass(func):
                entanglement.merge(
                    weave_class(func, aspect, owner=module, name=attr, methods=methods, lazy=lazy, bag=bag, **options),
                    #  it's not consistent with the other ways of weaving a class (it's never weaved as a routine).
                    #  therefore it's disabled until it's considered useful.
                    #  #patch_module_function(module, getattr(module, attr), aspect, force_name=attr, **options),
                )
    return entanglement

Response:
Low-level weaver for "whole module weaving".

    .. warning:: You should not use this directly.

    :returns: An :obj:`aspectlib.Rollback` object.


Instruction:
Can you create a Python 3 function that
patches an object in a module.

Response:
def patch_module(module, name, replacement, original=UNSPECIFIED, aliases=True, location=None, **_bogus_options):
    """
    Low-level attribute patcher.

    :param module module: Object to patch.
    :param str name: Attribute to patch
    :param replacement: The replacement value.
    :param original: The original value (in case the object beeing patched uses descriptors or is plain weird).
    :param bool aliases: If ``True`` patch all the attributes that have the same original value.

    :returns: An :obj:`aspectlib.Rollback` object.
    """
    rollback = Rollback()
    seen = False
    original = getattr(module, name) if original is UNSPECIFIED else original
    location = module.__name__ if hasattr(module, '__name__') else type(module).__module__
    target = module.__name__ if hasattr(module, '__name__') else type(module).__name__
    try:
        replacement.__module__ = location
    except (TypeError, AttributeError):
        pass
    for alias in dir(module):
        logdebug("alias:%s (%s)", alias, name)
        if hasattr(module, alias):
            obj = getattr(module, alias)
            logdebug("- %s:%s (%s)", obj, original, obj is original)
            if obj is original:
                if aliases or alias == name:
                    logdebug("= saving %s on %s.%s ...", replacement, target, alias)
                    setattr(module, alias, replacement)
                    rollback.merge(lambda alias=alias: setattr(module, alias, original))
                if alias == name:
                    seen = True
            elif alias == name:
                if ismethod(obj):
                    logdebug("= saving %s on %s.%s ...", replacement, target, alias)
                    setattr(module, alias, replacement)
                    rollback.merge(lambda alias=alias: setattr(module, alias, original))
                    seen = True
                else:
                    raise AssertionError("%s.%s = %s is not %s." % (module, alias, obj, original))

    if not seen:
        warnings.warn('Setting %s.%s to %s. There was no previous definition, probably patching the wrong module.' % (
            target, name, replacement
        ))
        logdebug("= saving %s on %s.%s ...", replacement, target, name)
        setattr(module, name, replacement)
        rollback.merge(lambda: setattr(module, name, original))
    return rollback


Instruction:
Write a Python 3 script for
patching a module function with a target function.

Response:
def patch_module_function(module, target, aspect, force_name=None, bag=BrokenBag, **options):
    """
    Low-level patcher for one function from a specified module.

    .. warning:: You should not use this directly.

    :returns: An :obj:`aspectlib.Rollback` object.
    """
    logdebug("patch_module_function (module=%s, target=%s, aspect=%s, force_name=%s, **options=%s",
             module, target, aspect, force_name, options)
    name = force_name or target.__name__
    return patch_module(module, name, _checked_apply(aspect, target, module=module), original=target, **options)


Instruction:
Can you generate the documentation for the following Python 3 function
def unframe(packet):

    if is_framed(packet):
        return packet.lstrip(CHR_DLE).rstrip(CHR_ETX).rstrip(CHR_DLE)
    else:
        raise ValueError('packet does not contain leading DLE and trailing DLE/ETX')

Response: Unframe a TSIP packet.


Instruction:
Can you tell what is the following Python 3 function doing
def stuff(packet):

    if is_framed(packet):
        raise ValueError('packet contains leading DLE and trailing DLE/ETX')
    else:
        return packet.replace(CHR_DLE, CHR_DLE + CHR_DLE)

Response: Add byte stuffing to TSIP packet.


Instruction:
Create a Python 3 function for
removing byte stuffing from a TSIP packet.

Response:
def unstuff(packet):
    """
    Remove byte stuffing from a TSIP packet.

    :param packet: TSIP packet with byte stuffing. The packet must already
        have been stripped or `ValueError` will be raised.
    :type packet: Binary string.
    :return: Packet without byte stuffing.

    """

    if is_framed(packet):
        raise ValueError('packet contains leading DLE and trailing DLE/ETX')
    else:
        return packet.replace(CHR_DLE + CHR_DLE, CHR_DLE)


Instruction:
Given the following Python 3 function, write the documentation
def parseFilename(filename):
    # Parse out any extension specified in filename
    _indx = filename.find('[')
    if _indx > 0:
        # Read extension name provided
        _fname = filename[:_indx]
        extn = filename[_indx+1:-1]

        # An extension was provided, so parse it out...
        if repr(extn).find(',') > 1:
            _extns = extn.split(',')
            # Two values given for extension:
            #    for example, 'sci,1' or 'dq,1'
            _extn = [_extns[0],int(_extns[1])]
        elif repr(extn).find('/') > 1:
            # We are working with GEIS group syntax
            _indx = str(extn[:extn.find('/')])
            _extn = [int(_indx)]
        elif isinstance(extn, str):
            # Only one extension value specified...
            if extn.isdigit():
                # We only have an extension number specified as a string...
                _nextn = int(extn)
            else:
                # We only have EXTNAME specified...
                _nextn = extn
            _extn = [_nextn]
        else:
            # Only integer extension number given, or default of 0 is used.
            _extn = [int(extn)]

    else:
        _fname = filename
        _extn = None
    return _fname,_extn

Response: Parse out a filename from any specified extensions.


Instruction:
Can you create a Python 3 function that
returns the shape of the data array associated with this file.

Response:
def _shape(self):
        """ Returns the shape of the data array associated with this file."""
        hdu = self.open()
        _shape = hdu.shape
        if not self.inmemory:
            self.close()
            del hdu
        return _shape


Instruction:
Write a Python 3 function for
returning the data array associated with this file and extenstion.

Response:
def _data(self):
        """ Returns the data array associated with this file/extenstion."""
        hdu = self.open()
        _data = hdu.data.copy()
        if not self.inmemory:
            self.close()
            del hdu
        return _data


Instruction:
Write a Python 3 function for
returning the shape of the data array associated with this file.

Response:
def type(self):
        """ Returns the shape of the data array associated with this file."""
        hdu = self.open()
        _type = hdu.data.dtype.name
        if not self.inmemory:
            self.close()
            del hdu
        return _type


Instruction:
Write a Python 3 script to
open the file for subsequent access.

Response:
def open(self):
        """ Opens the file for subsequent access. """

        if self.handle is None:
            self.handle = fits.open(self.fname, mode='readonly')

        if self.extn:
            if len(self.extn) == 1:
                hdu = self.handle[self.extn[0]]
            else:
                hdu = self.handle[self.extn[0],self.extn[1]]
        else:
            hdu = self.handle[0]
        if isinstance(hdu,fits.hdu.compressed.CompImageHDU):
            self.compress = True
        return hdu


Instruction:
How would you explain what the following Python 3 function does
def overlapsWith(self, targetStartTime, duration):
        targetEndTime = targetStartTime + datetime.timedelta(days=0, seconds=duration)
        return (self.startTime <= targetStartTime <= self.endTime) \
               or (targetStartTime <= self.startTime <= targetEndTime)

Response: Tests if the given times overlap with this measurement.


Instruction:
Can you tell what is the following Python 3 function doing
def updateDeviceStatus(self, deviceName, state, reason=None):
        logger.info('Updating recording device state for ' + deviceName + ' to ' + state.name +
                    ('' if reason is None else '[reason: ' + reason + ']'))
        currentState = self.recordingDevices.get(deviceName)
        count = 0
        if currentState is not None:
            if currentState['state'] == MeasurementStatus.RECORDING.name:
                count = currentState['count']
        self.recordingDevices[deviceName] = {
            'state': state.name,
            'reason': reason,
            'time': datetime.datetime.utcnow().strftime(DATETIME_FORMAT),
            'count': count
        }

Response: Updates the current status of the given device.


Instruction:
Given the following Python 3 function, write the documentation
def stillRecording(self, deviceId, dataCount):
        status = self.recordingDevices[deviceId]
        if status is not None:
            if status['state'] == MeasurementStatus.RECORDING.name:
                status['last'] = datetime.datetime.utcnow().strftime(DATETIME_FORMAT)
                status['count'] = status['count'] + dataCount

Response: Updates the last timestamp so we now when we last received data.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def inflate(self):
        if self.measurementParameters['accelerometerEnabled']:
            if len(self.data) == 0:
                logger.info('Loading measurement data for ' + self.name)
                self.data = {name: self._loadXYZ(name) for name, value in self.recordingDevices.items()}
            return True
        else:
            # TODO error handling
            return False

Response: Loads the recording into memory and returns it as a Signal


Instruction:
Make a summary of the following Python 3 code
def _sweep(self):
        while self.running:
            for am in list(self.activeMeasurements):
                now = datetime.datetime.utcnow()
                # devices were allocated and have completed == complete
                recordingDeviceCount = len(am.recordingDevices)
                if recordingDeviceCount > 0:
                    if all(entry['state'] == RecordStatus.COMPLETE.name for entry in am.recordingDevices.values()):
                        logger.info("Detected completedmeasurement " + am.id)
                        self._moveToComplete(am)

                # we have reached the end time and we have either all failed devices or no devices == kill
                if now > (am.endTime + datetime.timedelta(days=0, seconds=1)):
                    allFailed = all(entry['state'] == RecordStatus.FAILED.name
                                    for entry in am.recordingDevices.values())
                    if (recordingDeviceCount > 0 and allFailed) or recordingDeviceCount == 0:
                        logger.warning("Detected failed measurement " + am.id + " with " + str(recordingDeviceCount)
                                       + " devices, allFailed: " + str(allFailed))
                        self._moveToFailed(am)

                # we are well past the end time and we have failed devices or an ongoing recording == kill or deathbed
                if now > (am.endTime + datetime.timedelta(days=0, seconds=self.maxTimeTilDeathbedSeconds)):
                    if any(entry['state'] == RecordStatus.FAILED.name for entry in am.recordingDevices.values()):
                        logger.warning("Detected failed and incomplete measurement " + am.id + ", assumed dead")
                        self._moveToFailed(am)
                    elif all(entry['state'] == RecordStatus.RECORDING.name for entry in am.recordingDevices.values()):
                        self._handleDeathbed(am)
            time.sleep(0.1)
        logger.warning("MeasurementCaretaker is now shutdown")

Response: Sweep the activeMeasurements and check their state and passes them to the completed set if they are still running and if they are still in the deathbed set then evicts.


Instruction:
Can you generate the documentation for the following Python 3 function
def schedule(self, name, duration, startTime, description=None):
        if self._clashes(startTime, duration):
            return False, MEASUREMENT_TIMES_CLASH
        else:
            am = ActiveMeasurement(name, startTime, duration, self.targetStateProvider.state, description=description)
            logger.info("Scheduling measurement " + am.id + " for " + str(duration) + "s")
            self.activeMeasurements.append(am)
            devices = self.deviceController.scheduleMeasurement(am.id, am.duration, am.startTime)
            anyFail = False
            for device, status in devices.items():
                if status == 200:
                    deviceStatus = RecordStatus.SCHEDULED
                else:
                    deviceStatus = RecordStatus.FAILED
                    anyFail = True
                am.updateDeviceStatus(device.deviceId, deviceStatus)
            if anyFail:
                am.status = MeasurementStatus.FAILED
            else:
                if am.status is MeasurementStatus.NEW:
                    am.status = MeasurementStatus.SCHEDULED
            return True, None

Response: Schedules a new measurement with the given name.


Instruction:
Create a Python 3 function to
check that this measurement does not clash with an already scheduled measurement.

Response:
def _clashes(self, startTime, duration):
        """
        verifies that this measurement does not clash with an already scheduled measurement.
        :param startTime: the start time.
        :param duration: the duration.
        :return: true if the measurement is allowed.
        """
        return [m for m in self.activeMeasurements if m.overlapsWith(startTime, duration)]


Instruction:
How would you code a function in Python 3 to
start the measurement for the device.

Response:
def startMeasurement(self, measurementId, deviceId):
        """
        Starts the measurement for the device.
        :param deviceId: the device that is starting.
        :param measurementId: the measurement that is started.
        :return: true if it started (i.e. device and measurement exists).
        """
        am, handler = self.getDataHandler(measurementId, deviceId)
        if am is not None:
            am.status = MeasurementStatus.RECORDING
            am.updateDeviceStatus(deviceId, RecordStatus.RECORDING)
            handler.start(am.idAsPath)
            return True
        else:
            return False


Instruction:
Implement a function in Python 3 to
return the active measurement and handler for the given device

Response:
def getDataHandler(self, measurementId, deviceId):
        """
        finds the handler.
        :param measurementId: the measurement
        :param deviceId: the device.
        :return: active measurement and handler
        """
        am = next((m for m in self.activeMeasurements if m.id == measurementId), None)
        if am is None:
            return None, None
        else:
            device = self.deviceController.getDevice(deviceId)
            if device is None:
                return None, None
            else:
                return am, device.dataHandler


Instruction:
Can you write a function in Python 3 where it
passes the data to the handler.

Response:
def recordData(self, measurementId, deviceId, data):
        """
        Passes the data to the handler.
        :param deviceId: the device the data comes from.
        :param measurementId: the measurement id.
        :param data: the data.
        :return: true if the data was handled.
        """
        am, handler = self.getDataHandler(measurementId, deviceId)
        if handler is not None:
            am.stillRecording(deviceId, len(data))
            handler.handle(data)
            return True
        else:
            logger.error('Received data for unknown handler ' + deviceId + '/' + measurementId)
            return False


Instruction:
Here you have a function in Python 3, explain what it does
def completeMeasurement(self, measurementId, deviceId):
        am, handler = self.getDataHandler(measurementId, deviceId)
        if handler is not None:
            handler.stop(measurementId)
            am.updateDeviceStatus(deviceId, RecordStatus.COMPLETE)
            return True
        else:
            return False

Response: Completes the measurement session.


Instruction:
Make a summary of the following Python 3 code
def failMeasurement(self, measurementId, deviceName, failureReason=None):
        am, handler = self.getDataHandler(measurementId, deviceName)
        if handler is not None:
            am.updateDeviceStatus(deviceName, RecordStatus.FAILED, reason=failureReason)
            handler.stop(measurementId)
            return True
        else:
            return False

Response: Fail the measurement session.


Instruction:
Can you generate the documentation for the following Python 3 function
def _deleteCompletedMeasurement(self, measurementId):
        message, count, deleted = self.deleteFrom(measurementId, self.completeMeasurements)
        if count is 0:
            message, count, deleted = self.deleteFrom(measurementId, self.failedMeasurements)
        return message, count, deleted

Response: Deletes the named measurement from the completed measurement store if it exists.


Instruction:
Create a Python 3 function to
reload the completed measurements from the backing store.

Response:
def reloadCompletedMeasurements(self):
        """
        Reloads the completed measurements from the backing store.
        """
        from pathlib import Path
        reloaded = [self.load(x.resolve()) for x in Path(self.dataDir).glob('*/*/*') if x.is_dir()]
        logger.info('Reloaded ' + str(len(reloaded)) + ' completed measurements')
        self.completeMeasurements = [x for x in reloaded if x is not None and x.status == MeasurementStatus.COMPLETE]
        self.failedMeasurements = [x for x in reloaded if x is not None and x.status == MeasurementStatus.FAILED]


Instruction:
How would you explain what the following Python 3 function does
def getMeasurements(self, measurementStatus=None):
        if measurementStatus is None:
            return self.activeMeasurements + self.completeMeasurements + self.failedMeasurements
        elif measurementStatus == MeasurementStatus.COMPLETE:
            return self.completeMeasurements
        elif measurementStatus == MeasurementStatus.FAILED:
            return self.failedMeasurements
        elif measurementStatus == MeasurementStatus.DYING:
            return list(self.deathBed.keys())
        else:
            return [x for x in self.activeMeasurements if x.status == measurementStatus]

Response: Gets all available measurements.


Instruction:
How would you explain what the following Python 3 function does
def getMeasurement(self, measurementId, measurementStatus=None):
        return next((x for x in self.getMeasurements(measurementStatus) if x.id == measurementId), None)

Response: Gets the measurement with the given id.


Instruction:
How would you explain what the following Python 3 function does
def store(self, measurement):
        os.makedirs(self._getPathToMeasurementMetaDir(measurement.idAsPath), exist_ok=True)
        output = marshal(measurement, measurementFields)
        with open(self._getPathToMeasurementMetaFile(measurement.idAsPath), 'w') as outfile:
            json.dump(output, outfile)
        return output

Response: Stores the metadata of the active measurement in the database.


Instruction:
Can you generate the documentation for the following Python 3 function
def load(self, path):
        meta = self._loadMetaFromJson(path)
        return CompleteMeasurement(meta, self.dataDir) if meta is not None else None

Response: Loads a CompletedMeasurement from the path.