Skip to content

Commit

Permalink
"define" decorator now also accepts type classes instead of query nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
vmagamedov committed Sep 6, 2016
1 parent 3ddd6d5 commit 4c90437
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 35 deletions.
23 changes: 3 additions & 20 deletions hiku/checker.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from contextlib import contextmanager
from collections import deque, OrderedDict

from . import graph, query
from . import graph
from .refs import NamedRef, Ref
from .nodes import NodeTransformer, Symbol, Keyword, Tuple, List
from .types import Sequence, SequenceMeta, Record, RecordMeta, Optional
from .types import MappingMeta, Callable, OptionalMeta
from .types import MappingMeta, OptionalMeta
from .typedef.types import TypeRef, TypeRefMeta, Unknown, UnknownMeta


Expand Down Expand Up @@ -37,25 +37,8 @@ def graph_types(graph_):
return GraphTypes().visit(graph_)


def _query_to_types(obj):
if isinstance(obj, query.Edge):
return Record[[(f.name, _query_to_types(f)) for f in obj.fields]]
elif isinstance(obj, query.Link):
return _query_to_types(obj.edge)
elif isinstance(obj, query.Field):
return Unknown
else:
raise TypeError(type(obj))


def fn_types(functions):
return {
fn.__fn_name__: Callable[[
_query_to_types(r) if r is not None else Unknown
for r in fn.__requires__
]]
for fn in functions
}
return {fn.__def_name__: fn.__def_type__ for fn in functions}


class Environ(object):
Expand Down
42 changes: 30 additions & 12 deletions hiku/expr.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from functools import wraps
from itertools import chain
from collections import namedtuple

from .edn import loads
from .query import Edge, Link, Field
from .types import Record, Callable
from .nodes import Symbol, Tuple, List, Keyword, Dict
from .compat import text_type, string_types
from .typedef.types import Unknown
from .readers.simple import transform


Expand Down Expand Up @@ -33,7 +37,7 @@ def _to_expr(obj, fn_reg):
return obj.obj
elif isinstance(obj, _Func):
fn_reg.add(obj.expr)
return Tuple([Symbol(obj.expr.__fn_name__)] +
return Tuple([Symbol(obj.expr.__def_name__)] +
[_to_expr(arg, fn_reg) for arg in obj.args])
elif isinstance(obj, list):
return List(_to_expr(v, fn_reg) for v in obj)
Expand All @@ -51,39 +55,53 @@ def to_expr(obj):
return node, tuple(functions)


def _query_to_types(obj):
if isinstance(obj, Edge):
return Record[[(f.name, _query_to_types(f)) for f in obj.fields]]
elif isinstance(obj, Link):
return _query_to_types(obj.edge)
elif isinstance(obj, Field):
return Unknown
else:
raise TypeError(type(obj))


def define(*requires, **kwargs):
def decorator(fn):
name = kwargs.pop('_name', None)
name = name or '{}/{}_{}'.format(fn.__module__, fn.__name__, id(fn))
assert not kwargs, 'Unknown keyword arguments: {!r}'.format(kwargs)
_name = kwargs.pop('_name', None)
assert not kwargs, repr(kwargs)

name = _name or '{}/{}_{}'.format(fn.__module__, fn.__name__, id(fn))

@wraps(fn)
def expr(*args):
return _Func(expr, args)

expr.fn = fn
expr.__fn_name__ = name
expr.__def_name__ = name
expr.__def_body__ = fn

if len(requires) == 1 and isinstance(requires[0], string_types):
reqs_list = loads(text_type(requires[0]))
expr.__requires__ = [transform(reqs) if reqs is not None else None
for reqs in reqs_list]
expr.__def_type__ = Callable[[(_query_to_types(transform(r))
if r is not None else Unknown)
for r in reqs_list]]
else:
expr.__requires__ = requires
expr.__def_type__ = Callable[requires]

return expr
return decorator


@define(None, None, None, _name='each')
@define(Unknown, Unknown, Unknown, _name='each')
def each(var, col, expr):
pass


@define(None, None, None, _name='if')
@define(Unknown, Unknown, Unknown, _name='if')
def if_(test, then, else_):
pass


@define(None, None, None, _name='if_some')
@define(Unknown, Unknown, Unknown, _name='if_some')
def if_some(bind, then, else_):
pass
2 changes: 1 addition & 1 deletion hiku/sources/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def __init__(self, graph, edge):

def __call__(self, queue, ctx, task_set, edge, fields, ids):
graph_fields = [edge.fields_map[f.name] for f in fields]
fn_env = {f.__fn_name__: f.fn
fn_env = {f.__def_name__: f.__def_body__
for f in chain.from_iterable(e.functions
for e in graph_fields)}

Expand Down
7 changes: 5 additions & 2 deletions tests/test_refs.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from unittest import skip
from collections import OrderedDict

from hiku import graph as g
from hiku.expr import define, S, each, to_expr, if_some
from hiku.refs import Ref, NamedRef, ref_to_req, RequirementsExtractor
from hiku.graph import Many, One, Maybe
from hiku.query import Edge, Field, Link
from hiku.types import Record
from hiku.checker import check, graph_types, fn_types
from hiku.typedef.types import Unknown

from .base import reqs_eq_patcher

Expand Down Expand Up @@ -151,11 +154,11 @@ def test_query_each_root_edge_link_field():

def test_query_tuple_with_edge():

@define('[[:clacks :panicle]]')
@define(Record[OrderedDict([('clacks', Unknown), ('panicle', Unknown)])])
def foo():
pass

@define('[[:oloroso :gashes]]')
@define(Record[OrderedDict([('oloroso', Unknown), ('gashes', Unknown)])])
def bar():
pass

Expand Down

0 comments on commit 4c90437

Please sign in to comment.