mirror of
https://github.com/ae-utbm/sith.git
synced 2025-02-22 07:27:12 +00:00
Use requests for external requests
L'API de requests est beaucoup plus claire que celle d'urllib et urllib3.
This commit is contained in:
parent
3df33261ce
commit
85c8b7d11c
@ -2,7 +2,7 @@ from datetime import datetime, timedelta
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import final
|
from typing import final
|
||||||
|
|
||||||
import urllib3
|
import requests
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -35,16 +35,15 @@ class IcsCalendar:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_external(cls) -> Path | None:
|
def make_external(cls) -> Path | None:
|
||||||
calendar = urllib3.request(
|
calendar = requests.get(
|
||||||
"GET",
|
"https://calendar.google.com/calendar/ical/ae.utbm%40gmail.com/public/basic.ics"
|
||||||
"https://calendar.google.com/calendar/ical/ae.utbm%40gmail.com/public/basic.ics",
|
|
||||||
)
|
)
|
||||||
if calendar.status != 200:
|
if not calendar.ok:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
cls._CACHE_FOLDER.mkdir(parents=True, exist_ok=True)
|
cls._CACHE_FOLDER.mkdir(parents=True, exist_ok=True)
|
||||||
with open(cls._EXTERNAL_CALENDAR, "wb") as f:
|
with open(cls._EXTERNAL_CALENDAR, "wb") as f:
|
||||||
_ = f.write(calendar.data)
|
_ = f.write(calendar.content)
|
||||||
return cls._EXTERNAL_CALENDAR
|
return cls._EXTERNAL_CALENDAR
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -16,11 +16,11 @@ from com.calendar import IcsCalendar
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MockResponse:
|
class MockResponse:
|
||||||
status: int
|
ok: bool
|
||||||
value: str
|
value: str
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data(self):
|
def content(self):
|
||||||
return self.value.encode("utf8")
|
return self.value.encode("utf8")
|
||||||
|
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ class TestExternalCalendar:
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_request(self):
|
def mock_request(self):
|
||||||
mock = MagicMock()
|
mock = MagicMock()
|
||||||
with patch("urllib3.request", mock):
|
with patch("requests.get", mock):
|
||||||
yield mock
|
yield mock
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -52,15 +52,12 @@ class TestExternalCalendar:
|
|||||||
def clear_cache(self):
|
def clear_cache(self):
|
||||||
IcsCalendar._EXTERNAL_CALENDAR.unlink(missing_ok=True)
|
IcsCalendar._EXTERNAL_CALENDAR.unlink(missing_ok=True)
|
||||||
|
|
||||||
@pytest.mark.parametrize("error_code", [403, 404, 500])
|
def test_fetch_error(self, client: Client, mock_request: MagicMock):
|
||||||
def test_fetch_error(
|
mock_request.return_value = MockResponse(ok=False, value="not allowed")
|
||||||
self, client: Client, mock_request: MagicMock, error_code: int
|
|
||||||
):
|
|
||||||
mock_request.return_value = MockResponse(error_code, "not allowed")
|
|
||||||
assert client.get(reverse("api:calendar_external")).status_code == 404
|
assert client.get(reverse("api:calendar_external")).status_code == 404
|
||||||
|
|
||||||
def test_fetch_success(self, client: Client, mock_request: MagicMock):
|
def test_fetch_success(self, client: Client, mock_request: MagicMock):
|
||||||
external_response = MockResponse(200, "Definitely an ICS")
|
external_response = MockResponse(ok=True, value="Definitely an ICS")
|
||||||
mock_request.return_value = external_response
|
mock_request.return_value = external_response
|
||||||
response = client.get(reverse("api:calendar_external"))
|
response = client.get(reverse("api:calendar_external"))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
"""Set of functions to interact with the UTBM UV api."""
|
"""Set of functions to interact with the UTBM UV api."""
|
||||||
|
|
||||||
import urllib
|
import requests
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from pedagogy.schemas import ShortUvList, UtbmFullUvSchema, UtbmShortUvSchema, UvSchema
|
from pedagogy.schemas import ShortUvList, UtbmFullUvSchema, UtbmShortUvSchema, UvSchema
|
||||||
@ -12,8 +11,8 @@ def find_uv(lang, year, code) -> UvSchema | None:
|
|||||||
# query the UV list
|
# query the UV list
|
||||||
base_url = settings.SITH_PEDAGOGY_UTBM_API
|
base_url = settings.SITH_PEDAGOGY_UTBM_API
|
||||||
uvs_url = f"{base_url}/uvs/{lang}/{year}"
|
uvs_url = f"{base_url}/uvs/{lang}/{year}"
|
||||||
response = urllib.request.urlopen(uvs_url)
|
response = requests.get(uvs_url)
|
||||||
uvs: list[UtbmShortUvSchema] = ShortUvList.validate_json(response.read())
|
uvs: list[UtbmShortUvSchema] = ShortUvList.validate_json(response.content)
|
||||||
|
|
||||||
short_uv = next((uv for uv in uvs if uv.code == code), None)
|
short_uv = next((uv for uv in uvs if uv.code == code), None)
|
||||||
if short_uv is None:
|
if short_uv is None:
|
||||||
@ -21,12 +20,12 @@ def find_uv(lang, year, code) -> UvSchema | None:
|
|||||||
|
|
||||||
# get detailed information about the UV
|
# get detailed information about the UV
|
||||||
uv_url = f"{base_url}/uv/{lang}/{year}/{code}/{short_uv.code_formation}"
|
uv_url = f"{base_url}/uv/{lang}/{year}/{code}/{short_uv.code_formation}"
|
||||||
response = urllib.request.urlopen(uv_url)
|
response = requests.get(uv_url)
|
||||||
full_uv = UtbmFullUvSchema.model_validate_json(response.read())
|
full_uv = UtbmFullUvSchema.model_validate_json(response.content)
|
||||||
return _make_clean_uv(short_uv, full_uv)
|
return make_clean_uv(short_uv, full_uv)
|
||||||
|
|
||||||
|
|
||||||
def _make_clean_uv(short_uv: UtbmShortUvSchema, full_uv: UtbmFullUvSchema) -> UvSchema:
|
def make_clean_uv(short_uv: UtbmShortUvSchema, full_uv: UtbmFullUvSchema) -> UvSchema:
|
||||||
"""Cleans the data up so that it corresponds to our data representation.
|
"""Cleans the data up so that it corresponds to our data representation.
|
||||||
|
|
||||||
Some of the needed information are in the short uv schema, some
|
Some of the needed information are in the short uv schema, some
|
||||||
|
@ -44,6 +44,7 @@ dependencies = [
|
|||||||
"django-honeypot<2.0.0,>=1.2.1",
|
"django-honeypot<2.0.0,>=1.2.1",
|
||||||
"pydantic-extra-types<3.0.0,>=2.10.1",
|
"pydantic-extra-types<3.0.0,>=2.10.1",
|
||||||
"ical<9.0.0,>=8.3.0",
|
"ical<9.0.0,>=8.3.0",
|
||||||
|
"requests>=2.32.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
6
uv.lock
generated
6
uv.lock
generated
@ -155,7 +155,7 @@ name = "click"
|
|||||||
version = "8.1.8"
|
version = "8.1.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
|
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
|
||||||
wheels = [
|
wheels = [
|
||||||
@ -744,7 +744,7 @@ version = "1.6.1"
|
|||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "click" },
|
{ name = "click" },
|
||||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
||||||
{ name = "ghp-import" },
|
{ name = "ghp-import" },
|
||||||
{ name = "jinja2" },
|
{ name = "jinja2" },
|
||||||
{ name = "markdown" },
|
{ name = "markdown" },
|
||||||
@ -1437,6 +1437,7 @@ dependencies = [
|
|||||||
{ name = "pydantic-extra-types" },
|
{ name = "pydantic-extra-types" },
|
||||||
{ name = "python-dateutil" },
|
{ name = "python-dateutil" },
|
||||||
{ name = "reportlab" },
|
{ name = "reportlab" },
|
||||||
|
{ name = "requests" },
|
||||||
{ name = "sentry-sdk" },
|
{ name = "sentry-sdk" },
|
||||||
{ name = "sphinx" },
|
{ name = "sphinx" },
|
||||||
{ name = "tomli" },
|
{ name = "tomli" },
|
||||||
@ -1495,6 +1496,7 @@ requires-dist = [
|
|||||||
{ name = "pydantic-extra-types", specifier = ">=2.10.1,<3.0.0" },
|
{ name = "pydantic-extra-types", specifier = ">=2.10.1,<3.0.0" },
|
||||||
{ name = "python-dateutil", specifier = ">=2.9.0.post0,<3.0.0.0" },
|
{ name = "python-dateutil", specifier = ">=2.9.0.post0,<3.0.0.0" },
|
||||||
{ name = "reportlab", specifier = ">=4.2.5,<5.0.0" },
|
{ name = "reportlab", specifier = ">=4.2.5,<5.0.0" },
|
||||||
|
{ name = "requests", specifier = ">=2.32.3" },
|
||||||
{ name = "sentry-sdk", specifier = ">=2.19.2,<3.0.0" },
|
{ name = "sentry-sdk", specifier = ">=2.19.2,<3.0.0" },
|
||||||
{ name = "sphinx", specifier = ">=5,<6" },
|
{ name = "sphinx", specifier = ">=5,<6" },
|
||||||
{ name = "tomli", specifier = ">=2.2.1,<3.0.0" },
|
{ name = "tomli", specifier = ">=2.2.1,<3.0.0" },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user