示例#1
0
    def editReviewer(self, sort_name, prev_index):
        '''
        select Reviewer for editing as referenced by sort_name
        '''
        if self.details_modified():
            self.saveReviewerDetails()
            
        if sort_name is None:
            return
        panelist = self.reviewers.getReviewer(str(sort_name))

        self.details_panel.setFullName(panelist.getKey('full_name'))
        self.details_panel.setSortName(panelist.getKey('name'))
        self.details_panel.setPhone(panelist.getKey('phone'))
        self.details_panel.setEmail(panelist.getKey('email'))
        self.details_panel.setNotes(panelist.getKey('notes'))
        self.details_panel.setJoined(panelist.getKey('joined'))
        self.details_panel.setUrl(panelist.getKey('URL'))

        topics_list = panelist.getTopicList()
        if len(self.details_panel.topic_list) == 0:
            self._init_topic_widgets(panelist.topics)            # need to create topic widgets first
        for topic in topics_list:
            value = panelist.getTopic(topic)
            self.details_panel.setTopic(topic, value)
        # set reviewers
        self.prior_selection_index = self.listView.currentIndex()
        self.details_panel.modified = False
        history.addLog('selected reviewer: ' + str(sort_name))
 def onTopicValueChanged(self, topic):
     ''' '''
     value = self.topic_widgets[topic].getValue()
     history.addLog("topic (" + topic + ") value changed: " + str(value))
     self.modified = True
     prop_id = str(self.getProposalId())
     self.custom_signals.topicValueChanged.emit(prop_id, str(topic), value)
示例#3
0
 def onTopicValueChanged(self, topic):
     ''' '''
     value = self.topic_widgets[topic].getValue()
     history.addLog("topic (" + topic + ") value changed: " + str(value))
     self.modified = True
     prop_id = str(self.getProposalId())
     self.custom_signals.topicValueChanged.emit(prop_id, str(topic), value)
示例#4
0
    def doOpenPrpFile(self):
        '''
        open an existing PRP file
        '''
        history.addLog('Open PRP File requested', True)
        
        if self.cannotProceed():
            if self.confirmAbandonChangesNotOk():
                return
            self.forced_exit = False    # may have been set in confirmAbandonChangesNotOk()

        flags = QtGui.QFileDialog.DontResolveSymlinks
        title = 'Open PRP file'

        prp_file = self.settings.getPrpFile()
        if len(prp_file) == 0:
            prp_path = ''
        else:
            prp_path = os.path.dirname(prp_file)

        #open_cmd = QtGui.QFileDialog.getOpenFileName
        #filename = str(open_cmd(None, title, prp_path, AGUP_OPEN_FILTER))
        filename = self.getOpenFileName(None, title, prp_path, AGUP_OPEN_FILTER)

        if os.path.exists(filename):
            self.openPrpFile(filename)
            history.addLog('selected PRP file: ' + filename)
示例#5
0
 def onTopicValueChanged(self, topic):
     ''' '''
     value = self.topic_widgets[topic].getValue()
     history.addLog("topic (" + topic + ") value changed: " + str(value))
     self.modified = True
     sort_name = str(self.getSortName())
     self.custom_signals.topicValueChanged.emit(sort_name, str(topic), value)
示例#6
0
 def doAgupInfo(self, *args, **kw):
     '''
     describe this application and where to get more info
     '''
     history.addLog('Info... box requested', False)
     # bless the Mac that it handles "about" differently
     ui = about.InfoBox(self, self.settings)    
     ui.show()
示例#7
0
    def _init_mainwindow_widget_values_(self):
        self.setPrpFileText(self.settings.getPrpFile())
        self.setRcFileText(self.settings.fileName())
        self.setReviewCycleText(self.settings.getReviewCycle())
 
        for key in sorted(self.settings.allKeys()):
            value = self.settings.getKey(key)
            history.addLog('Configuration option: %s = %s' % (key, str(value)), False)
 def onTopicValueChanged(self, topic):
     ''' '''
     value = self.topic_widgets[topic].getValue()
     history.addLog("topic (" + topic + ") value changed: " + str(value))
     self.modified = True
     sort_name = str(self.getSortName())
     self.custom_signals.topicValueChanged.emit(sort_name, str(topic),
                                                value)
示例#9
0
 def doResetDefaultSettings(self):
     '''
     user requested to reset the settings to their default values
     
     Note: does not write to the rcfile
     '''
     history.addLog('Reset to Default Settings requested', False)
     self.settings.resetDefaults()
     self.adjustMainWindowTitle()
示例#10
0
 def _handler_(self, msg_type, msg_string):
     if msg_type == QtCore.QtDebugMsg:
         adjective = 'Debug'
     elif msg_type == QtCore.QtWarningMsg:
         adjective = 'Warning'
     elif msg_type == QtCore.QtCriticalMsg:
         adjective = 'Critical'
     elif msg_type == QtCore.QtFatalMsg:
         adjective = 'Fatal'
     history.addLog('QtCore.qInstallMsgHandler-' + adjective + ': ' + msg_string)
示例#11
0
 def _handler_(self, msg_type, msg_string):
     if msg_type == QtCore.QtDebugMsg:
         adjective = 'Debug'
     elif msg_type == QtCore.QtWarningMsg:
         adjective = 'Warning'
     elif msg_type == QtCore.QtCriticalMsg:
         adjective = 'Critical'
     elif msg_type == QtCore.QtFatalMsg:
         adjective = 'Fatal'
     history.addLog('QtCore.qInstallMsgHandler-' + adjective + ': ' +
                    msg_string)
示例#12
0
 def editProposal(self, prop_id, prev_prop_index):
     '''
     select Proposal for editing as referenced by ID number
     '''
     if prop_id is None:
         return
     proposal = self.proposals.getProposal(str(prop_id))
     self.details_panel.setupProposal(proposal)
     self.prior_selection_index = self.listView.currentIndex()
     self.details_panel.modified = False
     history.addLog('selected proposal: ' + str(prop_id))
示例#13
0
    def doImportReviewers(self):
        '''
        copy the list of Reviewers into this project from another PRP Project file
        '''
        history.addLog('Import Reviewers requested', False)
        title = 'Choose a PRP Project file to copy its Reviewers'
        prp_path = os.path.dirname(self.settings.getPrpFile())

        open_cmd = QtGui.QFileDialog.getOpenFileName
        path = str(open_cmd(None, title, prp_path, AGUP_OPEN_FILTER))
        if os.path.exists(path):
            self.importReviewers(path)
示例#14
0
    def doClose(self, *args, **kw):
        '''
        called when user chooses exit (or quit), or from closeEvent()
        '''
        history.addLog('application exit requested', False)
        if self.cannotProceed():
            if self.confirmAbandonChangesNotOk():
                return

        self.saveWindowGeometry()
        self.closeSubwindows()
        self.close()
示例#15
0
 def doAutomatedAssignment(self):
     '''
     make automated assignments of reviewers to proposals
     '''
     auto_assign = auto_assignment.Auto_Assign(self.agup)
     number_changed = auto_assign.simpleAssignment()
     history.addLog('doAutomatedAssignment() complete', False)
     if number_changed > 0:
         if self.windows[PROPOSAL_VIEW] is not None:
             self.windows[PROPOSAL_VIEW].close()
             self.windows[PROPOSAL_VIEW] = None
         self.modified = True
         self.onAssignmentsChanged()
示例#16
0
    def doImportTopics(self):
        '''
        copy the list of Topics from another PRP file into this project
        '''
        history.addLog('Import Topics requested', False)
        title = 'Choose a PRP Project file to copy its Topics'
        prp_path = os.path.dirname(self.settings.getPrpFile())

        open_cmd = QtGui.QFileDialog.getOpenFileName
        filename = str(open_cmd(None, title, prp_path, AGUP_OPEN_FILTER))
        if os.path.exists(filename):
            self.importTopics(filename)
            history.addLog('imported Topics from: ' + filename)
示例#17
0
    def confirmAbandonChangesNotOk(self):
        '''
        Ask user to save changes before exit or opening another project.
        
        Return True if application should *NOT* exit.
        '''
        ret = self.requestConfirmation('The project data has changed.', 
                                    'Save the changes?', 
                                    QtGui.QMessageBox.Save 
                                   | QtGui.QMessageBox.Discard
                                   | QtGui.QMessageBox.Cancel, 
                                    QtGui.QMessageBox.Save)

        if ret == QtGui.QMessageBox.Save:
            history.addLog('Save before action proceeds')
            self.doSave()
        elif ret == QtGui.QMessageBox.Cancel:
            history.addLog('action was canceled')
            return True     # action should NOT proceed
        elif ret == QtGui.QMessageBox.Discard:
            self.forced_exit = True
            history.addLog('Discard Changes before action proceeds')
        else:
            msg = 'wrong button value from confirmAbandonChangesNotOk dialog: ' + str(ret)
            history.addLog('ValueError: ' + msg)
            raise ValueError(msg)
        return False    # application should exit
示例#18
0
 def closeEvent(self, event):
     '''
     called when user clicks the big [X] to quit
     '''
     history.addLog('application forced quit requested', False)
     if self.cannotProceed():
         if self.confirmAbandonChangesNotOk():
             event.ignore()
         else:
             self.doClose()
             event.accept()
     else:
         self.doClose()
         event.accept() # let the window close
示例#19
0
    def openPrpFile(self, filename):
        '''
        '''
        if not os.path.exists(filename):
            history.addLog('PRP File not found: ' + filename)
            return False
        self.clearAllData()
        filename = str(filename)
        self.importTopics(filename)
        self.importReviewers(filename)
        self.importProposals(filename)
        self.importEmailTemplate(filename)
        self.modified = False

        return True
示例#20
0
 def doLicense(self):
     '''show the license'''
     if self.license_box is None:
         history.addLog('opening License in new window')
         #history.addLog('DEBUG: ' + LICENSE_FILE)
         lfile = resources.resource_file(LICENSE_FILE, '.')
         #history.addLog('DEBUG: ' + lfile)
         license_text = open(lfile, 'r').read()
         #history.addLog('DEBUG: ' + license_text)
         ui = plainTextEdit.TextWindow(None, 'LICENSE', license_text,
                                       self.settings)
         ui.setMinimumSize(700, 500)
         self.license_box = ui
         #ui.setWindowModality(QtCore.Qt.ApplicationModal)
         #history.addLog('DEBUG: ' + str(ui))
     self.license_box.show()
示例#21
0
 def doEditEmailTemplate(self):
     '''
     edit the template to send emails, include editor for keyword substitutions
     '''
     import editor_email_template
     history.addLog('doEditEmailTemplate() requested', False)
     win = self.windows[window_key]
     if win is None:
         try:
             win = editor_email_template.Editor(None, self.agup, self.settings)
         except Exception:
             history.addLog(traceback.format_exc())
         self.windows[EMAIL_TEMPLATE_EDITOR] = win
         win.custom_signals.changed.connect(self.onTemplateChanged)
     else:
         win.show()
示例#22
0
    def importTopics(self, filename):
        '''read Topics from an AGUP PRP Project file and set the model accordingly'''
        try:
            self.agup.importTopics(filename)
        except Exception:
            history.addLog(traceback.format_exc())
            self.requestConfirmation(
                filename + ' was not an AGUP Project file',
                'Import Topics failed'
            )
            return

#         self.setNumTopicsWidget(len(self.agup.topics))
        self.onTopicValuesChanged('', '', 0.0)
        self.modified = True
        self.setIndicators()
        history.addLog('imported topics from: ' + filename)
示例#23
0
 def doLettersReport(self):
     '''
     prepare the email form letters to each reviewer with their assignments
     '''
     import email_mvc_view
     history.addLog('doLettersReport() requested', False)
     win = self.windows[EMAIL_REPORT]
     if win is None:
         try:
             win = email_mvc_view.AGUP_Emails_View(None, self.agup, self.settings)
             self.windows[EMAIL_REPORT] = win
             win.show()
             self.custom_signals.checkBoxGridChanged.connect(win.update)
         except Exception:
             history.addLog(traceback.format_exc())
     else:
         win.update()
         win.show()
示例#24
0
    def importReviewers(self, filename):
        '''read Reviewers from a PRP Project file and set the model accordingly'''
        try:
            self.agup.importReviewers(filename)
        except Exception as exc:
            tb = traceback.format_exc()
            history.addLog(tb)
            summary = 'Import Reviewers failed.'
            msg = os.path.basename(filename) + ': '
            msg += str(exc.message)
            self.requestConfirmation(msg, summary)

#         self.setNumTopicsWidget(len(self.agup.topics))
#         self.setNumReviewersWidget(len(self.agup.reviewers))
        self.onAssignmentsChanged()
        self.modified = True
        self.setIndicators()
        history.addLog('imported Reviewers from: ' + filename)
示例#25
0
 def doLicense(self):
     '''show the license'''
     if self.license_box is None:
         history.addLog('opening License in new window')
         #history.addLog('DEBUG: ' + LICENSE_FILE)
         lfile = resources.resource_file(LICENSE_FILE, '.')
         #history.addLog('DEBUG: ' + lfile)
         license_text = open(lfile, 'r').read()
         #history.addLog('DEBUG: ' + license_text)
         ui = plainTextEdit.TextWindow(None, 
                                       'LICENSE', 
                                       license_text, 
                                       self.settings)
         ui.setMinimumSize(700, 500)
         self.license_box = ui
         #ui.setWindowModality(QtCore.Qt.ApplicationModal)
         #history.addLog('DEBUG: ' + str(ui))
     self.license_box.show()
示例#26
0
 def doAssignmentsReport(self):
     '''
     show a read-only text page with assignments for each proposal
     '''
     import report_assignments
     history.addLog('doAssignmentsReport() requested', False)
     win = self.windows[ASSIGNMENT_REPORT]
     if win is None:
         try:
             win = report_assignments.Report(None, self.agup, self.settings)
             self.windows[ASSIGNMENT_REPORT] = win
             win.show()
             self.custom_signals.checkBoxGridChanged.connect(win.update)
         except Exception:
             history.addLog(traceback.format_exc())
     else:
         win.update()
         win.show()
示例#27
0
 def doSummaryReport(self):
     '''
     this report is helpful to balance proposal assignments
     
     show a read-only text page with how many primary and secondary proposals assigned to each reviewer
     '''
     import report_summary
     history.addLog('doSummaryReport() requested', False)
     win = self.windows[SUMMARY_REPORT]
     if win is None:
         try:
             win = report_summary.Report(None, self.agup, self.settings)
             self.windows[SUMMARY_REPORT] = win
             self.custom_signals.checkBoxGridChanged.connect(win.update)
         except Exception:
             history.addLog(traceback.format_exc())
     else:
         win.update()
         win.show()
示例#28
0
 def doAnalysis_gridReport(self):
     '''
     show a table with dotProducts for each reviewer against each proposal *and* assignments
     '''
     import report_analysis_grid
     history.addLog('doAnalysis_gridReport() requested', False)
     win = self.windows[ANALYSISGRID_REPORT]
     if win is None:
         try:
             win = report_analysis_grid.Report(None, self.agup, self.settings)
             self.windows[ANALYSISGRID_REPORT] = win
             win.show()
             self.custom_signals.checkBoxGridChanged.connect(win.update)
             self.custom_signals.topicValueChanged.connect(win.update)
         except Exception:
             history.addLog(traceback.format_exc())
     else:
         win.update()
         win.show()
示例#29
0
    def doSaveAs(self):
        '''
        save the self.agup data to the data file name selected from a dialog box
        
        You may choose any file name and extension that you prefer.
        It is strongly suggested you choose the default file extension,
        to identify AGUP PRP Project files more easily on disk.
        Multiple projects files, perhaps for different review cycles,
        can be saved in the same directory.  Or you can save each project file
        in a different directory as you choose.

        By default, the file extension will be **.agup**, indicating
        that this is an AGUP PRP Project file.  The extensions *.prp* or *.xml*
        may be used as alternatives.  Each of these describes a file with *exactly 
        the same file format*, an XML document.
        '''
        history.addLog('Save As requested', False)
        filename = self.settings.getPrpFile()
        filename = QtGui.QFileDialog.getSaveFileName(parent=self, 
                                                     caption="Save the PRP project", 
                                                     directory=filename,
                                                     filter=AGUP_filters)
        filename = os.path.abspath(str(filename))
        if len(filename) == 0:
            return
        if os.path.isdir(filename):
            history.addLog('cannot save, selected a directory: ' + filename)
            return
        if os.path.islink(filename):     # might need deeper analysis
            history.addLog('cannot save, selected a link: ' + filename)
            return
        if os.path.ismount(filename):
            history.addLog('cannot save, selected a mount point: ' + filename)
            return

        self.agup.write(filename)
        self.setPrpFileText(filename)
        self.modified = False
        for w in (self.windows[PROPOSAL_VIEW], self.windows[REVIEWER_VIEW]):
            if w is not None:
                w.details_panel.modified = False
        history.addLog('saved: ' + filename)
        self.adjustMainWindowTitle()
示例#30
0
    def doUnassignProposals(self):
        '''
        Remove ALL assignments of reviewers to proposals
        '''
        history.addLog('doUnassignProposals() requested', False)
        ret = self.requestConfirmation('Remove ALL assignments of reviewers to proposals', 
                                    'Remove ALL?', 
                                    QtGui.QMessageBox.Ok
                                    | QtGui.QMessageBox.Cancel, 
                                    QtGui.QMessageBox.Cancel)
        if ret == QtGui.QMessageBox.Cancel:
            history.addLog('doUnassignProposals() was canceled', False)
            return

        counter = 0
        for prop in self.agup.proposals:
            for full_name, value in prop.eligible_reviewers.items():
                if value is not None:
                    prop.eligible_reviewers[full_name] = None
                    counter += 1
        if counter == 0:
            msg = 'no assignments to be removed'
        else:
            msg = str(counter)
            msg += ' assignment'
            if counter > 1:
                msg += 's'
            msg += ' removed'
            self.modified = True
        history.addLog(msg)
        if self.windows[PROPOSAL_VIEW] is not None:
            self.windows[PROPOSAL_VIEW].close()
            self.windows[PROPOSAL_VIEW] = None
        self.onAssignmentsChanged()
示例#31
0
    def saveReviewerDetails(self):
        '''
        copied Reviewer details from editor panel to main data structure
        '''
        sort_name = str(self.details_panel.getSortName())
        if len(sort_name) == 0:
            return
        panelist = self.reviewers.getReviewer(sort_name)    # raises IndexError if not found

        kv = dict(
            full_name=self.details_panel.getFullName,
            name=self.details_panel.getSortName,
            phone=self.details_panel.getPhone,
            email=self.details_panel.getEmail,
            notes=self.details_panel.getNotes,
            joined=self.details_panel.getJoined,
            URL=self.details_panel.getUrl,
        )
        for k, v in kv.items():
            panelist.setKey(k, v())
        history.addLog('saved reviewer details: ' + sort_name)
        self.details_panel.modified = False
示例#32
0
    def doNewPrpFile(self):
        '''
        clear the data in self.agup
        '''
        history.addLog('New PRP File requested', False)

        if self.cannotProceed():
            ret = self.requestConfirmation('There are unsaved changes.', 
                                        'Forget about them?', 
                                        QtGui.QMessageBox.Ok
                                        | QtGui.QMessageBox.Cancel, 
                                        QtGui.QMessageBox.Cancel)
            if ret == QtGui.QMessageBox.Cancel:
                return

        self.closeSubwindows()
        #self.agup.clearAllData()        # TODO: Why not make a new self.agup object?
        self.agup = agup_data.AGUP_Data(self, self.settings)
        self.modified = False
        self.setPrpFileText('')
        self.setIndicators()
        history.addLog('New PRP File')
        self.adjustMainWindowTitle()
示例#33
0
    def __init__(self):
        self.settings = settings.ApplicationQSettings()
        self.agup = agup_data.AGUP_Data(self, self.settings)

        QtGui.QMainWindow.__init__(self)
        resources.loadUi(UI_FILE, baseinstance=self)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.main_window_title = self.windowTitle()
        self.restoreWindowGeometry()

        self.modified = False
        self.forced_exit = False

        # keep these objects in a dictionary to simplify admin
        self.windows = {}
        self.windows[ANALYSISGRID_REPORT] = None
        self.windows[ASSIGNMENT_REPORT] = None
        self.windows[EMAIL_REPORT] = None
        self.windows[EMAIL_TEMPLATE_EDITOR] = None
        self.windows[PROPOSAL_VIEW] = None
        self.windows[REVIEWER_VIEW] = None
        self.windows[SUMMARY_REPORT] = None

        self._init_history_()
        history.addLog('loaded "' + UI_FILE + '"', False)

        self.custom_signals = signals.CustomSignals()

        self._init_mainwindow_widget_values_()
        self._init_connections_()
        
        filename = self.settings.getPrpFile()
        if os.path.exists(filename):
            self.openPrpFile(filename)

        self.modified = False
        self.adjustMainWindowTitle()
示例#34
0
    def importProposals(self, filename):
        '''read a proposals XML file and set the model accordingly'''
        try:
            self.agup.importProposals(filename)
        except Exception as exc:
            tb = traceback.format_exc()
            history.addLog(tb)
            summary = 'Import Proposals failed.'
            msg = os.path.basename(filename) + ': '
            msg += str(exc.message)
            self.requestConfirmation(msg, summary)

        # ensure each imported proposal has the correct Topics
        for prop in self.agup.proposals:
            added, removed = self.agup.topics.diff(prop.topics)
            prop.addTopics(added)
            prop.removeTopics(removed)
        
        self.modified = True
        self.setIndicators()
        history.addLog('imported Proposals from: ' + filename)

        if self.getReviewCycleText() == '':
            self.setReviewCycleText(self.agup.proposals.cycle)
示例#35
0
    def doImportProposals(self):
        '''
        import the proposal file as downloaded from the APS web site
        '''
        history.addLog('Import Proposals requested', False)
        title = 'Choose XML file with proposals'
        prp_path = os.path.dirname(self.settings.getPrpFile())

        open_cmd = QtGui.QFileDialog.getOpenFileName
        path = str(open_cmd(None, title, prp_path, "Proposals (*.xml)"))
        if os.path.exists(path):
            history.addLog('selected file: ' + path, False)
            self.importProposals(path)
            history.addLog('imported proposals file: ' + path)
示例#36
0
 def doIssuesUrl(self):
     '''opening issues URL in default browser'''
     history.addLog('opening issues URL in default browser')
     self.doUrl(ISSUES_URL)
示例#37
0
 def doDocsUrl(self):
     '''opening documentation URL in default browser'''
     history.addLog('opening documentation URL in default browser')
     self.doUrl(DOCS_URL)
示例#38
0
 def update(self):
     """
     """
     text = self.makeText()
     self.setText(text)
     history.addLog(self.__class__.__name__ + ".update()", False)
示例#39
0
 def update(self):
     ''' '''
     history.addLog(self.__class__.__name__ + '.update()', False)
示例#40
0
 def update(self):
     ''' '''
     # TODO: update the checkboxes
     history.addLog(self.__class__.__name__ + '.update()', False)
示例#41
0
 def update(self):
     ''' '''
     text = self.makeText()
     self.setText(text)
     history.addLog(self.__class__.__name__ + '.update()', False)
示例#42
0
 def update(self):
     ''' '''
     history.addLog(self.__class__.__name__ + '.update()', False)
     grid = self.reviewers_gb.layout()
示例#43
0
    def simpleAssignment(self):
        '''
        assign the first two reviewers with the highest scores to *unassigned* proposals
        
        * no attempt to balance assignment loads in this procedure
        * score must be above zero to qualify
        '''
        def sort_reviewers(scores):
            '''
            order the reviewers by score on this proposal
            '''
            xref = {}
            for who, score in scores.items():
                if score not in xref:
                    xref[score] = []
                xref[score].append(who)
            name_list = []
            for s, names in sorted(xref.items(), reverse=True):
                if s > 0:
                    name_list += names
            return name_list
        
        counter = 0
        for prop in self.agup.proposals:
            # check for any existing assignments
            assigned = prop.getAssignedReviewers()
            if None not in assigned:
                continue    # all assigned, skip this proposal

            scores = self.getScores(prop)
            
            # mark existing assigned reviewers to exclude further consideration, this round
            for role, full_name in enumerate(assigned):
                if full_name in prop.eligible_reviewers:
                    scores[full_name] = SCORE_ALREADY_ASSIGNED
            
            # order the reviewers by score on this proposal
            for full_name in sort_reviewers(scores):
                role = None
                if assigned[0] is None:
                    role = 0
                elif assigned[1] is None:
                    role = 1
                else:
                    break
                if role is not None:
                    assigned[role] = full_name
                    counter += 1
                if None not in assigned:
                    break    # all assigned, move to next proposal
            
            for role, full_name in enumerate(assigned):
                prop.eligible_reviewers[full_name] = role + 1

        msg = 'Auto_Assign.simpleAssignment: '
        msg += str(counter)
        msg += ' assignment'
        if counter > 1:
            msg += 's'
        history.addLog(msg)
        return counter
示例#44
0
 def update(self):
     # not called
     history.addLog(self.__class__.__name__ + '.update()', False)