Coder Social home page Coder Social logo

etuples's Introduction

etuples

Tests Coverage Status PyPI

Python S-expression emulation using tuple-like objects.

Examples

etuples are like tuples:

>>> from operator import add
>>> from etuples import etuple, etuplize

>>> et = etuple(add, 1, 2)
>>> et
ExpressionTuple((<built-in function add>, 1, 2))

>>> from IPython.lib.pretty import pprint
>>> pprint(et)
e(<function _operator.add(a, b, /)>, 1, 2)

>>> et[0:2]
ExpressionTuple((<built-in function add>, 1))

etuples can also be evaluated:

>>> et.evaled_obj
3

Evaluated etuples are cached:

>>> et = etuple(add, "a", "b")
>>> et.evaled_obj
'ab'

>>> et.evaled_obj is et.evaled_obj
True

Reconstructed etuples and their evaluation results are preserved across tuple operations:

>>> et_new = (et[0],) + et[1:]
>>> et_new is et
True
>>> et_new.evaled_obj is et.evaled_obj
True

rator, rands, and apply will return the operator, the operands, and apply the operation to the operands:

>>> from etuples import rator, rands, apply
>>> et = etuple(add, 1, 2)

>>> rator(et)
<built-in function add>

>>> rands(et)
ExpressionTuple((1, 2))

>>> apply(rator(et), rands(et))
3

rator and rands are multipledispatch functions that can be extended to handle arbitrary objects:

from etuples.core import ExpressionTuple
from collections.abc import Sequence


class Node:
    def __init__(self, rator, rands):
        self.rator, self.rands = rator, rands

    def __eq__(self, other):
        return self.rator == other.rator and self.rands == other.rands


class Operator:
    def __init__(self, op_name):
        self.op_name = op_name

    def __call__(self, *args):
        return Node(Operator(self.op_name), args)

    def __repr__(self):
        return self.op_name

    def __eq__(self, other):
        return self.op_name == other.op_name


rands.add((Node,), lambda x: x.rands)
rator.add((Node,), lambda x: x.rator)


@apply.register(Operator, (Sequence, ExpressionTuple))
def apply_Operator(rator, rands):
    return Node(rator, rands)
>>> mul_op, add_op = Operator("*"), Operator("+")
>>> mul_node = Node(mul_op, [1, 2])
>>> add_node = Node(add_op, [mul_node, 3])

etuplize will convert non-tuple objects into their corresponding etuple form:

>>> et = etuplize(add_node)
>>> pprint(et)
e(+, e(*, 1, 2), 3)

>>> et.evaled_obj is add_node
True

etuplize can also do shallow object-to-etuple conversions:

>>> et = etuplize(add_node, shallow=True)
>>> pprint(et)
e(+, <__main__.Node at 0x7f347361a080>, 3)

Installation

Using pip:

pip install etuples

Development

First obtain the project source:

git clone [email protected]:pythological/etuples.git

Create a virtual environment and install the development dependencies:

$ pip install -r requirements.txt

Set up pre-commit hooks:

$ pre-commit install --install-hooks

Tests can be run with the provided Makefile:

make check

etuples's People

Contributors

brandonwillard avatar oscargus avatar rlouf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

etuples's Issues

Add Mypy typing

It would be good to have type hints and a mypy pre-commit hook.

index on repr

When the structures get really nested, it would be nice to have an index printed out in the structure.

.eval_obj as a call

Why is .eval_obj an attribute instead of a call?

I know, in English, it implies that processing will occur, but in python semantics, that's an attribute (implying a low overhead op). In python, you'd have something like .eval().

generator op

Is this expected behavior?

In [60]: etuple(lambda xs: list(x+1 for x in xs), (range(5)) ).eval_obj
Out[60]: [1, 2, 3, 4, 5]

In [61]: etuple(lambda xs: (x+1 for x in xs), (range(5)) ).eval_obj
Out[61]: 5

Etuplize Python lists using `cons`

etuplize currently transforms a Python list to an expression tuple that contains the elements of the list:

from etuples import etuplize
from etuples.core import InvalidExpression

et = etuplize([1, 2])
print(et)
# e(1, 2)

This expression tuple is invalid and cannot be evaluated:

try:
    et.evaled_obj
except InvalidExpression as e:
    print(e)
# ExpressionTuple does not have a callable operator.

I thus suggest that etuplize returns the following expression that uses cons, which can be emulated by registering _car and _cdr from cons.core for lists:

from cons.core import _car, _cdr, cons
from etuples import etuple

@_car.register(list)
def car_list(x):
    return cons

@_cdr.register(list)
def cdr_list(x):
    return etuple(*x, [])

et = etuplize([1, 2])
print(et)
# e(<class 'cons.core.ConsPair'>, 1, 2, [])

Tests fail: TypeError: Tried to dispatch on non-type: [<class 'object'>]

============================================================================================================ ERRORS ============================================================================================================
_____________________________________________________________________________________________ ERROR collecting tests/test_core.py ______________________________________________________________________________________________
tests/test_core.py:7: in <module>
    from etuples.core import ExpressionTuple, InvalidExpression, KwdPair, etuple
etuples/__init__.py:2: in <module>
    from .core import etuple
etuples/core.py:343: in <module>
    def etuple(*args, **kwargs):
/usr/local/lib/python3.9/site-packages/multipledispatch/core.py:68: in _
    dispatcher.add(types, func, on_ambiguity=on_ambiguity)
/usr/local/lib/python3.9/site-packages/multipledispatch/dispatcher.py:133: in add
    raise TypeError("Tried to dispatch on non-type: %s\n"
E   TypeError: Tried to dispatch on non-type: [<class 'object'>]
E   In signature: <[<class 'object'>]>
E   In function: etuple
___________________________________________________________________________________________ ERROR collecting tests/test_dispatch.py ____________________________________________________________________________________________
tests/test_dispatch.py:6: in <module>
    from etuples.core import ExpressionTuple, KwdPair, etuple
etuples/__init__.py:2: in <module>
    from .core import etuple
etuples/core.py:343: in <module>
    def etuple(*args, **kwargs):
/usr/local/lib/python3.9/site-packages/multipledispatch/core.py:68: in _
    dispatcher.add(types, func, on_ambiguity=on_ambiguity)
/usr/local/lib/python3.9/site-packages/multipledispatch/dispatcher.py:133: in add
    raise TypeError("Tried to dispatch on non-type: %s\n"
E   TypeError: Tried to dispatch on non-type: [<class 'object'>]
E   In signature: <[<class 'object'>]>
E   In function: etuple
======================================================================================================= warnings summary =======================================================================================================
../../../../../local/lib/python3.9/site-packages/multipledispatch/core.py:79
../../../../../local/lib/python3.9/site-packages/multipledispatch/core.py:79
  /usr/local/lib/python3.9/site-packages/multipledispatch/core.py:79: DeprecationWarning: inspect.getargspec() is deprecated since Python 3.0, use inspect.signature() or inspect.getfullargspec()
    spec = inspect.getargspec(func)

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 2 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================================================================ 2 warnings, 2 errors in 0.78s =================================================================================================

Version: 0.3.9
Python-3.9
FreeBSD 13.2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.