/usr/share/pyshared/moosic/utilities.py is in moosic 1.5.6-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | # -*- coding: iso-8859-1 -*-
# utilities.py - A library of commonly useful functions and classes.
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>
"""A library of commonly useful functions and classes.
This module contains a varied collection of functions and classes that are
potentially useful in a wide range of programming tasks.
It is safe to "import *" from this module.
"""
from __future__ import generators
import re, random, string, operator, os, os.path
__all__ = ('grep', 'antigrep', 'staggered_merge', 'parse_range', 'wrap',
'xmlrpc_server_doc', 'center_text', 'uniq', 'sh_escape', 'flatten',
'canLoopOver', 'isStringLike', 'isScalar', 'make_string_filter')
def uniq(seq):
"""Returns a list of all the elements of the given sequence in their
original order, but without duplicates.
Unlike the Unix tool of the same name, duplicates are removed even if they
aren't adjacent. This function only works if the elements of the input
sequence are hashable.
"""
d = {}
return [d.setdefault(i, i) for i in seq if i not in d]
# The following four functions were written by Luther Blissett, and were taken
# from recipe 1.12 in the Python Cookbook.
def canLoopOver(maybeIterable):
'Tests whether an object can be looped over.'
try: iter(maybeIterable)
except: return False
else: return True
def isStringLike(obj):
'Tests whether an object behaves like a string.'
try: obj+''
except TypeError: return False
else: return True
def isScalar(obj):
'Tests whether an object is a scalar value. Strings are considered scalar.'
return isStringLike(obj) or not canLoopOver(obj)
def flatten(seq, scalarp=isScalar):
'''Flattens a nested sequence.
For example, [[1, 2], [3, [4, 5]] becomes [1, 2, 3, 4, 5].
'''
for item in seq:
if scalarp(item):
yield item
else:
for subitem in flatten(item, scalarp):
yield subitem
def shuffle(seq):
"""Returns a shuffled version of the given sequence. (Deprecated)
The returned list contains exactly the same elements as the given sequence,
but in a random order. This function is much slower than the shuffle
function in the random module in the standard library, and it returns a new
list instead of shuffling the sequence in place. Using this function is not
recommended.
"""
shuffled = []
seq = list(seq)
while seq:
shuffled.append( seq.pop( random.choice( range( len(seq) ) ) ) )
return shuffled
def staggered_merge_old(*sequences):
"""Merges multiple sequences, interleaving their elements. (Old version.)
This returns a sequence whose elements alternate between the elements of
the input sequences. For example, if the input sequences are (1, 2, 3) and
(11, 12, 13), then the output will be (1, 11, 2, 12, 3, 13). And if the
input sequences are (a, b, c), (v, w, x, y, z), and (q, r, s, t), then the
output will be (a, v, q, b, w, r, c, x, s, y, t, z).
Beware that this function throws away input elements that are equal to
None. This is the price that must be paid in order to merge sequences of
different lengths.
"""
# If "sequences" is empty, then the later call to map() won't have enough
# arguments. In that case, it is replaced with a 1-tuple whose single
# element is the empty tuple.
sequences = sequences or ((),)
# step 3: filter out the "None" values.
return filter(
(lambda x: x is not None),
# step 2: concatenate the tuples together.
reduce(
operator.concat,
# step 1: collect the corresponding elements into a list of tuples.
map(*((None,) + sequences)),
# The argument list for map() must be built dynamically because
# map() takes a variable number of arguments, and we want each
# member of "sequences" to be a separate argument to map().
()
)
)
# The astute reader might exclaim here that I could have used the builtin
# zip() function instead of using map() with the identity function.
# However, zip() truncates all sequences that are longer than the shortest
# sequence in the series, meaning that elements can get thrown away, which
# is not what I want.
def staggered_merge(*sequences):
"""Merges multiple sequences, interleaving their elements.
This returns a sequence whose elements alternate between the elements of
the input sequences. For example, if the input sequences are (1, 2, 3) and
(11, 12, 13), then the output will be (1, 11, 2, 12, 3, 13). And if the
input sequences are (a, b, c), (v, w, x, y, z), and (q, r, s, t), then the
output will be (a, v, q, b, w, r, c, x, s, y, t, z).
Backward compatibility notes: This function does not throw away None values
found in the input sequences, although previous versions did. Also, this
function always returns a list, while previous versions tended to always
return a tuple.
"""
if not len(sequences):
return [] # base case: there's nothing to merge.
else:
cars = [i[0] for i in sequences if i[:1]] # each list's head item
cdrs = [i[1:] for i in sequences if i[1:]] # each list's tail items
return cars + staggered_merge(*cdrs)
def grep(regex, seq):
"""Returns a list of the elements of "seq" that match the regular expression
represented by "regex", which may be a string or a regular expression
object.
"""
if isStringLike(regex):
regex = re.compile(regex)
search = regex.search
return [i for i in seq if search(i)]
def antigrep(regex, seq):
"""Returns a list of the elements of "seq" that do not match the regular
expression represented by "regex", which may be a string or a regular
expression object.
"""
if isStringLike(regex):
regex = re.compile(regex)
search = regex.search
return [i for i in seq if not search(i)]
def parse_range(range, start=0, end=0):
'''Changes a string representing a range into the indices of the range.
This function converts a string with a form similar to that of the Python
array slice notation into into a pair of ints which represent the starting
and ending indices of of the slice.
If the string contains a pair of colon-separated integers, a 2-tuple of
ints with the respective values of those integers will be returned. If the
first number in this pair is omitted, then the value of the "start"
argument is used. If the second number in this pair is omitted, then the
value of the "end" argument is used.
If the string contains a single integer, then a pair of ints with the value
of that integer and its successor, respectively, will be returned. The
exception to this rule is when the successor of the single integer is zero,
in which case the value of the second element of the returned pair will be
the value of the "end" argument.
The string can optionally be bracketed by single non-digit, non-dash
characters at the beginning and/or the end. The character at the beginning
doesn't have to be the same as the one at the end. If either of these
characters exist, they will be stripped away (and ignored) before any of
the above-mentioned processing is done.
If the string contains anything else, it is considered invalid and a
ValueError will be thrown.
'''
if not range:
raise ValueError, 'Invalid range: empty string.'
if not (range[0].isdigit() or range[0] in ('-', ':')):
range = range[1:]
if not (range[-1].isdigit() or range[-1] in ('-', ':')):
range = range[:-1]
colon_count = string.count(range, ':')
if colon_count == 1:
a, b = string.split(range, ':')
try:
if a:
start = int(a)
if b:
end = int(b)
except ValueError:
raise ValueError, 'Invalid range (non-integer value): "%s".' % range
elif colon_count == 0:
try:
start = int(range)
except ValueError:
raise ValueError, 'Invalid range (non-integer value): "%s".' % range
if (start + 1) != 0:
end = start + 1
else:
raise ValueError, 'Invalid range (wrong number of colons): "%s".' % range
return start, end
# The following function was written by Mike Brown, and was taken from the
# Python Cookbook. I would like to dearly thank my grandparents, Sari and Larry
# Pearson, for buying me this book for my birthday.
def wrap(text, width=79):
"""A word-wrap function that preserves existing line breaks and most spaces
in the text. Expects that existing line breaks are posix newlines (\\n).
"""
return reduce(lambda line, word, width=width: '%s%s%s' %
(line,
' \n'[(len(line[line.rfind('\n')+1:])
+ len(word.split('\n',1)[0]) >= width)],
word),
text.split(' ')
)
# The following function is modeled after recipe 3.7 from the Python Cookbook,
# which was written by JÜrgen Hermann and Nick Perkins.
def make_string_filter(keep):
'''Return a function that takes a string and returns a partial copy of that
string consisting only of the characters in 'keep'.
'''
allchars = string.maketrans('', '')
delchars = allchars.translate(allchars, keep)
def string_filter(s, a=allchars, d=delchars): return s.translate(a, d)
return string_filter
def center_text(text, line_width=80, pad_char='-'):
'Returns the given text centered within a line, with padding.'
if len(text) > line_width:
text = text[:line_width-4-3] + '...'
pad_len = (line_width - len(text) - 2) // 2
extra = pad_char * (len(text) % 2)
return '%s %s %s' % (pad_char * pad_len, text, pad_char * pad_len + extra)
def sh_escape(text):
'''Returns a version of the given text that uses backslashes to make it
safe to pass to a Bourne-type shell if you enclose it in double quotes.
'''
return re.sub(r'([$`\"])', r'\\\1', text)
def xmlrpc_server_doc(server_proxy):
'''Produces documentation for the methods of an XML-RPC server.
This function queries an XML-RPC server via the introspection API, and
returns a collection of descriptions that document each of the server's
methods. The returned collection is a dictionary whose keys are the names of
the methods and whose values are blurbs of text that describe the methods.
This was inspired by the xml-rpc-api2txt Perl script that comes with
xmlrpc-c.
'''
method_docs = {}
for method in server_proxy.system.listMethods():
method_docs[method] = ''
signature = server_proxy.system.methodSignature(method)
for sig in signature:
method_docs[method] += '=item %s B<%s> (%s)\n\n' % \
(sig[0], method, ', '.join(sig[1:]))
help = server_proxy.system.methodHelp(method)
method_docs[method] += re.sub(r'(?m)^', r' ', help)
return method_docs
def splitpath(path):
'''Splits a Unix pathname into a list of its components.
If the pathname is absolute, the resulting list will have '/' as its first
element.
'''
plist = []
while path not in ('/', ''):
path, plist[0:0] = os.path.dirname(path), [os.path.basename(path)]
if path:
plist[0:0] = path
return plist
def is_overlapping(A, B, n):
'''Tests whether the slices described by two ranges overlap each other.
Arguments "A" and "B": pairs (2-tuples) of integers, each of which
represents a range within a sequence. The first of each pair is the index
of the first item included in the range, and the second of each pair is the
index of the item that terminates the range (but is not included in the
range).
Argument "n": an integer that represents the length of the sequence in which
these ranges will be applied. This is needed to handle negative range
indices sensibly.
Returns: True if the ranges overlap, otherwise False.
'''
# Handle negative numbers as range indices.
if A[0] < 0: A[0] = n - A[0]
if A[1] < 0: A[1] = n - A[1]
if B[0] < 0: B[0] = n - B[0]
if B[1] < 0: B[1] = n - B[1]
# Any one of these tests indicate overlap.
if A[0] == B[0]: return True
if A[1] == B[1]: return True
if A[0] < B[0] < A[1]: return True
if A[0] < B[1] < A[1]: return True
if B[0] < A[0] < B[1]: return True
if B[0] < A[1] < B[1]: return True
return False
|