/trunk/nubox/src/nubox/util.py
https://code.google.com/p/nubox/ · Python · 394 lines · 159 code · 21 blank · 214 comment · 28 complexity · 96983e34e954fd794f76febc7596cdf6 MD5 · raw file
- # -*- coding: utf-8 -*-
- """
- :mod:`nubox.util`
- =================
- Provides utility functions used within ``nubox``.
- """
- from __future__ import (division, with_statement, absolute_import, generators,
- nested_scopes)
- from math import floor
- from .shim import (xrange, product, izip, bytes)
- from .const import (TYPE_TO_TYPECODE, TYPECODES, ARRAY_TYPECODES, INT_TYPECODES,
- FLOAT_TYPECODES, UNICODE_TYPECODES, OBJECT_TYPECODES)
- def gettype(item):
- """
- Determines the ``type`` and typecode of an **item**. Returns a ``tuple``
- with a Python ``type`` or ``class`` and itemcode ``str``.
-
- Arguments:
-
- - item(``object``) an **item** to be placed in an ``NdArray``
-
- """
- item_type = type(item)
- try:
- item_typecode = TYPE_TO_TYPECODE[item_type]
- except KeyError:
- item_typecode = OBJECT_TYPECODES[0]
- return (item_type, item_typecode)
- def compatypecodes(typecodes):
- """
- Determines if an iterable of typecodes is represents the same Python
- ``type``. Returns a ``bool``. Typecodes that resolve to the same ``type``
- are "compatible" and generally can be stored in the same array without loss.
-
- Arguments:
-
- - typecodes(sequence) a sequence of typecodes from most likely from
- ``nubox.const.TYPECODES``
-
- """
- all_tc = len(typecodes)
- for cls in (INT_TYPECODES, FLOAT_TYPECODES, UNICODE_TYPECODES,
- OBJECT_TYPECODES):
- if len([tc for tc in typecodes if tc in cls]) == all_tc:
- return True
- return False
- def checktypecode(typecode):
- """
- Determines ``bool`` values of typecode properties returns a ``tuple`` of
- ``(istc, isatc, isutc, isotc, isftc, isitc)``, where:
-
- - ``istc`` is any valid typecode
- - ``isatc`` is an ``array`` typecode (valid for ``array.array`` instances)
- - ``isutc`` is an ``unicode`` typecode
- - ``isotc`` is an ``object`` typecode
- - ``isftc`` is a ``float`` typecode
- - ``isitc`` is an ``int`` or ``long`` typecode
-
- Arguments:
-
- - typecode(``str``) A single character identifying the typecode most
- likely one of ``nubox.const.TYPECODES``
-
- """
- istc = typecode in TYPECODES
- isatc = typecode in ARRAY_TYPECODES
- isutc = typecode in UNICODE_TYPECODES
- isotc = typecode in OBJECT_TYPECODES
- isftc = typecode in FLOAT_TYPECODES
- isitc = typecode in INT_TYPECODES
- return (istc, isatc, isutc, isotc, isftc, isitc)
- def checkitem(item):
- """
- Determines **item** properties and returns ``bool`` values. Returns a
- ``tuple`` of ``(isiterable, isarray, isarrayitem, islistitem)``, where:
-
- - ``isatomic`` is ``True`` if **item** is atomic i.e. not a container
- - ``isiterable`` is ``True`` if **item** is an iterable
- - ``isarray`` is ``True`` if **item** is an ``array.array`` instance
- - ``isarrayitem`` is ``True`` if **item** can be an ``array.array``
- **item**
- - ``islistitem`` is ``True`` if **item** can be a ``list`` **item**
-
- Arguments:
-
- - item(``object``) an **item** to be placed in an ``NdArray``
-
- """
- item_type, item_typecode = gettype(item)
- try:
- iter(item)
- isiterable = True
- if (item_type in (bytes, unicode)) and (len(item) == 1): # str or unicode
- isatomic = True
- else:
- isatomic = False
- except TypeError:
- isiterable = False
- isatomic = True
- isarray = hasattr(item_type, '_kwargs') and hasattr(item_type, 'data')
- if item_typecode in ARRAY_TYPECODES:
- isarrayitem = True
- islistitem = True
- elif item_typecode in TYPECODES:
- isarrayitem = False
- islistitem = True
- else:
- isarrayitem = False
- islistitem = False
- return (isatomic, isiterable, isarray, isarrayitem, islistitem)
- def flatten(l):
- """
- Flattens a ``list`` or ``tuple``. Returns a ``list`` with all elements.
-
- Arguments:
-
- - l(sequence) A possibly nested ``list`` or ``tuple`` of elements
-
- """
- if isinstance(l, (list, tuple)):
- return sum(map(flatten, l), [])
- else:
- return [l]
- def unnest(l):
- """
- For a given iterable of iterables returns a ``list``, which contains all
- sub-sequences in a depth-first manner. For example given a nested iterable:
- ``[(1, 2, 3), (3, (4, 5))]`` it returns: ``[[(1, 2, 3), (3, (4, 5))],
- (1, 2, 3), 1, 2, 3, (3, (4, 5)), 3, (4, 5), 4, 5]``.
-
- Arguments:
-
- - l(sequence) A possibly nested ``list`` or ``tuple`` of elements
-
- """
- u = []
- u.append(l)
- if isinstance(l, (list, tuple)):
- for e in l:
- u.extend(unnest(e))
- return u
- def slices_shape2indices_shape(slices, shape):
- """
- Translates and iterable of ``slice`` instances and the corresponding "shape"
- i.e. lengths of each dimension into a ``tuple`` of indices and a new shape.
- This function de facto implements an nD-slice.
-
- Arguments:
-
- - slices(iterable of ``slice``) a sequence of ``slice`` instances
- - shape(``tuple``) a sequence of dimensions i.e. lengths for each of the
- ``slices``.
-
- """
- if len(slices) != len(shape):
- raise ValueError("number of slices must match shape")
- nd_indices = []
- nd_shape = []
- for dim, slice in izip(shape, slices):
- sss = slice.indices(dim) # start,stop,step obeying len
- indices = range(*sss) # this -> [] if sss is an empty slice
- dim = len(indices)
- nd_indices.append(indices)
- nd_shape.append(dim)
- nd_indices = tuple(product(*nd_indices))
- nd_shape = tuple(nd_shape) if nd_indices else () # at least on 0 in nd_shape
- return (nd_indices, tuple(nd_shape))
- def hex_to_rgb(value):
- """
- Converts a hex ``string`` into a RGB ``tuple``.
-
- Arguments:
-
- - value(``str``) A ``string`` representation of a hexadecimal
- number.
-
- """
- value = value.lstrip('#')
- lv = len(value)
- return tuple(int(value[i:i + int(lv / 3)], 16) for i in range(0, lv, int(lv / 3)))
- def rgb_to_hex(rgb):
- """
- Converts a RGB ``sequence`` into a hex ``string``.
-
- Arguments:
-
- - rgb(sequence) A sequence of ``int`` in the 0-255 range.
-
- """
- return '#%02x%02x%02x' % rgb
- def make_colors(breakpoints, length=240):
- """
- Creates a linear color map given RGB "breakpoints". Returns an array of
- colors of specified "length". A breakpoint is any RGB color-tuple. By
- default returns an array valid for ``hijack_colors``.
-
- Arguments:
-
- - breakpoints (sequence) A sequence of ``tuples`` of RGB values
- each RGB value is a floating point number from ``0.`` to ``1.``.
- - length(``int``) [default: ``240``] The number of colors in the returned
- ``list``
- """
- ln = len(breakpoints)
- rng = floor(length / (ln - 1)) #
- if ln < 2:
- raise ValueError('at least 2 breakpoints required')
- breakids = []
- for i in xrange(0, ln):
- breakids.append(int(length * (i) / float(ln - 1)))
- # we have a dynamic range of 240
- colors = []
- for start in xrange(ln - 1):
- lor, log, lob = breakpoints[start]
- hir, hig, hib = breakpoints[start + 1]
- for id_ in xrange(*breakids[start:start + 2]):
- r = (id_ % (rng)) / float(rng) # linear space
- clr = [hir * r + lor * (1 - r),
- hig * r + log * (1 - r),
- hib * r + lob * (1 - r)]
- colors.append(clr)
- return colors
- #
- #def hijack_colors(colors):
- # """
- # Sets the 240 i.e. 256 - 16 available colors of a terminal to RGB values in
- # "colors". Colors should be a sequence of tuples or a rank-2
- # ``numpy.ndarray``.
- #
- # Arguments:
- #
- # - colors (``sequence`` or ``numpy.ndarray``) A sequence of 240 RGB
- # 3-tuples.
- # """
- # if len(colors) != 240:
- # raise ValueError("Array has to be of length 240.")
- # init = ''
- # for i, (r, g, b) in enumerate(colors):
- # init += "\x1b]4;%d;rgb:%02x/%02x/%02x\x1b\\" % \
- # (16 + i, int(r * 255), int(g * 255), int(b * 255))
- # init += '\n'
- # sys.stdout.write(init)
- #
- #def print_array(array, colors=None):
- # """
- # Prints an "array" to ``sys.stdout``. The color map is given by "colors".
- # Custom color maps can be constructed by the ``make_colors`` function.
- #
- # Arguments:
- #
- # - array (``numpy.ndarray``) Any array which makes sense viewed as
- # ``float``.
- # - colors (``sequence``) [default: ``COLDHOT``] See: ``make_colors`` and
- # ``hijack_colors``
- #
- # """
- # if array.typecode not in FLOAT_TYPECODES:
- # raise ValueError('array must be of float typecode')
- # if len(array.shape) != 3:
- # raise ValueError('array must be of rank-3')
- # colors = colors or COLDHOT
- # hijack_colors(colors)
- # # shift to positive
- # min_ = array.item_min()[0]
- # max_ = array.item_max()[0]
- # # normalize array to 0-1
- # norm_array = array.new()
- # norm_array.map_item('sub', min_)
- # norm_array.map_item('div', max_)
- # data = []
- # for row in norm_array.child_iter_fast():
- # for el in row.child_iter_fast():
- # clr_idx = int(el.data[0] * 239) + 16
- # assert clr_idx < 256
- # data.append("\x1b[48;5;%dm " % clr_idx)
- # data.append('\x1b[0m \n')
- # sys.stdout.write("".join(data))
- #def make_ruler(length, major=(20, '|'), minor=(10, '.')):
- # """
- # Constructs a ruler like that::
- #
- # # |---------.---------|-------
- # # 0 20
- #
- # Allows to specify the distance and character of minor/major ticks. Returns
- # two strings for the ruler and for the numbers corresponding to major ticks.
- #
- # Arguments:
- #
- # - length (``int``) length of the constructed ruler
- # - major (``tuple``) [default: (10, '.')] A tuple of the form
- # ``(N, 'X')``, where N is an integer, which means that a major-tick of
- # character 'X' will be placed every N symbols starting and including 0.
- # - minor (``tuple``) [default: (10, '.')] A tuple of the form
- # ``(M, 'Y')``, where M is an integer, which means that a minor-tick of
- # character 'Y' will be placed every M symbols, but only where no
- # major-tick is placed.
- # """
- # ruler = []
- # value = []
- # for pos in range(length):
- # if not pos % major[0]:
- # ruler.append('|')
- # s = "%" + ("-%ss" % major[0])
- # value.append(s % pos)
- # elif not pos % minor[0]:
- # ruler.append('.')
- # else:
- # ruler.append('-')
- # return ("".join(ruler), "".join(value))
- #def print_strings(strings, raw_strings=(), ruler=True, width=80, **kwargs):
- # """
- # Formats and prints strings wrapped to the specified "width" and interleaved.
- # Optionally a ruler is included.
- #
- # Arguments:
- #
- # - strings (``sequence``) A sequence of strings.
- # - raw_strings (``sequence``) A sequence of pre-wrapped
- # strings. A wrapped string is a sequence of strings of right length.
- # This is useful if string includes non-printable characters.
- # - ruler (``bool``) If ``True`` a ruler will be included *below* the
- # strings.
- # - width (``int``) The maximum width of the print-out.
- #
- # Additional keyworded arguments are passed to ``make_ruler``.
- # """
- # maxlen = max([len(string) for string in strings])
- # rul, num = make_ruler(maxlen, **kwargs)
- # wvals = []
- # for raw_seqs in raw_strings:
- # wvals.append(raw_seqs)
- # for seq in strings:
- # wvals.append(wrap(seq, width=width, break_on_hyphens=False))
- # if ruler:
- # wvals.append(wrap(rul, width=width, break_on_hyphens=False))
- # wvals.append(wrap(num, width=width, break_on_hyphens=False))
- #
- # for block in izip_longest(*wvals):
- # for part in block:
- # if part:
- # sys.stdout.write(part)
- # sys.stdout.write('\n')
- # sys.stdout.write('\n')
- GRAY = make_colors([
- (0., 0., 0.),
- (1., 1., 1.)
- ])
- COLDHOT = make_colors([
- (0.0, 0.0, 1.0),
- (0.0, 0.5, 1.0),
- (1.0, 1.0, 1.0),
- (1.0, 1.0, 0.0),
- (1.0, 0.0, 0.0)
- ])
- COLD = make_colors([
- (0.0, 0.0, 1.0),
- (0.5, 0.5, 1.0),
- (1.0, 1.0, 1.0)
- ])
- HOT = make_colors([
- (1.0, 1.0, 1.0),
- (1.0, 1.0, 0.0),
- (1.0, 0.0, 0.0)
- ])
- HEAT = make_colors([
- (0.0, 0.0, 0.0),
- (1.0, 0.0, 0.0),
- (1.0, 1.0, 0.0),
- (1.0, 1.0, 1.0)
- ])