comparison planemo/lib/python3.7/site-packages/galaxy/util/jstree.py @ 1:56ad4e20f292 draft

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