changeset 6:ba0f10adb44b

add filters
author sheep@wintermute
date Wed, 14 Apr 2010 12:14:55 +0200
parents e69a0207568a
children 8b9133467904
files jpath.py
diffstat 1 files changed, 54 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/jpath.py	Wed Apr 14 11:39:51 2010 +0200
+++ b/jpath.py	Wed Apr 14 12:14:55 2010 +0200
@@ -140,6 +140,51 @@
     def parse(self, tokens, data):
         return Token.apply(tokens, data[self.start:self.end:self.step])
 
+@Tokenizer.token
+class FilterToken(Token):
+    """(foo=3)"""
+
+    regexp = (r'[(](?P<filter_path>[^(=)]+)\s*=\s*'
+              r'(?P<filter_value>"([^"]|\\")*"|-?[0-9]|true|false)[)]')
+    name = '_filter'
+    priority = 50
+
+    def __init__(self, _filter, filter_path, filter_value):
+        """
+        >>> FilterToken(r'(foo="b\"ar")', r'foo', r'"b\"ar"').value
+        'b"ar'
+        >>> FilterToken(r'(bar=-1)', r'bar', r'-1').value
+        -1
+        """
+        self.path = filter_path
+        if filter_value.startswith('"'):
+            self.value = filter_value[1:-1].replace(r'\"', '"')
+        elif filter_value in ('true', 'false'):
+            self.value = filter_value == 'true'
+        else:
+            self.value = int(filter_value)
+
+    def parse(self, tokens, data):
+        try:
+            token, *tokens = tokens
+        except ValueError:
+            token = NoneToken()
+        try:
+            # If it's a dict, iterate over values, not keys.
+            data = data.values()
+        except AttributeError:
+            pass
+        for item in data:
+            if get(self.path, item) == self.value:
+                try:
+                    for value in token.parse(tokens, item):
+                        yield value
+                except (TypeError, IndexError, KeyError):
+                    # Ignore errors inside branches, because some
+                    # of the branches may have different structure
+                    # than our jpath wants.
+                    pass
+
 
 @Tokenizer.token
 class WildcardToken(Token):
@@ -201,7 +246,7 @@
                 except TypeError:
                     continue
                 for item in data:
-                    if not isinstance(item, (str, int)):
+                    if not isinstance(item, str):
                         # Strings are nasty, because they can be iterated
                         # recursively idefinitely.
                         stack.append(item)
@@ -276,6 +321,14 @@
     [[2, 3]]
     >>> get_all('[:-1]', [1, 2, 3])
     [[1, 2]]
+    >>> get_all('[::2]', [1, 2, 3, 4])
+    [[1, 3]]
+    >>> get_all('(x=1).y', [{'x':1, 'y':2}, {'x':0, 'y':3}, {'x':1, 'y':4}])
+    [2, 4]
+    >>> get_all('(x=1).y', [{'x':1, 'y':2}, {'x':0, 'y':3}, {'x':1}])
+    [2]
+    >>> get_all('..', {'a':1, 'x':[2], 'c':[{'b': '3'}]})
+    [{'a': 1, 'x': [2], 'c': [{'b': '3'}]}, 1, [2], [{'b': '3'}], {'b': '3'}, 2]
     """
 
     return list(Token.apply(TOKENIZER.tokenize(jpath), data))