|
1 | 1 | from flask import request
|
2 |
| -from typing import Iterable, List, Union, Optional |
3 |
| -from ._printer import APrinter |
| 2 | +from typing import Iterable, List, Union, Optional, Tuple |
| 3 | +from ._printer import ValidationFailedException |
4 | 4 |
|
5 | 5 |
|
6 |
| -def require_all(printer: APrinter, *values: Iterable[str]) -> bool: |
| 6 | +def require_all(*values: Iterable[str]) -> bool: |
7 | 7 | """
|
8 |
| - returns true if all fields are present in the request |
| 8 | + returns true if all fields are present in the request otherwise raises an exception |
9 | 9 | :returns bool
|
10 | 10 | """
|
11 | 11 | for value in values:
|
12 | 12 | if not request.values.get(value):
|
13 |
| - printer.print_validation_failed(f"missing parameter: need [{values}]") |
14 |
| - return False |
| 13 | + raise ValidationFailedException(f"missing parameter: need [{values}]") |
15 | 14 | return True
|
16 | 15 |
|
17 | 16 |
|
18 |
| -def require_any(printer: APrinter, *values: Iterable[str]) -> bool: |
| 17 | +def require_any(*values: Iterable[str]) -> bool: |
19 | 18 | """
|
20 |
| - returns true if any fields are present in the request |
| 19 | + returns true if any fields are present in the request otherwise raises an exception |
21 | 20 | :returns bool
|
22 | 21 | """
|
23 | 22 | for value in values:
|
24 | 23 | if request.values.get(value):
|
25 | 24 | return True
|
26 |
| - printer.print_validation_failed(f"missing parameter: need one of [{values}]") |
27 |
| - return False |
| 25 | + raise ValidationFailedException(f"missing parameter: need one of [{values}]") |
28 | 26 |
|
29 | 27 |
|
30 |
| -def date_string(value: int) -> str: |
31 |
| - # converts a date integer (YYYYMMDD) into a date string (YYYY-MM-DD) |
32 |
| - # $value: the date as an 8-digit integer |
33 |
| - year = int(value / 10000) % 10000 |
34 |
| - month = int(value / 100) % 100 |
35 |
| - day = value % 100 |
36 |
| - return "{0:04d}-{1:02d}-{2:%02d}".format(year, month, day) |
| 28 | +def extract_strings(key: str) -> Optional[List[str]]: |
| 29 | + s = request.values.get(key) |
| 30 | + if not s: |
| 31 | + # nothing to do |
| 32 | + return None |
| 33 | + return s.split(",") |
37 | 34 |
|
38 | 35 |
|
39 |
| -def extract_values( |
40 |
| - s: str, value_type="str" |
41 |
| -) -> Optional[List[Union[Tuple[str, str], Tuple[int, int], str, int]]]: |
42 |
| - # extracts an array of values and/or ranges from a string |
43 |
| - # $str: the string to parse |
44 |
| - # $type: |
45 |
| - # - 'int': interpret dashes as ranges, cast values to integers |
46 |
| - # - 'ordered_string': interpret dashes as ranges, keep values as strings |
47 |
| - # - otherwise: ignore dashes, keep values as strings |
48 |
| - if not str: |
| 36 | +IntRange = Union[Tuple[int, int], int] |
| 37 | + |
| 38 | + |
| 39 | +def extract_ints(key: str) -> Optional[List[IntRange]]: |
| 40 | + s = request.values.get(key) |
| 41 | + if not s: |
49 | 42 | # nothing to do
|
50 | 43 | return None
|
51 |
| - # whether to parse a value with a dash as a range of values |
52 |
| - should_parse_range = value_type == "int" or value_type == "ordered_string" |
53 |
| - # maintain a list of values and/or ranges |
54 |
| - values: List[Union[Tuple[str, str], Tuple[int, int], str, int]] = [] |
55 |
| - # split on commas and loop over each entry, which could be either a single value or a range of values |
56 |
| - parts = s.split(",") |
57 |
| - for part in parts: |
58 |
| - if should_parse_range and "-" in part: |
59 |
| - # split on the dash |
60 |
| - [first, last] = part.split("-", 2) |
61 |
| - if value_type == "int": |
62 |
| - first = int(first) |
63 |
| - last = int(last) |
64 |
| - if first == last: |
65 |
| - # the first and last numbers are the same, just treat it as a singe value |
66 |
| - values.append(first) |
67 |
| - elif last > first: |
68 |
| - # add the range as an array |
69 |
| - values.append((first, last)) |
70 |
| - else: |
71 |
| - # the range is inverted, this is an error |
72 |
| - return None |
73 |
| - else: |
74 |
| - # this is a single value |
75 |
| - if value_type == "int": |
76 |
| - # cast to integer |
77 |
| - value = int(part) |
78 |
| - else: |
79 |
| - # interpret the string literally |
80 |
| - value = part |
81 |
| - # add the extracted value to the list |
82 |
| - values.append(value) |
83 |
| - # success, return the list |
84 |
| - return values |
| 44 | + |
| 45 | + def _parse_range(part: str): |
| 46 | + if "-" not in part: |
| 47 | + return int(part) |
| 48 | + r = part.split("-", 2) |
| 49 | + first = int(r[0]) |
| 50 | + last = int(r[1]) |
| 51 | + if first == last: |
| 52 | + # the first and last numbers are the same, just treat it as a singe value |
| 53 | + return first |
| 54 | + elif last > first: |
| 55 | + # add the range as an array |
| 56 | + return (first, last) |
| 57 | + # the range is inverted, this is an error |
| 58 | + return None |
| 59 | + |
| 60 | + values = [_parse_range(part) for part in s.split(",")] |
| 61 | + # check for invalid values |
| 62 | + return None if any(v is None for v in values) else values |
85 | 63 |
|
86 | 64 |
|
87 | 65 | def parse_date(s: str) -> int:
|
88 | 66 | # parses a given string in format YYYYMMDD or YYYY-MM-DD to a number in the form YYYYMMDD
|
89 | 67 | return int(s.replace("-", ""))
|
90 | 68 |
|
91 | 69 |
|
92 |
| -def extract_dates(s: str) -> Optional[List[Union[Tuple[int, int], int]]]: |
| 70 | +DateRange = Union[Tuple[int, int], int] |
| 71 | + |
| 72 | + |
| 73 | +def extract_dates(s: str) -> Optional[List[DateRange]]: |
93 | 74 | # extracts an array of values and/or ranges from a string
|
94 | 75 | # $str: the string to parse
|
95 | 76 | if not s:
|
|
0 commit comments