audiolazy/lazy_misc.py
def rint(x, step=1):
  """
  Round to integer.

  Parameters
  ----------
  x :
    Input number (integer or float) to be rounded.
  step :
    Quantization level (defaults to 1). If set to 2, the output will be the
    "best" even number.

  Result
  ------
  The step multiple nearest to x. When x is exactly halfway between two
  possible outputs, it'll result the one farthest to zero.

  """
  div, mod = divmod(x, step)
  err = min(step / 10., .1)
  result = div * step
  if x > 0:
    result += err
  elif x < 0:
    result -= err
  if (operator.ge if x >= 0 else operator.gt)(2 * mod, step):
    result += step
  return int(result)
audiolazy/lazy_misc.py
def elementwise(name="", pos=None):
  """
  Function auto-map decorator broadcaster.

  Creates an "elementwise" decorator for one input parameter. To create such,
  it should know the name (for use as a keyword argument and the position
  "pos" (input as a positional argument). Without a name, only the
  positional argument will be used. Without both name and position, the
  first positional argument will be used.

  """
  if (name == "") and (pos is None):
    pos = 0
  def elementwise_decorator(func):
    """
    Element-wise decorator for functions known to have 1 input and 1
    output be applied directly on iterables. When made to work with more
    than 1 input, all "secondary" parameters will the same in all
    function calls (i.e., they will not even be a copy).

    """
    @wraps(func)
    def wrapper(*args, **kwargs):

      # Find the possibly Iterable argument
      positional = (pos is not None) and (pos < len(args))
      arg = args[pos] if positional else kwargs[name]

      if isinstance(arg, Iterable) and not isinstance(arg, STR_TYPES):
        if positional:
          data = (func(*(args[:pos] + (x,) + args[pos+1:]),
                       **kwargs)
                  for x in arg)
        else:
          data = (func(*args,
                       **dict(it.chain(iteritems(kwargs), [(name, x)])))
                  for x in arg)

        # Generators should still return generators
        if isinstance(arg, SOME_GEN_TYPES):
          return data

        # Cast to numpy array or matrix, if needed, without actually
        # importing its package
        type_arg = type(arg)
        try:
          is_numpy = type_arg.__module__ == "numpy"
        except AttributeError:
          is_numpy = False
        if is_numpy:
          np_type = {"ndarray": sys.modules["numpy"].array,
                     "matrix": sys.modules["numpy"].mat
                    }[type_arg.__name__]
          return np_type(list(data))

        # If it's a Stream, let's use the Stream constructor
        from .lazy_stream import Stream
        if issubclass(type_arg, Stream):
          return Stream(data)

        # Tuple, list, set, dict, deque, etc.. all falls here
        return type_arg(data)

      return func(*args, **kwargs) # wrapper returned value
    return wrapper # elementwise_decorator returned value
  return elementwise_decorator
audiolazy/lazy_misc.py
@almost_eq.strategy("bits")
def almost_eq(a, b, bits=32, tol=1, ignore_type=True, pad=0.):
  """
  Almost equal, based on the amount of floating point significand bits.

  Alternative to "a == b" for float numbers and iterables with float numbers,
  and tests for sequence contents (i.e., an elementwise a == b, that also
  works with generators, nested lists, nested generators, etc.). If the type
  of both the contents and the containers should be tested too, set the
  ignore_type keyword arg to False.
  Default version is based on 32 bits IEEE 754 format (23 bits significand).
  Could use 64 bits (52 bits significand) but needs a
  native float type with at least that size in bits.
  If a and b sizes differ, at least one will be padded with the pad input
  value to keep going with the comparison.

  Note
  ----
  Be careful with endless generators!

  """
  if not (ignore_type or type(a) == type(b)):
    return False
  is_it_a = isinstance(a, Iterable)
  is_it_b = isinstance(b, Iterable)
  if is_it_a != is_it_b:
    return False
  if is_it_a:
    return all(almost_eq.bits(ai, bi, bits, tol, ignore_type)
               for ai, bi in xzip_longest(a, b, fillvalue=pad))
  significand = {32: 23, 64: 52, 80: 63, 128: 112
                }[bits] # That doesn't include the sign bit
  power = tol - significand - 1
  return abs(a - b) <= 2 ** power * abs(a + b)
audiolazy/lazy_misc.py
def cached(func):
  """
  Cache decorator for a function without keyword arguments

  You can access the cache contents using the ``cache`` attribute in the
  resulting function, which is a dictionary mapping the arguments tuple to
  the previously returned function result.
  """
  class Cache(dict):
    def __missing__(self, key):
      result = self[key] = func(*key)
      return result
  cache = Cache()
  f = wraps(func)(lambda *key: cache[key])
  f.cache = cache
  return f
audiolazy/lazy_misc.py
def lag2freq(v):
  """ Converts from lag (number of samples) to frequency (rad/sample). """
  return 2 * pi / v
audiolazy/lazy_math.py
def log(x, base=None):
def log1p(x):
def log10(x):
def log2(x):
def factorial(n):
def dB10(data):
def dB20(data):
def sign(x):
audiolazy/lazy_stream.py
class Stream(meta(Iterable, metaclass=StreamMeta)):
  """
  Stream class. Stream instances are iterables that can be seem as generators
  with elementwise operators.

  Examples
  --------
  If you want something like:

  >>> import itertools
  >>> x = itertools.count()
  >>> y = itertools.repeat(3)
  >>> z = 2*x + y
  Traceback (most recent call last):
      ...
  TypeError: unsupported operand type(s) for *: 'int' and ...

  That won't work with standard itertools. That's an error, and not only
  __mul__ but also __add__ isn't supported by their types. On the other hand,
  you can use this Stream class:

  >>> x = Stream(itertools.count()) # Iterable
  >>> y = Stream(3) # Non-iterable repeats endlessly
  >>> z = 2*x + y
  >>> z
  <audiolazy.lazy_stream.Stream object at 0x...>
  >>> z.take(12)
  [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25]

  If you just want to use your existing code, an "itertools" alternative is
  already done to help you:

  >>> from audiolazy import lazy_itertools as itertools
  >>> x = itertools.count()
  >>> y = itertools.repeat(3)
  >>> z = 2*x + y
  >>> w = itertools.takewhile(lambda pair: pair[0] < 10, enumerate(z))
  >>> list(el for idx, el in w)
  [3, 5, 7, 9, 11, 13, 15, 17, 19, 21]

  All operations over Stream objects are lazy and not thread-safe.

  See Also
  --------
  thub :
    "Tee" hub to help using the Streams like numbers in equations and filters.
  tee :
    Just like itertools.tee, but returns a tuple of Stream instances.
  Stream.tee :
    Keeps the Stream usable and returns a copy to be used safely.
  Stream.copy :
    Same to ``Stream.tee``.

  Notes
  -----
  In that example, after declaring z as function of x and y, you should
  not use x and y anymore. Use the thub() or the tee() functions, or
  perhaps the x.tee() or x.copy() Stream methods instead, if you need
  to use x again otherwhere.

  """
  __ignored_classes__ = tuple()

  def __init__(self, *dargs):
    """
    Constructor for a Stream.

    Parameters
    ----------
    *dargs:
      The parameters should be iterables that will be chained together. If
      they're not iterables, the stream will be an endless repeat of the
      given elements. If any parameter is a generator and its contents is
      used elsewhere, you should use the "tee" (Stream method or itertools
      function) before.

    Notes
    -----
    All operations that works on the elements will work with this iterator
    in a element-wise fashion (like Numpy 1D arrays). When the stream
    sizes differ, the resulting stream have the size of the shortest
    operand.

    Examples
    --------
    A finite sequence:

    >>> x = Stream([1,2,3]) + Stream([8,5]) # Finite constructor
    >>> x
    <audiolazy.lazy_stream.Stream object at 0x...>
    >>> tuple(x)
    (9, 7)

    But be careful:

    >>> x = Stream(1,2,3) + Stream(8,5) # Periodic constructor
    >>> x
    <audiolazy.lazy_stream.Stream object at 0x...>
    >>> x.take(15) # Don't try "tuple" or "list": this Stream is endless!
    [9, 7, 11, 6, 10, 8, 9, 7, 11, 6, 10, 8, 9, 7, 11]

    """
    if len(dargs) == 0:
      raise TypeError("Missing argument(s)")

    elif len(dargs) == 1:
      if isinstance(dargs[0], Iterable):
        self._data = iter(dargs[0])
      else:
        self._data = it.repeat(dargs[0])

    else:
      if all(isinstance(arg, Iterable) for arg in dargs):
        self._data = it.chain(*dargs)
      elif not any(isinstance(arg, Iterable) for arg in dargs):
        self._data = it.cycle(dargs)
      else:
        raise TypeError("Input with both iterables and non-iterables")

  def __iter__(self):
    """ Returns the Stream contents iterator. """
    return self._data

  def __bool__(self):
    """
    Boolean value of a stream, called by the bool() built-in and by "if"
    tests. As boolean operators "and", "or" and "not" couldn't be overloaded,
    any trial to cast an instance of this class to a boolean should be seen
    as a mistake.
    """
    raise TypeError("Streams can't be used as booleans.\n"
                    "If you need a boolean stream, try using bitwise "
                    "operators & and | instead of 'and' and 'or'. If using "
                    "'not', you can use the inversion operator ~, casting "
                    "its returned int back to bool.\n"
                    "If you're using it in a 'if' comparison (e.g. for unit "
                    "testing), try to freeze the stream before with "
                    "list(my_stream) or tuple(my_stream).")

  __nonzero__ = __bool__ # For Python 2.x compatibility

  def blocks(self, *args, **kwargs):
    """
    Interface to apply audiolazy.blocks directly in a stream, returning
    another stream. Use keyword args.
    """
    return Stream(blocks(iter(self), *args, **kwargs))

  def take(self, n=None, constructor=list):
    """
    Returns a container with the n first elements from the Stream, or less if
    there aren't enough. Use this without args if you need only one element
    outside a list.

    Parameters
    ----------
    n :
      Number of elements to be taken. Defaults to None.
      Rounded when it's a float, and this can be ``inf`` for taking all.
    constructor :
      Container constructor function that can receie a generator as input.
      Defaults to ``list``.

    Returns
    -------
    The first ``n`` elements of the Stream sequence, created by the given
    constructor unless ``n == None``, which means returns the next element
    from the sequence outside any container.
    If ``n`` is None, this can raise StopIteration due to lack of data in
    the Stream. When ``n`` is a number, there's no such exception.

    Examples
    --------
    >>> Stream(5).take(3) # Three elements
    [5, 5, 5]
    >>> Stream(1.2, 2, 3).take() # One element, outside a container
    1.2
    >>> Stream(1.2, 2, 3).take(1) # With n = 1 argument, it'll be in a list
    [1.2]
    >>> Stream(1.2, 2, 3).take(1, constructor=tuple) # Why not a tuple?
    (1.2,)
    >>> Stream([1, 2]).take(3) # More than the Stream size, n is integer
    [1, 2]
    >>> Stream([]).take() # More than the Stream size, n is None
    Traceback (most recent call last):
      ...
    StopIteration

    Taking rounded float quantities and "up to infinity" elements
    (don't try using ``inf`` with endless Stream instances):

    >>> Stream([4, 3, 2, 3, 2]).take(3.4)
    [4, 3, 2]
    >>> Stream([4, 3, 2, 3, 2]).take(3.6)
    [4, 3, 2, 3]
    >>> Stream([4, 3, 2, 3, 2]).take(inf)
    [4, 3, 2, 3, 2]

    See Also
    --------
    Stream.peek :
      Returns the n first elements from the Stream, without removing them.

    Note
    ----
    You should avoid using take() as if this would be an iterator. Streams
    are iterables that can be easily part of a "for" loop, and their
    iterators (the ones automatically used in for loops) are slightly faster.
    Use iter() builtin if you need that, instead, or perhaps the blocks
    method.

    """
    if n is None:
      return next(self._data)
    if isinf(n) and n > 0:
      return constructor(self._data)
    if isinstance(n, float):
      n = rint(n) if n > 0 else 0 # So this works with -inf and nan
    return constructor(next(self._data) for _ in xrange(n))

  def copy(self):
    """
    Returns a "T" (tee) copy of the given stream, allowing the calling
    stream to continue being used.
    """
    a, b = it.tee(self._data) # 2 generators, not thread-safe
    self._data = a
    return Stream(b)

  def peek(self, n=None, constructor=list):
    """
    Sees/peeks the next few items in the Stream, without removing them.

    Besides that this functions keeps the Stream items, it's the same to the
    ``Stream.take()`` method.

    See Also
    --------
    Stream.take :
      Returns the n first elements from the Stream, removing them.

    Note
    ----
    When applied in a StreamTeeHub, this method doesn't consume a copy.
    Data evaluation is done only once, i.e., after peeking the data is simply
    stored to be yielded again when asked for.

    """
    return self.copy().take(n=n, constructor=constructor)

  def skip(self, n):
    """
    Throws away the first ``n`` values from the Stream.

    Note
    ----
    Performs the evaluation lazily, i.e., the values are thrown away only
    after requesting the next value.

    """
    def skipper(data):
      for _ in xrange(int(round(n))):
        next(data)
      for el in data:
        yield el

    self._data = skipper(self._data)
    return self

  def limit(self, n):
    """
    Enforces the Stream to finish after ``n`` items.
    """
    data = self._data
    self._data = (next(data) for _ in xrange(int(round(n))))
    return self

  def __getattr__(self, name):
    """
    Returns a Stream of attributes or methods, got in an elementwise fashion.
    """
    if name == NEXT_NAME:
      raise AttributeError("Streams are iterable, not iterators")
    return Stream(getattr(a, name) for a in self._data)

  def __call__(self, *args, **kwargs):
    """
    Returns the results from calling elementwise (where each element is
    assumed to be callable), with the same arguments.
    """
    return Stream(a(*args, **kwargs) for a in self._data)

  def append(self, *other):
    """
    Append self with other stream(s). Chaining this way has the behaviour:

      ``self = Stream(self, *others)``

    """
    self._data = it.chain(self._data, Stream(*other)._data)
    return self

  def map(self, func):
    """
    A lazy way to apply the given function to each element in the stream.
    Useful for type casting, like:

    >>> from audiolazy import count
    >>> count().take(5)
    [0, 1, 2, 3, 4]
    >>> my_stream = count().map(float)
    >>> my_stream.take(5) # A float counter
    [0.0, 1.0, 2.0, 3.0, 4.0]

    """
    self._data = xmap(func, self._data)
    return self

  def filter(self, func):
    """
    A lazy way to skip elements in the stream that gives False for the given
    function.
    """
    self._data = xfilter(func, self._data)
    return self

  @classmethod
  def register_ignored_class(cls, ignore):
    cls.__ignored_classes__ += (ignore,)

  def __abs__(self):
    return self.map(abs)
audiolazy/lazy_synth.py
@tostream
def line(dur, begin=0., end=1., finish=False):
  """
  Finite Stream with a straight line, could be used as fade in/out effects.

  Parameters
  ----------
  dur :
    Duration, given in number of samples. Use the sHz function to help with
    durations in seconds.
  begin, end :
    First and last (or stop) values to be yielded. Defaults to [0., 1.],
    respectively.
  finish :
    Choose if ``end`` it the last to be yielded or it shouldn't be yield at
    all. Defauts to False, which means that ``end`` won't be yield. The last
    sample won't have "end" amplitude unless finish is True, i.e., without
    explicitly saying "finish=True", the "end" input works like a "stop" range
    parameter, although it can [should] be a float. This is so to help
    concatenating several lines.

  Returns
  -------
  A finite Stream with the linearly spaced data.

  Examples
  --------
  With ``finish = True``, it works just like NumPy ``np.linspace``, besides
  argument order and lazyness:

  >>> import numpy as np # This test needs Numpy
  >>> np.linspace(.2, .7, 6)
  array([ 0.2,  0.3,  0.4,  0.5,  0.6,  0.7])
  >>> line(6, .1, .7, finish=True)
  <audiolazy.lazy_stream.Stream object at 0x...>
  >>> list(line(6, .2, .7, finish=True))
  [0.2, 0.3, 0.4, 0.5, 0.6, 0.7]
  >>> list(line(6, 1, 4)) # With finish = False (default)
  [1.0, 1.5, 2.0, 2.5, 3.0, 3.5]

  Line also works with Numpy arrays and matrices

  >>> a = np.mat([[1, 2], [3, 4]])
  >>> b = np.mat([[3, 2], [2, 1]])
  >>> for el in line(4, a, b):
  ...   print(el)
  [[ 1.  2.]
   [ 3.  4.]]
  [[ 1.5   2.  ]
   [ 2.75  3.25]]
  [[ 2.   2. ]
   [ 2.5  2.5]]
  [[ 2.5   2.  ]
   [ 2.25  1.75]]

  And also with ZFilter instances:

  >>> from audiolazy import z
  >>> for el in line(4, z ** 2 - 5, z + 2):
  ...   print(el)
  z^2 - 5
  0.75 * z^2 + 0.25 * z - 3.25
  0.5 * z^2 + 0.5 * z - 1.5
  0.25 * z^2 + 0.75 * z + 0.25

  Note
  ----
  Amplitudes commonly should be float numbers between -1 and 1.
  Using line(<inputs>).append([end]) you can finish the line with one extra
  sample without worrying with the "finish" input.

  See Also
  --------
  sHz :
    Second and hertz constants from samples/second rate.

  """
  m = (end - begin) / (dur - (1. if finish else 0.))
  for sample in xrange(int(dur + .5)):
    yield begin + sample * m
audiolazy/lazy_misc.py
def freq2lag(v):
  """ Converts from frequency (rad/sample) to lag (number of samples). """
  return 2 * pi / v
audiolazy/lazy_compat.py
def orange(*args, **kwargs):
def iteritems(dictionary):
def itervalues(dictionary):
def im_func(method):
def meta(*bases, **kwargs):
    def __new__(mcls, name, mbases, namespace):
PYTHON2 = sys.version_info.major == 2
STR_TYPES = (getattr(builtins, "basestring", str),)
INT_TYPES = (int, getattr(builtins, "long", None)) if PYTHON2 else (int,)
SOME_GEN_TYPES = (types.GeneratorType, xrange(0).__class__, enumerate, xzip,
                  xzip_longest, xmap, xfilter)
NEXT_NAME = "next" if PYTHON2 else "__next__"
HAS_MATMUL = sys.version_info >= (3,5)
  class NewMeta(type):


Question: import pytest
import itertools as it
import cmath, operator
from functools import reduce
from ..lazy_misc import (rint, elementwise, freq2lag, lag2freq, almost_eq,
                         cached)
from ..lazy_compat import INT_TYPES, orange, xrange
from ..lazy_math import pi
from ..lazy_stream import Stream
from ..lazy_synth import line
# -*- coding: utf-8 -*-
# This file is part of AudioLazy, the signal processing Python package.
# Copyright (C) 2012-2016 Danilo de Jesus da Silva Bellini
#
# AudioLazy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Testing module for the lazy_misc module
"""

p = pytest.mark.parametrize


# Audiolazy internal imports

class TestRInt(object):
  table = [
    (.499, 0),
    (-.499, 0),
    (.5, 1),
    (-.5, -1),
    (1.00001e3, 1000),
    (-227.0090239, -227),
    (-12.95, -13),
  ]

  @p(("data", "expected"), table)
  def tests_from_table_default_step(self, data, expected):
    result = rint(data)
    assert isinstance(result, INT_TYPES)
    assert result == expected

  @p(("data", "expected"), table)
  @p("n", [2, 3, 10])
  def tests_from_step_n(self, data, expected, n):
    data_n, expected_n = n * data, n * expected # Inputs aren't in step n
    result = rint(data_n, step=n)
    assert isinstance(result, INT_TYPES)
    assert result == expected_n


class TestElementwise(object):
  _data = [1, 7, 9, -11, 0, .3, "ab", True, None, rint]
  @p("data", it.chain(_data, [_data], tuple(_data),
                      it.combinations_with_replacement(_data, 2))
    )
  def test_identity_with_single_and_generic_hybrid_tuple_and_list(self, data):
    f = elementwise()(lambda x: x)
    assert f(data) == data

  def test_generator_and_lazy_range_inputs(self):
    f = elementwise()(lambda x: x*2)
    fx = f(xrange(42))
    gen = (x*4 for x in xrange(42))
    fg = f(x*2 for x in xrange(42))
    assert type(fx) == type(gen)
    assert type(fg) == type(gen)
    assert list(fx) == orange(0,42*2,2)
    assert list(fg) == list(gen)


class TestConverters(object):

  def test_freq_lag_converters_are_inverses(self):
    for v in [37, 12, .5, -2, 1, .18, 4, 1e19, 2.7e-34]:

Answer:       assert freq2lag(v) == lag2freq(v)