source: tracformsplugin/tags/tracforms-0.4.1/0.11/tracforms/environment.py

Last change on this file was 10490, checked in by Steffen Hoffmann, 12 years ago

TracFormsPlugin: Release maintenance version 0.4.1 for compatibility with Trac 0.11, closes #9000.

These are changes cherry-picked from trunk and merged into tracforms-0.4 to
establish full compatibility with Trac 0.11 on level with plugin's own claims.

File size: 3.2 KB
Line 
1# -*- coding: utf-8 -*-
2
3import fnmatch
4import re
5
6from api import _
7from compat import json
8
9
10class FormEnvironment(dict):
11    """Handles the environment used by TracForms macros.
12
13This dictionary is stackable and provides recursive context
14for pseudo-variables.
15
16>>> outer = FormEnvironment(None)
17>>> outer['hello'] = 'World'
18>>> outer['test:ACK'] = 'OOP'
19>>> outer['test:FOO'] = 'BAR'
20>>> inner = FormEnvironment(outer, ('test:',))
21>>> inner['hello']
22'World'
23>>> inner['ACK']
24'OOP'
25>>> inner.getmany('test:*')
26('OOP', 'BAR')
27>>> tuple(sorted(inner.keyset('/.el/')))
28('hello',)
29>>> tuple(sorted(inner.keyset('/.el/')))
30('hello',)
31>>> tuple(sorted(inner.keyset('*')))
32('test:ACK', 'test:FOO')
33>>> tuple(sorted(inner.keyset('*', all=True)))
34('hello', 'test:ACK', 'test:FOO')
35>>> inner.getmany('/.el/')
36('World',)
37>>> web = FormEnvironment(None, ('test',))
38>>> web.addform('a=5&a=7&b=hello', 'test')
39>>> web['a']
40'5\t7'
41    """
42
43    def __init__(self, base=None, prefixes=()):
44        if base is not None:
45            self.update(base)
46        self.base = base
47        self.prefixes = prefixes + ('',)
48
49    def __getitem__(self, key, NOT_FOUND=KeyError):
50        obj = self.get(key, NOT_FOUND)
51        if obj is NOT_FOUND:
52            raise KeyError(key)
53        else:
54            return obj
55
56    def get(self, search, default=None, singleton=True, all=False):
57        values = tuple(dict.__getitem__(self, key)
58                        for key in sorted(self.keyset(search, all)))
59        if singleton:
60            if not values:
61                return default
62            elif len(values) == 1:
63                return values[0]
64            else:
65                raise ValueError(
66                    _("Too many results for singleton %r" % key))
67        else:
68            return values
69
70    def keyset(self, search, all=False):
71        if search[:1] == '/' and search[-1:] == '/':
72            def matches(prefix, keys):
73                regexp = re.compile(prefix + search[1:-1])
74                return (key for key in keys
75                        if regexp.match(key))
76        elif '*' in search or '?' in search or '|' in search:
77            def matches(prefix, keys):
78                regexp = re.compile(fnmatch.translate(prefix + search))
79                return (key for key in keys
80                        if regexp.match(key))
81        else:
82            def matches(prefix, keys):
83                check = prefix + search
84                return (key for key in keys
85                        if key == check)
86        keys = self.sorted_keys
87        values = set()
88        for prefix in self.prefixes:
89            values |= set(key for key in matches(prefix, keys))
90            if values and not all:
91                break
92        return values
93
94    _sorted = None
95    @property
96    def sorted_keys(self):
97        keys = self._sorted
98        if keys is None:
99            keys = self._sorted = sorted(self)
100        return keys
101
102    def getmany(self, search, all=False):
103        return self.get(search, singleton=False, all=all)
104
105    def addform(self, data):
106        for name, value in json.loads(state or '{}').iteritems():
107            keys = [prefix + ':' + name for prefix in self.prefixes]
108            for key in keys:
109                self[key] = tuple(value)
110
Note: See TracBrowser for help on using the repository browser.