Skip to content

Commit

Permalink
added modes and template mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Kurt Rose committed Oct 23, 2019
1 parent 0e9c98f commit 512bc31
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 2 deletions.
2 changes: 2 additions & 0 deletions glom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
OMIT, # backwards compat
SKIP,
STOP,
MODE,
Check,
Path,
Literal,
Expand All @@ -21,6 +22,7 @@

from glom.reduction import Sum, Fold, Flatten, flatten, FoldError, Merge, merge
from glom.mutation import Assign, assign, PathAssignError
from glom.template import Template

# there's no -ion word that really fits what "streaming" means.
# generation, production, iteration, all have more relevant meanings
Expand Down
28 changes: 26 additions & 2 deletions glom/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@
[0, 1, 2, 3, 4]
"""

MODE = make_sentinel('MODE')


class GlomError(Exception):
"""The base exception for all the errors that might be raised from
Expand Down Expand Up @@ -1134,6 +1136,22 @@ def glomit(self, target, scope):
return ret


class Build(object):
"""
switch to builder mode (the default)
TODO: this seems like it should be a sub-class of class Spec() --
if Spec() could help define the interface for new "modes" or dialects
that would also help make match mode feel less duct-taped on
"""
def __init__(self, spec):
self.spec = spec

def glomit(self, target, scope):
scope[MODE] = _glom_build
return scope[glom](target, self.spec, scope)


class _AbstractIterable(_AbstractIterableBase):
__metaclass__ = ABCMeta
@classmethod
Expand Down Expand Up @@ -1442,7 +1460,8 @@ def glom(target, spec, **kwargs):
skip_exc = kwargs.pop('skip_exc', () if default is _MISSING else GlomError)
scope = _DEFAULT_SCOPE.new_child({
Path: kwargs.pop('path', []),
Inspect: kwargs.pop('inspector', None)
Inspect: kwargs.pop('inspector', None),
MODE: _glom_build,
})
scope.update(kwargs.pop('scope', {}))
if kwargs:
Expand All @@ -1465,7 +1484,12 @@ def _glom(target, spec, scope):
return _t_eval(target, spec, scope)
elif callable(getattr(spec, 'glomit', None)):
return spec.glomit(target, scope)
elif isinstance(spec, dict):

return scope[MODE](target, spec, scope)


def _glom_build(target, spec, scope):
if isinstance(spec, dict):
return _handle_dict(target, spec, scope)
elif isinstance(spec, list):
return _handle_list(target, spec, scope)
Expand Down
28 changes: 28 additions & 0 deletions glom/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
template mode is for building python literals,
similar to quasi-quoting in lisp
"""
from glom import glom, MODE


class Template(object):
def __init__(self, spec):
self.spec = spec

def glomit(self, target, scope):
scope[MODE] = _template
return scope[glom](target, self.spec, scope)


def _template(target, spec, scope):
recurse = lambda val: scope[glom](target, val, scope)
if type(spec) is dict:
return {recurse(key): recurse(val) for key, val in spec.items()}
if type(spec) in (list, tuple, set, frozenset):
result = [recurse(val) for val in spec]
if type(spec) is list:
return result
return type(spec)(result)
if callable(spec):
return spec(target)
return spec
7 changes: 7 additions & 0 deletions glom/test/test_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from glom import Template, T, glom

def test():
assert glom('abc', Template((T[0], {T[1]: T[2]}))) == ('a', {'b': 'c'})
assert glom('123', Template({T[0], frozenset([T[1], T[2]])})) == {'1', frozenset(['2', '3'])}
assert glom('xyz', Template([T[0], T[1], T[2]]))
assert glom('abc', Template(lambda t: t.upper())) == 'ABC'

0 comments on commit 512bc31

Please sign in to comment.