コード例 #1
0
ファイル: user_config.py プロジェクト: jstnlth/rapuma
class UserConfig(object):
    def __init__(self):
        """Intitate the whole class and create the object."""

        self.rapumaHome = os.environ.get("RAPUMA_BASE")
        self.defaultUserHome = os.environ.get("RAPUMA_USER")
        self.userConfFileName = "rapuma.conf"
        self.tools = Tools()

        # Point to the right user config
        # Look for a web installation first, if not go to default
        # Note that a slash is put before var as it is off of root
        # That kind of stops this from being cross-platform
        rapumaWebConfig = os.path.join("/var", "lib", "rapuma", "config", self.userConfFileName)
        defaultConfig = os.path.join(self.defaultUserHome, self.userConfFileName)
        if os.path.exists(rapumaWebConfig):
            self.userConfFile = rapumaWebConfig
        else:
            self.userConfFile = defaultConfig

        # Check to see if the file is there, then read it in and break it into
        # sections. If it fails, scream really loud!
        rapumaXMLDefaults = os.path.join(self.rapumaHome, "config", "rapuma.xml")
        if os.path.exists(rapumaXMLDefaults):
            self.tools.sysXmlConfig = self.tools.xml_to_section(rapumaXMLDefaults)
        else:
            raise IOError, "Can't open " + rapumaXMLDefaults

        #        import pdb; pdb.set_trace()

        # Now make the users local rapuma.conf file if it isn't there
        if not os.path.exists(self.userConfFile):
            self.initUserHome()

        # Load the Rapuma conf file into an object
        self.userConfig = ConfigObj(self.userConfFile, encoding="utf-8")

        # Initialize the user's home folders, like resources, etc
        self.makeHomeFolders()

        # Log messages for this module
        self.errorCodes = {"0000": ["MSG", "Placeholder message"]}

    ###############################################################################
    ############################ User Config Functions ############################
    ###############################################################################

    def initUserHome(self):
        """Initialize a user config file on a new install or system re-init."""

        # Create home folders
        if not os.path.isdir(self.defaultUserHome):
            os.mkdir(self.defaultUserHome)

        # Make the default global rapuma.conf for custom environment settings
        if not os.path.isfile(self.userConfFile):
            self.userConfig = ConfigObj(self.tools.sysXmlConfig.dict(), encoding="utf-8")
            self.userConfig.filename = self.userConfFile
            self.userConfig["System"]["initDate"] = self.tools.tStamp()
            self.userConfig.write()

    def setSystemSettings(self, section, key, value):
        """Function to make system settings."""

        oldValue = self.userConfig[section][key]
        if oldValue != value:
            self.userConfig[section][key] = value
            # Write out the results
            self.userConfig.write()
            self.tools.terminal("\nRapuma user name setting changed from [" + oldValue + "] to [" + value + "].\n\n")
        else:
            self.tools.terminal("\nSame value given, nothing to changed.\n\n")

    def makeHomeFolders(self):
        """Setup the default Rapuma resource folders."""

        #        import pdb; pdb.set_trace()

        # We do not write out unless this flag is set
        confWriteFlag = False

        # Setup Resources section if needed
        if not self.userConfig.has_key("Resources"):
            self.tools.buildConfSection(self.userConfig, "Resources")

        # Get the user config project folder location (or set a default)
        if not self.userConfig["Resources"].has_key("projects") or not self.userConfig["Resources"]["projects"]:
            projects = os.path.join(os.environ.get("HOME"), "Publishing")
            if not os.path.exists(projects):
                os.makedirs(projects)
            self.userConfig["Resources"]["projects"] = projects
            confWriteFlag = True
        elif not os.path.exists(self.tools.resolvePath(self.userConfig["Resources"]["projects"])):
            sys.exit(
                "\nERROR: Invalid projects folder path: "
                + self.userConfig["Resources"]["projects"]
                + "\n\nProcess halted.\n"
            )
        else:
            projects = self.tools.resolvePath(self.userConfig["Resources"]["projects"])

        # Note: The following was commented because it no longer is necessary to load in locations
        # for various resouces. That will be dynamically. If the program ever reaches the point
        # where this would be good to have, it can be handled by a GUI. (djd - 20160223)

        #        # Get the user config Rapuma resource folder location
        #        if not self.userConfig['Resources'].has_key('rapumaResource') :
        #            # Check for pre-typo-fix value ('rapumaResouce') before creating new section
        #            if self.userConfig['Resources'].has_key('rapumaResouce') :
        #                self.userConfig['Resources'].rename('rapumaResouce', 'rapumaResource')
        #                confWriteFlag = True
        #            else:
        #                self.tools.buildConfSection(self.userConfig['Resources'], 'rapumaResource')
        #                confWriteFlag = True
        #        if len(self.userConfig['Resources']['rapumaResource']) > 0 :
        #            rapumaResource = self.userConfig['Resources']['rapumaResource']
        #        else :
        #            # This is the default location
        #            rapumaResource = os.path.join(site.USER_BASE, 'share', 'rapuma')
        #            self.userConfig['Resources']['rapumaResource'] = rapumaResource
        #            confWriteFlag = True

        #        # Make a list of sub-folders to make in the Rapuma resourcs folder
        #        resourceFolders = ['archive', 'backup', 'font', 'illustration', \
        #                            'macro','script', 'template']

        #        for r in resourceFolders :
        #            # Build the path and check if it can be made
        #            thisPath = os.path.join(rapumaResource, r)
        #            if not os.path.isdir(thisPath) :
        #                os.makedirs(thisPath)
        #            self.userConfig['Resources'][r] = thisPath
        #            confWriteFlag = True

        # Write out if needed
        if confWriteFlag:
            self.userConfig.write()
        return True
コード例 #2
0
ファイル: usfm.py プロジェクト: jstnlth/rapuma
class Usfm (Group) :
    '''This class contains information about a type of component 
    used in a type of project.'''

    # Shared values
    xmlConfFile     = 'usfm.xml'

    def __init__(self, project, cfg) :
        super(Usfm, self).__init__(project, cfg)

#        import pdb; pdb.set_trace()

        # Set values for this manager
        self.pid                    = project.projectIDCode
        self.gid                    = project.gid
        self.cType                  = 'usfm'
        self.Ctype                  = self.cType.capitalize()
        self.project                = project
        self.local                  = project.local
        self.tools                  = Tools()
        self.proj_font              = ProjFont(self.pid)
        self.proj_illustration      = ProjIllustration(self.pid, self.gid)
        self.proj_config            = Config(self.pid, self.gid)
        self.proj_config.getProjectConfig()
        self.proj_config.getAdjustmentConfig()
        self.projectConfig          = self.proj_config.projectConfig
        self.adjustmentConfig       = self.proj_config.adjustmentConfig
        self.log                    = project.log
        self.cfg                    = cfg
        self.mType                  = project.projectMediaIDCode
        self.renderer               = project.projectConfig['CompTypes'][self.Ctype]['renderer']
        self.sourceEditor           = project.projectConfig['CompTypes'][self.Ctype]['sourceEditor']
        self.macPackId              = project.projectConfig['CompTypes'][self.Ctype]['macroPackage']
        # Get the comp settings
        self.compSettings           = project.projectConfig['CompTypes'][self.Ctype]
        # Build a tuple of managers this component type needs to use
        self.usfmManagers = ('text', self.renderer)

        # Init the general managers
        for self.mType in self.usfmManagers :
            self.project.createManager(self.mType)

        # Create the internal ref names we use in this module
        self.text                   = self.project.managers[self.cType + '_Text']
        # File names

        # Folder paths
        self.projScriptFolder       = self.local.projScriptFolder
        self.projComponentFolder    = self.local.projComponentFolder
        self.gidFolder              = os.path.join(self.projComponentFolder, self.gid)
        # File names with folder paths
        self.rapumaXmlCompConfig    = os.path.join(self.project.local.rapumaConfigFolder, self.xmlConfFile)



        # Get persistant values from the config if there are any
        newSectionSettings = self.tools.getPersistantSettings(self.projectConfig['CompTypes'][self.Ctype], self.rapumaXmlCompConfig)
        if newSectionSettings != self.projectConfig['CompTypes'][self.Ctype] :
            self.projectConfig['CompTypes'][self.Ctype] = newSectionSettings
        # Set them here
        for k, v in self.compSettings.iteritems() :
            setattr(self, k, v)

        # Module Error Codes
        self.errorCodes     = {

            #'USFM-000' : ['MSG', 'Messages for the USFM module.'],
            #'USFM-005' : ['MSG', 'Unassigned error message ID.'],
            #'USFM-010' : ['ERR', 'Could not process character pair. This error was found: [<<1>>]. Process could not complete. - usfm.pt_tools.getNWFChars()'],
            #'USFM-020' : ['ERR', 'Improper character pair found: [<<1>>].  Process could not complete. - usfm.pt_tools.getNWFChars()'],
            #'USFM-025' : ['WRN', 'No non-word-forming characters were found in the PT settings file. - usfm.pt_tools.getNWFChars()'],
            #'USFM-040' : ['ERR', 'Hyphenation source file not found: [<<1>>]. Process halted!'],
            #'USFM-080' : ['LOG', 'Normalizing Unicode text to the [<<1>>] form.'],
            #'USFM-090' : ['ERR', 'USFM file: [<<1>>] did NOT pass the validation test. Because of an encoding conversion, the terminal output is from the file [<<2>>]. Please only edit [<<1>>].'],
            #'USFM-095' : ['WRN', 'Validation for USFM file: [<<1>>] was turned off.'],
            #'USFM-100' : ['MSG', 'Source file editor [<<1>>] is not recognized by this system. Please double check the name used for the source text editor setting.'],
            #'USFM-110' : ['ERR', 'Source file name could not be built because the Name Form ID for [<<1>>] is missing or incorrect. Double check to see which editor created the source text.'],
            #'USFM-120' : ['ERR', 'Source file: [<<1>>] not found! Cannot copy to project. Process halting now.'],
            #'USFM-130' : ['ERR', 'Failed to complete preprocessing on component [<<1>>]'],
            #'USFM-140' : ['MSG', 'Completed installation on [<<1>>] component working text.'],
            #'USFM-150' : ['ERR', 'Unable to copy [<<1>>] to [<<2>>] - error in text.'],

            '0010' : ['LOG', 'Created the [<<1>>] master adjustment file.'],
            '0220' : ['ERR', 'Cannot find: [<<1>>] working file, unable to complete preprocessing for rendering.'],
            '0230' : ['LOG', 'Created the [<<1>>] component adjustment file.'],
            '0240' : ['LOG', 'Could not find adjustments section for [<<1>>], created place holder setting.'],
            '0245' : ['LOG', 'Could not find adjustments for [<<1>>]. No ajustment file has been output.'],
            '0255' : ['LOG', 'Illustrations not being used. The piclist file has been removed from the [<<1>>] illustrations folder.'],
            '0260' : ['LOG', 'Piclist file for [<<1>>] has been created.'],
            '0265' : ['ERR', 'Failed to create piclist file for [<<1>>]!'],
            '0300' : ['ERR', 'One or more illustration files are missing from the project. Please import these files before continuing.']
        }


###############################################################################
############################ Functions Begin Here #############################
###############################################################################
######################## Error Code Block Series = 0200 #######################
###############################################################################

    def makeFileName(self, cid) :
        '''From what we know, return the full file name.'''

        # FIXME: We default this to "base" but for a diglot implementation
        # this is not going to work because we need to have a second
        # file name. Cross that bridge...

        return cid + '_base'


    def makeFileNameWithExt(self, cid) :
        '''From what we know, return the full file name.'''

        return self.makeFileName(cid) + '.' + self.cType


    def getCidPath (self, cid) :
        '''Return the full path of the cName working text file. This assumes
        the cid is valid.'''

        return os.path.join(self.local.projComponentFolder, cid, self.makeFileNameWithExt(cid))


    def getCidAdjPath (self, cid) :
        '''Return the full path of the cName working text adjustments file. 
        This assumes the cName is valid. Note that all macro packages that have
        a manual adjustment feature must use this naming scheme. The name syntax
        comes from the "mother" macro package which is ptx2pdf.'''

        return os.path.join(self.local.projComponentFolder, cid, self.makeFileNameWithExt(cid) + '.adj')


    def render(self, gid, cidList, pages, override, save) :
        '''Does USFM specific rendering of a USFM component'''

#        import pdb; pdb.set_trace()

        # If the whole group is being rendered, we need to preprocess it
        cids = []
        if not cidList :
            cids = self.projectConfig['Groups'][gid]['cidList']
        else :
            cids = cidList

        # Preprocess all subcomponents (one or more)
        # Stop if it breaks at any point
        for cid in cids :
            if not self.preProcessGroup(gid, [cid]) :
                return False

        # With everything in place we can render the component.
        # Note: We pass the cidList straight through
        self.project.managers['usfm_' + self.renderer.capitalize()].run(gid, cidList, pages, override, save)

        return True


    def preProcessGroup (self, gid, cidList) :
        '''This will prepare a component group for rendering by checking for
        and/or creating any dependents it needs to render properly.'''

#        import pdb; pdb.set_trace()

        # Get some relevant settings
        # FIXME: Note page border has not really been implemented yet.
        # It is different from backgound management
        useIllustrations        = self.tools.str2bool(self.projectConfig['Groups'][gid]['useIllustrations'])
        useManualAdjustments    = self.tools.str2bool(self.projectConfig['Groups'][gid]['useManualAdjustments'])

        # See if the working text is present for each subcomponent in the
        # component and try to install it if it is not
        for cid in cidList :
            cType = self.cfg['cType']
            cidUsfm = self.getCidPath(cid)
            # Test for source here and die if it isn't there
            if not os.path.isfile(cidUsfm) :
                self.log.writeToLog(self.errorCodes['0220'], [cidUsfm], 'usfm.preProcessGroup():0220')
            # Add/manage the dependent files for this cid

# FIXME: Some changes may be needed here to guide creation of adjustment files
            # Component adjustment file
            cidAdjFile = self.getCidAdjPath(cid)
            if useManualAdjustments :
                self.createCompAdjustmentFile(cid)
            else :
                # If no adjustments, remove any exsiting file
                if os.path.isfile(cidAdjFile) :
                    os.remove(cidAdjFile)
            # Component piclist file
            cidPiclistFile = self.proj_illustration.getCidPiclistFile(cid)
            if useIllustrations :
                if self.proj_illustration.hasIllustrations(cid) :
                    # Check for missing illustrations (die here if not found)
                    if self.proj_illustration.missingIllustrations(cid) :
                        self.log.writeToLog(self.errorCodes['0300'])
                    # Create piclist file if not there or if the config has changed
                    if not os.path.isfile(cidPiclistFile) or self.tools.isOlder(cidPiclistFile, self.local.illustrationConfFile) :
                        # Now make a fresh version of the piclist file
                        if self.proj_illustration.createPiclistFile(cid) :
                            self.log.writeToLog(self.errorCodes['0260'], [cid])
                        else :
                            self.log.writeToLog(self.errorCodes['0265'], [cid])
                    else :
                        for f in [self.local.layoutConfFile, self.local.illustrationConfFile] :
                            if self.tools.isOlder(cidPiclistFile, f) or not os.path.isfile(cidPiclistFile) :
                                # Remake the piclist file
                                if self.proj_illustration.createPiclistFile(cid) :
                                    self.log.writeToLog(self.errorCodes['0260'], [cid])
                                else :
                                    self.log.writeToLog(self.errorCodes['0265'], [cid])
                else :
                    # Does not seem to be any illustrations for this cid
                    # clean out any piclist file that might be there
                    if os.path.isfile(cidPiclistFile) :
                        os.remove(cidPiclistFile)
            else :
                # If we are not using illustrations then any existing piclist file will be removed
                if os.path.isfile(cidPiclistFile) :
                    os.remove(cidPiclistFile)
                    self.log.writeToLog(self.errorCodes['0255'], [cid])

        # Any more stuff to run?

        return True

# FIXME: Moved this to xetex.py as that was the only place it was called from
    #def checkStartPageNumber (self) :
        #'''Adjust page number for the current group. The current logic is
        #if there is no number in the startPageNumber setting, we can put
        #one in there as a suggestion. If there is already one there, the
        #user will be responsible for seeing that it is correct.'''

##        import pdb; pdb.set_trace()

        #try :
            ## Simply try to return anything that is in the field
            #cStrPgNo = self.projectConfig['Groups'][self.gid]['startPageNumber']
            #if cStrPgNo != '' :
                #return cStrPgNo
        #except :
            ## If nothing is there, we'll make a suggestion
            #pGrp = str(self.projectConfig['Groups'][self.gid]['precedingGroup'])
            #if pGrp == 'None' :
                #self.projectConfig['Groups'][self.gid]['startPageNumber'] = 1
                #self.tools.writeConfFile(self.projectConfig)
                #return '1'
            #else :
                ## Calculate the suggested number based on the preceeding group
                #try :
                    #cStrPgNo    = str(self.projectConfig['Groups'][self.gid]['startPageNumber'])
                #except :
                    #cStrPgNo    = 1
                    #self.projectConfig['Groups'][self.gid]['startPageNumber'] = 1
                #try :
                    #pGrpPgs     = int(self.projectConfig['Groups'][pGrp]['totalPages'])
                    #pGrpStrPgNo = int(self.projectConfig['Groups'][pGrp]['startPageNumber'])
                #except :
                    ## FIXME: Maybe this could go out and find out exactly how many pages were in the preceeding group
                    #pGrpPgs     = 1
                    #pGrpStrPgNo = 1
                    #self.projectConfig['Groups'][pGrp]['totalPages'] = 1
                    #self.projectConfig['Groups'][pGrp]['startPageNumber'] = 1
                ## Whether this is right or wrong set it the way it is
                #self.projectConfig['Groups'][self.gid]['startPageNumber'] = (pGrpStrPgNo + pGrpPgs)
                #self.tools.writeConfFile(self.projectConfig)
                #return self.projectConfig['Groups'][pGrp]['startPageNumber']


    def createCompAdjustmentFile (self, cid) :
        '''Create an adjustment file for this cid. If entries exsist in
        the adjustment.conf file.'''

        description = 'Auto-generated text adjustments file for: ' + cid + '\n'

#        import pdb; pdb.set_trace()

        # Check for a master adj conf file
        if os.path.exists(self.local.adjustmentConfFile) :
            adjFile = self.getCidAdjPath(cid)
            # Clean up old file if there is one so we can start fresh
            if os.path.exists(adjFile) :
                os.remove(adjFile)
            # Nothing to do if no gid section is found
            if not self.adjustmentConfig.has_key(self.gid) :
                self.tools.buildConfSection(self.adjustmentConfig, self.gid)
            if not self.adjustmentConfig[self.gid].has_key(cid) :
                self.tools.buildConfSection(self.adjustmentConfig[self.gid], cid)
                self.adjustmentConfig[self.gid][cid]['%1.1'] = '1'
                self.tools.writeConfFile(self.adjustmentConfig)
                self.log.writeToLog(self.errorCodes['0240'], [cid])
                return False
            # Sort through commented adjustment lines ()
            if self.adjustmentConfig[self.gid].has_key(cid) :
                c = False
                for k in self.adjustmentConfig[self.gid][cid].keys() :
                    if not re.search(r'%|#', k) :
                        c = True
                if not c :
                    self.log.writeToLog(self.errorCodes['0245'], [cid])
                    return False
            # If we make it this far, create the new adjustment file
            with codecs.open(adjFile, "w", encoding='utf_8') as writeObject :
                writeObject.write(self.tools.makeFileHeader(adjFile, description, True))
                # Output like this: JAS 1.13 +1
                for k, v in self.adjustmentConfig[self.gid][cid].iteritems() :
                    if re.search(r'%|#', k) :
                        continue
                    adj = v
                    if int(v) > 0 : 
                        adj = '+' + str(v)
                    writeObject.write(cid.upper() + ' ' + k + ' ' + adj + '\n')

                self.log.writeToLog(self.errorCodes['0230'], [self.tools.fName(adjFile)])

            return True


    def createProjAdjustmentConfFile (self) :
        '''Create a project master component adjustment file that group component
        ajustment files will be created automatically from. This will run every 
        time preprocess is run but after the first time it will only add a sections
        for new groups or components.'''

        if not os.path.exists(self.adjustmentConfFile) :
            self.adjustmentConfig = ConfigObj(self.adjustmentConfFile, encoding='utf-8')
            self.adjustmentConfig.filename = self.adjustmentConfFile
            self.updateCompAdjustmentConf()
        return True


    def updateCompAdjustmentConf (self) :
        '''Update an adjustmentConfig based on changes in the projectConfig.'''

        for gid in self.projectConfig['Groups'].keys() :
            if gid not in self.adjustmentConfig.keys() :
                self.tools.buildConfSection(self.adjustmentConfig, gid)
            for comp in self.projectConfig['Groups'][gid]['cidList'] :
                if not self.adjustmentConfig[gid].has_key(comp) :
                    self.tools.buildConfSection(self.adjustmentConfig[gid], comp)
                self.adjustmentConfig[gid][comp]['%1.1'] = '1'
        self.tools.writeConfFile(self.adjustmentConfig)
        return True


###############################################################################
######################## USFM Component Text Functions ########################
###############################################################################
######################## Error Code Block Series = 0400 #######################
###############################################################################


    def getComponentType (self, gid) :
        '''Return the cType for a component.'''

#        import pdb; pdb.set_trace()

        try :
            cType = self.projectConfig['Groups'][gid]['cType']
        except Exception as e :
            # If we don't succeed, we should probably quite here
            self.log.writeToLog('COMP-200', ['Key not found ' + str(e)])
            self.tools.dieNow()

        return cType


    def isCompleteComponent (self, gid, cid) :
        '''A two-part test to see if a component has a config entry and a file.'''

        if self.hasCidFile(gid, cid) :
            return True


    def hasUsfmCidInfo (self, cid) :
        '''Return True if this cid is in the PT USFM cid info dictionary.'''

        if cid in self.usfmCidInfo().keys() :
            return True


    def hasCidFile (self, gid, cid) :
        '''Return True or False depending on if a working file exists 
        for a given cName.'''

        cType = self.projectConfig['Groups'][gid]['cType']
        return os.path.isfile(os.path.join(self.local.projComponentFolder, cid, cid + '.' + cType))


    def usfmCidInfo (self) :
        '''Return a dictionary of all valid information about USFMs used in PT. Note
        that a couple special non-standard IDs have been added at the top of the list.'''

    #            ID     Comp Name                               Comp ID                         PT ID  Chps
        return {
                '_z_' : ['USFM InternalCaller',                 'usfm_internal_caller',         '00',   0], 
                'gen' : ['Genesis',                             'genesis',                      '01',  50], 
                'exo' : ['Exodus',                              'exodus',                       '02',  40], 
                'lev' : ['Leviticus',                           'leviticus',                    '03',  27], 
                'num' : ['Numbers',                             'numbers',                      '04',  36], 
                'deu' : ['Deuteronomy',                         'deuteronomy',                  '05',  34], 
                'jos' : ['Joshua',                              'joshua',                       '06',  24], 
                'jdg' : ['Judges',                              'judges',                       '07',  21], 
                'rut' : ['Ruth',                                'ruth',                         '08',   4], 
                '1sa' : ['1 Samuel',                            '1_samuel',                     '09',  31], 
                '2sa' : ['2 Samuel',                            '2_samuel',                     '10',  24], 
                '1ki' : ['1 Kings',                             '1_kings',                      '11',  22], 
                '2ki' : ['2 Kings',                             '2_kings',                      '12',  25], 
                '1ch' : ['1 Chronicles',                        '1_chronicles',                 '13',  29], 
                '2ch' : ['2 Chronicles',                        '2_chronicles',                 '14',  36], 
                'ezr' : ['Ezra',                                'ezra',                         '15',  10], 
                'neh' : ['Nehemiah',                            'nehemiah',                     '16',  13], 
                'est' : ['Esther',                              'esther',                       '17',  10], 
                'job' : ['Job',                                 'job',                          '18',  42], 
                'psa' : ['Psalms',                              'psalms',                       '19', 150], 
                'pro' : ['Proverbs',                            'proverbs',                     '20',  31], 
                'ecc' : ['Ecclesiastes',                        'ecclesiastes',                 '21',  12], 
                'sng' : ['Song of Songs',                       'song_of_songs',                '22',   8], 
                'isa' : ['Isaiah',                              'isaiah',                       '23',  66], 
                'jer' : ['Jeremiah',                            'jeremiah',                     '24',  52], 
                'lam' : ['Lamentations',                        'lamentations',                 '25',   5], 
                'ezk' : ['Ezekiel',                             'ezekiel',                      '26',  48], 
                'dan' : ['Daniel',                              'daniel',                       '27',  12], 
                'hos' : ['Hosea',                               'hosea',                        '28',  14], 
                'jol' : ['Joel',                                'joel',                         '29',   3], 
                'amo' : ['Amos',                                'amos',                         '30',   9], 
                'oba' : ['Obadiah',                             'obadiah',                      '31',   1], 
                'jon' : ['Jonah',                               'jonah',                        '32',   4], 
                'mic' : ['Micah',                               'micah',                        '33',   7], 
                'nam' : ['Nahum',                               'nahum',                        '34',   3], 
                'hab' : ['Habakkuk',                            'habakkuk',                     '35',   3], 
                'zep' : ['Zephaniah',                           'zephaniah',                    '36',   3], 
                'hag' : ['Haggai',                              'haggai',                       '37',   2], 
                'zec' : ['Zechariah',                           'zechariah',                    '38',  14], 
                'mal' : ['Malachi',                             'malachi',                      '39',   4],
                'mat' : ['Matthew',                             'matthew',                      '41',  28], 
                'mrk' : ['Mark',                                'mark',                         '42',  16], 
                'luk' : ['Luke',                                'luke',                         '43',  24], 
                'jhn' : ['John',                                'john',                         '44',  21], 
                'act' : ['Acts',                                'acts',                         '45',  28], 
                'rom' : ['Romans',                              'romans',                       '46',  16], 
                '1co' : ['1 Corinthians',                       '1_corinthians',                '47',  16], 
                '2co' : ['2 Corinthians',                       '2_corinthians',                '48',  13], 
                'gal' : ['Galatians',                           'galatians',                    '49',   6], 
                'eph' : ['Ephesians',                           'ephesians',                    '50',   6], 
                'php' : ['Philippians',                         'philippians',                  '51',   4], 
                'col' : ['Colossians',                          'colossians',                   '52',   4], 
                '1th' : ['1 Thessalonians',                     '1_thessalonians',              '53',   5], 
                '2th' : ['2 Thessalonians',                     '2_thessalonians',              '54',   3], 
                '1ti' : ['1 Timothy',                           '1_timothy',                    '55',   6], 
                '2ti' : ['2 Timothy',                           '2_timothy',                    '56',   4], 
                'tit' : ['Titus',                               'titus',                        '57',   3], 
                'phm' : ['Philemon',                            'philemon',                     '58',   1], 
                'heb' : ['Hebrews',                             'hebrews',                      '59',  13], 
                'jas' : ['James',                               'james',                        '60',   5], 
                '1pe' : ['1 Peter',                             '1_peter',                      '61',   5], 
                '2pe' : ['2 Peter',                             '2_peter',                      '62',   3], 
                '1jn' : ['1 John',                              '1_john',                       '63',   5], 
                '2jn' : ['2 John',                              '2_john',                       '64',   1], 
                '3jn' : ['3 John',                              '3_john',                       '65',   1], 
                'jud' : ['Jude',                                'jude',                         '66',   1], 
                'rev' : ['Revelation',                          'revelation',                   '67',  22], 
                'tob' : ['Tobit',                               'tobit',                        '68', '?'], 
                'jdt' : ['Judith',                              'judith',                       '69', '?'], 
                'esg' : ['Esther',                              'esther',                       '70', '?'], 
                'wis' : ['Wisdom of Solomon',                   'wisdom_of_solomon',            '71', '?'], 
                'sir' : ['Sirach',                              'sirach',                       '72', '?'], 
                'bar' : ['Baruch',                              'baruch',                       '73', '?'], 
                'lje' : ['Letter of Jeremiah',                  'letter_of_jeremiah',           '74', '?'], 
                's3y' : ['Song of the Three Children',          'song_3_children',              '75', '?'], 
                'sus' : ['Susanna',                             'susanna',                      '76', '?'], 
                'bel' : ['Bel and the Dragon',                  'bel_dragon',                   '77', '?'], 
                '1ma' : ['1 Maccabees',                         '1_maccabees',                  '78', '?'], 
                '2ma' : ['2 Maccabees',                         '2_maccabees',                  '79', '?'], 
                '3ma' : ['3 Maccabees',                         '3_maccabees',                  '80', '?'], 
                '4ma' : ['4 Maccabees',                         '4_maccabees',                  '81', '?'], 
                '1es' : ['1 Esdras',                            '1_esdras',                     '82', '?'], 
                '2es' : ['2 Esdras',                            '2_esdras',                     '83', '?'], 
                'man' : ['Prayer of Manasses',                  'prayer_of_manasses',           '84', '?'], 
                'ps2' : ['Psalms 151',                          'psalms_151',                   '85', '?'], 
                'oda' : ['Odae',                                'odae',                         '86', '?'], 
                'pss' : ['Psalms of Solomon',                   'psalms_of_solomon',            '87', '?'], 
                'jsa' : ['Joshua A',                            'joshua_a',                     '88', '?'], 
                'jdb' : ['Joshua B',                            'joshua_b',                     '89', '?'], 
                'tbs' : ['Tobit S',                             'tobit_s',                      '90', '?'], 
                'sst' : ['Susannah (Theodotion)',               'susannah_t',                   '91', '?'], 
                'dnt' : ['Daniel (Theodotion)',                 'daniel_t',                     '92', '?'], 
                'blt' : ['Bel and the Dragon (Theodotion)',     'bel_dragon_t',                 '93', '?'], 
                'frt' : ['Front Matter',                        'front_matter',                 'A0',   0], 
                'int' : ['Introductions',                       'introductions',                'A7',   0], 
                'bak' : ['Back Matter',                         'back_matter',                  'A1',   0], 
                'cnc' : ['Concordance',                         'concordance',                  'A8',   0], 
                'glo' : ['Glossary',                            'glossary',                     'A9',   0], 
                'tdx' : ['Topical Index',                       'topical_index',                'B0',   0], 
                'ndx' : ['Names Index',                         'names_index',                  'B1',   0], 
                'xxa' : ['Extra A',                             'extra_a',                      '94',   0], 
                'xxb' : ['Extra B',                             'extra_b',                      '95',   0], 
                'xxc' : ['Extra C',                             'extra_c',                      '96',   0], 
                'xxd' : ['Extra D',                             'extra_d',                      '97',   0],
                'xxe' : ['Extra E',                             'extra_e',                      '98',   0], 
                'xxf' : ['Extra F',                             'extra_f',                      '99',   0], 
                'xxg' : ['Extra G',                             'extra_g',                      '100',  0], 
                'oth' : ['Other',                               'other',                        'A2',   0], 
                'eza' : ['Apocalypse of Ezra',                  'apocalypse_of_ezra',           'A4', '?'], 
                '5ez' : ['5 Ezra',                              '5_ezra_lp',                    'A5', '?'], 
                '6ez' : ['6 Ezra (Latin Epilogue)',             '6_ezra_lp',                    'A6', '?'], 
                'dag' : ['Daniel Greek',                        'daniel_greek',                 'B2', '?'], 
                'ps3' : ['Psalms 152-155',                      'psalms_152-155',               'B3', '?'], 
                '2ba' : ['2 Baruch (Apocalypse)',               '2_baruch_apocalypse',          'B4', '?'], 
                'lba' : ['Letter of Baruch',                    'letter_of_baruch',             'B5', '?'], 
                'jub' : ['Jubilees',                            'jubilees',                     'B6', '?'], 
                'eno' : ['Enoch',                               'enoch',                        'B7', '?'], 
                '1mq' : ['1 Meqabyan',                          '1_meqabyan',                   'B8', '?'], 
                '2mq' : ['2 Meqabyan',                          '2_meqabyan',                   'B9', '?'], 
                '3mq' : ['3 Meqabyan',                          '3_meqabyan',                   'C0', '?'], 
                'rep' : ['Reproof (Proverbs 25-31)',            'reproof_proverbs_25-31',       'C1', '?'], 
                '4ba' : ['4 Baruch (Rest of Baruch)',           '4_baruch',                     'C2', '?'], 
                'lao' : ['Laodiceans',                          'laodiceans',                   'C3', '?'] 

               }
コード例 #3
0
ファイル: project.py プロジェクト: sillsdev/rapuma
class Project (object) :

    def __init__(self, pid, gid) :
        '''Instantiate this class.'''

        self.pid                    = pid
        self.gid                    = gid
        self.user                   = UserConfig()
        self.userConfig             = self.user.userConfig
        self.projHome               = os.path.join(os.environ['RAPUMA_PROJECTS'], self.pid)
        self.config                 = Config(self.pid)
        self.config.getProjectConfig()
        self.projectConfig          = self.config.projectConfig
        self.cType                  = self.projectConfig['Groups'][self.gid]['cType']
        self.Ctype                  = self.cType.capitalize()
        self.local                  = ProjLocal(pid, gid, self.cType)
        self.log                    = ProjLog(self.pid)
        self.tools                  = Tools()
        self.groups                 = {}
        self.components             = {}
        self.managers               = {}
        self.projectMediaIDCode     = self.projectConfig['ProjectInfo']['projectMediaIDCode']
        self.projectIDCode          = self.projectConfig['ProjectInfo']['projectIDCode']
        self.projectName            = self.projectConfig['ProjectInfo']['projectTitle']
        self.plid                   = self.projectConfig['ProjectInfo']['languageCode']
        self.psid                   = self.projectConfig['ProjectInfo']['scriptCode']
        
        # The gid cannot generally be set yet but we will make a placeholder
        # for it here and the functions below will set it. (I'm just say'n)

#        import pdb; pdb.set_trace()

        m = import_module('rapuma.manager.' + self.projectMediaIDCode)
        self.__class__ = getattr(m, self.projectMediaIDCode[0].upper() + self.projectMediaIDCode[1:])

        # Update the existing config file with the project type XML file
        # if needed
        newXmlDefaults = os.path.join(self.local.rapumaConfigFolder, self.projectMediaIDCode + '.xml')
        xmlConfig = self.tools.getXMLSettings(newXmlDefaults)
        newConf = ConfigObj(xmlConfig.dict(), encoding='utf-8').override(self.projectConfig)
        for s,v in self.projectConfig.items() :
            if s not in newConf :
                newConf[s] = v

        # Replace with new conf if new is different from old
        # Rem new conf doesn't have a filename, give it one
        if self.projectConfig != newConf :
            self.projectConfig = newConf
            self.projectConfig.filename = self.local.projectConfFile

        # Log messages for this module
        self.errorCodes     = {
            'PROJ-000' : ['MSG', 'Project module messages'],
            'PROJ-030' : ['MSG', 'Changed  [<<1>>][<<2>>][<<3>>] setting from \"<<4>>\" to \"<<5>>\".'],
            'PROJ-040' : ['ERR', 'Problem making setting change. Section [<<1>>] missing from configuration file.'],
            'PROJ-050' : ['ERR', 'Component [<<1>>] working text file was not found in the project configuration.'],
            'PROJ-060' : ['ERR', 'Component [<<1>>] was not found in the project configuration.'],
            'PROJ-070' : ['ERR', 'Source file not found: [<<1>>].'],
            'PROJ-080' : ['MSG', 'Successful copy of [<<1>>] to [<<2>>].'],
            'PROJ-090' : ['ERR', 'Target file [<<1>>] already exists. Use force (-f) to overwrite.'],

            '0205' : ['LOG', 'Created the [<<1>>] manager object.'],
            '0210' : ['LOG', 'Wrote out [<<1>>] settings to the project configuration file.'],
            '0211' : ['ERR', 'Failed to write out project [<<1>>] settings to the project configuration file.'],

            '0660' : ['ERR', 'Invalid component ID: [<<1>>].'],

        }

###############################################################################
############################ Manager Level Functions ##########################
###############################################################################
######################## Error Code Block Series = 200 ########################
###############################################################################

    def createManager (self, mType) :
        '''Check to see if a manager is listed in the config and load it if
        it is not already.'''

        fullName = self.cType + '_' + mType.capitalize()
        if fullName not in self.managers :
            self.addManager(mType)
            self.loadManager(mType)
            self.log.writeToLog(self.errorCodes['0205'], [fullName])


    def loadManager (self, mType) :
        '''Do basic load on a manager.'''

        fullName = self.cType + '_' + mType.capitalize()
        cfg = self.projectConfig['Managers'][fullName]
        module = import_module('rapuma.manager.' + mType)
        ManagerClass = getattr(module, mType.capitalize())
        manobj = ManagerClass(self, cfg, self.cType)
        self.managers[fullName] = manobj


    def addManager (self, mType) :
        '''Create a manager reference in the project config that components
        will point to.'''

#        import pdb; pdb.set_trace()

        fullName = self.cType + '_' + mType.capitalize()
        managerDefaults = None
        # Insert the Manager section if it is not already there
        self.tools.buildConfSection(self.projectConfig, 'Managers')
        if not self.projectConfig['Managers'].has_key(fullName) :
            self.tools.buildConfSection(self.projectConfig['Managers'], fullName)

        # Update settings if needed
        update = False
        managerDefaults = self.tools.getXMLSettings(os.path.join(self.local.rapumaConfigFolder, mType + '.xml'))
        for k, v, in managerDefaults.iteritems() :
            # Do not overwrite if a value is already there
            if not self.projectConfig['Managers'][fullName].has_key(k) :
                self.projectConfig['Managers'][fullName][k] = v
                # If we are dealing with an empty string, don't bother writing out
                # Trying to avoid needless conf updating here. Just in case we are
                # working with a list, we'll use len()
                if len(v) > 0 :
                    update = True
        # Update the conf if one or more settings were changed
        if update :
            if self.tools.writeConfFile(self.projectConfig) :
                self.log.writeToLog(self.errorCodes['0210'],[fullName])
            else :
                self.log.writeToLog(self.errorCodes['0211'],[fullName])


###############################################################################
############################ Group Level Functions ############################
###############################################################################
####################### Error Code Block Series = 0600 ########################
###############################################################################


    def renderGroup (self, cidList = '', pages = '', override = '', save = False) :
        '''Render a group of subcomponents or any number of components
        in the group specified in the cidList.'''

#        import pdb; pdb.set_trace()

        # If there are any cids listed we need to test them
        if cidList :
            self.isValidCidList(cidList)

        # Otherwise, do a basic test for exsistance and move on
        if self.projectConfig['Groups'].has_key(self.gid) :
            # Now create the group and pass the params on
            self.createGroup().render(self.gid, cidList, pages, override, save)
            return True


    def createGroup (self) :
        '''Create a group object that can be acted on. It is assumed
        this only happens for one group per session. This group
        will contain one or more compoenents. The information for
        each one will be contained in the group object.'''

#        import pdb; pdb.set_trace()

        # If the object already exists just return it
        if self.gid in self.groups: 
            return self.groups[self.gid]

        cType = self.projectConfig['Groups'][self.gid]['cType']
        # Create a special component object if called
        cfg = self.projectConfig['Groups'][self.gid]
        module = import_module('rapuma.group.' + cType)
        ManagerClass = getattr(module, cType.capitalize())
        groupObj = ManagerClass(self, cfg)
        self.groups[self.gid] = groupObj

        return groupObj


    def isValidCidList (self, thisCidlist) :
        '''Check to see if all the components in the list are in the group.'''

        cidList = self.projectConfig['Groups'][self.gid]['cidList']
        for cid in thisCidlist :
            # If this is not a usfm type we do not need to validate
            if self.cType == 'usfm' :
                if not cid in cidList :
                    self.log.writeToLog(self.errorCodes['0660'],[cid])


    def listAllComponents (self, cType) :
        '''Generate a list of valid component IDs and cNames for this cType.'''

        # Create the component object now with a special component caller ID
        self.createComponent('usfm_internal_caller')
        # Get the component info dictionary
        comps = self.components['usfm_internal_caller'].usfmCidInfo()
        # List and sort
        cList = list(comps.keys())
        cList.sort()
        # For now we'll output to terminal but may want to change this later.
        for c in cList :
            if c != '_z_' :
                print c, comps[c][1]


###############################################################################
############################ System Level Functions ###########################
###############################################################################

    def run (self, command, opts, userConfig) :
        '''Run a command'''

        if command in self.commands :
            self.commands[command].run(opts, self, userConfig)
        else :
            self.tools.terminalError('The command: [' + command + '] failed to run with these options: ' + str(opts))
コード例 #4
0
ファイル: proj_font.py プロジェクト: jstnlth/rapuma
class ProjFont (object) :

    def __init__(self, pid) :
        '''Do the primary initialization for this class.'''

        self.pid                            = pid
        self.tools                          = Tools()
        self.user                           = UserConfig()
        self.log                            = ProjLog(pid)
        self.userConfig                     = self.user.userConfig
        self.proj_config                    = Config(pid)
        self.proj_config.getProjectConfig()
        self.projectConfig                  = self.proj_config.projectConfig
        self.proj_config.getFontConfig()
        self.fontConfig                     = self.proj_config.fontConfig
        self.local                          = ProjLocal(pid, self.projectConfig)

        # Load all font settings for use in this module
        if self.fontConfig :
            for k, v in self.fontConfig['GeneralSettings'].iteritems() :
                setattr(self, k, v)

        # Log messages for this module
        self.errorCodes     = {
            'FONT-000' : ['MSG', 'Font module messages'],
            'FONT-005' : ['MSG', 'FONT-005 - Unassigned error message ID.'],
            'FONT-015' : ['MSG', 'FONT-015 - Unassigned error message ID.'],
            'FONT-020' : ['ERR', 'Failed to find font setting in ParaTExt project (.ssf file). A primary font must be set before this component can be successfully rendered.'],
            'FONT-025' : ['ERR', 'No source editor was found for this project. Please enter this setting before continuing.'],
            'FONT-042' : ['MSG', 'The [<<1>>] font setup information was added to project config'],
            'FONT-050' : ['ERR', 'Halt! [<<1>>] not found. - font.copyInFont()'],
            'FONT-070' : ['LOG', 'Copied the [<<1>>] font file into the project. - proj_font.copyInFont()'],
            'FONT-100' : ['ERR', 'This function has not been implemented yet!.  - proj_font.setGlyphMap()'],

            '0010' : ['LOG', 'Wrote out new font configuration (font.__init__())'],

            '1220' : ['ERR', 'The Font bundle file [<<1>>] could not be found. Process halted.'],
            '1235' : ['MSG', 'Font [<<1>>] has been installed into the project.'],
            '1237' : ['MSG', 'Font [<<1>>] has been updated.'],
            '1240' : ['ERR', 'Font bundle file [<<1>>] not found.'],
            '1241' : ['ERR', 'Font bundle [<<1>>] not found.'],
            '1245' : ['LOG', '<<1>> font setup information added to project config'],
            '1250' : ['ERR', 'The [<<1>>] font is apparently part of this project. Please remove before trying to re-add this font.'],
            '1260' : ['MSG', 'The <<1>> font bundle has been copied into the project font folder.'],
            '1262' : ['LOG', 'The <<1>> font bundle already exsits in the font folder.'],
            '1265' : ['ERR', 'Failed to extract the [<<1>>] font bundle into the project. Font install process failed.'],
            '1267' : ['LOG', 'The <<1>> font bundle has been copied into the project font folder.'],
            '1280' : ['MSG', 'Failed to install the font: [<<1>>] into the project.'],
            '1370' : ['LOG', 'Removed [<<1>>] font name from project component type: [<<2>>].'],
            '1380' : ['MSG', 'Removed the [<<1>>] font from the project.'],
            '1382' : ['MSG', 'Force switch was set (-f). This process has completely removed the [<<1>>] font and settings from the project. - proj_font.removeFont()'],
            '1390' : ['LOG', 'Removed the [<<1>>] font package.'],
            '1395' : ['MSG', 'Could not remove the [<<1>>] font package. It may be used by another group. Use force (-f) to remove the package from the font folder.']

        }


###############################################################################
############################ Project Level Functions ##########################
###############################################################################
######################## Error Code Block Series = 1000 #######################
###############################################################################


    def setGlyphMap (self, cType, font) :
        '''If needed, set the glyph map used for this component type font.'''

        self.log.writeToLog('FONT-100')


    def getFontIdFromFileName (self, fileName) :
        '''Return the font ID based on the file name'''

        # File name less ext is the font ID
        parts = len(fileName.split('.'))
        return '.'.join(fileName.split('.')[:parts-1])
    
    
    def getFontIdFromSource (self, source) :
        '''Return the font ID based on the complete path and file name.'''

        # Get the file name from the path
        fileName = self.tools.fName(source)
        # Return the font ID
        return self.getFontIdFromFileName(fileName)


    def recordFont (self, fontId, cType=None) :
        '''Check for the exsitance of the specified font in the font folder.
        Then extract the meta data into the appropreate configurations.'''

#        import pdb; pdb.set_trace()

        # Set vars do initial checks
        metaDataSource = os.path.join(self.local.projFontFolder, fontId, fontId + '.xml')
        if not os.path.isfile(metaDataSource) :
            self.log.writeToLog(self.errorCodes['1240'], [fontId + '.xml', 'proj_font.recordFont():1240'])
        
        # Build the Fonts section in the config (if needed)
        self.tools.buildConfSection(self.fontConfig, 'Fonts')

        # (Re)Inject the font info into the macPack config file.
        fInfo = self.tools.getXMLSettings(metaDataSource)
        self.fontConfig['Fonts'][fontId] = fInfo.dict()

        # Save the settings now
        self.tools.writeConfFile(self.fontConfig)
        
        # If a component type was specified, record that as well
        if cType :
            self.projectConfig['CompTypes'][cType.capitalize()]['fontName'] = fontId
            self.tools.writeConfFile(self.projectConfig)
        
        return True


    def copyInFont (self, source) :
        '''Copy a font into a project. The font is bundled with other 
        necessary components in a .zip file. If the font folder is
        already there we assume there is a font there and we do not 
        proceed. The user will be prompted to remove the old one first.'''

        fontId = self.getFontIdFromSource(source)
        confXml = os.path.join(self.local.projFontFolder, fontId, fontId + '.xml')
        if not os.path.isfile(source) :
            self.log.writeToLog(self.errorCodes['1220'], [source])

        # Install new copy
        if self.tools.pkgExtract(source, self.local.projFontFolder, confXml) :
            self.log.writeToLog(self.errorCodes['1260'], [self.tools.fName(source)])
            return True
        else :
            self.log.writeToLog(self.errorCodes['1265'], [fontId])
            return False


    def addFont (self, source, cType=None) :
        '''It is a three step process to install a font. This will both
        copy in a font and record it in one call. Do not try to 
        install a substitute font. Path is assumed to exsist and contains
        the file name too.'''

#        import pdb; pdb.set_trace()

        fontId = self.getFontIdFromSource(source)
        # Check for existance, never copy over
        if self.isFont(fontId) :
            self.log.writeToLog(self.errorCodes['1250'], [fontId])
        # Now install and record
        if self.copyInFont(source) and self.recordFont(fontId, cType) :
            self.log.writeToLog(self.errorCodes['1235'], [fontId])
            return True
        else :
            self.log.writeToLog(self.errorCodes['1280'], [fontId])
            return False


    def updateFontPack (self, source, cType=None) :
        '''Update a font package but do not change any of the existing
        settings. If there are setting issues (changes) it would be
        best to remove, then reinstall. A potential confusion point
        is that updating a font normally means changing the ID. Then
        updating actually becomes just installing a font.'''

#        import pdb; pdb.set_trace()

        # Get the font ID
        fontId      = self.getFontIdFromSource(source)
        # Be sure the font is in the project
        if self.isFont(fontId) :
            # Remove old copy
            if os.path.exists(os.path.join(self.local.projFontFolder, fontId)) :
                shutil.rmtree(os.path.join(self.local.projFontFolder, fontId))
            # Bring in a fresh copy
            if self.copyInFont(source) :
                # If a component type was specified, record that as well
                if cType :
                    self.projectConfig['CompTypes'][cType.capitalize()]['fontName'] = fontId
                    self.tools.writeConfFile(self.projectConfig)
                self.log.writeToLog(self.errorCodes['1237'], [fontId])
                return True


    def removeFontSettings (self, fontId) :
        '''Remove the font settings from the project.'''

#        import pdb; pdb.set_trace()
        if self.fontConfig.has_key('Fonts') :
            if self.fontConfig['Fonts'].has_key(fontId) :
                del self.fontConfig['Fonts'][fontId]
                # Write out the new settings files
                self.tools.writeConfFile(self.fontConfig)
                self.log.writeToLog(self.errorCodes['1380'], [fontId])
            # Check to see if this font is listed in any of the cTypes
            # If so, remove it.
            found = 0
            for cType in self.projectConfig['CompTypes'].keys() :
                # It might be possible that the cType has no font settings, so we check
                if self.projectConfig['CompTypes'][cType.capitalize()].has_key('fontName') :
                    if self.projectConfig['CompTypes'][cType.capitalize()]['fontName'] == fontId :
                        self.projectConfig['CompTypes'][cType.capitalize()]['fontName'] = ''
                        self.log.writeToLog(self.errorCodes['1370'], [fontId, cType])
                        found +=1
            if found > 0 :
                self.tools.writeConfFile(self.projectConfig)

            return True


    def removeFontPack (self, fontId) :
        '''Remove a font from a component type which will virtually disconnect 
        it from the calling component type. However, if the force switch is set,
        then remove the font, regardless as to if it is used by another component
        or not. This is useful for purging a font from a project but should be
        used with care.'''

        # Purge the font files and folder
        fontDir = os.path.join(self.local.projFontFolder, fontId)
        if os.path.exists(fontDir) :
            shutil.rmtree(fontDir)
            self.log.writeToLog(self.errorCodes['1390'], [fontId])

        if self.removeFontSettings(fontId) :
            return True


###############################################################################
############################ Font Settings Functions ##########################
###############################################################################
######################## Error Code Block Series = 2000 #######################
###############################################################################

    def isFont (self, fontId) :
        '''Return if it is varified that this font is part of the project.'''
        
        # First do a cusory check to see if at least the font folder is there
        fontDir = os.path.join(self.local.projFontFolder, fontId)
        if not os.path.exists(fontDir) :
            return False
            
        # If the above passed, check in the font config to see if it is listed
        if not self.fontConfig['Fonts'].has_key(fontId) :
            return False
        
        # If the two tests above passed it is probably there
        return True