Hello community,
here is the log from the commit of package python-jmespath for openSUSE:Factory
checked in at 2020-06-05 19:59:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jmespath (Old)
and /work/SRC/openSUSE:Factory/.python-jmespath.new.3606 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jmespath"
Fri Jun 5 19:59:31 2020 rev:17 rq:810897 version:0.10.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-jmespath/python-jmespath.changes
2020-03-27 00:19:50.508091608 +0100
+++
/work/SRC/openSUSE:Factory/.python-jmespath.new.3606/python-jmespath.changes
2020-06-05 19:59:33.183801467 +0200
@@ -1,0 +2,7 @@
+Tue Jun 2 16:21:51 UTC 2020 - Dirk Mueller <[email protected]>
+
+- update to 0.10.0:
+ * Python 2.6 and 3.3 have reached end-of-life and have been deprecated.
(issue 175)
+ * Fix race condition when clearing cached parsed expressions. (issue 197)
+
+-------------------------------------------------------------------
Old:
----
jmespath-0.9.5.tar.gz
New:
----
jmespath-0.10.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jmespath.spec ++++++
--- /var/tmp/diff_new_pack.bFaErz/_old 2020-06-05 19:59:33.663803128 +0200
+++ /var/tmp/diff_new_pack.bFaErz/_new 2020-06-05 19:59:33.667803141 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-jmespath
-Version: 0.9.5
+Version: 0.10.0
Release: 0
Summary: Python module for declarative JSON document element extraction
License: MIT
++++++ jmespath-0.9.5.tar.gz -> jmespath-0.10.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/PKG-INFO new/jmespath-0.10.0/PKG-INFO
--- old/jmespath-0.9.5/PKG-INFO 2020-02-24 22:43:16.000000000 +0100
+++ new/jmespath-0.10.0/PKG-INFO 2020-05-13 00:01:49.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: jmespath
-Version: 0.9.5
+Version: 0.10.0
Summary: JSON Matching Expressions
Home-page: https://github.com/jmespath/jmespath.py
Author: James Saryerwinnie
@@ -55,6 +55,16 @@
The expression: ``foo.*.name`` will return ["one", "two"].
+ Installation
+ ============
+
+ You can install JMESPath from pypi with:
+
+ .. code:: bash
+
+ pip install jmespath
+
+
API
===
@@ -236,3 +246,4 @@
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
+Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/README.rst
new/jmespath-0.10.0/README.rst
--- old/jmespath-0.9.5/README.rst 2019-02-25 00:08:17.000000000 +0100
+++ new/jmespath-0.10.0/README.rst 2020-05-13 00:01:10.000000000 +0200
@@ -47,6 +47,16 @@
The expression: ``foo.*.name`` will return ["one", "two"].
+Installation
+============
+
+You can install JMESPath from pypi with:
+
+.. code:: bash
+
+ pip install jmespath
+
+
API
===
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/bin/jp.py
new/jmespath-0.10.0/bin/jp.py
--- old/jmespath-0.9.5/bin/jp.py 2017-05-13 19:21:34.000000000 +0200
+++ new/jmespath-0.10.0/bin/jp.py 2020-05-13 00:01:10.000000000 +0200
@@ -34,7 +34,7 @@
data = json.loads(data)
try:
sys.stdout.write(json.dumps(
- jmespath.search(expression, data), indent=4))
+ jmespath.search(expression, data), indent=4, ensure_ascii=False))
sys.stdout.write('\n')
except exceptions.ArityError as e:
sys.stderr.write("invalid-arity: %s\n" % e)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/jmespath/__init__.py
new/jmespath-0.10.0/jmespath/__init__.py
--- old/jmespath-0.9.5/jmespath/__init__.py 2020-02-24 22:43:09.000000000
+0100
+++ new/jmespath-0.10.0/jmespath/__init__.py 2020-05-13 00:01:13.000000000
+0200
@@ -1,7 +1,18 @@
+import warnings
+import sys
from jmespath import parser
from jmespath.visitor import Options
-__version__ = '0.9.5'
+__version__ = '0.10.0'
+
+
+if sys.version_info[:2] <= (2, 6) or ((3, 0) <= sys.version_info[:2] <= (3,
3)):
+ python_ver = '.'.join(str(x) for x in sys.version_info[:3])
+
+ warnings.warn(
+ 'You are using Python {0}, which will no longer be supported in '
+ 'version 0.11.0'.format(python_ver),
+ DeprecationWarning)
def compile(expression):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/jmespath/parser.py
new/jmespath-0.10.0/jmespath/parser.py
--- old/jmespath-0.9.5/jmespath/parser.py 2017-05-14 00:44:33.000000000
+0200
+++ new/jmespath-0.10.0/jmespath/parser.py 2020-05-13 00:01:10.000000000
+0200
@@ -490,7 +490,7 @@
def _free_cache_entries(self):
for key in random.sample(self._CACHE.keys(), int(self._MAX_SIZE / 2)):
- del self._CACHE[key]
+ self._CACHE.pop(key, None)
@classmethod
def purge(cls):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/jmespath.egg-info/PKG-INFO
new/jmespath-0.10.0/jmespath.egg-info/PKG-INFO
--- old/jmespath-0.9.5/jmespath.egg-info/PKG-INFO 2020-02-24
22:43:16.000000000 +0100
+++ new/jmespath-0.10.0/jmespath.egg-info/PKG-INFO 2020-05-13
00:01:49.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: jmespath
-Version: 0.9.5
+Version: 0.10.0
Summary: JSON Matching Expressions
Home-page: https://github.com/jmespath/jmespath.py
Author: James Saryerwinnie
@@ -55,6 +55,16 @@
The expression: ``foo.*.name`` will return ["one", "two"].
+ Installation
+ ============
+
+ You can install JMESPath from pypi with:
+
+ .. code:: bash
+
+ pip install jmespath
+
+
API
===
@@ -236,3 +246,4 @@
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
+Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/jmespath.egg-info/SOURCES.txt
new/jmespath-0.10.0/jmespath.egg-info/SOURCES.txt
--- old/jmespath-0.9.5/jmespath.egg-info/SOURCES.txt 2020-02-24
22:43:16.000000000 +0100
+++ new/jmespath-0.10.0/jmespath.egg-info/SOURCES.txt 2020-05-13
00:01:49.000000000 +0200
@@ -15,7 +15,4 @@
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/top_level.txt
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/setup.py new/jmespath-0.10.0/setup.py
--- old/jmespath-0.9.5/setup.py 2020-02-24 22:43:09.000000000 +0100
+++ new/jmespath-0.10.0/setup.py 2020-05-13 00:01:13.000000000 +0200
@@ -1,13 +1,24 @@
#!/usr/bin/env python
import io
+import sys
+import warnings
from setuptools import setup, find_packages
+if sys.version_info[:2] <= (2, 6) or ((3, 0) <= sys.version_info[:2] <= (3,
3)):
+ python_ver = '.'.join(str(x) for x in sys.version_info[:3])
+
+ warnings.warn(
+ 'You are using Python {0}, which will no longer be supported in '
+ 'version 0.11.0'.format(python_ver),
+ DeprecationWarning)
+
+
setup(
name='jmespath',
- version='0.9.5',
+ version='0.10.0',
description='JSON Matching Expressions',
long_description=io.open('README.rst', encoding='utf-8').read(),
author='James Saryerwinnie',
@@ -16,6 +27,7 @@
scripts=['bin/jp.py'],
packages=find_packages(exclude=['tests']),
license='MIT',
+ python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jmespath-0.9.5/tests/__init__.py
new/jmespath-0.10.0/tests/__init__.py
--- old/jmespath-0.9.5/tests/__init__.py 2017-03-10 01:45:59.000000000
+0100
+++ new/jmespath-0.10.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.9.5/tests/test_compliance.py
new/jmespath-0.10.0/tests/test_compliance.py
--- old/jmespath-0.9.5/tests/test_compliance.py 2017-05-13 19:21:34.000000000
+0200
+++ new/jmespath-0.10.0/tests/test_compliance.py 1970-01-01
01:00:00.000000000 +0100
@@ -1,109 +0,0 @@
-import os
-from pprint import pformat
-from tests import OrderedDict
-from tests import json
-
-from nose.tools import assert_equal
-
-from jmespath.visitor import Options
-
-
-TEST_DIR = os.path.dirname(os.path.abspath(__file__))
-COMPLIANCE_DIR = os.path.join(TEST_DIR, 'compliance')
-LEGACY_DIR = os.path.join(TEST_DIR, 'legacy')
-NOT_SPECIFIED = object()
-OPTIONS = Options(dict_cls=OrderedDict)
-
-
-def test_compliance():
- for full_path in _walk_files():
- if full_path.endswith('.json'):
- for given, test_type, test_data in load_cases(full_path):
- t = test_data
- # Benchmark tests aren't run as part of the normal
- # test suite, so we only care about 'result' and
- # 'error' test_types.
- if test_type == 'result':
- yield (_test_expression, given, t['expression'],
- t['result'], os.path.basename(full_path))
- elif test_type == 'error':
- yield (_test_error_expression, given, t['expression'],
- t['error'], os.path.basename(full_path))
-
-
-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)
- for root, dirnames, filenames in os.walk(LEGACY_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']:
- if 'result' in case:
- test_type = 'result'
- elif 'error' in case:
- test_type = 'error'
- elif 'bench' in case:
- test_type = 'bench'
- else:
- raise RuntimeError("Unknown test type: %s" % json.dumps(case))
- yield (given, test_type, case)
-
-
-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, options=OPTIONS)
- 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, pformat(parsed.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:
- # Test passes, it raised a parse error as expected.
- pass
- except Exception as e:
- # Failure because an unexpected exception was raised.
- error_msg = ("\n\n (%s) The expression '%s' was suppose to be a "
- "syntax error, but it raised an unexpected error:\n\n%s"
% (
- filename, expression, e))
- error_msg = error_msg.replace(r'\n', '\n')
- raise AssertionError(error_msg)
- 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, pformat(parsed.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.9.5/tests/test_parser.py
new/jmespath-0.10.0/tests/test_parser.py
--- old/jmespath-0.9.5/tests/test_parser.py 2017-05-13 19:21:34.000000000
+0200
+++ new/jmespath-0.10.0/tests/test_parser.py 1970-01-01 01:00:00.000000000
+0100
@@ -1,368 +0,0 @@
-#!/usr/bin/env python
-
-import re
-from tests import unittest, OrderedDict
-
-from jmespath import parser
-from jmespath import visitor
-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"})
-
- def test_function_call_with_and_statement(self):
- self.assert_parsed_ast(
- 'f(@ && @)',
- {'children': [{'children': [{'children': [], 'type': 'current'},
- {'children': [], 'type': 'current'}],
- 'type': 'and_expression'}],
- 'type': 'function_expression',
- 'value': 'f'})
-
-
-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, '
- '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_incomplete_expression_with_missing_paren(self):
- error_message = (
- 'Invalid jmespath expression: Incomplete expression:\n'
- '"length(@,"\n'
- ' ^')
- self.assert_error_message('length(@,', error_message)
-
- def test_bad_lexer_values(self):
- error_message = (
- 'Bad jmespath expression: '
- 'Unclosed " delimiter:\n'
- 'foo."bar\n'
- ' ^')
- self.assert_error_message('foo."bar', 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 TestParsedResultAddsOptions(unittest.TestCase):
- def test_can_have_ordered_dict(self):
- p = parser.Parser()
- parsed = p.parse('{a: a, b: b, c: c}')
- options = visitor.Options(dict_cls=OrderedDict)
- result = parsed.search(
- {"c": "c", "b": "b", "a": "a"}, options=options)
- # The order should be 'a', 'b' because we're using an
- # OrderedDict
- self.assertEqual(list(result), ['a', 'b', 'c'])
-
-
-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()