Hello community, here is the log from the commit of package python-jmespath for openSUSE:Factory checked in at 2015-04-27 13:05:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-jmespath (Old) and /work/SRC/openSUSE:Factory/.python-jmespath.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jmespath" Changes: -------- --- /work/SRC/openSUSE:Factory/python-jmespath/python-jmespath.changes 2015-03-27 09:41:48.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-jmespath.new/python-jmespath.changes 2015-04-27 13:05:29.000000000 +0200 @@ -1,0 +2,14 @@ +Sun Apr 26 16:57:39 UTC 2015 - [email protected] + +- update to version 0.7.0: + * Add support for JEP-12, raw string literals + * Support .whl files +- additional changes from version 0.6.2: + * Implement JEP-10, slice projections + * Fix bug with filter projection parsing + * Add to_array function + * Add merge function + * Fix error messages for function argument type errors +- point source URL to pypi + +------------------------------------------------------------------- Old: ---- jmespath-0.6.1.tar.gz New: ---- jmespath-0.7.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-jmespath.spec ++++++ --- /var/tmp/diff_new_pack.FCyBNX/_old 2015-04-27 13:05:29.000000000 +0200 +++ /var/tmp/diff_new_pack.FCyBNX/_new 2015-04-27 13:05:29.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-jmespath # -# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,13 +19,13 @@ %define baseName jmespath Name: python-jmespath -Version: 0.6.1 +Version: 0.7.0 Release: 0 Summary: Extract elements from JSON document License: MIT Group: Development/Languages/Python Url: https://github.com/boto/jmespath -Source0: %{baseName}-%{version}.tar.gz +Source0: https://pypi.python.org/packages/source/j/%{baseName}/%{baseName}-%{version}.tar.gz Requires: python Requires: python-ply >= 3.4 BuildRequires: python ++++++ jmespath-0.6.1.tar.gz -> jmespath-0.7.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/PKG-INFO new/jmespath-0.7.0/PKG-INFO --- old/jmespath-0.6.1/PKG-INFO 2015-02-03 22:19:50.000000000 +0100 +++ new/jmespath-0.7.0/PKG-INFO 2015-04-21 08:34:36.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: jmespath -Version: 0.6.1 +Version: 0.7.0 Summary: JSON Matching Expressions Home-page: https://github.com/boto/jmespath Author: James Saryerwinnie @@ -9,11 +9,16 @@ Description: JMESPath ======== + + .. image:: https://badges.gitter.im/Join Chat.svg + :target: https://gitter.im/jmespath/chat + + .. image:: https://secure.travis-ci.org/jmespath/jmespath.py.png?branch=develop :target: http://travis-ci.org/jmespath/jmespath.py - JMESPath (pronounced ``\ˈjāmz path\``) allows you to declaratively specify how to + JMESPath (pronounced "james path") allows you to declaratively specify how to extract elements from a JSON document. For example, given this document:: @@ -46,9 +51,41 @@ The expression: ``foo.*.name`` will return ["one", "two"]. + API + === + + The ``jmespath.py`` library has two functions + that operate on python data structures. You can use ``search`` + and give it the jmespath expression and the data:: + + >>> import jmespath + >>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}}) + 'baz' + + Similar to the ``re`` module, you can use the ``compile`` function + to compile the JMESPath expression and use this parsed expression + to perform repeated searches:: + + >>> import jmespath + >>> expression = jmespath.compile('foo.bar') + >>> expression.search({'foo': {'bar': 'baz'}}) + 'baz' + >>> expression.search({'foo': {'bar': 'other'}}) + 'other' + + This is useful if you're going to use the same jmespath expression to + search multiple documents. This avoids having to reparse the + JMESPath expression each time you search a new document. + + Specification ============= + If you'd like to learn more about the JMESPath language, you can check out + the `JMESPath tutorial <http://jmespath.org/tutorial.html>`__. Also check + out the `JMESPath examples page <http://jmespath.org/examples.html>`__ for + examples of more complex jmespath queries. + The grammar is specified using ABNF, as described in `RFC4234 <http://www.ietf.org/rfc/rfc4234.txt>`_. You can find the most up to date @@ -57,9 +94,6 @@ You can read the full `JMESPath specification here <http://jmespath.org/specification.html>`__. - If you'd like to learn more about the JMESPath language, you can check out - the `JMESPath tutorial <http://jmespath.org/tutorial.html>`__. - Testing ======= @@ -70,29 +104,12 @@ to verify they are producing the correct output. Each json file is grouped by feature. - Python Library - ============== - The included python implementation has two convenience functions - that operate on python data structures. You can use ``search`` - and give it the jmespath expression and the data:: - - >>> import jmespath - >>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}}) - 'baz' - - Similar to the ``re`` module, you can store the compiled expressions - and reuse them to perform repeated searches:: - - >>> import jmespath - >>> path = jmespath.compile('foo.bar') - >>> path.search({'foo': {'bar': 'baz'}}) - 'baz' - >>> path.search({'foo': {'bar': 'other'}}) - 'other' + Discuss + ======= - You can also use the ``jmespath.parser.Parser`` class directly - if you want more control. + Join us on our `Gitter channel <https://gitter.im/jmespath/chat>`__ + if you want to chat or if you have any questions. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/README.rst new/jmespath-0.7.0/README.rst --- old/jmespath-0.6.1/README.rst 2015-02-03 22:19:02.000000000 +0100 +++ new/jmespath-0.7.0/README.rst 2015-03-20 03:58:23.000000000 +0100 @@ -1,11 +1,16 @@ JMESPath ======== + +.. image:: https://badges.gitter.im/Join Chat.svg + :target: https://gitter.im/jmespath/chat + + .. image:: https://secure.travis-ci.org/jmespath/jmespath.py.png?branch=develop :target: http://travis-ci.org/jmespath/jmespath.py -JMESPath (pronounced ``\ˈjāmz path\``) allows you to declaratively specify how to +JMESPath (pronounced "james path") allows you to declaratively specify how to extract elements from a JSON document. For example, given this document:: @@ -38,9 +43,41 @@ The expression: ``foo.*.name`` will return ["one", "two"]. +API +=== + +The ``jmespath.py`` library has two functions +that operate on python data structures. You can use ``search`` +and give it the jmespath expression and the data:: + + >>> import jmespath + >>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}}) + 'baz' + +Similar to the ``re`` module, you can use the ``compile`` function +to compile the JMESPath expression and use this parsed expression +to perform repeated searches:: + + >>> import jmespath + >>> expression = jmespath.compile('foo.bar') + >>> expression.search({'foo': {'bar': 'baz'}}) + 'baz' + >>> expression.search({'foo': {'bar': 'other'}}) + 'other' + +This is useful if you're going to use the same jmespath expression to +search multiple documents. This avoids having to reparse the +JMESPath expression each time you search a new document. + + Specification ============= +If you'd like to learn more about the JMESPath language, you can check out +the `JMESPath tutorial <http://jmespath.org/tutorial.html>`__. Also check +out the `JMESPath examples page <http://jmespath.org/examples.html>`__ for +examples of more complex jmespath queries. + The grammar is specified using ABNF, as described in `RFC4234 <http://www.ietf.org/rfc/rfc4234.txt>`_. You can find the most up to date @@ -49,9 +86,6 @@ You can read the full `JMESPath specification here <http://jmespath.org/specification.html>`__. -If you'd like to learn more about the JMESPath language, you can check out -the `JMESPath tutorial <http://jmespath.org/tutorial.html>`__. - Testing ======= @@ -62,26 +96,9 @@ to verify they are producing the correct output. Each json file is grouped by feature. -Python Library -============== -The included python implementation has two convenience functions -that operate on python data structures. You can use ``search`` -and give it the jmespath expression and the data:: - - >>> import jmespath - >>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}}) - 'baz' - -Similar to the ``re`` module, you can store the compiled expressions -and reuse them to perform repeated searches:: - - >>> import jmespath - >>> path = jmespath.compile('foo.bar') - >>> path.search({'foo': {'bar': 'baz'}}) - 'baz' - >>> path.search({'foo': {'bar': 'other'}}) - 'other' +Discuss +======= -You can also use the ``jmespath.parser.Parser`` class directly -if you want more control. +Join us on our `Gitter channel <https://gitter.im/jmespath/chat>`__ +if you want to chat or if you have any questions. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/bin/jp new/jmespath-0.7.0/bin/jp --- old/jmespath-0.6.1/bin/jp 2014-04-23 21:00:09.000000000 +0200 +++ new/jmespath-0.7.0/bin/jp 2015-04-18 20:54:14.000000000 +0200 @@ -51,9 +51,6 @@ except exceptions.UnknownFunctionError as e: sys.stderr.write("unknown-function: %s\n" % e) return 1 - except exceptions.LexerError as e: - sys.stderr.write("syntax-error: %s\n" % e) - return 1 except exceptions.ParseError as e: sys.stderr.write("syntax-error: %s\n" % e) return 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath/__init__.py new/jmespath-0.7.0/jmespath/__init__.py --- old/jmespath-0.6.1/jmespath/__init__.py 2015-02-03 22:19:10.000000000 +0100 +++ new/jmespath-0.7.0/jmespath/__init__.py 2015-04-21 08:29:17.000000000 +0200 @@ -1,6 +1,6 @@ from jmespath import parser -__version__ = '0.6.1' +__version__ = '0.7.0' def compile(expression): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath/exceptions.py new/jmespath-0.7.0/jmespath/exceptions.py --- old/jmespath-0.6.1/jmespath/exceptions.py 2015-01-29 20:42:34.000000000 +0100 +++ new/jmespath-0.7.0/jmespath/exceptions.py 2015-04-18 20:54:14.000000000 +0200 @@ -22,8 +22,8 @@ # self.lex_position +1 to account for the starting double quote char. underline = ' ' * (self.lex_position + 1) + '^' return ( - '%s: Parse error at column %s near ' - 'token "%s" (%s) for expression:\n"%s"\n%s' % ( + '%s: Parse error at column %s, ' + 'token "%s" (%s), for expression:\n"%s"\n%s' % ( self.msg, self.lex_position, self.token_value, self.token_type, self.expression, underline)) @@ -71,19 +71,29 @@ self.expression = None def __str__(self): - return ("Expected %s arguments for function %s(), " - "received %s" % (self.expected_arity, - self.function_name, - self.actual_arity)) + return ("Expected %s %s for function %s(), " + "received %s" % ( + self.expected_arity, + self._pluralize('argument', self.expected_arity), + self.function_name, + self.actual_arity)) + + def _pluralize(self, word, count): + if count == 1: + return word + else: + return word + 's' @with_str_method class VariadictArityError(ArityError): def __str__(self): - return ("Expected at least %s arguments for function %s, " - "received %s" % (self.expected_arity, - self.function_name, - self.actual_arity)) + return ("Expected at least %s %s for function %s(), " + "received %s" % ( + self.expected_arity, + self._pluralize('argument', self.expected_arity), + self.function_name, + self.actual_arity)) @with_str_method diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath/functions.py new/jmespath-0.7.0/jmespath/functions.py --- old/jmespath-0.6.1/jmespath/functions.py 2015-01-31 22:18:30.000000000 +0100 +++ new/jmespath-0.7.0/jmespath/functions.py 2015-04-18 20:54:14.000000000 +0200 @@ -186,6 +186,13 @@ return argument @builtin_function({'types': []}) + def _func_to_array(self, arg): + if isinstance(arg, list): + return arg + else: + return [arg] + + @builtin_function({'types': []}) def _func_to_string(self, arg): if isinstance(arg, STRING_TYPE): return arg @@ -252,6 +259,13 @@ else: return None + @builtin_function({"types": ["object"], "variadic": True}) + def _func_merge(self, *arguments): + merged = {} + for arg in arguments: + merged.update(arg) + return merged + @builtin_function({"types": ['array-number', 'array-string']}) def _func_min(self, arg): if arg: @@ -303,7 +317,7 @@ # that validates that type, which requires that remaining array # elements resolve to the same type as the first element. required_type = self._convert_to_jmespath_type( - self.interpreter.visit(expref.expression, array[0])) + type(self.interpreter.visit(expref.expression, array[0])).__name__) if required_type not in ['number', 'string']: raise exceptions.JMESPathTypeError( 'sort_by', array[0], required_type, ['string', 'number']) @@ -331,7 +345,9 @@ def keyfunc(x): result = interpreter.visit(expr_node, x) - jmespath_type = self._convert_to_jmespath_type(result) + actual_typename = type(result).__name__ + jmespath_type = self._convert_to_jmespath_type(actual_typename) + # allowed_types is in term of jmespath types, not python types. if jmespath_type not in allowed_types: raise exceptions.JMESPathTypeError( function_name, result, jmespath_type, allowed_types) @@ -339,4 +355,4 @@ return keyfunc def _convert_to_jmespath_type(self, pyobject): - return TYPES_MAP.get(type(pyobject).__name__, 'unknown') + return TYPES_MAP.get(pyobject, 'unknown') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath/lexer.py new/jmespath-0.7.0/jmespath/lexer.py --- old/jmespath-0.6.1/jmespath/lexer.py 2015-01-29 20:42:34.000000000 +0100 +++ new/jmespath-0.7.0/jmespath/lexer.py 2015-04-21 08:28:55.000000000 +0200 @@ -1,4 +1,5 @@ import re +import warnings from json import loads from jmespath.exceptions import LexerError, EmptyExpressionError @@ -9,6 +10,7 @@ r'(?P<number>-?\d+)|' r'(?P<unquoted_identifier>([a-zA-Z_][a-zA-Z_0-9]*))|' r'(?P<quoted_identifier>("(?:\\\\|\\"|[^"])*"))|' + r'(?P<string_literal>(\'(?:\\\\|\\\'|[^\'])*\'))|' r'(?P<literal>(`(?:\\\\|\\`|[^`])*`))|' r'(?P<filter>\[\?)|' r'(?P<or>\|\|)|' @@ -93,6 +95,9 @@ lexer_value=value, message=error_message) + def _token_string_literal(self, value, start, end): + return value[1:-1] + def _token_literal(self, value, start, end): actual_value = value[1:-1] actual_value = actual_value.replace('\\`', '`').lstrip() @@ -113,7 +118,10 @@ # don't have to be quoted. This is only true if the # string doesn't start with chars that could start a valid # JSON value. - return loads(potential_value) + value = loads(potential_value) + warnings.warn("deprecated string literal syntax", + PendingDeprecationWarning) + return value except ValueError: raise LexerError(lexer_position=start, lexer_value=value, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath/parser.py new/jmespath-0.7.0/jmespath/parser.py --- old/jmespath-0.6.1/jmespath/parser.py 2015-02-03 22:19:02.000000000 +0100 +++ new/jmespath-0.7.0/jmespath/parser.py 2015-04-21 08:28:55.000000000 +0200 @@ -46,6 +46,7 @@ 'number': 0, 'current': 0, 'expref': 0, + 'colon': 0, 'pipe': 1, 'eq': 2, 'gt': 2, @@ -56,9 +57,9 @@ 'or': 5, 'flatten': 6, 'star': 20, + 'filter': 20, 'dot': 40, 'lbrace': 50, - 'filter': 50, 'lbracket': 55, 'lparen': 60, } @@ -126,6 +127,9 @@ current_token = self._current_token() return left + def _token_nud_string_literal(self, token): + return ast.literal(token['value']) + def _token_nud_literal(self, token): return ast.literal(token['value']) @@ -165,7 +169,12 @@ def _token_nud_lbracket(self, token): if self._current_token() in ['number', 'colon']: - return self._parse_index_expression() + right = self._parse_index_expression() + # We could optimize this and remove the identity() node. + # We don't really need an index_expression node, we can + # just use emit an index node here if we're not dealing + # with a slice. + return self._project_if_slice(ast.identity(), right) elif self._current_token() == 'star' and \ self._lookahead(1) == 'rbracket': self._advance() @@ -300,10 +309,13 @@ if token['type'] in ['number', 'colon']: right = self._parse_index_expression() if left['type'] == 'index_expression': + # Optimization: if the left node is an index expr, + # we can avoid creating another node and instead just add + # the right node as a child of the left. left['children'].append(right) return left else: - return ast.index_expression([left, right]) + return self._project_if_slice(left, right) else: # We have a projection self._match('star') @@ -311,6 +323,15 @@ right = self._parse_projection_rhs(self.BINDING_POWER['star']) return ast.projection(left, right) + def _project_if_slice(self, left, right): + index_expr = ast.index_expression([left, right]) + if right['type'] == 'slice': + return ast.projection( + index_expr, + self._parse_projection_rhs(self.BINDING_POWER['star'])) + else: + return index_expr + def _parse_comparator(self, left, comparator): right = self._expression(self.BINDING_POWER[comparator]) return ast.comparator(comparator, left, right) @@ -409,6 +430,9 @@ "Token %s not allowed to be: %s" % (actual_type, token_types)) def _error_nud_token(self, token): + if token['type'] == 'eof': + raise exceptions.IncompleteExpressionError( + token['start'], token['value'], token['type']) raise exceptions.ParseError(token['start'], token['value'], token['type'], 'Invalid token.') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath.egg-info/PKG-INFO new/jmespath-0.7.0/jmespath.egg-info/PKG-INFO --- old/jmespath-0.6.1/jmespath.egg-info/PKG-INFO 2015-02-03 22:19:49.000000000 +0100 +++ new/jmespath-0.7.0/jmespath.egg-info/PKG-INFO 2015-04-21 08:34:35.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: jmespath -Version: 0.6.1 +Version: 0.7.0 Summary: JSON Matching Expressions Home-page: https://github.com/boto/jmespath Author: James Saryerwinnie @@ -9,11 +9,16 @@ Description: JMESPath ======== + + .. image:: https://badges.gitter.im/Join Chat.svg + :target: https://gitter.im/jmespath/chat + + .. image:: https://secure.travis-ci.org/jmespath/jmespath.py.png?branch=develop :target: http://travis-ci.org/jmespath/jmespath.py - JMESPath (pronounced ``\ˈjāmz path\``) allows you to declaratively specify how to + JMESPath (pronounced "james path") allows you to declaratively specify how to extract elements from a JSON document. For example, given this document:: @@ -46,9 +51,41 @@ The expression: ``foo.*.name`` will return ["one", "two"]. + API + === + + The ``jmespath.py`` library has two functions + that operate on python data structures. You can use ``search`` + and give it the jmespath expression and the data:: + + >>> import jmespath + >>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}}) + 'baz' + + Similar to the ``re`` module, you can use the ``compile`` function + to compile the JMESPath expression and use this parsed expression + to perform repeated searches:: + + >>> import jmespath + >>> expression = jmespath.compile('foo.bar') + >>> expression.search({'foo': {'bar': 'baz'}}) + 'baz' + >>> expression.search({'foo': {'bar': 'other'}}) + 'other' + + This is useful if you're going to use the same jmespath expression to + search multiple documents. This avoids having to reparse the + JMESPath expression each time you search a new document. + + Specification ============= + If you'd like to learn more about the JMESPath language, you can check out + the `JMESPath tutorial <http://jmespath.org/tutorial.html>`__. Also check + out the `JMESPath examples page <http://jmespath.org/examples.html>`__ for + examples of more complex jmespath queries. + The grammar is specified using ABNF, as described in `RFC4234 <http://www.ietf.org/rfc/rfc4234.txt>`_. You can find the most up to date @@ -57,9 +94,6 @@ You can read the full `JMESPath specification here <http://jmespath.org/specification.html>`__. - If you'd like to learn more about the JMESPath language, you can check out - the `JMESPath tutorial <http://jmespath.org/tutorial.html>`__. - Testing ======= @@ -70,29 +104,12 @@ to verify they are producing the correct output. Each json file is grouped by feature. - Python Library - ============== - The included python implementation has two convenience functions - that operate on python data structures. You can use ``search`` - and give it the jmespath expression and the data:: - - >>> import jmespath - >>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}}) - 'baz' - - Similar to the ``re`` module, you can store the compiled expressions - and reuse them to perform repeated searches:: - - >>> import jmespath - >>> path = jmespath.compile('foo.bar') - >>> path.search({'foo': {'bar': 'baz'}}) - 'baz' - >>> path.search({'foo': {'bar': 'other'}}) - 'other' + Discuss + ======= - You can also use the ``jmespath.parser.Parser`` class directly - if you want more control. + Join us on our `Gitter channel <https://gitter.im/jmespath/chat>`__ + if you want to chat or if you have any questions. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath.egg-info/SOURCES.txt new/jmespath-0.7.0/jmespath.egg-info/SOURCES.txt --- old/jmespath-0.6.1/jmespath.egg-info/SOURCES.txt 2015-02-03 22:19:50.000000000 +0100 +++ new/jmespath-0.7.0/jmespath.egg-info/SOURCES.txt 2015-04-21 08:34:36.000000000 +0200 @@ -1,6 +1,7 @@ LICENSE.txt MANIFEST.in README.rst +setup.cfg setup.py bin/jp jmespath/__init__.py @@ -14,7 +15,5 @@ jmespath.egg-info/PKG-INFO jmespath.egg-info/SOURCES.txt jmespath.egg-info/dependency_links.txt -jmespath.egg-info/top_level.txt -tests/__init__.py -tests/test_compliance.py -tests/test_parser.py \ No newline at end of file +jmespath.egg-info/pbr.json +jmespath.egg-info/top_level.txt \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/jmespath.egg-info/pbr.json new/jmespath-0.7.0/jmespath.egg-info/pbr.json --- old/jmespath-0.6.1/jmespath.egg-info/pbr.json 1970-01-01 01:00:00.000000000 +0100 +++ new/jmespath-0.7.0/jmespath.egg-info/pbr.json 2015-04-21 08:34:36.000000000 +0200 @@ -0,0 +1 @@ +{"is_release": true, "git_version": "0466cc1"} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/setup.cfg new/jmespath-0.7.0/setup.cfg --- old/jmespath-0.6.1/setup.cfg 2015-02-03 22:19:50.000000000 +0100 +++ new/jmespath-0.7.0/setup.cfg 2015-04-21 08:34:36.000000000 +0200 @@ -1,3 +1,6 @@ +[bdist_wheel] +universal = 1 + [egg_info] tag_build = tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/setup.py new/jmespath-0.7.0/setup.py --- old/jmespath-0.6.1/setup.py 2015-02-03 22:19:10.000000000 +0100 +++ new/jmespath-0.7.0/setup.py 2015-04-21 08:29:17.000000000 +0200 @@ -25,7 +25,7 @@ setup( name='jmespath', - version='0.6.1', + version='0.7.0', description='JSON Matching Expressions', long_description=io.open('README.rst', encoding='utf-8').read(), author='James Saryerwinnie', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/tests/__init__.py new/jmespath-0.7.0/tests/__init__.py --- old/jmespath-0.6.1/tests/__init__.py 2014-04-23 21:00:09.000000000 +0200 +++ new/jmespath-0.7.0/tests/__init__.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,40 +0,0 @@ -import sys -from jmespath import ast - - -# The unittest module got a significant overhaul -# in 2.7, so if we're in 2.6 we can use the backported -# version unittest2. -if sys.version_info[:2] == (2, 6): - import unittest2 as unittest - import simplejson as json - from ordereddict import OrderedDict -else: - import unittest - import json - from collections import OrderedDict - - -# Helper method used to create an s-expression -# of the AST to make unit test assertions easier. -# You get a nice string diff on assert failures. -def as_s_expression(node): - parts = [] - _as_s_expression(node, parts) - return ''.join(parts) - - -def _as_s_expression(node, parts): - parts.append("(%s" % (node.__class__.__name__.lower())) - if isinstance(node, ast.Field): - parts.append(" %s" % node.name) - elif isinstance(node, ast.FunctionExpression): - parts.append(" %s" % node.name) - elif isinstance(node, ast.KeyValPair): - parts.append(" %s" % node.key_name) - for child in node.children: - parts.append(" ") - _as_s_expression(child, parts) - parts.append(")") - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/tests/test_compliance.py new/jmespath-0.7.0/tests/test_compliance.py --- old/jmespath-0.6.1/tests/test_compliance.py 2015-01-31 22:18:30.000000000 +0100 +++ new/jmespath-0.7.0/tests/test_compliance.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,93 +0,0 @@ -import os -from pprint import pformat -from tests import OrderedDict -from tests import json - -from nose.tools import assert_equal - -import jmespath -from jmespath.visitor import TreeInterpreter - - -TEST_DIR = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'compliance') -NOT_SPECIFIED = object() -TreeInterpreter.MAP_TYPE = OrderedDict - - -def test_compliance(): - for full_path in _walk_files(): - if full_path.endswith('.json'): - for given, expression, result, error in _load_cases(full_path): - if error is NOT_SPECIFIED and result is not NOT_SPECIFIED: - yield (_test_expression, given, expression, - result, os.path.basename(full_path)) - elif result is NOT_SPECIFIED and error is not NOT_SPECIFIED: - yield (_test_error_expression, given, expression, - error, os.path.basename(full_path)) - else: - parts = (given, expression, result, error) - raise RuntimeError("Invalid test description: %s" % parts) - - -def _walk_files(): - # Check for a shortcut when running the tests interactively. - # If a JMESPATH_TEST is defined, that file is used as the - # only test to run. Useful when doing feature development. - single_file = os.environ.get('JMESPATH_TEST') - if single_file is not None: - yield os.path.abspath(single_file) - else: - for root, dirnames, filenames in os.walk(TEST_DIR): - for filename in filenames: - yield os.path.join(root, filename) - - -def _load_cases(full_path): - all_test_data = json.load(open(full_path), object_pairs_hook=OrderedDict) - for test_data in all_test_data: - given = test_data['given'] - for case in test_data['cases']: - yield (given, case['expression'], - case.get('result', NOT_SPECIFIED), - case.get('error', NOT_SPECIFIED)) - - -def _test_expression(given, expression, expected, filename): - import jmespath.parser - try: - parsed = jmespath.compile(expression) - except ValueError as e: - raise AssertionError( - 'jmespath expression failed to compile: "%s", error: %s"' % - (expression, e)) - actual = parsed.search(given) - expected_repr = json.dumps(expected, indent=4) - actual_repr = json.dumps(actual, indent=4) - error_msg = ("\n\n (%s) The expression '%s' was suppose to give:\n%s\n" - "Instead it matched:\n%s\nparsed as:\n%s\ngiven:\n%s" % ( - filename, expression, expected_repr, - actual_repr, parsed, - json.dumps(given, indent=4))) - error_msg = error_msg.replace(r'\n', '\n') - assert_equal(actual, expected, error_msg) - - -def _test_error_expression(given, expression, error, filename): - import jmespath.parser - if error not in ('syntax', 'invalid-type', - 'unknown-function', 'invalid-arity', 'invalid-value'): - raise RuntimeError("Unknown error type '%s'" % error) - try: - parsed = jmespath.compile(expression) - parsed.search(given) - except ValueError as e: - # Test passes, it raised a parse error as expected. - pass - else: - error_msg = ("\n\n (%s) The expression '%s' was suppose to be a " - "syntax error, but it successfully parsed as:\n\n%s" % ( - filename, expression, parsed)) - error_msg = error_msg.replace(r'\n', '\n') - raise AssertionError(error_msg) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jmespath-0.6.1/tests/test_parser.py new/jmespath-0.7.0/tests/test_parser.py --- old/jmespath-0.6.1/tests/test_parser.py 2015-01-31 22:18:30.000000000 +0100 +++ new/jmespath-0.7.0/tests/test_parser.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,345 +0,0 @@ -#!/usr/bin/env python - -import re -from tests import unittest - -from jmespath import parser -from jmespath import ast -from jmespath import exceptions - - -class TestParser(unittest.TestCase): - def setUp(self): - self.parser = parser.Parser() - - def assert_parsed_ast(self, expression, expected_ast): - parsed = self.parser.parse(expression) - self.assertEqual(parsed.parsed, expected_ast) - - def test_parse_empty_string_raises_exception(self): - with self.assertRaises(exceptions.EmptyExpressionError): - self.parser.parse('') - - def test_field(self): - self.assert_parsed_ast('foo', ast.field('foo')) - - def test_dot_syntax(self): - self.assert_parsed_ast('foo.bar', - ast.subexpression([ast.field('foo'), - ast.field('bar')])) - - def test_multiple_dots(self): - parsed = self.parser.parse('foo.bar.baz') - self.assertEqual( - parsed.search({'foo': {'bar': {'baz': 'correct'}}}), 'correct') - - def test_index(self): - parsed = self.parser.parse('foo[1]') - self.assertEqual( - parsed.search({'foo': ['zero', 'one', 'two']}), - 'one') - - def test_quoted_subexpression(self): - self.assert_parsed_ast('"foo"."bar"', - ast.subexpression([ - ast.field('foo'), - ast.field('bar')])) - - def test_wildcard(self): - parsed = self.parser.parse('foo[*]') - self.assertEqual( - parsed.search({'foo': ['zero', 'one', 'two']}), - ['zero', 'one', 'two']) - - def test_wildcard_with_children(self): - parsed = self.parser.parse('foo[*].bar') - self.assertEqual( - parsed.search({'foo': [{'bar': 'one'}, {'bar': 'two'}]}), - ['one', 'two']) - - def test_or_expression(self): - parsed = self.parser.parse('foo || bar') - self.assertEqual(parsed.search({'foo': 'foo'}), 'foo') - self.assertEqual(parsed.search({'bar': 'bar'}), 'bar') - self.assertEqual(parsed.search({'foo': 'foo', 'bar': 'bar'}), 'foo') - self.assertEqual(parsed.search({'bad': 'bad'}), None) - - def test_complex_or_expression(self): - parsed = self.parser.parse('foo.foo || foo.bar') - self.assertEqual(parsed.search({'foo': {'foo': 'foo'}}), 'foo') - self.assertEqual(parsed.search({'foo': {'bar': 'bar'}}), 'bar') - self.assertEqual(parsed.search({'foo': {'baz': 'baz'}}), None) - - def test_or_repr(self): - self.assert_parsed_ast('foo || bar', ast.or_expression(ast.field('foo'), - ast.field('bar'))) - - def test_unicode_literals_escaped(self): - self.assert_parsed_ast(r'`"\u2713"`', ast.literal(u'\u2713')) - - def test_multiselect(self): - parsed = self.parser.parse('foo.{bar: bar,baz: baz}') - self.assertEqual( - parsed.search({'foo': {'bar': 'bar', 'baz': 'baz', 'qux': 'qux'}}), - {'bar': 'bar', 'baz': 'baz'}) - - def test_multiselect_subexpressions(self): - parsed = self.parser.parse('foo.{"bar.baz": bar.baz, qux: qux}') - self.assertEqual( - parsed.search({'foo': {'bar': {'baz': 'CORRECT'}, 'qux': 'qux'}}), - {'bar.baz': 'CORRECT', 'qux': 'qux'}) - - def test_multiselect_with_all_quoted_keys(self): - parsed = self.parser.parse('foo.{"bar": bar.baz, "qux": qux}') - result = parsed.search({'foo': {'bar': {'baz': 'CORRECT'}, 'qux': 'qux'}}) - self.assertEqual(result, {"bar": "CORRECT", "qux": "qux"}) - - -class TestErrorMessages(unittest.TestCase): - - def setUp(self): - self.parser = parser.Parser() - - def assert_error_message(self, expression, error_message, - exception=exceptions.ParseError): - try: - self.parser.parse(expression) - except exception as e: - self.assertEqual(error_message, str(e)) - return - except Exception as e: - self.fail( - "Unexpected error raised (%s: %s) for bad expression: %s" % - (e.__class__.__name__, e, expression)) - else: - self.fail( - "ParseError not raised for bad expression: %s" % expression) - - def test_bad_parse(self): - with self.assertRaises(exceptions.ParseError): - self.parser.parse('foo]baz') - - def test_bad_parse_error_message(self): - error_message = ( - 'Unexpected token: ]: Parse error at column 3 ' - 'near token "]" (RBRACKET) for expression:\n' - '"foo]baz"\n' - ' ^') - self.assert_error_message('foo]baz', error_message) - - def test_bad_parse_error_message_with_multiselect(self): - error_message = ( - 'Invalid jmespath expression: Incomplete expression:\n' - '"foo.{bar: baz,bar: bar"\n' - ' ^') - self.assert_error_message('foo.{bar: baz,bar: bar', error_message) - - def test_bad_lexer_values(self): - error_message = ( - 'Bad jmespath expression: ' - 'Starting quote is missing the ending quote:\n' - 'foo."bar\n' - ' ^') - self.assert_error_message('foo."bar', error_message, - exception=exceptions.LexerError) - - def test_bad_lexer_literal_value_with_json_object(self): - error_message = ('Bad jmespath expression: ' - 'Bad token `{{}`:\n`{{}`\n^') - self.assert_error_message('`{{}`', error_message, - exception=exceptions.LexerError) - - def test_bad_unicode_string(self): - # This error message is straight from the JSON parser - # and pypy has a slightly different error message, - # so we're not using assert_error_message. - error_message = re.compile( - r'Bad jmespath expression: ' - r'Invalid \\uXXXX escape.*\\uAZ12', re.DOTALL) - with self.assertRaisesRegexp(exceptions.LexerError, error_message): - self.parser.parse(r'"\uAZ12"') - - -class TestParserWildcards(unittest.TestCase): - def setUp(self): - self.parser = parser.Parser() - self.data = { - 'foo': [ - {'bar': [{'baz': 'one'}, {'baz': 'two'}]}, - {'bar': [{'baz': 'three'}, {'baz': 'four'}, {'baz': 'five'}]}, - ] - } - - def test_multiple_index_wildcards(self): - parsed = self.parser.parse('foo[*].bar[*].baz') - self.assertEqual(parsed.search(self.data), - [['one', 'two'], ['three', 'four', 'five']]) - - def test_wildcard_mix_with_indices(self): - parsed = self.parser.parse('foo[*].bar[0].baz') - self.assertEqual(parsed.search(self.data), - ['one', 'three']) - - def test_wildcard_mix_last(self): - parsed = self.parser.parse('foo[0].bar[*].baz') - self.assertEqual(parsed.search(self.data), - ['one', 'two']) - - def test_indices_out_of_bounds(self): - parsed = self.parser.parse('foo[*].bar[2].baz') - self.assertEqual(parsed.search(self.data), - ['five']) - - def test_root_indices(self): - parsed = self.parser.parse('[0]') - self.assertEqual(parsed.search(['one', 'two']), 'one') - - def test_root_wildcard(self): - parsed = self.parser.parse('*.foo') - data = {'top1': {'foo': 'bar'}, 'top2': {'foo': 'baz'}, - 'top3': {'notfoo': 'notfoo'}} - # Sorted is being used because the order of the keys are not - # required to be in any specific order. - self.assertEqual(sorted(parsed.search(data)), sorted(['bar', 'baz'])) - self.assertEqual(sorted(self.parser.parse('*.notfoo').search(data)), - sorted(['notfoo'])) - - def test_only_wildcard(self): - parsed = self.parser.parse('*') - data = {'foo': 'a', 'bar': 'b', 'baz': 'c'} - self.assertEqual(sorted(parsed.search(data)), sorted(['a', 'b', 'c'])) - - def test_escape_sequences(self): - self.assertEqual(self.parser.parse(r'"foo\tbar"').search( - {'foo\tbar': 'baz'}), 'baz') - self.assertEqual(self.parser.parse(r'"foo\nbar"').search( - {'foo\nbar': 'baz'}), 'baz') - self.assertEqual(self.parser.parse(r'"foo\bbar"').search( - {'foo\bbar': 'baz'}), 'baz') - self.assertEqual(self.parser.parse(r'"foo\fbar"').search( - {'foo\fbar': 'baz'}), 'baz') - self.assertEqual(self.parser.parse(r'"foo\rbar"').search( - {'foo\rbar': 'baz'}), 'baz') - - def test_consecutive_escape_sequences(self): - parsed = self.parser.parse(r'"foo\\nbar"') - self.assertEqual(parsed.search({'foo\\nbar': 'baz'}), 'baz') - - parsed = self.parser.parse(r'"foo\n\t\rbar"') - self.assertEqual(parsed.search({'foo\n\t\rbar': 'baz'}), 'baz') - - def test_escape_sequence_at_end_of_string_not_allowed(self): - with self.assertRaises(ValueError): - self.parser.parse('foobar\\') - - def test_wildcard_with_multiselect(self): - parsed = self.parser.parse('foo.*.{a: a, b: b}') - data = { - 'foo': { - 'one': { - 'a': {'c': 'CORRECT', 'd': 'other'}, - 'b': {'c': 'ALSOCORRECT', 'd': 'other'}, - }, - 'two': { - 'a': {'c': 'CORRECT', 'd': 'other'}, - 'c': {'c': 'WRONG', 'd': 'other'}, - }, - } - } - match = parsed.search(data) - self.assertEqual(len(match), 2) - self.assertIn('a', match[0]) - self.assertIn('b', match[0]) - self.assertIn('a', match[1]) - self.assertIn('b', match[1]) - - -class TestMergedLists(unittest.TestCase): - def setUp(self): - self.parser = parser.Parser() - self.data = { - "foo": [ - [["one", "two"], ["three", "four"]], - [["five", "six"], ["seven", "eight"]], - [["nine"], ["ten"]] - ] - } - - def test_merge_with_indices(self): - parsed = self.parser.parse('foo[][0]') - match = parsed.search(self.data) - self.assertEqual(match, ["one", "three", "five", "seven", - "nine", "ten"]) - - def test_trailing_merged_operator(self): - parsed = self.parser.parse('foo[]') - match = parsed.search(self.data) - self.assertEqual( - match, - [["one", "two"], ["three", "four"], - ["five", "six"], ["seven", "eight"], - ["nine"], ["ten"]]) - - -class TestParserCaching(unittest.TestCase): - def test_compile_lots_of_expressions(self): - # We have to be careful here because this is an implementation detail - # that should be abstracted from the user, but we need to make sure we - # exercise the code and that it doesn't blow up. - p = parser.Parser() - compiled = [] - compiled2 = [] - for i in range(parser.Parser._MAX_SIZE + 1): - compiled.append(p.parse('foo%s' % i)) - # Rerun the test and half of these entries should be from the - # cache but they should still be equal to compiled. - for i in range(parser.Parser._MAX_SIZE + 1): - compiled2.append(p.parse('foo%s' % i)) - self.assertEqual(len(compiled), len(compiled2)) - self.assertEqual( - [expr.parsed for expr in compiled], - [expr.parsed for expr in compiled2]) - - def test_cache_purge(self): - p = parser.Parser() - first = p.parse('foo') - cached = p.parse('foo') - p.purge() - second = p.parse('foo') - self.assertEqual(first.parsed, - second.parsed) - self.assertEqual(first.parsed, - cached.parsed) - - -class TestParserAddsExpressionAttribute(unittest.TestCase): - def test_expression_available_from_parser(self): - p = parser.Parser() - parsed = p.parse('foo.bar') - self.assertEqual(parsed.expression, 'foo.bar') - - -class TestRenderGraphvizFile(unittest.TestCase): - def test_dot_file_rendered(self): - p = parser.Parser() - result = p.parse('foo') - dot_contents = result._render_dot_file() - self.assertEqual(dot_contents, - 'digraph AST {\nfield1 [label="field(foo)"]\n}') - - def test_dot_file_subexpr(self): - p = parser.Parser() - result = p.parse('foo.bar') - dot_contents = result._render_dot_file() - self.assertEqual( - dot_contents, - 'digraph AST {\n' - 'subexpression1 [label="subexpression()"]\n' - ' subexpression1 -> field2\n' - 'field2 [label="field(foo)"]\n' - ' subexpression1 -> field3\n' - 'field3 [label="field(bar)"]\n}') - - -if __name__ == '__main__': - unittest.main()
