comparison env/lib/python3.9/site-packages/galaxy/util/jstree.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 import copy
2 import os
3 from collections import namedtuple
4
5 import dictobj
6
7 Path = namedtuple('Path', ('path', 'id', 'options'))
8
9
10 class Node(dictobj.DictionaryObject):
11 """
12 Copyright 2012 "Grim Apps"
13
14 Licensed under the Apache License, Version 2.0 (the "License");
15 you may not use this file except in compliance with the License.
16 You may obtain a copy of the License at
17
18 http://www.apache.org/licenses/LICENSE-2.0
19
20 Unless required by applicable law or agreed to in writing, software
21 distributed under the License is distributed on an "AS IS" BASIS,
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 See the License for the specific language governing permissions and
24 limitations under the License.
25
26 Helper class written by William Grim - grimwm
27 Original repo: https://github.com/grimwm/py-jstree
28 Code adjusted according to the idea of Frank Blechschmidt - FraBle
29 Thank you!
30 ************************
31 This class exists as a helper to the JSTree. Its "jsonData" method can
32 generate sub-tree JSON without putting the logic directly into the JSTree.
33
34 This data structure is only semi-immutable. The JSTree uses a directly
35 iterative (i.e. no stack is managed) builder pattern to construct a
36 tree out of paths. Therefore, the children are not known in advance, and
37 we have to keep the children attribute mutable.
38 """
39
40 def __init__(self, path, oid, **kwargs):
41 """
42 kwargs allows users to pass arbitrary information into a Node that
43 will later be output in jsonData(). It allows for more advanced
44 configuration than the default path handling that JSTree currently allows.
45 For example, users may want to pass "attr" or some other valid jsTree options.
46
47 Example:
48 >>> node = Node('a', None)
49 >>> assert node._items == {'text': 'a', 'children': dictobj.MutableDictionaryObject({})}
50 >>> assert node.jsonData() == {'text': 'a'}
51
52 >>> node = Node('a', 1)
53 >>> assert node._items == {'text': 'a', 'children': dictobj.MutableDictionaryObject({}), 'li_attr': dictobj.DictionaryObject({'id': 1}), 'id': 1}
54 >>> assert node.jsonData() == {'text': 'a', 'id': 1, 'li_attr': {'id': 1}}
55
56 >>> node = Node('a', 5, icon="folder", state = {'opened': True})
57 >>> assert node._items == {'text': 'a', 'id': 5, 'state': dictobj.DictionaryObject({'opened': True}), 'children': dictobj.MutableDictionaryObject({}), 'li_attr': dictobj.DictionaryObject({'id': 5}), 'icon': 'folder'}
58 >>> assert node.jsonData() == {'text': 'a', 'state': {'opened': True}, 'id': 5, 'li_attr': {'id': 5}, 'icon': 'folder'}
59 """
60 super().__init__()
61
62 children = kwargs.get('children', {})
63 if len([key for key in children if not isinstance(children[key], Node)]):
64 raise TypeError(
65 "One or more children were not instances of '%s'" % Node.__name__)
66 if 'children' in kwargs:
67 del kwargs['children']
68 self._items['children'] = dictobj.MutableDictionaryObject(children)
69
70 if oid is not None:
71 li_attr = kwargs.get('li_attr', {})
72 li_attr['id'] = oid
73 kwargs['li_attr'] = li_attr
74 self._items['id'] = oid
75
76 self._items.update(dictobj.DictionaryObject(**kwargs))
77 self._items['text'] = path
78
79 def jsonData(self):
80 children = [self.children[k].jsonData() for k in sorted(self.children)]
81 output = {}
82 for k in self._items:
83 if 'children' == k:
84 continue
85 if isinstance(self._items[k], dictobj.DictionaryObject):
86 output[k] = self._items[k].asdict()
87 else:
88 output[k] = self._items[k]
89 if len(children):
90 output['children'] = children
91 return output
92
93
94 class JSTree(dictobj.DictionaryObject):
95 """
96 An immutable dictionary-like object that converts a list of "paths"
97 into a tree structure suitable for jQuery's jsTree.
98 """
99
100 def __init__(self, paths, **kwargs):
101 """
102 Take a list of paths and put them into a tree. Paths with the same prefix should
103 be at the same level in the tree.
104
105 kwargs may be standard jsTree options used at all levels in the tree. These will be outputted
106 in the JSON.
107
108 """
109 if len([p for p in paths if not isinstance(p, Path)]):
110 raise TypeError(
111 "All paths must be instances of '%s'" % Path.__name__)
112
113 super().__init__()
114
115 root = Node('', None, **kwargs)
116 for path in sorted(paths):
117 curr = root
118 subpaths = path.path.split(os.path.sep)
119 for i, subpath in enumerate(subpaths):
120 if subpath not in curr.children:
121 opt = copy.deepcopy(kwargs)
122 if len(subpaths) - 1 == i:
123 oid = path.id
124 opt.update(path.options) if path.options is not None else None
125 else:
126 oid = None
127 curr.children[subpath] = Node(subpath, oid, **opt)
128 # oid = path.id if len(subpaths) - 1 == i else None
129 # curr.children[subpath] = Node(subpath, oid, **kwargs)
130 curr = curr.children[subpath]
131 self._items['_root'] = root
132
133 def pretty(self, root=None, depth=0, spacing=2):
134 """
135 Create a "pretty print" represenation of the tree with customized indentation at each
136 level of the tree.
137 """
138 if root is None:
139 root = self._root
140 fmt = "%s%s/" if root.children else "%s%s"
141 s = fmt % (" " * depth * spacing, root.text)
142 for child in root.children:
143 child = root.children[child]
144 s += "\n%s" % self.pretty(child, depth + 1, spacing)
145 return s
146
147 def jsonData(self):
148 """
149 Returns a copy of the internal tree in a JSON-friendly format,
150 ready for consumption by jsTree. The data is represented as a
151 list of dictionaries, each of which are our internal nodes.
152
153 """
154 return [self._root.children[k].jsonData() for k in sorted(self._root.children)]