def get_items(node, branches_expr=args['branches_expr'], md=md): md._push(InstanceDict(node, md)) items = branches_expr(md) md._pop() return items
def test_getitem_2(self): # It does not break the acquisition chain of stored objects. from DocumentTemplate._DocumentTemplate import InstanceDict main = Item('main') main.sub = Item('sub') side = Item('side') side.here = Item('here') path = side.here.__of__(main) i_dict = InstanceDict(path, {}, getattr) self.assertEqual(main.sub, i_dict['sub'])
def test_getitem(self): # The acquisition chain of the object a got method is bound to # does not contain the InstanceDict instance itself. # This is a test for the fix of the regression described in # https://github.com/zopefoundation/Zope/issues/292 from DocumentTemplate._DocumentTemplate import InstanceDict inst = Item('a').__of__(Item('b')) i_dict = InstanceDict(inst, {}, getattr) for element in Acquisition.aq_chain(i_dict['method1'].__self__): self.assertNotIsInstance(element, InstanceDict)
def test_instancedict(self): context = ['context'] here = ['here'] request = {'request': 1} names = {'context': context, 'here': here, 'request': request} td = RestrictedTemplateDict() td.this = context td._push(request) td._push(InstanceDict(td.this, td)) td._push(names) def func(td): return td.this result = func(td) self.assertTrue(result is context)
def call_with_ns(f, ns, arg=1): td = Rtd() # prefer 'context' to 'here'; fall back to 'None' this = ns.get('context', ns.get('here')) td.this = this request = ns.get('request', {}) if hasattr(request, 'taintWrapper'): request = request.taintWrapper() td._push(request) td._push(InstanceDict(td.this, td)) td._push(ns) try: if arg == 2: return f(None, td) else: return f(td) finally: td._pop(3)
def test_taintwrapper(self): class Request(dict): def taintWrapper(self): return {'tainted': 'found'} context = ['context'] here = ['here'] request = Request().taintWrapper() names = {'context': context, 'here': here, 'request': request} td = RestrictedTemplateDict() td.this = context td._push(request) td._push(InstanceDict(td.this, td)) td._push(names) def func(td): return td['tainted'] found = func(td) self.assertEqual(found, 'found')
def _exec(self, bound_data, args, kw): # Cook if we haven't already self._cook_check() # If this object has no encoding set, we use the old default encoding = getattr(self, 'encoding', OLD_DEFAULT_ENCODING) # Get our caller's namespace, and set up our own. cns = bound_data['caller_namespace'] ns = self._Bindings_ns_class() push = ns._push ns.guarded_getattr = None ns.guarded_getitem = None req = None kw_bind = kw if cns: # Someone called us. push(cns) ns.level = cns.level + 1 ns.this = getattr(cns, 'this', None) # Get their bindings. Copy the request reference # forward, and include older keyword arguments in the # current 'keyword_args' binding. try: last_bound = ns[('current bindings',)] last_req = last_bound.get('REQUEST', None) if last_req: bound_data['REQUEST'] = last_req old_kw = last_bound['keyword_args'] if old_kw: kw_bind = old_kw.copy() kw_bind.update(kw) except Exception: pass else: # We're first, so get the REQUEST. try: req = aq_acquire(self, 'REQUEST') if hasattr(req, 'taintWrapper'): req = req.taintWrapper() except Exception: pass bound_data['REQUEST'] = req ns.this = bound_data['context'] # Bind 'keyword_args' to the complete set of keyword arguments. bound_data['keyword_args'] = kw_bind # Push globals, initialized variables, REQUEST (if any), # and keyword arguments onto the namespace stack for nsitem in (self.globals, self._vars, req, kw): if nsitem: push(nsitem) # Push the 'container' (default), 'context', or nothing. bind_to = self._Bindings_client if bind_to in ('container', 'client'): push(InstanceDict(bound_data[bind_to], ns)) # Push the name bindings, and a reference to grab later. push(bound_data) push({('current bindings',): bound_data}) security = getSecurityManager() security.addContext(self) try: value = self.ZDocumentTemplate_beforeRender(ns, _marker) if value is _marker: try: result = render_blocks(self._v_blocks, ns, encoding=encoding) except DTReturn as v: result = v.v self.ZDocumentTemplate_afterRender(ns, result) return result else: return value finally: security.removeContext(self) # Clear the namespace, breaking circular references. while len(ns): ns._pop()
def tpRenderTABLE( self, id, root_url, url, state, substate, diff, data, colspan, section, md, treeData, level=0, args=None, try_call_attr=try_call_attr, encoding=None, ): """Render a tree as a table""" encoding = encoding or 'latin-1' exp = 0 if level >= 0: urlattr = args['url'] if urlattr and hasattr(self, urlattr): tpUrl = try_call_attr(self, urlattr) url = (url and ('%s/%s' % (url, tpUrl))) or tpUrl root_url = root_url or tpUrl ptreeData = add_with_prefix(treeData, 'tree', args.get('prefix')) ptreeData['tree-item-url'] = url ptreeData['tree-level'] = level ptreeData['tree-item-expanded'] = 0 output = data.append items = None if 'assume_children' in args and \ args['assume_children'] and \ substate is not state: # We should not compute children unless we have to. # See if we've been asked to expand our children. for i in range(len(substate)): sub = substate[i] if sub[0] == id: exp = i + 1 break if not exp: items = 1 get = md.guarded_getattr if get is None: get = getattr if items is None: if 'branches' in args and hasattr(self, args['branches']): items = get(self, args['branches']) items = items() elif 'branches_expr' in args: items = args['branches_expr'](md) if not items and 'leaves' in args: items = 1 if items and items != 1: getitem = getattr(md, 'guarded_getitem', None) if getitem is not None: unauth = [] for index in range(len(items)): try: getitem(items, index) except ValidationError: unauth.append(index) if unauth: if 'skip_unauthorized' in args and args['skip_unauthorized']: items = list(items) unauth.reverse() for index in unauth: del items[index] else: raise ValidationError(unauth) if 'sort' in args: # Faster/less mem in-place sort if isinstance(items, tuple): items = list(items) sort = args['sort'] size = range(len(items)) for i in size: v = items[i] k = getattr(v, sort) try: k = k() except Exception: pass items[i] = (k, v) items.sort() for i in size: items[i] = items[i][1] if 'reverse' in args: items = list(items) # Copy the list items.reverse() if isinstance(id, six.binary_type): diff.append(id.decode(encoding)) else: diff.append(id) _td_colspan = '<td colspan="%s" style="white-space: nowrap"></td>' _td_single = '<td width="16" style="white-space: nowrap"></td>' sub = None if substate is state: output('<table cellspacing="0">\n') sub = substate[0] exp = items else: # Add prefix output('<tr>\n') # Add +/- icon if items: if level: if level > 3: output(_td_colspan % (level - 1)) elif level > 1: output(_td_single * (level - 1)) output(_td_single) output('\n') output('<td width="16" valign="top" style="white-space: nowrap">') for i in range(len(substate)): sub = substate[i] if sub[0] == id: exp = i + 1 break s = encode_str(compress(json.dumps(diff))) # bytes in ASCII enc. # For rendering the encoded state string in a URL under Python 3, # we must lose the "b" prefix by decoding if six.PY3: s = s.decode('ASCII') # Propagate extra args through tree. if 'urlparam' in args: param = args['urlparam'] param = "%s&" % param else: param = "" if exp: ptreeData['tree-item-expanded'] = 1 icon = ('<i title="Collapse..."' ' class="fas fa-caret-down text-muted"></i>') output('<a name="%s" href="%s?%stree-c=%s#%s">%s</a>' % (id, root_url, param, s, id, icon)) else: icon = ('<i title="Expand..."' ' class="fas fa-caret-right text-muted"></i>') output('<a name="%s" href="%s?%stree-e=%s#%s">%s</a>' % (id, root_url, param, s, id, icon)) output('</td>\n') else: if level > 2: output(_td_colspan % level) elif level > 0: output(_td_single * level) output(_td_single) output('\n') # add item text dataspan = colspan - level nowrap = (args.get('nowrap') and ' style="white-space: nowrap"') or '' output('<td%s%s valign="top" align="left">' % ((dataspan > 1 and (' colspan="%s"' % dataspan) or ''), nowrap)) output(render_blocks(section, md, encoding=encoding)) output('</td>\n</tr>\n') if exp: level = level + 1 dataspan = colspan - level if level > 2: h = _td_colspan % level elif level > 0: h = _td_single * level else: h = '' if 'header' in args: doc = args['header'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: ds = (dataspan > 1 and (' colspan="%s"' % dataspan)) or '' output( doc( None, md, standard_html_header=( '<tr>%s' '<td width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, ds)), standard_html_footer='</td></tr>', )) if items == 1: # leaves if 'leaves' in args: doc = args['leaves'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: ds = (dataspan > 1 and ' colspan="%s"' % dataspan) or '' treeData['-tree-substate-'] = sub ptreeData['tree-level'] = level md._push(treeData) try: output( doc( None, md, standard_html_header= ('<tr>%s<td ' 'width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, ds)), standard_html_footer='</td></tr>', )) finally: md._pop(1) elif 'expand' in args: doc = args['expand'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: ds = (dataspan > 1 and ' colspan="%s"' % dataspan) or '' treeData['-tree-substate-'] = sub ptreeData['tree-level'] = level md._push(treeData) try: output( doc( None, md, standard_html_header=( '<tr>%s<td ' 'width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, ds)), standard_html_footer='</td></tr>', )) finally: md._pop(1) else: __traceback_info__ = sub, args, state, substate ids = {} for item in items: id = extract_id(item, args['id']) if len(sub) == 1: sub.append([]) substate = sub[1] ids[id] = 1 md._push(InstanceDict(item, md)) try: data = tpRenderTABLE(item, id, root_url, url, state, substate, diff, data, colspan, section, md, treeData, level, args) finally: md._pop() if not sub[1]: del sub[1] ids = ids.__contains__ for i in range(len(substate) - 1, -1): if not ids(substate[i][0]): del substate[i] if 'footer' in args: doc = args['footer'] if doc in md: doc = md.getitem(doc, 0) else: doc = None if doc is not None: ds = (dataspan > 1 and ' colspan="%s"' % dataspan) or '' output( doc( None, md, standard_html_header=( '<tr>%s<td ' 'width="16" style="white-space: nowrap"></td>' '<td%s valign="top">' % (h, ds)), standard_html_footer='</td></tr>', )) del diff[-1] if not diff: output('</table>\n') return data
def tpRender(self, md, section, args, try_call_attr=try_call_attr, encoding=None): """Render data organized as a tree. We keep track of open nodes using a cookie. The cookie stored the tree state. State should be a tree represented like: [] # all closed ['eagle'], # eagle is open ['eagle'], ['jeep', [1983, 1985]] # eagle, jeep, 1983 jeep and 1985 jeep where the items are object ids. The state will be pickled to a compressed and base64ed string that gets unencoded, uncompressed, and unpickled on the other side. Note that ids used in state need not be connected to urls, since state manipulation is internal to rendering logic. Note that to make unpickling safe, we use the MiniPickle module, that only creates safe objects """ data = [] id = extract_id(self, args['id']) try: # see if we are being run as a sub-document root = md['tree-root-url'] url = md['tree-item-url'] state = md['tree-state'] diff = md['tree-diff'] substate = md['-tree-substate-'] colspan = md['tree-colspan'] level = md['tree-level'] except KeyError: # OK, we are a top-level invocation level = -1 if 'collapse_all' in md: state = [id, []], elif 'expand_all' in md: if 'branches' in args: def get_items(node, branches=args['branches'], md=md): get = md.guarded_getattr if get is None: get = getattr items = get(node, branches) return items() elif 'branches_expr' in args: def get_items(node, branches_expr=args['branches_expr'], md=md): md._push(InstanceDict(node, md)) items = branches_expr(md) md._pop() return items state = [id, tpValuesIds(self, get_items, args)], else: if 'tree-s' in md: state = md['tree-s'] state = decode_seq(state) try: if state[0][0] != id: state = [id, []], except IndexError: state = [id, []], else: state = [id, []], if 'tree-e' in md: diff = decode_seq(md['tree-e']) apply_diff(state, diff, 1) if 'tree-c' in md: diff = decode_seq(md['tree-c']) apply_diff(state, diff, 0) colspan = tpStateLevel(state) substate = state diff = [] url = '' root = md['URL'] right_end = root.rfind('/') if right_end >= 0: root = root[right_end + 1:] treeData = { 'tree-root-url': root, 'tree-colspan': colspan, 'tree-state': state } prefix = args.get('prefix') if prefix: for k, v in treeData.items(): treeData[prefix + k[4:].replace('-', '_')] = v md._push(InstanceDict(self, md)) md._push(treeData) try: tpRenderTABLE(self, id, root, url, state, substate, diff, data, colspan, section, md, treeData, level, args, encoding=encoding) finally: md._pop(2) if state is substate and not ('single' in args and args['single']): state = state or ([id], ) state = encode_seq(state) md['RESPONSE'].setCookie('tree-s', state) return ''.join(data)