Projet

Général

Profil

0001-utils-try-to-guess-type-of-params-38328.patch

Valentin Deniaud, 04 février 2020 10:35

Télécharger (8,05 ko)

Voir les différences:

Subject: [PATCH] utils: try to guess type of params (#38328)

And fix a bug where they did not appear in documentation.
 passerelle/utils/api.py        | 31 +++++++++++++++++--
 passerelle/views.py            | 44 +++++++++++++-------------
 tests/test_generic_endpoint.py | 56 ++++++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+), 24 deletions(-)
passerelle/utils/api.py
148 148
        return {}
149 149

  
150 150
    def get_params(self):
151

  
152
        def type_to_str(value):
153
            if isinstance(value, bool):
154
                return 'boolean'
155
            elif isinstance(value, int):
156
                return 'integer'
157
            elif isinstance(value, float):
158
                return 'float'
159

  
151 160
        params = []
152 161
        defaults = dict(zip(
153 162
            reversed(inspect.getargspec(self.func).args),
......
156 165
            if param == 'post_data':
157 166
                continue
158 167
            param_info = {'name': param}
159
            if self.parameters and param in self.parameters and self.parameters[param].get('description'):
160
                param_info['description'] = self.parameters[param].get('description')
168
            if self.parameters and param in self.parameters:
169
                info = self.parameters[param]
170
                if info.get('description'):
171
                    param_info['description'] = info['description']
172
                if 'type' in info:
173
                    typ = info['type']
174
                    if typ == 'int':
175
                        param_info['type'] = 'integer'
176
                    elif typ == 'bool':
177
                        param_info['type'] = 'boolean'
178
                    else:
179
                        param_info['type'] = typ
180
                elif 'example_value' in info:
181
                    typ = type_to_str(info['example_value'])
182
                    if typ:
183
                        param_info['type'] = typ
161 184
            if param in defaults:
162 185
                param_info['optional'] = True
163 186
                param_info['default_value'] = defaults[param]
187
                if 'type' not in param_info:
188
                    typ = type_to_str(defaults[param])
189
                    if typ:
190
                        param_info['type'] = typ
164 191
            params.append(param_info)
165 192
        return params
passerelle/views.py
319 319
                continue
320 320
            if not d.get(key):
321 321
                d[key] = other_params[key]
322
        if self.endpoint.endpoint_info.parameters:
322
        for parameter_info in self.endpoint.endpoint_info.get_params():
323 323
            # check and convert parameter values
324
            for parameter, parameter_info in self.endpoint.endpoint_info.parameters.items():
325
                if parameter not in d:
326
                    continue
327
                if parameter_info.get('type') == 'bool':
328
                    if d[parameter].lower() in ('true', 'on'):
329
                        d[parameter] = True
330
                    elif d[parameter].lower() in ('false', 'off'):
331
                        d[parameter] = False
332
                    else:
333
                        raise InvalidParameterValue(parameter)
334
                elif parameter_info.get('type') == 'int':
335
                    try:
336
                        d[parameter] = int(d[parameter])
337
                    except ValueError:
338
                        raise InvalidParameterValue(parameter)
339
                elif parameter_info.get('type') == 'float':
340
                    d[parameter] = d[parameter].replace(',', '.')
341
                    try:
342
                        d[parameter] = float(d[parameter])
343
                    except ValueError:
344
                        raise InvalidParameterValue(parameter)
324
            parameter = parameter_info['name']
325
            if parameter not in d:
326
                continue
327
            if parameter_info.get('type') in ('bool', 'boolean'):
328
                if d[parameter].lower() in ('true', 'on'):
329
                    d[parameter] = True
330
                elif d[parameter].lower() in ('false', 'off'):
331
                    d[parameter] = False
332
                else:
333
                    raise InvalidParameterValue(parameter)
334
            elif parameter_info.get('type') in ('int', 'integer'):
335
                try:
336
                    d[parameter] = int(d[parameter])
337
                except ValueError:
338
                    raise InvalidParameterValue(parameter)
339
            elif parameter_info.get('type') == 'float':
340
                d[parameter] = d[parameter].replace(',', '.')
341
                try:
342
                    d[parameter] = float(d[parameter])
343
                except ValueError:
344
                    raise InvalidParameterValue(parameter)
345 345

  
346 346
        if request.method == 'POST' and self.endpoint.endpoint_info.post:
347 347
            request_body = self.endpoint.endpoint_info.post.get('request_body', {})
tests/test_generic_endpoint.py
563 563
    assert json_res['err_desc'] == 'invalid value for parameter "floating"'
564 564

  
565 565

  
566
def test_endpoint_params_type_detection(app, db, monkeypatch):
567

  
568
    @endpoint(methods=['get'],
569
              parameters={
570
                  'bool_by_example': {
571
                      'example_value': True,
572
                  },
573
                  'int_by_example': {
574
                      'example_value': 1,
575
                  },
576
                  'float_by_example': {
577
                      'example_value': 1.1,
578
                  },
579
              })
580
    def httpcall(obj, request, boolean=False, integer=1, floating=1.1,
581
                 bool_by_example=None, int_by_example=None, float_by_example=None):
582
        return {'boolean': boolean, 'integer': integer, 'floating': floating,
583
                'bool_by_example': bool_by_example, 'int_by_example': int_by_example,
584
                'float_by_example': float_by_example}
585

  
586
    monkeypatch.setattr(StubInvoicesConnector, 'httpcall', httpcall, raising=False)
587

  
588
    connector = StubInvoicesConnector(slug='fake')
589
    connector.save()
590

  
591
    json_res = app.get('/stub-invoices/fake/httpcall?boolean=True').json
592
    assert json_res['boolean'] is True
593
    json_res = app.get('/stub-invoices/fake/httpcall?bool_by_example=True').json
594
    assert json_res['bool_by_example'] is True
595

  
596
    json_res = app.get('/stub-invoices/fake/httpcall?integer=2').json
597
    assert json_res['integer'] == 2
598
    json_res = app.get('/stub-invoices/fake/httpcall?int_by_example=2').json
599
    assert json_res['int_by_example'] == 2
600

  
601
    json_res = app.get('/stub-invoices/fake/httpcall?floating=1.5').json
602
    assert json_res['floating'] == 1.5
603
    json_res = app.get('/stub-invoices/fake/httpcall?float_by_example=1.5').json
604
    assert json_res['float_by_example'] == 1.5
605

  
606
    res = app.get('/stub-invoices/fake/')
607
    for param in res.pyquery('ul.get-params li'):
608
        param_details = param.getchildren()
609
        name = next(el for el in param_details if 'param-name' in el.attrib['class']).text
610
        typ = next(el for el in param_details if 'type' in el.attrib['class']).text
611
        typ = typ.strip('()')
612
        if 'bool' in name:
613
            assert typ == 'boolean'
614
        elif 'int' in name:
615
            assert typ == 'integer'
616
        elif 'float' in name:
617
            assert typ == 'float'
618
        else:
619
            assert typ == 'string'
620

  
621

  
566 622
class DummyConnectorBase(BaseResource):
567 623
    def get_availability_status(self):
568 624
        # naive get_availability_status method for testing
569
-