udata-hydra 2.0.0.dev2730__tar.gz → 2.0.0.dev2867__tar.gz

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.
Files changed (54) hide show
  1. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/PKG-INFO +1 -1
  2. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/pyproject.toml +12 -12
  3. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/analysis/csv.py +1 -1
  4. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/app.py +3 -6
  5. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/config_default.toml +7 -5
  6. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/routes/resources.py +0 -1
  7. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/__init__.py +1 -0
  8. udata_hydra-2.0.0.dev2867/udata_hydra/utils/auth.py +72 -0
  9. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/README.md +0 -0
  10. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/__init__.py +0 -0
  11. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/analysis/__init__.py +0 -0
  12. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/analysis/errors.py +0 -0
  13. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/analysis/helpers.py +0 -0
  14. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/analysis/resource.py +0 -0
  15. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/cli.py +0 -0
  16. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/context.py +0 -0
  17. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/crawl.py +0 -0
  18. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/db/__init__.py +0 -0
  19. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/db/check.py +0 -0
  20. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/db/resource.py +0 -0
  21. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/logger.py +0 -0
  22. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/__init__.py +0 -0
  23. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/csv/20221205_initial_up_rev1.sql +0 -0
  24. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/csv/20230130_drop_migrations.sql +0 -0
  25. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/csv/20230206_datetime_aware.sql +0 -0
  26. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20221205_initial_up_rev1.sql +0 -0
  27. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20221206_rev1_up_rev2.sql +0 -0
  28. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20221206_rev2_up_rev3.sql +0 -0
  29. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20221208_rev3_up_rev4.sql +0 -0
  30. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20221208_rev4_up_rev5.sql +0 -0
  31. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20230119_rev5_up_rev6.sql +0 -0
  32. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20230121_rev6_up_rev7.sql +0 -0
  33. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20230121_rev7_up_rev8.sql +0 -0
  34. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20230130_drop_migrations.sql +0 -0
  35. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20230206_datetime_aware.sql +0 -0
  36. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20230515_rev8_up_rev9.sql +0 -0
  37. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20230606_rev9_up_rev10.sql +0 -0
  38. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/migrations/main/20231102_drop_csv_analysis.sql +0 -0
  39. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/routes/__init__.py +0 -0
  40. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/routes/checks.py +0 -0
  41. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/routes/status.py +0 -0
  42. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/schemas/__init__.py +0 -0
  43. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/schemas/check.py +0 -0
  44. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/schemas/resource.py +0 -0
  45. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/app_version.py +0 -0
  46. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/csv.py +0 -0
  47. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/file.py +0 -0
  48. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/http.py +0 -0
  49. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/minio.py +0 -0
  50. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/parquet.py +0 -0
  51. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/queue.py +0 -0
  52. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/reader.py +0 -0
  53. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/utils/timer.py +0 -0
  54. {udata_hydra-2.0.0.dev2730 → udata_hydra-2.0.0.dev2867}/udata_hydra/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: udata-hydra
3
- Version: 2.0.0.dev2730
3
+ Version: 2.0.0.dev2867
4
4
  Summary: Async crawler and parsing service for data.gouv.fr
5
5
  License: MIT
6
6
  Author: Opendata Team
@@ -9,7 +9,7 @@ readme = "README.md"
9
9
 
10
10
  [tool.poetry]
11
11
  name = "udata-hydra"
12
- version = "2.0.0.dev2730"
12
+ version = "2.0.0.dev2867"
13
13
  description = "Async crawler and parsing service for data.gouv.fr"
14
14
  authors = ["Opendata Team <opendatateam@data.gouv.fr>"]
15
15
  license = "MIT"
@@ -17,27 +17,27 @@ readme = "README.md"
17
17
 
18
18
  [tool.poetry.dependencies]
19
19
  python = "^3.9"
20
+ aiocontextvars = "^0.2.2"
20
21
  aiohttp = "^3.10.3"
21
22
  asyncpg = "^0.29.0"
23
+ coloredlogs = "^15.0.1"
24
+ csv-detective = "0.7.2.dev800"
25
+ dateparser = "^1.1.7"
22
26
  humanfriendly = "^10.0"
23
27
  marshmallow = "^3.14.1"
24
28
  minicli = "^0.5.3"
25
- progressist = "^0.1.0"
29
+ minio = "7.2.7"
30
+ pyarrow = "16.1.0"
31
+ python-dateutil = "^2.8.2"
26
32
  python-magic = "^0.4.25"
33
+ progressist = "^0.1.0"
27
34
  redis = "^4.1.4"
28
- sentry-sdk = "^2.10.0"
29
- aiocontextvars = "^0.2.2"
30
- coloredlogs = "^15.0.1"
31
35
  rq = "^1.11.1"
32
- toml = "^0.10.2"
36
+ sentry-sdk = "^2.10.0"
37
+ sqlalchemy = "^1.4.46"
33
38
  str2float = "^0.0.9"
34
39
  str2bool = "^1.1"
35
- sqlalchemy = "^1.4.46"
36
- dateparser = "^1.1.7"
37
- python-dateutil = "^2.8.2"
38
- csv-detective = "0.7.2.dev800"
39
- pyarrow = "16.1.0"
40
- minio = "7.2.7"
40
+ toml = "^0.10.2"
41
41
 
42
42
  [tool.poetry.group.dev.dependencies]
43
43
  aiohttp-devtools = "^1.0.post0"
@@ -74,7 +74,7 @@ RESERVED_COLS = ("__id", "tableoid", "xmin", "cmin", "xmax", "cmax", "ctid")
74
74
  minio_client = MinIOClient()
75
75
 
76
76
 
77
- async def notify_udata(check_id: str, table_name: str) -> None:
77
+ async def notify_udata(check_id: int, table_name: str) -> None:
78
78
  """Notify udata of the result of a parsing"""
79
79
  check = await Check.get(check_id)
80
80
  resource_id = check["resource_id"]
@@ -4,6 +4,7 @@ from aiohttp import web
4
4
 
5
5
  from udata_hydra import context
6
6
  from udata_hydra.routes import routes
7
+ from udata_hydra.utils import token_auth_middleware
7
8
 
8
9
 
9
10
  async def app_factory() -> web.Application:
@@ -14,16 +15,12 @@ async def app_factory() -> web.Application:
14
15
  if "pool" in app:
15
16
  await app["pool"].close()
16
17
 
17
- app = web.Application()
18
+ app = web.Application(middlewares=[token_auth_middleware(exclude_methods=("GET",))])
18
19
  app.add_routes(routes)
19
20
  app.on_startup.append(app_startup)
20
21
  app.on_cleanup.append(app_cleanup)
21
22
  return app
22
23
 
23
24
 
24
- def run():
25
- web.run_app(app_factory(), path=os.environ.get("HYDRA_APP_SOCKET_PATH"))
26
-
27
-
28
25
  if __name__ == "__main__":
29
- run()
26
+ web.run_app(app_factory(), path=os.environ.get("HYDRA_APP_SOCKET_PATH"))
@@ -12,6 +12,8 @@ TESTING = false
12
12
  MAX_POOL_SIZE = 50
13
13
  USER_AGENT = "udata-hydra/1.0"
14
14
 
15
+ API_TOKEN = "to-change"
16
+
15
17
  # -- crawler settings -- #
16
18
 
17
19
  CATALOG_URL = "https://www.data.gouv.fr/fr/datasets/r/4babf5f2-6a9c-45b5-9144-ca5eae6a7a6d"
@@ -30,8 +32,8 @@ NO_BACKOFF_DOMAINS = [
30
32
  ]
31
33
  # max number of _completed_ requests per domain per period
32
34
  BACKOFF_NB_REQ = 180
33
- BACKOFF_PERIOD = 360 # in seconds
34
- COOL_OFF_PERIOD = 86400 # 1 day to cool off when we've messed up
35
+ BACKOFF_PERIOD = 360 # in seconds
36
+ COOL_OFF_PERIOD = 86400 # 1 day to cool off when we've messed up
35
37
  # ids of the resources that are too large to be processed normally
36
38
  # but that we want to have anyway
37
39
  LARGE_RESOURCES_EXCEPTIONS = [
@@ -50,9 +52,9 @@ SLEEP_BETWEEN_BATCHES = 60
50
52
  # max download filesize in bytes (100 MB)
51
53
  MAX_FILESIZE_ALLOWED.csv = 104857600
52
54
  MAX_FILESIZE_ALLOWED.csvgz = 104857600
53
- MAX_FILESIZE_ALLOWED.xls = 52428800 # /2
54
- MAX_FILESIZE_ALLOWED.xlsx = 13107200 # /8
55
- MAX_FILESIZE_ALLOWED.ods = 10485760 # /10
55
+ MAX_FILESIZE_ALLOWED.xls = 52428800 # /2
56
+ MAX_FILESIZE_ALLOWED.xlsx = 13107200 # /8
57
+ MAX_FILESIZE_ALLOWED.ods = 10485760 # /10
56
58
 
57
59
 
58
60
  CSV_ANALYSIS = true
@@ -3,7 +3,6 @@ import json
3
3
  from aiohttp import web
4
4
  from marshmallow import ValidationError
5
5
 
6
- from udata_hydra import config
7
6
  from udata_hydra.db.resource import Resource
8
7
  from udata_hydra.schemas import ResourceSchema
9
8
  from udata_hydra.utils import get_request_params
@@ -1,4 +1,5 @@
1
1
  from .app_version import get_app_version
2
+ from .auth import token_auth_middleware
2
3
  from .csv import detect_tabular_from_headers
3
4
  from .file import compute_checksum_from_file, download_resource, read_csv_gz
4
5
  from .http import get_request_params, send
@@ -0,0 +1,72 @@
1
+ import re
2
+ from typing import Coroutine, Tuple
3
+
4
+ from aiohttp import web
5
+
6
+ from udata_hydra import config
7
+
8
+
9
+ def _is_exclude(request, exclude: Tuple[str]) -> bool:
10
+ for pattern in exclude:
11
+ if re.fullmatch(pattern, request.path):
12
+ return True
13
+ return False
14
+
15
+
16
+ def token_auth_middleware(
17
+ request_property: str = "user",
18
+ auth_scheme: str = "Bearer",
19
+ exclude_routes: Tuple[str] = tuple(),
20
+ exclude_methods: Tuple[str] = tuple(),
21
+ ) -> Coroutine:
22
+ """Checks a auth token and adds a user in request.
23
+
24
+ Token auth middleware that checks the "Authorization" http header for token and, if the token in the requet headers is valid, then middleware adds the user to request with key that contain the "request_property" variable, else it will raise an HTTPForbiddenexception.
25
+
26
+ Args:
27
+ request_property (str, optional): Key for save in request object.
28
+ Defaults to 'user'.
29
+ auth_scheme (str, optional): Prefix for value in "Authorization" header.
30
+ Defaults to 'Bearer'.
31
+ exclude_routes: (Tuple, optional): Tuple of pathes that will be excluded.
32
+ Defaults to empty tuple.
33
+ exclude_methods(Tuple, optional): Tuple of http methods that will be
34
+ excluded. Defaults to empty tuple.
35
+
36
+ Raises:
37
+ web.HTTPUnauthorized: If "Authorization" token is missing.
38
+ web.HTTPForbidden: Wrong token, schema or header.
39
+
40
+ Returns:
41
+ Coroutine: Aiohttp middleware.
42
+ """
43
+
44
+ @web.middleware
45
+ async def middleware(request, handler):
46
+ if _is_exclude(request, exclude_routes) or request.method in exclude_methods:
47
+ return await handler(request)
48
+
49
+ try:
50
+ scheme, token = request.headers["Authorization"].strip().split(" ")
51
+ except KeyError:
52
+ raise web.HTTPUnauthorized(
53
+ reason="Missing authorization header",
54
+ )
55
+ except ValueError:
56
+ raise web.HTTPForbidden(
57
+ reason="Invalid authorization header",
58
+ )
59
+
60
+ if auth_scheme.lower() != scheme.lower():
61
+ raise web.HTTPForbidden(
62
+ reason="Invalid token scheme",
63
+ )
64
+
65
+ if token == config.API_TOKEN:
66
+ request[request_property] = {"username": "admin"}
67
+ else:
68
+ raise web.HTTPForbidden(reason="Invalid authentication token")
69
+
70
+ return await handler(request)
71
+
72
+ return middleware