Projet

Général

Profil

0001-general-don-t-flatten-to-invalid-keys-52579.patch

Frédéric Péters, 12 avril 2021 20:41

Télécharger (6,3 ko)

Voir les différences:

Subject: [PATCH] general: don't flatten to invalid keys (#52579)

 tests/backoffice_pages/test_all.py | 10 ++++++++++
 tests/test_formdata.py             | 18 ++++++++++++++++++
 wcs/backoffice/management.py       | 10 ++++++++--
 wcs/formdata.py                    |  6 ++----
 wcs/qommon/substitution.py         |  8 +++++++-
 5 files changed, 45 insertions(+), 7 deletions(-)
tests/backoffice_pages/test_all.py
4447 4447
    assert 'form_user_f3' not in resp.text
4448 4448
    assert 'form_user_f_' not in resp.text
4449 4449

  
4450
    # make sure workflow data itself is not displayed, as it's available in
4451
    # expanded variables
4452
    assert not pq('[title="form_workflow_data"]')
4453

  
4454
    # but do display it if it has some invalid contents
4455
    formdata.workflow_data['invalid key'] = 'foobar'
4456
    formdata.store()
4457
    resp = login(get_app(pub)).get(resp.request.url)
4458
    assert resp.pyquery('[title="form_workflow_data"]')
4459

  
4450 4460
    # check functions
4451 4461
    assert re.findall('Recipient.*foobar', resp.text)
4452 4462

  
tests/test_formdata.py
546 546
    assert substvars['foo_var_file_url']
547 547

  
548 548

  
549
def test_workflow_data_invalid_keys(pub, formdef):
550
    formdata = formdef.data_class()()
551
    formdata.store()
552
    formdata.workflow_data = {
553
        'valid_key': {'invalid key': 'foo', 'valid_key': 'bar'},
554
        'invalid key': 'baz',
555
    }
556
    substvars = formdata.get_substitution_variables()
557
    assert 'form_workflow_data_valid_key' in substvars
558
    assert 'form_workflow_data_invalid key' not in substvars
559
    assert 'form_workflow_data_valid_key_valid_key' in substvars
560
    assert 'form_workflow_data_valid_key_invalid key' not in substvars
561
    assert substvars['form_workflow_data_valid_key_valid_key'] == 'bar'
562
    with pytest.raises(KeyError):
563
        # noqa pylint: disable=pointless-statement
564
        substvars['form_workflow_data_invalid key']
565

  
566

  
549 567
def test_evolution_get_status(pub):
550 568
    Workflow.wipe()
551 569
    workflow = Workflow(name='test')
wcs/backoffice/management.py
3279 3279
                    'inspect_url': v['form'].backoffice_url + 'inspect',
3280 3280
                    'display_name': v['form_display_name'],
3281 3281
                }
3282
            elif hasattr(v, 'inspect_keys') or isinstance(v, dict):
3283
                # skip expanded
3282
            elif hasattr(v, 'inspect_keys'):
3283
                # skip as there are expanded identifiers
3284 3284
                continue
3285 3285
            else:
3286
                if isinstance(v, dict):
3287
                    # only display dictionaries if they have invalid keys
3288
                    # (otherwise the expanded identifiers are a better way
3289
                    # to get to the values).
3290
                    if all(CompatibilityNamesDict.valid_key_regex.match(k) for k in v):
3291
                        continue
3286 3292
                r += htmltext('<li><code title="%s">%s</code>') % (k, k)
3287 3293
                r += htmltext('  <div class="value"><span>%s</span>') % ellipsize(safe(v), 10000)
3288 3294
                if not isinstance(v, str):
wcs/formdata.py
29 29
from .qommon.evalutils import make_datetime
30 30
from .qommon.publisher import get_cfg
31 31
from .qommon.storage import Contains, Intersects, Null, StorableObject
32
from .qommon.substitution import Substitutions, invalidate_substitution_cache
32
from .qommon.substitution import CompatibilityNamesDict, Substitutions, invalidate_substitution_cache
33 33
from .qommon.template import Template
34 34

  
35 35

  
......
908 908
    def get_substitution_variables(self, minimal=False):
909 909
        from wcs.workflows import AttachmentsSubstitutionProxy
910 910

  
911
        from .qommon.substitution import CompatibilityNamesDict
912

  
913 911
        variables = CompatibilityNamesDict(
914 912
            {
915 913
                'form': self.get_as_lazy(),
......
949 947

  
950 948
            d = copy.deepcopy(d)
951 949
            flatten_dict(d)
952
            variables.update(d)
950
            variables.update({k: v for k, v in d.items() if CompatibilityNamesDict.valid_key_regex.match(k)})
953 951

  
954 952
        return variables
955 953

  
wcs/qommon/substitution.py
14 14
# You should have received a copy of the GNU General Public License
15 15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import re
17 18
from contextlib import contextmanager
18 19

  
19 20
from quixote import get_publisher
......
161 162
class CompatibilityNamesDict(dict):
162 163
    # custom dictionary that provides automatic fallback to legacy variable
163 164
    # names (namespaced with underscores)
165

  
166
    valid_key_regex = re.compile(r'^[a-zA-Z][a-zA-Z0-9_]*$')
167

  
164 168
    def get(self, key, default=None):
165 169
        try:
166 170
            return self.__getitem__(key)
......
178 182
            if hasattr(item, 'inspect_keys'):
179 183
                sub_keys = item.inspect_keys()
180 184
            elif isinstance(item, dict):
181
                sub_keys = item.keys()
185
                sub_keys = [x for x in item.keys() if self.valid_key_regex.match(x)]
182 186
            else:
183 187
                return
184 188
            for sub_key in sub_keys:
......
226 230
        raise KeyError
227 231

  
228 232
    def __getitem__(self, key):
233
        if not self.valid_key_regex.match(key):
234
            raise KeyError(key)
229 235
        parts = key.split('_')
230 236
        try:
231 237
            return self.get_path(self, parts)
232
-