udata-hydra-csvapi 0.4.3.dev2__py3-none-any.whl → 0.4.3.dev3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
api_tabular/core/query.py CHANGED
@@ -56,7 +56,7 @@ def build_sql_query_string(
56
56
  agg_query += f'"{column[1:-1]}__{operator}":{column}.{operator}(),'
57
57
  # we pop the trailing comma (it's always there, by construction)
58
58
  sql_query.append(agg_query[:-1])
59
- if page_size:
59
+ if page_size is not None:
60
60
  sql_query.append(f"limit={page_size}")
61
61
  if offset >= 1:
62
62
  sql_query.append(f"offset={offset}")
@@ -2,6 +2,7 @@ from typing import cast
2
2
 
3
3
  import yaml
4
4
 
5
+ from api_tabular import config
5
6
  from api_tabular.core.utils import is_aggregation_allowed
6
7
 
7
8
  TYPE_POSSIBILITIES = {
@@ -165,9 +166,9 @@ def swagger_parameters(resource_columns: dict, resource_id: str) -> list:
165
166
  {
166
167
  "name": "page",
167
168
  "in": "query",
168
- "description": "Specific page (page=value)",
169
+ "description": "Specific page, starting at 1 (page=value)",
169
170
  "required": False,
170
- "schema": {"type": "integer"},
171
+ "schema": {"type": "integer", "minimum": 1},
171
172
  "example": 1,
172
173
  },
173
174
  {
@@ -175,7 +176,7 @@ def swagger_parameters(resource_columns: dict, resource_id: str) -> list:
175
176
  "in": "query",
176
177
  "description": "Number of results per page (page_size=value)",
177
178
  "required": False,
178
- "schema": {"type": "integer"},
179
+ "schema": {"type": "integer", "minimum": 1, "maximum": config.PAGE_SIZE_MAX},
179
180
  "example": 20,
180
181
  },
181
182
  {
api_tabular/core/utils.py CHANGED
@@ -1,3 +1,5 @@
1
+ from collections.abc import Mapping
2
+
1
3
  from aiohttp.client import ClientResponse
2
4
  from aiohttp.web_response import Response
3
5
 
@@ -19,7 +21,24 @@ def process_total(res: Response | ClientResponse) -> int:
19
21
  return int(str_total)
20
22
 
21
23
 
22
- def build_offset(page: int, page_size: int) -> int:
24
+ def _parse_int_param(query: Mapping[str, str], name: str, label: str, default: int) -> int:
25
+ raw = query.get(name)
26
+ if raw is None:
27
+ return default
28
+ try:
29
+ return int(raw)
30
+ except ValueError:
31
+ raise QueryException(400, None, "Invalid query string", f"{label} must be an integer")
32
+
33
+
34
+ def parse_pagination(query: Mapping[str, str]) -> tuple[int, int, int]:
35
+ """Return (page, page_size, offset) from the query, raising a 400 on invalid values"""
36
+ page = _parse_int_param(query, "page", "Page", 1)
37
+ page_size = _parse_int_param(query, "page_size", "Page size", config.PAGE_SIZE_DEFAULT)
38
+ if page < 1:
39
+ raise QueryException(400, None, "Invalid query string", "Page must be at least 1")
40
+ if page_size < 1:
41
+ raise QueryException(400, None, "Invalid query string", "Page size must be at least 1")
23
42
  if page_size > config.PAGE_SIZE_MAX:
24
43
  raise QueryException(
25
44
  400,
@@ -27,4 +46,4 @@ def build_offset(page: int, page_size: int) -> int:
27
46
  "Invalid query string",
28
47
  f"Page size exceeds allowed maximum: {config.PAGE_SIZE_MAX}",
29
48
  )
30
- return page_size * (page - 1) if page > 1 else 0
49
+ return page, page_size, page_size * (page - 1)
@@ -14,7 +14,7 @@ from api_tabular.core.health import check_health
14
14
  from api_tabular.core.query import build_sql_query_string
15
15
  from api_tabular.core.sentry import get_sentry_kwargs
16
16
  from api_tabular.core.url import build_link_with_page
17
- from api_tabular.core.utils import build_offset, process_total
17
+ from api_tabular.core.utils import parse_pagination, process_total
18
18
  from api_tabular.core.version import get_app_version
19
19
 
20
20
  routes = web.RouteTableDef()
@@ -40,10 +40,7 @@ async def metrics_data(request):
40
40
  """
41
41
  model = request.match_info["model"]
42
42
  query_string = request.query_string.split("&") if request.query_string else []
43
- page = int(request.query.get("page", "1"))
44
- page_size = int(request.query.get("page_size", config.PAGE_SIZE_DEFAULT))
45
-
46
- offset = build_offset(page, page_size)
43
+ page, page_size, offset = parse_pagination(request.query)
47
44
  try:
48
45
  sql_query = build_sql_query_string(query_string, page_size=page_size, offset=offset)
49
46
  except ValueError as e:
@@ -12,7 +12,7 @@ from api_tabular.core.health import check_health
12
12
  from api_tabular.core.sentry import get_sentry_kwargs
13
13
  from api_tabular.core.swagger import build_swagger_file
14
14
  from api_tabular.core.url import build_link_with_page, url_for
15
- from api_tabular.core.utils import build_offset
15
+ from api_tabular.core.utils import parse_pagination
16
16
  from api_tabular.core.version import get_app_version
17
17
  from api_tabular.tabular.utils import (
18
18
  get_potential_indexes,
@@ -97,10 +97,7 @@ def build_next_page(
97
97
  async def resource_data(request):
98
98
  resource_id = request.match_info["rid"]
99
99
  query_string = request.query_string.split("&") if request.query_string else []
100
- page = int(request.query.get("page", "1"))
101
- page_size = int(request.query.get("page_size", config.PAGE_SIZE_DEFAULT))
102
-
103
- offset = build_offset(page, page_size)
100
+ page, page_size, offset = parse_pagination(request.query)
104
101
 
105
102
  sql_query = await try_build_query(request, query_string, resource_id, page_size, offset)
106
103
  resource = await get_resource(request.app["csession"], resource_id, ["parsing_table"])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: udata-hydra-csvapi
3
- Version: 0.4.3.dev2
3
+ Version: 0.4.3.dev3
4
4
  Summary: API for CSV converted by udata-hydra
5
5
  Author-email: "data.gouv.fr" <opendatateam@data.gouv.fr>
6
6
  License-Expression: MIT
@@ -365,8 +365,8 @@ column_name__sum
365
365
 
366
366
  #### Pagination
367
367
  ```
368
- page=1 # Page number (default: 1)
369
- page_size=20 # Items per page (default: 20, max: 50)
368
+ page=1 # Page number (default: 1, min: 1)
369
+ page_size=20 # Items per page (default: 20, min: 1, max: 50)
370
370
  ```
371
371
 
372
372
  #### Column Selection
@@ -5,19 +5,19 @@ api_tabular/core/cors.py,sha256=QY006pAnR1fMBMJJTAeRGcopL_4LkY7YoA3y8KYk4dI,825
5
5
  api_tabular/core/data.py,sha256=5j-3d_el7LMoHpn6V__UdhYHD6GiJbwdH67jrnOYWZQ,1459
6
6
  api_tabular/core/error.py,sha256=xRt6fkQfsiupv0tWWzdX0DJjAKbw1n0tRxFyt15VBLA,1062
7
7
  api_tabular/core/health.py,sha256=NeFT1C00onvm3CbgesFAcN1N8bmelbQdEYFbmmftICQ,647
8
- api_tabular/core/query.py,sha256=Twlv-xLYzZ0YGzCDiJ1uJAH2nZT9hEATNSSPiHVnRU8,10226
8
+ api_tabular/core/query.py,sha256=J7woFLDzA8RpMBXJKpKm8olDdZsp2_TQEROJtIaeokM,10238
9
9
  api_tabular/core/sentry.py,sha256=fN5MrDZszLnzLXF3b_nUymPVB0ffNn4PI7xS1GtJNyE,948
10
- api_tabular/core/swagger.py,sha256=eSCAu0TQsT2tlQiW7i-ueZB14qTd8TfHbUypZeeB-0w,14640
10
+ api_tabular/core/swagger.py,sha256=mMEESM4UlgK-voyRTKrddVuUrlUMfTDOQtK1VrVp7Ak,14748
11
11
  api_tabular/core/url.py,sha256=af7VKfrMtKMzlHrGgtLDLuRBim4qFv7xlt2PYxAyW2g,761
12
- api_tabular/core/utils.py,sha256=VTxPiNWE3FF6f2aX5Q21XPezCL3sVZ_KICIrGBJRm_E,1071
12
+ api_tabular/core/utils.py,sha256=Ghd9Un0HugFg4oEcEb5yB5FEop7tDSoX4OCzR8mcM-Y,1922
13
13
  api_tabular/core/version.py,sha256=OKLg0l1CpDRHV2hsqVgtSihoo3tg0aMG6kzMILtQ-bY,250
14
14
  api_tabular/metrics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- api_tabular/metrics/app.py,sha256=JY7GZSqCsihEcQy7SFTiKqvoyxfGRFaJ48CovNQTq4Y,4408
15
+ api_tabular/metrics/app.py,sha256=m2H4qOvzvi8oDjCg1R23JAK6VaqDcrqYCz6ScIk9iAc,4305
16
16
  api_tabular/tabular/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- api_tabular/tabular/app.py,sha256=tbf1Ni_r_bbeivxlMNllVKRoqpajZId6SiurCn1hTas,6645
17
+ api_tabular/tabular/app.py,sha256=fBnbIR2H3jm0suVVEfNuVdSccOwZeMKH__iekwmDVa8,6542
18
18
  api_tabular/tabular/utils.py,sha256=BL2nl04-3imBQG-RZiYvVMjxoBORi4lwrKq8NiWecLY,4487
19
- udata_hydra_csvapi-0.4.3.dev2.dist-info/licenses/LICENSE,sha256=fb-HAYw94ffh--z1cZrWbpk6YKM0p9WFG7kdd0K7uGQ,1062
20
- udata_hydra_csvapi-0.4.3.dev2.dist-info/METADATA,sha256=M20YFIrIz04duIJaLWGY05yNw7MDXO7kUmfSHTcdYVE,21819
21
- udata_hydra_csvapi-0.4.3.dev2.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
22
- udata_hydra_csvapi-0.4.3.dev2.dist-info/top_level.txt,sha256=MAaK09hxwPhIBBC0i1TdEBAgdu3W_gXnAZqk767gVak,12
23
- udata_hydra_csvapi-0.4.3.dev2.dist-info/RECORD,,
19
+ udata_hydra_csvapi-0.4.3.dev3.dist-info/licenses/LICENSE,sha256=fb-HAYw94ffh--z1cZrWbpk6YKM0p9WFG7kdd0K7uGQ,1062
20
+ udata_hydra_csvapi-0.4.3.dev3.dist-info/METADATA,sha256=mBjWOUsIDJAxQWABC7L49YdknGyNsX2tKDG3Sh7spTk,21835
21
+ udata_hydra_csvapi-0.4.3.dev3.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
22
+ udata_hydra_csvapi-0.4.3.dev3.dist-info/top_level.txt,sha256=MAaK09hxwPhIBBC0i1TdEBAgdu3W_gXnAZqk767gVak,12
23
+ udata_hydra_csvapi-0.4.3.dev3.dist-info/RECORD,,