[python-snuggs] 01/02: Imported Upstream version 1.3.1

Johan Van de Wauw johanvdw-guest at moszumanska.debian.org
Wed Apr 29 12:26:29 UTC 2015


This is an automated email from the git hooks/post-receive script.

johanvdw-guest pushed a commit to branch master
in repository python-snuggs.

commit e59942de7c216a5364d5321167a3c9773e55042f
Author: Johan Van de Wauw <johan.vandewauw at gmail.com>
Date:   Fri Apr 24 21:26:13 2015 +0200

    Imported Upstream version 1.3.1
---
 .travis.yml        |  12 +++
 CHANGES.txt        |  22 ++++++
 LICENSE            |  22 ++++++
 README.rst         | 106 +++++++++++++++++++++++++++
 setup.py           |  30 ++++++++
 snuggs/__init__.py | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 test_snuggs.py     | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 609 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..673c733
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+language: python
+python:
+  - "2.7"
+  - "3.4"
+install:
+  - "pip install pytest"
+  - "pip install coveralls"
+  - "pip install -e ."
+script: 
+  - coverage run --source=snuggs -m py.test
+after_success:
+  - coveralls
diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 0000000..8cd9018
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,22 @@
+Changes
+=======
+
+1.3.1 (2015-04-03)
+------------------
+- Revert to operator functions in op_map (#4).
+
+1.3.0 (2015-03-30)
+------------------
+- Added nil keyword (#2).
+
+1.2.0 (2015-03-25)
+------------------
+- Helpfully formatted error messages, as Python SyntaxError.
+
+1.1.0 (2015-02-17)
+------------------
+- Add `map` and `partial` higher-order functions.
+
+1.0.0 (2015-02-13)
+------------------
+- First release.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3e1c06d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Mapbox
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+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 OR COPYRIGHT HOLDERS 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.
+
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..67e8ade
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,106 @@
+======
+snuggs
+======
+
+.. image:: https://travis-ci.org/mapbox/snuggs.svg?branch=master
+   :target: https://travis-ci.org/mapbox/snuggs
+
+.. image:: https://coveralls.io/repos/mapbox/snuggs/badge.svg
+   :target: https://coveralls.io/r/mapbox/snuggs
+
+Snuggs are s-expressions for Numpy
+
+.. code-block:: python
+
+    >>> snuggs.eval("(+ (asarray 1 1) (asarray 2 2))")
+    array([3, 3])
+
+Syntax
+======
+
+Snuggs wraps Numpy in expressions with the following syntax:
+
+.. code-block::
+
+    expression = "(" (operator | function) *arg ")"
+    arg = expression | name | number | string
+
+Examples
+========
+
+Addition of two numbers
+-----------------------
+
+.. code-block:: python
+
+    import snuggs
+    snuggs.eval('(+ 1 2)')
+    # 3
+
+Multiplication of a number and an array
+---------------------------------------
+
+Arrays can be created using ``asarray``.
+
+.. code-block:: python
+
+    snuggs.eval("(* 3.5 (asarray 1 1))")
+    # array([ 3.5,  3.5])
+
+Evaluation context
+------------------
+
+Expressions can also refer by name to arrays in a local context.
+
+.. code-block:: python
+
+    snuggs.eval("(+ (asarray 1 1) b)", b=np.array([2, 2]))
+    # array([3, 3])
+
+Functions and operators
+=======================
+
+Arithmetic (``* + / -``) and logical (``< <= == != >= > & |``) operators are
+available. Members of the ``numpy`` module such as ``asarray()``, ``mean()``,
+and ``where()`` are also available.
+
+.. code-block:: python
+
+    snuggs.eval("(mean (asarray 1 2 4))")
+    # 2.3333333333333335
+
+.. code-block:: python
+
+    snuggs.eval("(where (& tt tf) 1 0)",
+        tt=numpy.array([True, True]),
+        tf=numpy.array([True, False]))
+    # array([1, 0])
+
+Higher-order functions
+======================
+
+New in snuggs 1.1 are higher-order functions ``map`` and ``partial``.
+
+.. code-block:: python
+
+    snuggs.eval("((partial * 2) 2)")
+    # 4
+
+    snuggs.eval('(asarray (map (partial * 2) (asarray 1 2 3)))')
+    # array([2, 4, 6])
+
+Performance notes
+=================
+
+Snuggs makes simple calculator programs possible. None of the optimizations
+of, e.g., `numexpr <https://github.com/pydata/numexpr>`__ (multithreading,
+elimination of temporary data, etc) are currently available.
+
+If you're looking to combine Numpy with a more complete Lisp, see
+`Hy <https://github.com/hylang/hy>`__:
+
+.. code-block:: clojure
+
+    => (import numpy)
+    => (* 2 (.asarray numpy [1 2 3]))
+    array([2, 4, 6])
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..dbb588a
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,30 @@
+from codecs import open as codecs_open
+from setuptools import setup, find_packages
+
+
+# Get the long description from the relevant file
+with codecs_open('README.rst', encoding='utf-8') as f:
+    long_description = f.read()
+
+
+setup(name='snuggs',
+      version='1.3.1',
+      description=u"Snuggs are s-expressions for Numpy",
+      long_description=long_description,
+      classifiers=[],
+      keywords='',
+      author=u"Sean Gillies",
+      author_email='sean at mapbox.com',
+      url='https://github.com/mapbox/snuggs',
+      license='MIT',
+      packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=[
+          'click',
+          'numpy',
+          'pyparsing'
+      ],
+      extras_require={
+          'test': ['pytest'],
+      })
diff --git a/snuggs/__init__.py b/snuggs/__init__.py
new file mode 100644
index 0000000..e91cf98
--- /dev/null
+++ b/snuggs/__init__.py
@@ -0,0 +1,210 @@
+"""
+Snuggs are s-expressions for Numpy.
+"""
+
+import functools
+import itertools
+import operator
+import re
+import sys
+
+from pyparsing import (
+    alphanums, ZeroOrMore, nums, oneOf, Word, Literal, Combine, QuotedString,
+    ParseException, Forward, Group, CaselessLiteral, Optional, alphas,
+    OneOrMore, ParseResults, ParseException)
+
+import numpy
+
+
+__all__ = ['eval']
+__version__ = "1.3.1"
+
+# Python 2-3 compatibility
+string_types = (str,) if sys.version_info[0] >= 3 else (basestring,)
+
+
+class Context(object):
+
+    def __init__(self):
+        self._data = {}
+
+    def add(self, name, val):
+        self._data[name] = val
+
+    def get(self, name):
+        return self._data[name]
+
+    def lookup(self, index, subindex=None):
+        s = list(self._data.values())[int(index)-1]
+        if subindex:
+            return s[int(subindex)-1]
+        else:
+            return s
+
+    def clear(self):
+        self._data = {}
+
+_ctx = Context()
+
+
+class ctx(object):
+
+    def __init__(self, **kwds):
+        self.kwds = kwds
+
+    def __enter__(self):
+        _ctx.clear()
+        for k, v in self.kwds.items():
+            _ctx.add(k, v)
+        return self
+
+    def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
+        self.kwds = None
+        _ctx.clear()
+
+
+class ExpressionError(SyntaxError):
+    """Snuggs specific syntax errors"""
+    filename = "<string>"
+    lineno = 1
+
+op_map = {
+    '*': operator.mul,
+    '+': operator.add,
+    '/': operator.truediv,
+    '-': operator.sub,
+    '<': operator.lt,
+    '<=': operator.le,
+    '==': operator.eq,
+    '!=': operator.ne,
+    '>=': operator.ge,
+    '>': operator.gt,
+    '&': operator.and_,
+    '|': operator.or_,
+    }
+
+def asarray(*args):
+    if len(args) == 1 and hasattr(args[0], '__iter__'):
+        return numpy.asanyarray(list(args[0]))
+    else:
+        return numpy.asanyarray(list(args))
+
+func_map = {
+    'asarray': asarray,
+    'read': _ctx.lookup,
+    'take': lambda a, idx: numpy.take(a, idx-1, axis=0),
+    }
+
+higher_func_map = {
+    'map': map if sys.version_info[0] >= 3 else itertools.imap,
+    'partial': functools.partial,
+    }
+
+# Definition of the grammar.
+decimal = Literal('.')
+e = CaselessLiteral('E')
+sign = Literal('+') | Literal('-')
+number = Word(nums)
+name = Word(alphas)
+nil = Literal('nil').setParseAction(lambda s, l, t: [None])
+
+def resolve_var(s, l, t):
+    try:
+        return _ctx.get(t[0])
+    except KeyError:
+        err = ExpressionError(
+            "name '%s' is not defined" % t[0])
+        err.text = s
+        err.offset = l + 1
+        raise err
+
+var = name.setParseAction(resolve_var)
+
+integer = Combine(
+    Optional(sign) +
+    number
+    ).setParseAction(lambda s, l, t: int(t[0]))
+
+real = Combine(
+    integer +
+    decimal + Optional(number) +
+    Optional(e + integer)
+    ).setParseAction(lambda s, l, t: float(t[0]))
+
+string = QuotedString("'") | QuotedString('"')
+
+lparen = Literal('(').suppress()
+rparen = Literal(')').suppress()
+
+op = oneOf(' '.join(op_map.keys())).setParseAction(
+    lambda s, l, t: op_map[t[0]])
+
+
+def resolve_func(s, l, t):
+    try:
+        return func_map[t[0]] if t[0] in func_map else getattr(numpy, t[0])
+    except AttributeError:
+        err = ExpressionError(
+            "'%s' is not a function or operator" % t[0])
+        err.text = s
+        err.offset = l + 1
+        raise err
+
+func = Word(alphanums + '_').setParseAction(resolve_func)
+
+higher_func = oneOf('map partial').setParseAction(
+    lambda s, l, t: higher_func_map[t[0]])
+
+func_expr = Forward()
+higher_func_expr = Forward()
+expr = higher_func_expr | func_expr
+
+operand = higher_func_expr | func_expr | nil | var | real | integer | string
+
+func_expr << Group(
+    lparen +
+    (higher_func_expr | op | func) +
+    operand +
+    ZeroOrMore(operand) +
+    rparen)
+
+higher_func_expr << Group(
+    lparen +
+    higher_func +
+    (nil | higher_func_expr | op | func) +
+    ZeroOrMore(operand) +
+    rparen)
+
+
+def processArg(arg):
+    if not isinstance(arg, ParseResults):
+        return arg
+    else:
+        return processList(arg)
+
+
+def processList(lst):
+    args = [processArg(x) for x in lst[1:]]
+    func = processArg(lst[0])
+    return func(*args)
+
+
+def handleLine(line):
+    try:
+        result = expr.parseString(line)
+        return processList(result[0])
+    except ParseException as exc:
+        text = str(exc)
+        m = re.search(r'(Expected .+) \(at char (\d+)\), \(line:(\d+)', text)
+        msg = m.group(1)
+        if 'map|partial' in msg:
+            msg = "expected a function or operator"
+        err = ExpressionError(msg)
+        err.text = line
+        err.offset = int(m.group(2)) + 1
+        raise err
+
+
+def eval(source, **kwds):
+    with ctx(**kwds):
+        return handleLine(source)
diff --git a/test_snuggs.py b/test_snuggs.py
new file mode 100644
index 0000000..ca5d074
--- /dev/null
+++ b/test_snuggs.py
@@ -0,0 +1,207 @@
+import numpy
+import pytest
+
+import snuggs
+
+# Fixtures follow the tests. See the end of the file.
+
+
+def test_integer():
+    assert list(snuggs.integer.parseString('1')) == [1]
+
+
+def test_real():
+    assert list(snuggs.real.parseString('1.1')) == [1.1]
+
+
+def test_int_expr():
+    assert snuggs.eval('(+ 1 2)') == 3
+
+
+def test_real_expr():
+    assert round(snuggs.eval('(* 0.1 0.2)'), 3) == 0.02
+
+
+def test_int_real_expr():
+    assert snuggs.eval('(+ 2 1.1)') == 3.1
+
+
+def test_real_int_expr():
+    assert snuggs.eval('(+ 1.1 2)') == 3.1
+
+
+def test_arr_var(ones):
+    r = snuggs.eval('(+ foo 0)', foo=ones)
+    assert list(r.flatten()) == [1, 1, 1, 1]
+
+
+def test_arr_lookup(ones):
+    r = snuggs.eval('(read 1)', foo=ones)
+    assert list(r.flatten()) == [1, 1, 1, 1]
+
+
+def test_arr_lookup_2(ones):
+    r = snuggs.eval('(read 1 1)', foo=ones)
+    assert list(r.flatten()) == [1, 1]
+
+
+def test_arr_take(ones):
+    r = snuggs.eval('(take foo 1)', foo=ones)
+    assert list(r.flatten()) == [1, 1]
+    r = snuggs.eval('(take foo 2)', foo=ones)
+    assert list(r.flatten()) == [1, 1]
+
+
+def test_int_arr_expr(ones):
+    result = snuggs.eval('(+ foo 1)', foo=ones)
+    assert list(result.flatten()) == [2, 2, 2, 2]
+
+
+def test_int_arr_expr_by_name(ones):
+    result = snuggs.eval('(+ (read 1) 1.5)', foo=ones)
+    assert list(result.flatten()) == [2.5, 2.5, 2.5, 2.5]
+
+
+def test_int_arr_read(ones):
+    result = snuggs.eval('(+ (read 1 1) 1.5)', foo=ones)
+    assert list(result.flatten()) == [2.5, 2.5]
+
+
+def test_list(ones):
+    result = snuggs.eval(
+        '(asarray (take foo 1) (take foo 1) (take bar 1) (take bar 1))',
+        foo=ones, bar=ones)
+    assert list(result.flatten()) == [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
+
+
+def test_eq(ones):
+    ones[0][0] = 2
+    result = snuggs.eval('(== foo 1)', foo=ones)
+    assert list(result.flatten()) == [False, True, True, True]
+
+
+def test_or(truetrue, truefalse):
+    result = snuggs.eval(
+        '(| foo bar)', foo=truetrue, bar=truefalse)
+    assert list(result.flatten()) == [True, True]
+
+
+def test_and(truetrue, truefalse):
+    result = snuggs.eval(
+        '(& foo bar)', foo=truetrue, bar=truefalse)
+    assert list(result.flatten()) == [True, False]
+
+
+def test_ones_like(truefalse):
+    result = snuggs.eval("(ones_like foo 'uint8')", foo=truefalse)
+    assert list(result.flatten()) == [1.0, 1.0]
+
+
+def test_full_like(truefalse):
+    result = snuggs.eval("(full_like foo 3.14 'float64')", foo=truefalse)
+    assert list(result.flatten()) == [3.14, 3.14]
+    result = snuggs.eval('(full_like foo 3.14 "float64")', foo=truefalse)
+    assert list(result.flatten()) == [3.14, 3.14]
+
+
+def test_ufunc(truetrue, truefalse):
+    result = snuggs.eval(
+        '(where (& foo bar) 1 0)', foo=truetrue, bar=truefalse)
+    assert list(result.flatten()) == [1.0, 0.0]
+
+
+def test_partial():
+    result = snuggs.eval('((partial * 2) 2)')
+    assert result == 4
+
+
+def test_map_func():
+    result = snuggs.eval('(map sqrt (asarray 1 4 9))')
+    assert list(result) == [1, 2, 3]
+
+
+def test_map_partial():
+    result = snuggs.eval('(map (partial * 2) (asarray 1 2 3))')
+    assert list(result) == [2, 4, 6]
+
+
+def test_map_asarray():
+    result = snuggs.eval('(asarray (map (partial * 2) (asarray 1 2 3)))')
+    assert list(result) == [2, 4, 6]
+
+
+def test_nil():
+    assert snuggs.eval('(== nil nil)')
+    assert not snuggs.eval('(== 1 nil)')
+    assert not snuggs.eval('(== nil 1)')
+    assert snuggs.eval('(!= 1 nil)')
+    assert snuggs.eval('(!= nil 1)')
+
+
+def test_masked_arr():
+    foo = numpy.ma.masked_equal(numpy.array([0, 0, 0, 1], dtype='uint8'), 0)
+    r = snuggs.eval('(+ foo 1)', foo=foo)
+    assert list(r.data.flatten()) == [0, 0, 0, 2]
+    assert list(r.flatten()) == [numpy.ma.masked, numpy.ma.masked, numpy.ma.masked, 2]
+
+
+# Parse and syntax error testing.
+def test_missing_closing_paren():
+    with pytest.raises(SyntaxError) as excinfo:
+        result = snuggs.eval("(+ 1 2")
+    assert excinfo.value.lineno == 1
+    assert excinfo.value.offset == 7
+    assert str(excinfo.value) == 'Expected ")"'
+
+
+def test_missing_func():
+    with pytest.raises(SyntaxError) as excinfo:
+        result = snuggs.eval("(0 1 2)")
+    assert excinfo.value.lineno == 1
+    assert excinfo.value.offset == 2
+    assert str(excinfo.value) == "'0' is not a function or operator"
+
+
+def test_missing_func2():
+    with pytest.raises(SyntaxError) as excinfo:
+        result = snuggs.eval("(# 1 2)")
+    assert excinfo.value.lineno == 1
+    assert excinfo.value.offset == 2
+    assert str(excinfo.value) == "expected a function or operator"
+
+
+def test_undefined_var():
+    with pytest.raises(SyntaxError) as excinfo:
+        result = snuggs.eval("(+ 1 bogus)")
+    assert excinfo.value.lineno == 1
+    assert excinfo.value.offset == 6
+    assert str(excinfo.value) == "name 'bogus' is not defined"
+
+
+def test_bogus_higher_order_func():
+    with pytest.raises(SyntaxError) as excinfo:
+        result = snuggs.eval("((bogus * 2) 2)")
+    assert excinfo.value.lineno == 1
+    assert excinfo.value.offset == 3
+    assert str(excinfo.value) == "expected a function or operator"
+
+
+def test_type_error():
+    with pytest.raises(TypeError) as excinfo:
+        result = snuggs.eval("(+ 1 'bogus')")
+
+
+# Fixtures.
+ at pytest.fixture
+def ones():
+    return numpy.ones((2, 2))
+
+
+ at pytest.fixture
+def truetrue():
+    return numpy.array([True, True])
+
+
+ at pytest.fixture
+def truefalse():
+    return numpy.array([True, False])

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/python-snuggs.git



More information about the Pkg-grass-devel mailing list