Source code for p4.var

import sys
import os
import numpy
from p4.p4exceptions import P4Error

# A           Ala            Alanine
# R           Arg            Arginine
# N           Asn            Asparagine
# D           Asp            Aspartic acid
# C           Cys            Cysteine
# Q           Gln            Glutamine
# E           Glu            Glutamic acid
# G           Gly            Glycine
# H           His            Histidine
# I           Ile            Isoleucine
# L           Leu            Leucine
# K           Lys            Lysine
# M           Met            Methionine
# F           Phe            Phenylalanine
# P           Pro            Proline
# O           Pyl            Pyrrolysine (22nd amino acid)
# U           Sec            Selenocysteine (21st amino acid)
# S           Ser            Serine
# T           Thr            Threonine
# W           Trp            Tryptophan
# Y           Tyr            Tyrosine
# V           Val            Valine
# B           Asx            Aspartic acid or Asparagine
# Z           Glx            Glutamine or Glutamic acid
# J           Xle            Isoleucine or Valine (mass spec ambiguity)
# X           Xaa            Any or unknown amino acid

[docs]class Var(object): """An instance of this class is the global bucket. An instance of this class is made, called 'var'. It can be read and changed by the user, and it is imported by other classes that need access to 'global' variables contained in it. """ def __init__(self): self._examplesDir = None # self.examplesDir is a property, see below #: Files read in from the command line. self.fileNames = [] #: A list of alignments. Only those alignments read from the command line and from read() self.alignments = [] #: A list of SequenceList objects from files from the command line or from read() self.sequenceLists = [] #: Tree objects from files from the command line or from read() self.trees = [] #: A single NexusSets object (not a list) from files from the command line #: or from read(). If more sets info is read in, it all gets #: put in the single NexusSets object self.nexusSets = None #: Whether to do the splash screen on startup with no args. #: When you get tired of it, turn it off in a customization #: file. You can always see it again with :func:`p4.func.splash`. self.doSplash = 1 #: Running commentary on p4's attempts to read in files. self.verboseRead = 0 #: If you give read() a string that is not a file, p4 points #: it out, in case its a mistake. self.warnReadNoFile = 0 #: In the p4 script, non-filename command-line args are accommodated, #: awkwardly. They need to be put after #: a double dash. They can then be found #: here. self.argvAfterDoubleDash = None # Dangerous to change this. Not widely implemented. self.allowDupedTaxonNames = False # Experimental hack. It does not work on taxNames # -- just on the tree nodes. Setting it to # True is verbose, and at least tells you that you # have dupes. Setting it to 2 is silent -- # especially dangerous. self.doRepairDupedTaxonNames = 0 # 0 means don't do it. # 1 means do it verbosely, # 2 means do it silently. # It is possible to have root-on-a-stick style trees, self.warnAboutTerminalRootWithNoName = True # where the root may or may not be a leaf, and may or # may not have a taxon name. If it is a root on a stick, # it is by default considered a leaf, and if it has no # name then a warning is given, if this is set. # These comments are always read in by TreePartitions self.doTreeReadMcmcModelUsageComments = 0 # objects. This says whether they are read # in by Tree objects as well. #: Require that MCMC run numbers are in order. # Ensure chains are init'ed sequentially self.strictRunNumberChecking = False # changed from True April 2019 self.NO_ORDER = -10000 # pre and postOrder for unused nodes. #: Beast trees use command comments eg [&stuff=0.12345] a lot. To #: read them, turn var.nexus_getAllCommandComments on, and then #: turn this on. self.nexus_readBeastTreeCommandComments = False #: The NEXUS spec does not allow names that are all numerals. #: Temporarily override by True-ing this. self.nexus_allowAllDigitNames = False #: In Nexus data, the characters for gap and missing can be set #: to almost anything you like, but I like them to be '-' and #: '?', which is more usual. So if needed, I switch them. #: Dodgy! -- But at least I warn the user, unless that warning #: is turned off. self.nexus_warnSwitchGapChar = True self.nexus_warnSwitchMissingChar = True """See :attr:`Var.nexus_warnSwitchGapChar`""" #: In nexus, if you have dna, rna, or protein datatype, you #: can, according to the nexus standard, add extra symbols, #: defined in the format command. I don't like that, so I #: don't allow it. However, at least I warn the user, either #: as a warning (if True) or a glitch (if False). self.nexus_ignoreFormatCommandSymbols = True self.nexus_warnSkipUnknownBlock = True """Print a little message if p4 encounters a NEXUS block that it does not know what to do with.""" self.nexus_allowUTREE = False """UTREE has been deprecated since at least 1997. But if you need to read UTREE-containing tree files, you can turn it on with this. """ self.newick_allowSpacesInNames = False """Allow unquoted taxon names in Newick and Nexus trees to have spaces. This will allow reading trees like (A, B C, (D E, F)G H); Multiple spaces are collapsed into single spaces. """ self.topologyDistanceMetrics = [ 'sd', 'wrf', 'bld', 'diffs', 'scqdist', 'tqdist'] # 'triplet'? """A list of metrics. At the time of writing, ``sd``, ``wrf``, ``bld``, ``diffs``, ``scqdist``, ``tqdist``. Used by :meth:`p4.tree.Tree.topologyDistance` and :meth:`p4.trees.Trees.topologyDistanceMatrix` """ # These are used by TreePicture self.TEXTDRAW_NONE = 0 self.TEXTDRAW_COMP = 1 self.TEXTDRAW_RMATRIX = 2 self.TEXTDRAW_GDASRV = 3 self.TEXTDRAW_NTHINGS = 4 # ie the max number self.recipesWriteToFile = True # See # # no period, '!', #, @, _, &, ^, %, $ self.nexus_punctuation = """()[]{}\\/,;:=*'"`+-<>""" # no period, '!', #, @, _, &, ^, %, $ self.nexus_safeChars = "!#@_&^%$" #self.phylip_punctuation = '\(\)\,\;\:' self.phylip_punctuation = '(),;:' self.punctuation = self.nexus_punctuation self.validDnaChars = 'acgt-?nrykmswbdhv' # no u self.validRnaChars = 'acgu-?nrykmswbdhv' # no t self.validNucleotideChars = 'acgt-?nurykmswbdhv' # u and t, both # "*" (stop) for Genbank and gde. self.validProteinChars = 'acdefghiklmnpqrstvwy-?xbzju*' self.phylipDataMaxNameLength = 10 """The length of the taxon name in phylip data. Unfortunately the phylip data format has a lot of variations. Even in the 'official' phylip data format, the name length is a compile-time variable. Its usually 10, tho. You can change it with this.""" self.writeFastaUppercase = False """Whether fasta sequences are written in uppercase.""" # Check sequence files that are read in and become Alignment objects. self.doCheckForAllGapColumns = True self.doCheckForBlankSequences = True self.doCheckForDuplicateSequences = True self.doCheckForDuplicateSequenceNames = True self.SAME = 0 self.DIFFERENT = 1 # The python that shiped with MacOS was usually old and was # not built with readline. Thats ok, 'cuz it was easy enough # to install a new python that had readline. The one from # was fine. Now the python that comes with # MacOS 10.5 is fairly up-to-date, and it is built with # readline -- sort of. The problem is that the readline # python module does not use GNU libreadline, it uses the # editline library (libedit ?), and it has a different syntax # for parse_and_bind(). And it is partly broken, in that it # does not pass a 'text' arg to the drop-in 'complete' # function. # # It hurts. # # I suspect that the python is still built with # gnu readline, and is ok, but I have not confirmed. If you # are using the Mac python that uses editline, then change the # following to 'True'. Completion will be slightly broken, in # that getting the argspec inside functions and methods will # not work, but the rest of it seems to work. # # Update on the above. I got my python2.5, and now python2.6 # from MacPorts, and they were both fine. And 2.7 from HomeBrew. self.readlineUsesEditline = False # A pointer to a gsl random number generator SEEMS TO BE A LITTLE # MEMORY LEAK! self.gsl_rng = None self.doDataPart = 0 # Experimental # Modify behavior of NexusToken.nextTok() function. self._nexus_writeVisibleComments = numpy.array([0], numpy.int32) # write, but do not get, all [!...] self._nexus_getP4CommandComments = numpy.array([0], numpy.int32) # all [&&p4 ...] self._nexus_getWeightCommandComments = numpy.array([1], numpy.int32) # all [&w ...] self._nexus_getAllCommandComments = numpy.array([0], numpy.int32) # all [&...] self._nexus_getLineEndingsAsTokens = numpy.array([0], numpy.int32) self.rMatrixProteinSpecs = ['cpREV', 'd78', 'jtt', 'mtREV24', 'mtmam', 'wag', 'rtRev', 'tmjtt94', 'tmlg99', 'lg', 'blosum62', 'hivb', 'mtart', 'mtzoa', 'gcpREV', 'stmtREV', 'vt', 'pmb'] """A list of the currently available protein models.""" self.rMatrixSpecs = [ 'ones', '2p', 'specified', 'optimized'] + self.rMatrixProteinSpecs self.compSpecs = [ 'equal', 'empirical', 'specified'] + self.rMatrixProteinSpecs self.modelSymbols = ['=', '@', '#', '$', '%', '&', '*', '+', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '<', '!', '>', '^', '[', ']', ':', '(', ')', '~', '"', '|' ] # no '-', '?' """A list of symbols used in text tree drawings, showing model disposition on the tree.""" # This next variable (var.rMatrixNormalizeTo1 is a property) # determines whether the elements of a GTR-like rMatrix are # normalized to sum to 1, or else whether the bottom corner # rate (G->T in DNA GTR) is set to 1 and the other rate # elements are relative to it. self._rMatrixNormalizeTo1 = numpy.array([1], numpy.int32) self._PIVEC_MIN = numpy.array([1.0e-13], numpy.float64) # Changed from 1e-18 March 2019, to avoid getting negative bigP values self._PIVEC_MAX = numpy.array([0.999], numpy.float64) #self._RATE_MIN = 1.0e-14 # ie for rMatrices, changed from 1.0e-8 nov 2016, because self._rMatrixNormalizeTo1 is set self._RATE_MIN = numpy.array([1.0e-13], numpy.float64) # changed from 1.e-14 March 2019, to avoid getting negative bigP values self._RATE_MAX = numpy.array([0.9999999], numpy.float64) # changed from 1.0e8 nov 2016, also because self._rMatrixNormalizeTo1 is set self._GAMMA_SHAPE_MIN = numpy.array([0.1], numpy.float64) # changed from 0.000001 april 2019, with alpha=0.1, slowest cat is 5.e-7 self._GAMMA_SHAPE_MAX = numpy.array([300.0], numpy.float64) self._PINVAR_MIN = numpy.array([0.0], numpy.float64) self._PINVAR_MAX = numpy.array([0.99], numpy.float64) self._RELRATE_MIN = numpy.array([1.0e-8], numpy.float64) self._RELRATE_MAX = numpy.array([1.0e8], numpy.float64) self._KAPPA_MIN = numpy.array([0.000001], numpy.float64) self._KAPPA_MAX = numpy.array([100.0], numpy.float64) self._BRLEN_MIN = numpy.array([1.0e-8], numpy.float64) self._BRLEN_MAX = numpy.array([3.0], numpy.float64) self._newtAndBrentPowellOptPassLimit = numpy.array([50], numpy.int32) self.GAP_CODE = -1 self.QMARK_CODE = -2 self.N_LIKE = -3 self.EQUATES_BASE = -64 self.doMcmcSp = True # speedier like calcs in mcmc # # Modify behavior of NexusToken.nextTok() function. # # write, but do not get, all [!...] # self._nexus_writeVisibleComments = 0 # self._nexus_getP4CommandComments = 0 # all [&&p4 ...] # self._nexus_getWeightCommandComments = 1 # all [&w ...] # self._nexus_getAllCommandComments = 0 # all [&...] # self._nexus_getLineEndingsAsTokens = 0 # self._rMatrixNormalizeTo1 = 1 self._interactiveHelper = None self._excepthookEditor = None self.allowEmptyCharSetsAndTaxSets = False #self.mcmc_swapVector = False # (old) matrix or (new) vector, both mcmc and stmcmc self.mcmc_swapTunerDoTuning = True # whether to do swap tuning self.mcmc_swapTunerSampleSize = 250 # mcmc and stmcmc self.stmcmc_useFastSpa = False self.mcmc_sameBigTToStartOnAllChains = False # mcmc and stmcmc, for debugging, and fixed toplogy runs #self.mcmc_doTuneChainTemp = False self.mcmc_allowUnresolvedStartingTree = False self.mcmc_simTemp_tempCurveLogBase = 2.8 # higher -> more curvey; lower -> more linear # This next one is a list of digit strings, used to thin the # chain in a simTemp MCMC. Samples taken only if f"{mcmc.gen # + 1}" ends with one of these. self.mcmc_simTemp_thinning = ['0'] self.mcmc_logTunings = False # verbose logging of on-the-fly changes to tunings self.mcmc_doCheck_PIVEC_MIN_etc = True # check PIVEC_MIN, RATE_MIN, BRLEN_MIN, GAMMA_SHAPE_MIN in Mcmc # This mcmc_swapTunerVTnLimitHi refers to the swapTunerV, the # vector (non-matrix) version of the swap tuner that only # allows swaps between adjacent temperatures. The "TnLimitHi" # part refers to an upper limit that a temperature difference # can have before further increases are not allowed. So if # the limit is set to 50, and the temperature difference is # 55, then further proposed increases will be ignored. The # problem it attempts to address is that I have found that # very large temperature differences will sometimes slow the # chain down to a crawl. So if the MCMCMC slows down during # the run, lowering this limit might fix it. # Update: this was probably not the way to solve the slowing problem, so I am removing this #self.mcmc_swapTunerVTnLimitHi = 100. # Decrease (to eg 50?, 30?) if the MCMCMC slows. #self.mcmc_swapTunerVTnLimitLo = 0.0001 def _del_nothing(self): gm = ["Don't/Can't delete this property."] raise P4Error(gm) def _getPIVEC_MIN(self): return self._PIVEC_MIN[0] def _setPIVEC_MIN(self, newValue): self._PIVEC_MIN[0] = newValue PIVEC_MIN = property(_getPIVEC_MIN, _setPIVEC_MIN, _del_nothing, "(property) PIVEC_MIN (float)") def _getPIVEC_MAX(self): return self._PIVEC_MAX[0] def _setPIVEC_MAX(self, newValue): self._PIVEC_MAX[0] = newValue PIVEC_MAX = property(_getPIVEC_MAX, _setPIVEC_MAX, _del_nothing, "(property) PIVEC_MAX (float)") def _getRATE_MIN(self): return self._RATE_MIN[0] def _setRATE_MIN(self, newValue): self._RATE_MIN[0] = newValue RATE_MIN = property(_getRATE_MIN, _setRATE_MIN, _del_nothing, "(property) RATE_MIN (float)") def _getRATE_MAX(self): return self._RATE_MAX[0] def _setRATE_MAX(self, newValue): self._RATE_MAX[0] = newValue RATE_MAX = property(_getRATE_MAX, _setRATE_MAX, _del_nothing, "(property) RATE_MAX (float)") def _getGAMMA_SHAPE_MIN(self): return self._GAMMA_SHAPE_MIN[0] def _setGAMMA_SHAPE_MIN(self, newValue): self._GAMMA_SHAPE_MIN[0] = newValue GAMMA_SHAPE_MIN = property(_getGAMMA_SHAPE_MIN, _setGAMMA_SHAPE_MIN, _del_nothing, "(property) GAMMA_SHAPE_MIN (float)") def _getGAMMA_SHAPE_MAX(self): return self._GAMMA_SHAPE_MAX[0] def _setGAMMA_SHAPE_MAX(self, newValue): self._GAMMA_SHAPE_MAX[0] = newValue GAMMA_SHAPE_MAX = property(_getGAMMA_SHAPE_MAX, _setGAMMA_SHAPE_MAX, _del_nothing, "(property) GAMMA_SHAPE_MAX (float)") def _getPINVAR_MIN(self): return self._PINVAR_MIN[0] def _setPINVAR_MIN(self, newValue): self._PINVAR_MIN[0] = newValue PINVAR_MIN = property(_getPINVAR_MIN, _setPINVAR_MIN, _del_nothing, "(property) PINVAR_MIN (float)") def _getPINVAR_MAX(self): return self._PINVAR_MAX[0] def _setPINVAR_MAX(self, newValue): self._PINVAR_MAX[0] = newValue PINVAR_MAX = property(_getPINVAR_MAX, _setPINVAR_MAX, _del_nothing, "(property) PINVAR_MAX (float)") def _getRELRATE_MIN(self): return self._RELRATE_MIN[0] def _setRELRATE_MIN(self, newValue): self._RELRATE_MIN[0] = newValue RELRATE_MIN = property(_getRELRATE_MIN, _setRELRATE_MIN, _del_nothing, "(property) RELRATE_MIN (float)") def _getRELRATE_MAX(self): return self._RELRATE_MAX[0] def _setRELRATE_MAX(self, newValue): self._RELRATE_MAX[0] = newValue RELRATE_MAX = property(_getRELRATE_MAX, _setRELRATE_MAX, _del_nothing, "(property) RELRATE_MAX (float)") def _getKAPPA_MIN(self): return self._KAPPA_MIN[0] def _setKAPPA_MIN(self, newValue): self._KAPPA_MIN[0] = newValue KAPPA_MIN = property(_getKAPPA_MIN, _setKAPPA_MIN, _del_nothing, "(property) KAPPA_MIN (float)") def _getKAPPA_MAX(self): return self._KAPPA_MAX[0] def _setKAPPA_MAX(self, newValue): self._KAPPA_MAX[0] = newValue KAPPA_MAX = property(_getKAPPA_MAX, _setKAPPA_MAX, _del_nothing, "(property) KAPPA_MAX (float)") def _getBRLEN_MIN(self): return self._BRLEN_MIN[0] def _setBRLEN_MIN(self, newValue): self._BRLEN_MIN[0] = newValue BRLEN_MIN = property(_getBRLEN_MIN, _setBRLEN_MIN, _del_nothing, "(property) BRLEN_MIN (float)") def _getBRLEN_MAX(self): return self._BRLEN_MAX[0] def _setBRLEN_MAX(self, newValue): self._BRLEN_MAX[0] = newValue BRLEN_MAX = property(_getBRLEN_MAX, _setBRLEN_MAX, _del_nothing, "(property) BRLEN_MAX (float)") def _get_newtAndBrentPowellOptPassLimit(self): return self._newtAndBrentPowellOptPassLimit[0] def _set_newtAndBrentPowellOptPassLimit(self, newValue): self._newtAndBrentPowellOptPassLimit[0] = newValue newtAndBrentPowellOptPassLimit = property(_get_newtAndBrentPowellOptPassLimit, _set_newtAndBrentPowellOptPassLimit, _del_nothing, "(property) newtAndBrentPowellOptPassLimit (int)") # self._nexus_writeVisibleComments = 0 # write, but do not get, all [!...] # self._nexus_getP4CommandComments = 0 # all [&&p4 ...] # self._nexus_getWeightCommandComments = 1 # all [&w ...] # self._nexus_getAllCommandComments = 0 # all [&...] def _get_nexus_writeVisibleComments(self): return self._nexus_writeVisibleComments[0] def _set_nexus_writeVisibleComments(self, newVal): try: newVal = int(newVal) except: gm = ['This property should be set to an int.'] raise P4Error(gm) self._nexus_writeVisibleComments[0] = newVal nexus_writeVisibleComments = property(_get_nexus_writeVisibleComments, _set_nexus_writeVisibleComments, _del_nothing) """(property) nexus_writeVisibleComments (int)""" def _get_nexus_getP4CommandComments(self): return self._nexus_getP4CommandComments[0] def _set_nexus_getP4CommandComments(self, newVal): try: newVal = int(newVal) except: gm = ['This property should be set to an int.'] raise P4Error(gm) self._nexus_getP4CommandComments[0] = newVal nexus_getP4CommandComments = property(_get_nexus_getP4CommandComments, _set_nexus_getP4CommandComments, _del_nothing) """Whether to get p4-specific command comments in NEXUS trees.""" def _get_nexus_getWeightCommandComments(self): return self._nexus_getWeightCommandComments[0] def _set_nexus_getWeightCommandComments(self, newVal): try: newVal = int(newVal) except: gm = ['This property should be set to an int.'] raise P4Error(gm) self._nexus_getWeightCommandComments[0] = newVal nexus_getWeightCommandComments = property(_get_nexus_getWeightCommandComments, _set_nexus_getWeightCommandComments, _del_nothing) """Whether to get the 'weight' command comment in a NEXUS tree.""" def _get_nexus_getAllCommandComments(self): return self._nexus_getAllCommandComments[0] def _set_nexus_getAllCommandComments(self, newVal): try: newVal = int(newVal) except: gm = ['This property should be set to an int.'] raise P4Error(gm) self._nexus_getAllCommandComments[0] = newVal nexus_getAllCommandComments = property(_get_nexus_getAllCommandComments, _set_nexus_getAllCommandComments, _del_nothing) """Whether to get all command comments in NEXUS tree files.""" def _get_nexus_getLineEndingsAsTokens(self): return self._nexus_getLineEndingsAsTokens[0] def _set_nexus_getLineEndingsAsTokens(self, newVal): try: newVal = int(newVal) except: gm = ['This property should be set to an int.'] raise P4Error(gm) self._nexus_getLineEndingsAsTokens[0] = newVal nexus_getLineEndingsAsTokens = property(_get_nexus_getLineEndingsAsTokens, _set_nexus_getLineEndingsAsTokens, _del_nothing) """(property) Whether line endings get returned as nexus tokens (int)""" def _get_rMatrixNormalizeTo1(self): return self._rMatrixNormalizeTo1[0] def _set_rMatrixNormalizeTo1(self, newVal): # try: # newVal = int(newVal) # self._rMatrixNormalizeTo1[0] = newVal # except: # gm = ['This property should be set to an int.'] # raise P4Error(gm) gm = ["Var._set_rMatrixNormalizeTo1()"] gm.append( "This fundamental variable affects array lengths, and so should not be changed during a run--") gm.append( "It should only be set in, only to be read at start-up.") raise P4Error(gm) rMatrixNormalizeTo1 = property(_get_rMatrixNormalizeTo1, _set_rMatrixNormalizeTo1, _del_nothing) """(property) not user-settable""" def _get_interactiveHelper(self): return self._interactiveHelper def _set_interactiveHelper(self, newVal): goodValues = [None, 'bpython', 'ipython'] if newVal in goodValues: self._interactiveHelper = newVal else: gm = ['This property should be set to one of %s' % goodValues] raise P4Error(gm) interactiveHelper = property(_get_interactiveHelper, _set_interactiveHelper, _del_nothing) """For interactive use, set the helper. Set to bpython, or ipython. Default is None. """ def _get_excepthookEditor(self): return self._excepthookEditor def _set_excepthookEditor(self, newVal): assert newVal == None or isinstance(newVal,str) self._excepthookEditor = newVal excepthookEditor = property(_get_excepthookEditor, _set_excepthookEditor, _del_nothing) """The editor that is called by excepthook, or None Setting this to None or to the name of an editor acts as a Boolean to say whether to follow a traceback with a hook to call your editor. It is for using p4 at the terminal, writing scripts and source in an editor such as emacs or vi. The various files and lines of the traceback are given numbers that you can type in to get to the source. Handy! The editor needs to be clever enough to use the "+N" command line option to be able to go to a particular line (N). Emacs and vi can both do this. Set to, for example 'emacsclient -n', or 'vim'. Default is None. """ def _getExamplesDir(self): if self._examplesDir: return self._examplesDir else: try: from installation import p4ExamplesDir if os.path.exists(os.path.join(p4ExamplesDir, 'A_quickStart')) and \ os.path.exists(os.path.join(p4ExamplesDir, 'W_recipes')): self._examplesDir = p4ExamplesDir return p4ExamplesDir except ImportError: # It was not installed. It is running 'in-place' -- no # file. import p4 pth = p4.__file__ # print pth pth = os.path.split(pth)[0] pth = os.path.split(pth)[0] # print pth if os.path.exists(pth): pth = os.path.join(pth, 'share') if os.path.exists(pth): pth = os.path.join(pth, 'Examples') if os.path.exists(os.path.join(pth, 'A_quickStart')) and \ os.path.exists(os.path.join(pth, 'W_recipes')): self._examplesDir = pth return pth def _setExamplesDir(self, theDir): gm = ["Var._setExamplesDir()"] # No whitespace, no trailing slash theDir = theDir.strip() if theDir.endswith("/"): theDir = theDir[:-1] # if theDir does not exist, the following throws an OSError theDirList = os.listdir(theDir) if 'A_quickStart' in theDirList and 'W_recipes' in theDirList: self._examplesDir = theDir else: gm.append("The directory '%s'" % theDir) gm.append("does not appear to contain the p4 Examples.") raise P4Error(gm) examplesDir = property(_getExamplesDir, _setExamplesDir, _del_nothing) """The directory where the p4 examples can be found. Assuming that p4 can find them. """
# Make a single instance. var = Var()