source: tracformsplugin/trunk/tracforms/environment.py

Last change on this file was 16384, checked in by Ryan J Ollos, 7 years ago

TracForms 0.5dev: Conform to PEP8

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        super(FormEnvironment, self).__init__()
45        if base is not None:
46            self.update(base)
47        self.base = base
48        self.prefixes = prefixes + ('',)
49
50    def __getitem__(self, key, default=KeyError):
51        obj = self.get(key, default)
52        if obj is default:
53            raise KeyError(key)
54        else:
55            return obj
56
57    def get(self, search, default=None, singleton=True, all=False):
58        values = tuple(dict.__getitem__(self, key)
59                       for key in sorted(self.keyset(search, all)))
60        if singleton:
61            if not values:
62                return default
63            elif len(values) == 1:
64                return values[0]
65            else:
66                raise ValueError(
67                    _("Too many results for singleton %r" % key))
68        else:
69            return values
70
71    def keyset(self, search, all=False):
72        if search[:1] == '/' and search[-1:] == '/':
73            def matches(prefix, keys):
74                regexp = re.compile(prefix + search[1:-1])
75                return (key for key in keys
76                        if regexp.match(key))
77        elif '*' in search or '?' in search or '|' in search:
78            def matches(prefix, keys):
79                regexp = re.compile(fnmatch.translate(prefix + search))
80                return (key for key in keys
81                        if regexp.match(key))
82        else:
83            def matches(prefix, keys):
84                check = prefix + search
85                return (key for key in keys
86                        if key == check)
87        keys = self.sorted_keys
88        values = set()
89        for prefix in self.prefixes:
90            values |= set(key for key in matches(prefix, keys))
91            if values and not all:
92                break
93        return values
94
95    _sorted = None
96
97    @property
98    def sorted_keys(self):
99        keys = self._sorted
100        if keys is None:
101            keys = self._sorted = sorted(self)
102        return keys
103
104    def getmany(self, search, all=False):
105        return self.get(search, singleton=False, all=all)
106
107    def addform(self, data):
108        for name, value in json.loads(state or '{}').iteritems():
109            keys = [prefix + ':' + name for prefix in self.prefixes]
110            for key in keys:
111                self[key] = tuple(value)
Note: See TracBrowser for help on using the repository browser.