Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reformatting, cleanup, and coverage #193

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
todo_add_to_theme_to_keep_menus_expanded = """

<script type="text/javascript" src="_static/jquery.js"></script>
<script>$(document).ready(function() {$('.wy-side-scroll').on('click', function() {$('.toctree-l1').addClass('current')}); $('.toctree-l1').first().click(); });</script>
<script>
$(document).ready(function() {
$('.wy-side-scroll').on('click', function() {
$('.toctree-l1').addClass('current')});
$('.toctree-l1').first().click(); });
</script>

<!-- window.SphinxRtdTheme.ThemeNav.toggleCurrent = function(elem) {}; -->
"""
Expand Down Expand Up @@ -111,7 +116,7 @@

if on_rtd:
html_theme = 'default'
else: # only import and set the theme if we're building docs locally
else: # only import and set the theme if we're building docs locally
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = ['_themes', sphinx_rtd_theme.get_html_theme_path()]
Expand Down
14 changes: 4 additions & 10 deletions glom/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,15 @@
import sys
import json

from face import (Command,
Flag,
face_middleware,
PosArgSpec,
PosArgDisplay,
CommandLineError,
UsageError)
from face import Command, face_middleware, PosArgSpec, UsageError
from face.utils import isatty

import glom
from glom import Path, GlomError, Inspect

PY3 = (sys.version_info[0] == 3)


def glom_cli(target, spec, indent, debug, inspect):
"""Command-line interface to the glom library, providing nested data
access and data restructuring with the power of Python.
Expand Down Expand Up @@ -104,7 +99,8 @@ def console_main():
sys.exit(main(sys.argv) or 0)
except Exception:
if _enable_debug:
import pdb;pdb.post_mortem()
import pdb
pdb.post_mortem()
raise


Expand Down Expand Up @@ -135,14 +131,12 @@ def mw_handle_target(target_text, target_format):
else:
raise UsageError('expected target-format to be one of python, json, or yaml')


try:
target = load_func(target_text)
except Exception as e:
raise UsageError('could not load target data, got: %s: %s'
% (e.__class__.__name__, e))


return target


Expand Down
17 changes: 9 additions & 8 deletions glom/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@
import copy
import weakref
import operator
from abc import ABCMeta
from pprint import pprint
from abc import ABCMeta
import string
from collections import OrderedDict
import traceback

from face.helpers import get_wrap_width
from boltons.typeutils import make_sentinel
from boltons.iterutils import is_iterable
#from boltons.funcutils import format_invocation


PY2 = (sys.version_info[0] == 2)
if PY2:
Expand All @@ -55,7 +54,7 @@
_type_type = type

_MISSING = make_sentinel('_MISSING')
SKIP = make_sentinel('SKIP')
SKIP = make_sentinel('SKIP')
SKIP.__doc__ = """
The ``SKIP`` singleton can be returned from a function or included
via a :class:`~glom.Val` to cancel assignment into the output
Expand Down Expand Up @@ -105,7 +104,7 @@
in case of exceptions
"""

MODE = make_sentinel('MODE')
MODE = make_sentinel('MODE')

CHILD_ERRORS = make_sentinel('CHILD_ERRORS')
CHILD_ERRORS.__doc__ = """
Expand All @@ -121,6 +120,7 @@

_PKG_DIR_PATH = os.path.dirname(os.path.abspath(__file__))


class GlomError(Exception):
"""The base exception for all the errors that might be raised from
:func:`glom` processing logic.
Expand Down Expand Up @@ -231,6 +231,7 @@ def format_target_spec_trace(scope, root_error, width=TRACE_WIDTH, depth=0, prev
segments = []
indent = " " + "|" * depth
tick = "| " if depth else "- "

def mk_fmt(label, t=None):
pre = indent + (t or tick) + label + ": "
fmt_width = width - len(pre)
Expand Down Expand Up @@ -1588,7 +1589,6 @@ def _format_t(path, root=T):

class Val(object):
"""Val objects are specs which evaluate to the wrapped *value*.

>>> target = {'a': {'b': 'c'}}
>>> spec = {'a': 'a.b', 'readability': Val('counts')}
>>> pprint(glom(target, spec))
Expand Down Expand Up @@ -1717,6 +1717,7 @@ def __repr__(self):

class _AbstractIterable(_AbstractIterableBase):
__metaclass__ = ABCMeta

@classmethod
def __subclasshook__(cls, C):
if C in (str, bytes):
Expand Down Expand Up @@ -2109,12 +2110,12 @@ def chain_child(scope):
return nxt_in_chain


unbound_methods = set([type(str.__len__)]) #, type(Ref.glomit)])
unbound_methods = set([type(str.__len__)]) # , type(Ref.glomit)])


def _has_callable_glomit(obj):
glomit = getattr(obj, 'glomit', None)
return callable(glomit) and not isinstance(obj, type)
return callable(glomit) and not isinstance(obj, type)


def _glom(target, spec, scope):
Expand Down
1 change: 0 additions & 1 deletion glom/grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@ def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.size)



class Limit(object):
"""
Limits the number of values passed to sub-accumulator
Expand Down
27 changes: 15 additions & 12 deletions glom/matching.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import re
import sys
from pprint import pprint

from boltons.iterutils import is_iterable
from boltons.typeutils import make_sentinel
Expand Down Expand Up @@ -195,12 +194,18 @@ def __repr__(self):
sorted(e and e.__name__ or "None" for e in _RE_VALID_FUNCS))))

_RE_TYPES = ()
try: re.match(u"", u"")
except Exception: pass # pragma: no cover
else: _RE_TYPES += (type(u""),)
try: re.match(b"", b"")
except Exception: pass # pragma: no cover
else: _RE_TYPES += (type(b""),)
try:
re.match(u"", u"")
except Exception:
pass # pragma: no cover
else:
_RE_TYPES += (type(u""),)
try:
re.match(b"", b"")
except Exception:
pass # pragma: no cover
else:
_RE_TYPES += (type(b""),)


class Regex(object):
Expand Down Expand Up @@ -251,7 +256,7 @@ def __repr__(self):
return self.__class__.__name__ + args


#TODO: combine this with other functionality elsewhere?
# TODO: combine this with other functionality elsewhere?
def _bool_child_repr(child):
if child is M:
return repr(child)
Expand Down Expand Up @@ -567,7 +572,6 @@ def glomit(self, target, spec):
M = _MType()



class Optional(object):
"""Used as a :class:`dict` key in a :class:`~glom.Match()` spec,
marks that a value match key which would otherwise be required is
Expand Down Expand Up @@ -843,17 +847,16 @@ def __init__(self, cases, default=_MISSING):
% (self.__class__.__name__, self.cases))
return


def glomit(self, target, scope):
for keyspec, valspec in self.cases:
try:
scope[glom](target, keyspec, scope)
except GlomError as ge:
except GlomError:
continue
return scope[glom](target, valspec, chain_child(scope))
if self.default is not _MISSING:
return self.default
raise MatchError("no matches for target in %s" % self.__class__.__name__)
raise MatchError("no matches for target in %s" % self.__class__.__name__)

def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, bbrepr(self.cases))
Expand Down
5 changes: 2 additions & 3 deletions glom/mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import operator
from pprint import pprint

from .core import Path, T, S, Spec, glom, UnregisteredTarget, GlomError, PathAccessError, UP
from .core import Path, S, Spec, glom, PathAccessError, UP, T
from .core import TType, register_op, TargetRegistry, bbrepr, PathAssignError

try:
Expand Down Expand Up @@ -46,7 +46,6 @@ def get_message(self):
% (self.dest_name, self.path, self.exc))



class Assign(object):
"""*New in glom 18.3.0*

Expand Down Expand Up @@ -288,7 +287,7 @@ def glomit(self, target, scope):
dest_path = self.path
try:
dest = scope[glom](dest_target, dest_path, scope)
except PathAccessError as pae:
except PathAccessError:
if not self.ignore_missing:
raise
else:
Expand Down
4 changes: 1 addition & 3 deletions glom/reduction.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

from pprint import pprint
import operator
import itertools
from pprint import pprint

from boltons.typeutils import make_sentinel

Expand Down Expand Up @@ -310,7 +309,6 @@ def _fold(self, iterator):

return ret


def _agg(self, target, tree):
if self not in tree:
acc = tree[self] = self.init()
Expand Down
2 changes: 1 addition & 1 deletion glom/streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .core import glom, T, STOP, SKIP, _MISSING, Path, TargetRegistry, Call, Spec, S, bbrepr, format_invocation
from .matching import Check


class Iter(object):
"""``Iter()`` is glom's counterpart to Python's built-in :func:`iter()`
function. Given an iterable target, ``Iter()`` yields the result
Expand Down Expand Up @@ -257,7 +258,6 @@ def unique(self, key=T):
(key,),
lambda it, scope: unique_iter(it, key=lambda t: scope[glom](t, key, scope)))


def slice(self, *args):
"""Returns a new :class:`Iter()` spec which trims iterables in the
same manner as :func:`itertools.islice`.
Expand Down
30 changes: 15 additions & 15 deletions glom/test/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

import pytest

from glom import glom, SKIP, STOP, Path, Inspect, Coalesce, CoalesceError, Val, Call, T, S, Invoke, Spec, Ref
from glom import Auto, Fill, Iter, A, Vars, Val, Literal, GlomError, Pipe
from glom import glom, SKIP, STOP, Inspect, Coalesce, Val, Call, T, S, Invoke, Spec, Ref
from glom import Fill, Iter, Literal, Pipe
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, these imports are to ensure we don't regress the init of the module itself, I don't think we want to remove them.


import glom.core as glom_core
from glom.core import UP, ROOT, bbformat, bbrepr
from glom.mutation import PathAssignError
from glom.core import UP, bbformat, bbrepr

from glom import OMIT, Let, Literal # backwards compat
from glom import OMIT # backwards compat
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same with the backwards compat ones here. they can probably move up close to the other public ones, but keep the comment.



def test_initial_integration():
Expand Down Expand Up @@ -101,7 +100,6 @@ def test_coalesce():
Coalesce(bad_kwarg=True)



def test_skip():
assert OMIT is SKIP # backwards compat

Expand Down Expand Up @@ -197,6 +195,7 @@ def __init__(s, a, b, c): s.a, s.b, s.c = a, b, c
assert repr(call_f)
val = glom(1, call_f)
assert (val.a, val.b, val.c) == (1, 1, 1)

class F(object):
def __init__(s, a): s.a = a
val = glom({'one': F('two')}, Call(F, args=(T['one'].a,)))
Expand All @@ -219,6 +218,7 @@ def __init__(s, a): s.a = a

def test_invoke():
args = []

def test(*a, **kw):
args.append(a)
args.append(kw)
Expand All @@ -231,9 +231,9 @@ def test(*a, **kw):
'kwargs': {'a': 'a'},
'c': 'C',
}
spec = Invoke(test).star(args='args'
).constants(3, b='b').specs(c='c'
).star(args='args2', kwargs='kwargs')
spec = (Invoke(test).star(args='args')
.constants(3, b='b').specs(c='c')
.star(args='args2', kwargs='kwargs'))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is better than the one before, but i think one per line might read nice here.

repr(spec) # no exceptions
assert repr(Invoke(len).specs(T)) == 'Invoke(len).specs(T)'
assert (repr(Invoke.specfunc(next).constants(len).constants(1))
Expand All @@ -245,9 +245,9 @@ def test(*a, **kw):
args = []
assert glom(test, Invoke.specfunc(T)) == 'test'
assert args == [(), {}]
repr_spec = Invoke.specfunc(T).star(args='args'
).constants(3, b='b').specs(c='c'
).star(args='args2', kwargs='kwargs')
repr_spec = (Invoke.specfunc(T).star(args='args')
.constants(3, b='b').specs(c='c')
.star(args='args2', kwargs='kwargs'))
assert repr(eval(repr(repr_spec), locals(), globals())) == repr(repr_spec)

with pytest.raises(TypeError, match='expected func to be a callable or Spec instance'):
Expand Down Expand Up @@ -281,7 +281,6 @@ def ret_args(*a, **kw):
assert glom(target, spec) == 'hi'



def test_spec_and_recursion():
assert repr(Spec('a.b.c')) == "Spec('a.b.c')"

Expand Down Expand Up @@ -350,7 +349,6 @@ def test_python_native():
target = {'system': {'planets': [{'name': 'earth', 'moons': 1},
{'name': 'jupiter', 'moons': 69}]}}


output = glom(target, {'moon_count': ('system.planets', ['moons'], sum)})
assert output == {'moon_count': 70}

Expand Down Expand Up @@ -409,7 +407,7 @@ def test_ref():
assert repr(Ref('item', (T[1], Ref('item')))) == "Ref('item', (T[1], Ref('item')))"

etree2dicts = Ref('ElementTree',
{"tag": "tag", "text": "text", "attrib": "attrib", "children": (iter, [Ref('ElementTree')])})
{"tag": "tag", "text": "text", "attrib": "attrib", "children": (iter, [Ref('ElementTree')])})
etree2tuples = Fill(Ref('ElementTree', (T.tag, Iter(Ref('ElementTree')).all())))
etree = ElementTree.fromstring('''
<html>
Expand All @@ -430,6 +428,8 @@ def test_pipe():


_IS_PYPY = '__pypy__' in sys.builtin_module_names


@pytest.mark.skipif(_IS_PYPY, reason='pypy othertype.__repr__ is never object.__repr__')
def test_api_repr():
import glom
Expand Down
Loading