1- """Utilities for exploring nondeterminism in the recursive descent segment ."""
1+ """Command line utility for inspecting nondeterministic recursive descent orderings ."""
22
33from __future__ import annotations
44
55import json
6- import os
7- import random
86import sys
9- from collections import deque
107from typing import TYPE_CHECKING
11- from typing import Deque
12- from typing import Iterable
13- from typing import List
14- from typing import Optional
15- from typing import TextIO
16- from typing import Tuple
8+
9+ from jsonpath_rfc9535 . utils . nondeterministic_descent import AuxNode
10+ from jsonpath_rfc9535 . utils . nondeterministic_descent import all_perms
11+ from jsonpath_rfc9535 . utils . nondeterministic_descent import breadth_first_visit
12+ from jsonpath_rfc9535 . utils . nondeterministic_descent import pp_tree
13+ from jsonpath_rfc9535 . utils . nondeterministic_descent import pre_order_visit
1714
1815if TYPE_CHECKING :
19- from jsonpath_rfc9535 .environment import JSONLikeData
20-
21-
22- HORIZONTAL_SEP = "\N{BOX DRAWINGS LIGHT HORIZONTAL} " * 2
23- VERTICAL_SEP = "\N{BOX DRAWINGS LIGHT VERTICAL} "
24- BRANCH = "\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT} " + HORIZONTAL_SEP + " "
25- TERMINAL_BRANCH = "\N{BOX DRAWINGS LIGHT UP AND RIGHT} " + HORIZONTAL_SEP + " "
26- INDENT = VERTICAL_SEP + " " * 3
27- TERMINAL_INDENT = " " * 4
28-
29- COLOR_CODES = [
30- ("\033 [92m" , "\033 [0m" ),
31- ("\033 [93m" , "\033 [0m" ),
32- ("\033 [94m" , "\033 [0m" ),
33- ("\033 [95m" , "\033 [0m" ),
34- ("\033 [96m" , "\033 [0m" ),
35- ("\033 [91m" , "\033 [0m" ),
36- ]
37-
38-
39- class AuxNode :
40- def __init__ (
41- self ,
42- depth : int ,
43- value : object ,
44- children : Optional [List [AuxNode ]] = None ,
45- ) -> None :
46- self .value = value
47- self .children = children or []
48- self .depth = depth
49-
50- def __str__ (self ) -> str :
51- c_start , c_stop = COLOR_CODES [self .depth % len (COLOR_CODES )]
52- return f"{ c_start } { self .value } { c_stop } "
53-
54- @staticmethod
55- def from_ (data : JSONLikeData ) -> AuxNode :
56- def _visit (node : AuxNode , depth : int = 0 ) -> None :
57- if isinstance (node .value , dict ):
58- for val in node .value .values ():
59- _node = AuxNode (depth + 1 , val )
60- _visit (_node , depth + 1 )
61- node .children .append (_node )
62-
63- elif isinstance (node .value , list ):
64- for val in node .value :
65- _node = AuxNode (depth + 1 , val )
66- _visit (_node , depth + 1 )
67- node .children .append (_node )
68-
69- root = AuxNode (0 , data )
70- _visit (root )
71- return root
72-
73- @staticmethod
74- def collections (data : JSONLikeData ) -> AuxNode :
75- def _visit (node : AuxNode , depth : int = 0 ) -> None :
76- if isinstance (node .value , dict ):
77- for val in node .value .values ():
78- if isinstance (val , (list , dict )):
79- _node = AuxNode (depth + 1 , val )
80- _visit (_node , depth + 1 )
81- node .children .append (_node )
82-
83- elif isinstance (node .value , list ):
84- for val in node .value :
85- if isinstance (val , (list , dict )):
86- _node = AuxNode (depth + 1 , val )
87- _visit (_node , depth + 1 )
88- node .children .append (_node )
89-
90- root = AuxNode (0 , data )
91- _visit (root )
92- return root
93-
94-
95- def pptree (
96- node : AuxNode ,
97- indent : str = "" ,
98- buf : TextIO = sys .stdout ,
99- ) -> None :
100- """Pretty print the tree rooted at `node`."""
101- # Pre-order tree traversal
102- buf .write (str (node ) + os .linesep )
103-
104- if node .children :
105- # Recursively call pptree for all but the last child of `node`.
106- for child in node .children [:- 1 ]:
107- buf .write (indent + BRANCH )
108- pptree (child , indent = indent + INDENT , buf = buf )
109-
110- # Terminal branch case for last, possibly only, child of `node`.
111- buf .write (indent + TERMINAL_BRANCH )
112- pptree (node .children [- 1 ], indent = indent + TERMINAL_INDENT , buf = buf )
113-
114- # Base case. No children.
115-
116-
117- def pre_order_visit (node : AuxNode ) -> Iterable [AuxNode ]:
118- yield node
119-
120- for child in node .children :
121- yield from pre_order_visit (child )
122-
123-
124- def breadth_first_visit (node : AuxNode ) -> Iterable [AuxNode ]:
125- queue : Deque [AuxNode ] = deque ([node ])
126-
127- while queue :
128- _node = queue .popleft ()
129- yield _node
130- queue .extend (_node .children )
131-
132-
133- def nondeterministic_visit (root : AuxNode ) -> Iterable [AuxNode ]:
134- queue : Deque [AuxNode ] = deque (root .children )
135- yield root
136-
137- while queue :
138- _node = queue .popleft ()
139- yield _node
140- # Visit child nodes now or queue them for later?
141- visit_children = random .choice ([True , False ])
142- for child in _node .children :
143- if visit_children :
144- yield child
145- queue .extend (child .children )
146- else :
147- queue .append (child )
148-
149-
150- def get_perms (root : AuxNode ) -> List [Tuple [AuxNode , ...]]:
151- perms = {tuple (nondeterministic_visit (root )) for _ in range (1000 )}
152- perms .add (tuple (pre_order_visit (root )))
153- return sorted (perms , key = lambda t : str (t ))
154-
155-
156- def pp_json_path_perms (data : JSONLikeData ) -> None :
16+ from jsonpath_rfc9535 import JSONLikeData
17+
18+
19+ def pp_json_path_perms (data : JSONLikeData ) -> None : # noqa: D103
15720 print ("Input data" )
15821 print (f"\033 [92m{ data } \033 [0m" )
15922 aux_tree = AuxNode .from_ (data )
16023 print ("\n Tree view" )
161- pptree (aux_tree )
24+ pp_tree (aux_tree )
16225
16326 print ("\n Pre order" )
16427 print (", " .join (str (n ) for n in pre_order_visit (aux_tree )))
@@ -167,12 +30,12 @@ def pp_json_path_perms(data: JSONLikeData) -> None:
16730 print (", " .join (str (n ) for n in breadth_first_visit (aux_tree )))
16831
16932 print ("\n Nondeterministic order" )
170- for perm in get_perms (aux_tree ):
33+ for perm in all_perms (aux_tree ):
17134 print (", " .join (str (node ) for node in perm ))
17235
17336 print ("\n ---\n \n Collections only" )
174- aux_tree = AuxNode .collections (data )
175- pptree (aux_tree )
37+ aux_tree = AuxNode .from_ (data , collections_only = True )
38+ pp_tree (aux_tree )
17639
17740 print ("\n Pre order" )
17841 print (", " .join (str (n ) for n in pre_order_visit (aux_tree )))
@@ -181,7 +44,7 @@ def pp_json_path_perms(data: JSONLikeData) -> None:
18144 print (", " .join (str (n ) for n in breadth_first_visit (aux_tree )))
18245
18346 print ("\n Nondeterministic order" )
184- for perm in get_perms (aux_tree ):
47+ for perm in all_perms (aux_tree ):
18548 print (", " .join (str (node ) for node in perm ))
18649
18750
0 commit comments