import re LETTER = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') VALID = set('_0123456789') | LETTER def cleanName(name): clean = ''.join(c if c in VALID else '_' for c in name) if clean == '' or not clean[0] in LETTER: clean = 'x' + clean return clean def isClean(name): if name is None or len(name) == 0 or name[0] not in LETTER: return False return all(c in VALID for c in name[1:]) def expandDir(dirName, paths): if dirName.startswith('~'): dirName = dirName.replace('~', paths['home'], 1) elif dirName.startswith('..'): dirName = dirName.replace('..', paths['up'], 1) elif dirName.startswith('.'): dirName = dirName.replace('.', paths['cur'], 1) return dirName def setFromSpec(spec): covered = set() for r_str in spec.split(','): bounds = r_str.split('-') if len(bounds) == 1: covered.add(int(r_str)) else: b = int(bounds[0]) e = int(bounds[1]) if (e < b): (b, e) = (e, b) for n in range(b, e + 1): covered.add(n) return covered def rangesFromSet(nodeSet): ranges = [] curstart = None curend = None for n in sorted(nodeSet): if curstart is None: curstart = n curend = n elif n == curend + 1: curend = n else: ranges.append((curstart, curend)) curstart = n curend = n if curstart is not None: ranges.append((curstart, curend)) return ranges def rangesFromList(nodeList): # the list must be sorted ranges = [] curstart = None curend = None for n in nodeList: if curstart is None: curstart = n curend = n elif n == curend + 1: curend = n else: ranges.append((curstart, curend)) curstart = n curend = n if curstart is not None: ranges.append((curstart, curend)) return ranges def specFromRanges(ranges): # ranges must be normalized return ','.join( '{}'.format(r[0]) if r[0] == r[1] else '{}-{}'.format(*r) for r in ranges ) def valueFromTf(tf): return '\\'.join( x.replace('\\t', '\t').replace('\\n', '\n') for x in tf.split('\\\\') ) def tfFromValue(val): return str(val) if type(val) is int else val.replace('\\', '\\\\').replace( '\t', '\\t' ).replace('\n', '\\n') def makeInverse(data): inverse = {} for n in data: for m in data[n]: inverse.setdefault(m, set()).add(n) return inverse def makeInverseVal(data): inverse = {} for n in data: for (m, val) in data[n].items(): inverse.setdefault(m, {})[n] = val return inverse def nbytes(by): units = ['B', 'KB', 'MB', 'GB', 'TB'] for i in range(len(units)): if by < 1024 or i == len(units) - 1: fmt = '{:>5}{}' if i == 0 else '{:>5.1f}{}' return fmt.format(by, units[i]) by /= 1024 def collectFormats(config): varPattern = re.compile(r'\{([^}]+)\}') featureSet = set() def collectFormat(tpl): features = [] def varReplace(match): varText = match.group(1) fts = tuple(varText.split('/')) features.append(fts) for ft in fts: featureSet.add(ft) return '{}' rtpl = varPattern.sub(varReplace, tpl) return (rtpl, tuple(features)) formats = {} for (fmt, tpl) in sorted(config.items()): if fmt.startswith('fmt:'): formats[fmt[4:]] = collectFormat(tpl) return (formats, sorted(featureSet)) def compileFormats(cformats, features): xformats = {} for (fmt, (rtpl, feats)) in sorted(cformats.items()): tpl = rtpl.replace('\\n', '\n').replace('\\t', '\t') xformats[fmt] = compileFormat(tpl, feats, features) return xformats def compileFormat(rtpl, feats, features): replaceFuncs = [] for feat in feats: replaceFuncs.append(makeFunc(feat, features)) def g(n): values = tuple(replaceFunc(n) for replaceFunc in replaceFuncs) return rtpl.format(*values) return g def makeFunc(feat, features): if len(feat) == 1: ft = feat[0] f = features[ft].data return (lambda n: f.get(n, '')) elif len(feat) == 2: (ft1, ft2) = feat f1 = features[ft1].data f2 = features[ft2].data return (lambda n: (f1.get(n, f2.get(n, '')))) def itemize(string, sep=None): if not string: return [] if not sep: return string.strip().split() return string.strip().split(sep)