42api 0.1.1__tar.gz → 0.1.2__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.
- {42api-0.1.1 → 42api-0.1.2}/.gitignore +4 -1
- {42api-0.1.1 → 42api-0.1.2}/PKG-INFO +9 -7
- {42api-0.1.1 → 42api-0.1.2}/README.md +8 -6
- {42api-0.1.1 → 42api-0.1.2}/pyproject.toml +1 -1
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/__init__.py +10 -2
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/client.py +8 -0
- 42api-0.1.2/src/intra42/_async/resources/accreditations.py +16 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/cursus.py +4 -0
- 42api-0.1.2/src/intra42/_async/resources/exams.py +23 -0
- 42api-0.1.2/src/intra42/_async/resources/projects.py +19 -0
- 42api-0.1.2/src/intra42/_async/resources/projects_users.py +22 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/users.py +4 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/client.py +8 -0
- 42api-0.1.2/src/intra42/_sync/resources/accreditations.py +22 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/cursus.py +4 -0
- 42api-0.1.2/src/intra42/_sync/resources/exams.py +27 -0
- 42api-0.1.2/src/intra42/_sync/resources/projects.py +25 -0
- 42api-0.1.2/src/intra42/_sync/resources/projects_users.py +26 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/users.py +4 -0
- 42api-0.1.2/src/intra42/models/accreditation.py +29 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/cursus.py +6 -0
- 42api-0.1.2/src/intra42/models/exam.py +32 -0
- 42api-0.1.2/src/intra42/models/project.py +106 -0
- 42api-0.1.2/src/intra42/models/project_user.py +74 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/user.py +6 -0
- 42api-0.1.2/tests/integration/resources/test_resources_accreditations.py +78 -0
- 42api-0.1.2/tests/integration/resources/test_resources_exams.py +159 -0
- 42api-0.1.2/tests/integration/resources/test_resources_projects.py +193 -0
- 42api-0.1.2/tests/integration/resources/test_resources_projects_users.py +176 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/test_pagination_walk.py +3 -3
- {42api-0.1.1 → 42api-0.1.2}/tests/unit/test_public_api.py +8 -0
- {42api-0.1.1 → 42api-0.1.2}/uv.lock +1 -1
- {42api-0.1.1 → 42api-0.1.2}/.github/workflows/ci.yml +0 -0
- {42api-0.1.1 → 42api-0.1.2}/.github/workflows/publish.yml +0 -0
- {42api-0.1.1 → 42api-0.1.2}/.pre-commit-config.yaml +0 -0
- {42api-0.1.1 → 42api-0.1.2}/LICENSE +0 -0
- {42api-0.1.1 → 42api-0.1.2}/scripts/unasync_generate.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/__init__.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/query.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/__init__.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/base.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/campus_users.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/campuses.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/events.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_async/resources/locations.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_auth.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_config.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_pagination.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_query_params.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_rate_limit.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/__init__.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/query.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/__init__.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/base.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/campus_users.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/campuses.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/events.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/_sync/resources/locations.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/exceptions.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/__init__.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/base.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/campus.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/campus_user.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/event.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/models/location.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/src/intra42/py.typed +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/conftest.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/resources/test_resources_campus_users.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/resources/test_resources_campuses.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/resources/test_resources_cursus.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/resources/test_resources_events.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/resources/test_resources_locations.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/test_client_integration.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/integration/test_nested_access.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/unit/test_auth.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/unit/test_models_campus.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/unit/test_models_user.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/unit/test_pagination.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/unit/test_query_builder.py +0 -0
- {42api-0.1.1 → 42api-0.1.2}/tests/unit/test_rate_limit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: 42api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Object-oriented Python client for the 42 School API (api.intra.42.fr)
|
|
5
5
|
Project-URL: Homepage, https://github.com/Shadowaker/42api
|
|
6
6
|
Author-email: Dan <danyridolfo98@gmail.com>
|
|
@@ -55,7 +55,7 @@ with Client(client_id="...", client_secret="...") as client:
|
|
|
55
55
|
user = client.users.get("jdoe")
|
|
56
56
|
print(user.login, user.email)
|
|
57
57
|
|
|
58
|
-
for user in client.users.filter(
|
|
58
|
+
for user in client.users.filter(primary_campus_id=1).sort("-pool_year"):
|
|
59
59
|
print(user.login)
|
|
60
60
|
```
|
|
61
61
|
|
|
@@ -69,7 +69,7 @@ from intra42 import AsyncClient
|
|
|
69
69
|
async def main() -> None:
|
|
70
70
|
async with AsyncClient(client_id="...", client_secret="...") as client:
|
|
71
71
|
user = await client.users.get("jdoe")
|
|
72
|
-
async for user in client.users.filter(
|
|
72
|
+
async for user in client.users.filter(primary_campus_id=1).sort("-pool_year"):
|
|
73
73
|
print(user.login)
|
|
74
74
|
|
|
75
75
|
|
|
@@ -108,10 +108,12 @@ and `NetworkError` (connection/timeout failures).
|
|
|
108
108
|
|
|
109
109
|
## Status
|
|
110
110
|
|
|
111
|
-
Early-stage: currently covers `users`, `
|
|
112
|
-
`cursus`, `events`,
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
Early-stage: currently covers `users`, `accreditations`, `campuses`,
|
|
112
|
+
`campus_users`, `cursus`, `events`, `exams`, `locations`, `projects`, and
|
|
113
|
+
`projects_users` (`exams`, `locations`, and `projects_users` each include
|
|
114
|
+
their `graph` analytics endpoint). More resources are added incrementally
|
|
115
|
+
on top of the same client/model/query-builder pattern.
|
|
116
|
+
The api with restricted access are not implemented currently.
|
|
115
117
|
|
|
116
118
|
## Development
|
|
117
119
|
|
|
@@ -29,7 +29,7 @@ with Client(client_id="...", client_secret="...") as client:
|
|
|
29
29
|
user = client.users.get("jdoe")
|
|
30
30
|
print(user.login, user.email)
|
|
31
31
|
|
|
32
|
-
for user in client.users.filter(
|
|
32
|
+
for user in client.users.filter(primary_campus_id=1).sort("-pool_year"):
|
|
33
33
|
print(user.login)
|
|
34
34
|
```
|
|
35
35
|
|
|
@@ -43,7 +43,7 @@ from intra42 import AsyncClient
|
|
|
43
43
|
async def main() -> None:
|
|
44
44
|
async with AsyncClient(client_id="...", client_secret="...") as client:
|
|
45
45
|
user = await client.users.get("jdoe")
|
|
46
|
-
async for user in client.users.filter(
|
|
46
|
+
async for user in client.users.filter(primary_campus_id=1).sort("-pool_year"):
|
|
47
47
|
print(user.login)
|
|
48
48
|
|
|
49
49
|
|
|
@@ -82,10 +82,12 @@ and `NetworkError` (connection/timeout failures).
|
|
|
82
82
|
|
|
83
83
|
## Status
|
|
84
84
|
|
|
85
|
-
Early-stage: currently covers `users`, `
|
|
86
|
-
`cursus`, `events`,
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
Early-stage: currently covers `users`, `accreditations`, `campuses`,
|
|
86
|
+
`campus_users`, `cursus`, `events`, `exams`, `locations`, `projects`, and
|
|
87
|
+
`projects_users` (`exams`, `locations`, and `projects_users` each include
|
|
88
|
+
their `graph` analytics endpoint). More resources are added incrementally
|
|
89
|
+
on top of the same client/model/query-builder pattern.
|
|
90
|
+
The api with restricted access are not implemented currently.
|
|
89
91
|
|
|
90
92
|
## Development
|
|
91
93
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
with Client(client_id, client_secret) as client:
|
|
6
6
|
user = client.users.get("jdoe")
|
|
7
|
-
for user in client.users.filter(
|
|
7
|
+
for user in client.users.filter(primary_campus_id=1).sort("-pool_year"):
|
|
8
8
|
...
|
|
9
9
|
|
|
10
10
|
An async client with the same interface is available as ``AsyncClient``.
|
|
@@ -25,11 +25,15 @@ from .exceptions import (
|
|
|
25
25
|
ServerError,
|
|
26
26
|
ValidationError,
|
|
27
27
|
)
|
|
28
|
+
from .models.accreditation import Accreditation
|
|
28
29
|
from .models.campus import Campus
|
|
29
30
|
from .models.campus_user import CampusUser
|
|
30
31
|
from .models.cursus import Cursus
|
|
31
32
|
from .models.event import Event
|
|
33
|
+
from .models.exam import Exam
|
|
32
34
|
from .models.location import Location
|
|
35
|
+
from .models.project import Project
|
|
36
|
+
from .models.project_user import ProjectUser
|
|
33
37
|
from .models.user import User
|
|
34
38
|
|
|
35
39
|
__all__ = [
|
|
@@ -37,11 +41,15 @@ __all__ = [
|
|
|
37
41
|
"Client",
|
|
38
42
|
"ClientConfig",
|
|
39
43
|
"User",
|
|
44
|
+
"Accreditation",
|
|
40
45
|
"Campus",
|
|
41
46
|
"CampusUser",
|
|
42
47
|
"Cursus",
|
|
43
48
|
"Event",
|
|
49
|
+
"Exam",
|
|
44
50
|
"Location",
|
|
51
|
+
"Project",
|
|
52
|
+
"ProjectUser",
|
|
45
53
|
"FortyTwoAPIError",
|
|
46
54
|
"AuthenticationError",
|
|
47
55
|
"PermissionDeniedError",
|
|
@@ -52,4 +60,4 @@ __all__ = [
|
|
|
52
60
|
"NetworkError",
|
|
53
61
|
]
|
|
54
62
|
|
|
55
|
-
__version__ = "0.1.
|
|
63
|
+
__version__ = "0.1.2"
|
|
@@ -12,11 +12,15 @@ from .._auth import TokenManager
|
|
|
12
12
|
from .._config import DEFAULT_BASE_URL, ClientConfig
|
|
13
13
|
from .._rate_limit import RateLimiter
|
|
14
14
|
from ..exceptions import NetworkError, raise_for_status
|
|
15
|
+
from .resources.accreditations import AsyncAccreditationsResource
|
|
15
16
|
from .resources.campus_users import AsyncCampusUsersResource
|
|
16
17
|
from .resources.campuses import AsyncCampusesResource
|
|
17
18
|
from .resources.cursus import AsyncCursusResource
|
|
18
19
|
from .resources.events import AsyncEventsResource
|
|
20
|
+
from .resources.exams import AsyncExamsResource
|
|
19
21
|
from .resources.locations import AsyncLocationsResource
|
|
22
|
+
from .resources.projects import AsyncProjectsResource
|
|
23
|
+
from .resources.projects_users import AsyncProjectUsersResource
|
|
20
24
|
from .resources.users import AsyncUsersResource
|
|
21
25
|
|
|
22
26
|
|
|
@@ -58,11 +62,15 @@ class AsyncClient:
|
|
|
58
62
|
)
|
|
59
63
|
|
|
60
64
|
self.users = AsyncUsersResource(self)
|
|
65
|
+
self.accreditations = AsyncAccreditationsResource(self)
|
|
61
66
|
self.campuses = AsyncCampusesResource(self)
|
|
62
67
|
self.campus_users = AsyncCampusUsersResource(self)
|
|
63
68
|
self.cursus = AsyncCursusResource(self)
|
|
64
69
|
self.events = AsyncEventsResource(self)
|
|
70
|
+
self.exams = AsyncExamsResource(self)
|
|
65
71
|
self.locations = AsyncLocationsResource(self)
|
|
72
|
+
self.projects = AsyncProjectsResource(self)
|
|
73
|
+
self.projects_users = AsyncProjectUsersResource(self)
|
|
66
74
|
|
|
67
75
|
@property
|
|
68
76
|
def base_url(self) -> str:
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ...models.accreditation import Accreditation
|
|
4
|
+
from .base import AsyncResource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AsyncAccreditationsResource(AsyncResource[Accreditation]):
|
|
8
|
+
path = "/accreditations"
|
|
9
|
+
model = Accreditation
|
|
10
|
+
|
|
11
|
+
def _bind_relations(self, instance: Accreditation) -> None:
|
|
12
|
+
# Referenced in the users apidoc page: GET /accreditations/:id/users.
|
|
13
|
+
instance._bind_relation(
|
|
14
|
+
"users",
|
|
15
|
+
lambda: self._client.users._queryset(f"/accreditations/{instance.id}/users"),
|
|
16
|
+
)
|
|
@@ -17,3 +17,7 @@ class AsyncCursusResource(AsyncResource[Cursus]):
|
|
|
17
17
|
"events",
|
|
18
18
|
lambda: self._client.events._queryset(f"/cursus/{instance.id}/events"),
|
|
19
19
|
)
|
|
20
|
+
instance._bind_relation(
|
|
21
|
+
"projects",
|
|
22
|
+
lambda: self._client.projects._queryset(f"/cursus/{instance.id}/projects"),
|
|
23
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ...models.exam import Exam
|
|
4
|
+
from .base import AsyncResource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AsyncExamsResource(AsyncResource[Exam]):
|
|
8
|
+
path = "/exams"
|
|
9
|
+
model = Exam
|
|
10
|
+
|
|
11
|
+
async def graph(
|
|
12
|
+
self, *, field: str | None = None, interval: str | None = None
|
|
13
|
+
) -> dict[str, int]:
|
|
14
|
+
"""Grouped temporal counts (``GET /exams/graph...``)."""
|
|
15
|
+
path = "/exams/graph"
|
|
16
|
+
if interval is not None and field is None:
|
|
17
|
+
field = "created_at"
|
|
18
|
+
if field is not None:
|
|
19
|
+
path += f"/on/{field}"
|
|
20
|
+
if interval is not None:
|
|
21
|
+
path += f"/by/{interval}"
|
|
22
|
+
response = await self._client.request("GET", path)
|
|
23
|
+
return response.json()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ...models.project import Project
|
|
4
|
+
from .base import AsyncResource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AsyncProjectsResource(AsyncResource[Project]):
|
|
8
|
+
path = "/projects"
|
|
9
|
+
model = Project
|
|
10
|
+
|
|
11
|
+
def _bind_relations(self, instance: Project) -> None:
|
|
12
|
+
# Referenced in the projects_users apidoc page:
|
|
13
|
+
# GET /projects/:id/projects_users.
|
|
14
|
+
instance._bind_relation(
|
|
15
|
+
"projects_users",
|
|
16
|
+
lambda: self._client.projects_users._queryset(
|
|
17
|
+
f"/projects/{instance.id}/projects_users"
|
|
18
|
+
),
|
|
19
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ...models.project_user import ProjectUser
|
|
4
|
+
from .base import AsyncResource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AsyncProjectUsersResource(AsyncResource[ProjectUser]):
|
|
8
|
+
path = "/projects_users"
|
|
9
|
+
model = ProjectUser
|
|
10
|
+
|
|
11
|
+
async def graph(
|
|
12
|
+
self, *, field: str | None = None, interval: str | None = None
|
|
13
|
+
) -> dict[str, int]:
|
|
14
|
+
path = "/projects_users/graph"
|
|
15
|
+
if interval is not None and field is None:
|
|
16
|
+
field = "created_at"
|
|
17
|
+
if field is not None:
|
|
18
|
+
path += f"/on/{field}"
|
|
19
|
+
if interval is not None:
|
|
20
|
+
path += f"/by/{interval}"
|
|
21
|
+
response = await self._client.request("GET", path)
|
|
22
|
+
return response.json()
|
|
@@ -21,3 +21,7 @@ class AsyncUsersResource(AsyncResource[User]):
|
|
|
21
21
|
"locations",
|
|
22
22
|
lambda: self._client.locations._queryset(f"/users/{instance.id}/locations"),
|
|
23
23
|
)
|
|
24
|
+
instance._bind_relation(
|
|
25
|
+
"projects_users",
|
|
26
|
+
lambda: self._client.projects_users._queryset(f"/users/{instance.id}/projects_users"),
|
|
27
|
+
)
|
|
@@ -18,11 +18,15 @@ from .._auth import TokenManager
|
|
|
18
18
|
from .._config import DEFAULT_BASE_URL, ClientConfig
|
|
19
19
|
from .._rate_limit import RateLimiter
|
|
20
20
|
from ..exceptions import NetworkError, raise_for_status
|
|
21
|
+
from .resources.accreditations import AccreditationsResource
|
|
21
22
|
from .resources.campus_users import CampusUsersResource
|
|
22
23
|
from .resources.campuses import CampusesResource
|
|
23
24
|
from .resources.cursus import CursusResource
|
|
24
25
|
from .resources.events import EventsResource
|
|
26
|
+
from .resources.exams import ExamsResource
|
|
25
27
|
from .resources.locations import LocationsResource
|
|
28
|
+
from .resources.projects import ProjectsResource
|
|
29
|
+
from .resources.projects_users import ProjectUsersResource
|
|
26
30
|
from .resources.users import UsersResource
|
|
27
31
|
|
|
28
32
|
|
|
@@ -64,11 +68,15 @@ class Client:
|
|
|
64
68
|
)
|
|
65
69
|
|
|
66
70
|
self.users = UsersResource(self)
|
|
71
|
+
self.accreditations = AccreditationsResource(self)
|
|
67
72
|
self.campuses = CampusesResource(self)
|
|
68
73
|
self.campus_users = CampusUsersResource(self)
|
|
69
74
|
self.cursus = CursusResource(self)
|
|
70
75
|
self.events = EventsResource(self)
|
|
76
|
+
self.exams = ExamsResource(self)
|
|
71
77
|
self.locations = LocationsResource(self)
|
|
78
|
+
self.projects = ProjectsResource(self)
|
|
79
|
+
self.projects_users = ProjectUsersResource(self)
|
|
72
80
|
|
|
73
81
|
@property
|
|
74
82
|
def base_url(self) -> str:
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# GENERATED FILE — DO NOT EDIT BY HAND.
|
|
2
|
+
#
|
|
3
|
+
# Generated from the corresponding module under intra42._async by
|
|
4
|
+
# scripts/unasync_generate.py (via the `unasync` library). Edit the
|
|
5
|
+
# async source and re-run that script instead.
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ...models.accreditation import Accreditation
|
|
10
|
+
from .base import Resource
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AccreditationsResource(Resource[Accreditation]):
|
|
14
|
+
path = "/accreditations"
|
|
15
|
+
model = Accreditation
|
|
16
|
+
|
|
17
|
+
def _bind_relations(self, instance: Accreditation) -> None:
|
|
18
|
+
# Referenced in the users apidoc page: GET /accreditations/:id/users.
|
|
19
|
+
instance._bind_relation(
|
|
20
|
+
"users",
|
|
21
|
+
lambda: self._client.users._queryset(f"/accreditations/{instance.id}/users"),
|
|
22
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# GENERATED FILE — DO NOT EDIT BY HAND.
|
|
2
|
+
#
|
|
3
|
+
# Generated from the corresponding module under intra42._async by
|
|
4
|
+
# scripts/unasync_generate.py (via the `unasync` library). Edit the
|
|
5
|
+
# async source and re-run that script instead.
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ...models.exam import Exam
|
|
10
|
+
from .base import Resource
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ExamsResource(Resource[Exam]):
|
|
14
|
+
path = "/exams"
|
|
15
|
+
model = Exam
|
|
16
|
+
|
|
17
|
+
def graph(self, *, field: str | None = None, interval: str | None = None) -> dict[str, int]:
|
|
18
|
+
"""Grouped temporal counts (``GET /exams/graph...``)."""
|
|
19
|
+
path = "/exams/graph"
|
|
20
|
+
if interval is not None and field is None:
|
|
21
|
+
field = "created_at"
|
|
22
|
+
if field is not None:
|
|
23
|
+
path += f"/on/{field}"
|
|
24
|
+
if interval is not None:
|
|
25
|
+
path += f"/by/{interval}"
|
|
26
|
+
response = self._client.request("GET", path)
|
|
27
|
+
return response.json()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# GENERATED FILE — DO NOT EDIT BY HAND.
|
|
2
|
+
#
|
|
3
|
+
# Generated from the corresponding module under intra42._async by
|
|
4
|
+
# scripts/unasync_generate.py (via the `unasync` library). Edit the
|
|
5
|
+
# async source and re-run that script instead.
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ...models.project import Project
|
|
10
|
+
from .base import Resource
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ProjectsResource(Resource[Project]):
|
|
14
|
+
path = "/projects"
|
|
15
|
+
model = Project
|
|
16
|
+
|
|
17
|
+
def _bind_relations(self, instance: Project) -> None:
|
|
18
|
+
# Referenced in the projects_users apidoc page:
|
|
19
|
+
# GET /projects/:id/projects_users.
|
|
20
|
+
instance._bind_relation(
|
|
21
|
+
"projects_users",
|
|
22
|
+
lambda: self._client.projects_users._queryset(
|
|
23
|
+
f"/projects/{instance.id}/projects_users"
|
|
24
|
+
),
|
|
25
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# GENERATED FILE — DO NOT EDIT BY HAND.
|
|
2
|
+
#
|
|
3
|
+
# Generated from the corresponding module under intra42._async by
|
|
4
|
+
# scripts/unasync_generate.py (via the `unasync` library). Edit the
|
|
5
|
+
# async source and re-run that script instead.
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ...models.project_user import ProjectUser
|
|
10
|
+
from .base import Resource
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ProjectUsersResource(Resource[ProjectUser]):
|
|
14
|
+
path = "/projects_users"
|
|
15
|
+
model = ProjectUser
|
|
16
|
+
|
|
17
|
+
def graph(self, *, field: str | None = None, interval: str | None = None) -> dict[str, int]:
|
|
18
|
+
path = "/projects_users/graph"
|
|
19
|
+
if interval is not None and field is None:
|
|
20
|
+
field = "created_at"
|
|
21
|
+
if field is not None:
|
|
22
|
+
path += f"/on/{field}"
|
|
23
|
+
if interval is not None:
|
|
24
|
+
path += f"/by/{interval}"
|
|
25
|
+
response = self._client.request("GET", path)
|
|
26
|
+
return response.json()
|
|
@@ -27,3 +27,7 @@ class UsersResource(Resource[User]):
|
|
|
27
27
|
"locations",
|
|
28
28
|
lambda: self._client.locations._queryset(f"/users/{instance.id}/locations"),
|
|
29
29
|
)
|
|
30
|
+
instance._bind_relation(
|
|
31
|
+
"projects_users",
|
|
32
|
+
lambda: self._client.projects_users._queryset(f"/users/{instance.id}/projects_users"),
|
|
33
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""The ``Accreditation`` resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from .base import FortyTwoModel
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .._async.query import AsyncQuerySet
|
|
12
|
+
from .._sync.query import QuerySet
|
|
13
|
+
from .user import User
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Accreditation(FortyTwoModel):
|
|
17
|
+
id: int
|
|
18
|
+
name: str | None = None
|
|
19
|
+
user_id: int | None = None
|
|
20
|
+
cursus_id: int | None = None
|
|
21
|
+
difficulty: int | None = None
|
|
22
|
+
validated: bool | None = None
|
|
23
|
+
created_at: datetime | None = None
|
|
24
|
+
updated_at: datetime | None = None
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def users(self) -> AsyncQuerySet[User] | QuerySet[User]:
|
|
28
|
+
"""Users holding this accreditation (``GET /accreditations/{id}/users``)."""
|
|
29
|
+
return self._relation("users")
|
|
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
|
|
|
11
11
|
from .._async.query import AsyncQuerySet
|
|
12
12
|
from .._sync.query import QuerySet
|
|
13
13
|
from .event import Event
|
|
14
|
+
from .project import Project
|
|
14
15
|
from .user import User
|
|
15
16
|
|
|
16
17
|
|
|
@@ -33,3 +34,8 @@ class Cursus(FortyTwoModel):
|
|
|
33
34
|
def events(self) -> AsyncQuerySet[Event] | QuerySet[Event]:
|
|
34
35
|
"""Events for this cursus (``GET /cursus/{id}/events``)."""
|
|
35
36
|
return self._relation("events")
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def projects(self) -> AsyncQuerySet[Project] | QuerySet[Project]:
|
|
40
|
+
"""Projects belonging to this cursus (``GET /cursus/{id}/projects``)."""
|
|
41
|
+
return self._relation("projects")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""The ``Exam`` resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
from .base import FortyTwoModel
|
|
8
|
+
from .campus import Campus
|
|
9
|
+
from .cursus import Cursus
|
|
10
|
+
from .project import Project
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Exam(FortyTwoModel):
|
|
14
|
+
id: int
|
|
15
|
+
name: str | None = None
|
|
16
|
+
ip_range: str | None = None
|
|
17
|
+
begin_at: datetime | None = None
|
|
18
|
+
end_at: datetime | None = None
|
|
19
|
+
location: str | None = None
|
|
20
|
+
max_people: int | None = None
|
|
21
|
+
nbr_subscribers: int | None = None
|
|
22
|
+
created_at: datetime | None = None
|
|
23
|
+
updated_at: datetime | None = None
|
|
24
|
+
campus_id: int | None = None
|
|
25
|
+
campus: Campus | None = None
|
|
26
|
+
cursus: list[Cursus] | None = None
|
|
27
|
+
projects: list[Project] | None = None
|
|
28
|
+
visible: bool | None = None
|
|
29
|
+
validated: bool | None = None
|
|
30
|
+
validated_at: datetime | None = None
|
|
31
|
+
validator_id: int | None = None
|
|
32
|
+
prohibition_of_cancellation: int | None = None
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""The ``Project`` resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from .base import FortyTwoModel
|
|
9
|
+
from .campus import Campus
|
|
10
|
+
from .cursus import Cursus
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .._async.query import AsyncQuerySet
|
|
14
|
+
from .._sync.query import QuerySet
|
|
15
|
+
from .project_user import ProjectUser
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProjectRef(FortyTwoModel):
|
|
19
|
+
"""A lightweight project reference, used for ``parent`` and ``children``."""
|
|
20
|
+
|
|
21
|
+
id: int | None = None
|
|
22
|
+
name: str | None = None
|
|
23
|
+
slug: str | None = None
|
|
24
|
+
url: str | None = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ProjectSkill(FortyTwoModel):
|
|
28
|
+
id: int | None = None
|
|
29
|
+
name: str | None = None
|
|
30
|
+
created_at: datetime | None = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ProjectTag(FortyTwoModel):
|
|
34
|
+
id: int | None = None
|
|
35
|
+
name: str | None = None
|
|
36
|
+
kind: str | None = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ProjectSessionScale(FortyTwoModel):
|
|
40
|
+
id: int | None = None
|
|
41
|
+
correction_number: int | None = None
|
|
42
|
+
is_primary: bool | None = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ProjectSessionUpload(FortyTwoModel):
|
|
46
|
+
id: int | None = None
|
|
47
|
+
name: str | None = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ProjectSession(FortyTwoModel):
|
|
51
|
+
id: int | None = None
|
|
52
|
+
solo: bool | None = None
|
|
53
|
+
begin_at: datetime | None = None
|
|
54
|
+
end_at: datetime | None = None
|
|
55
|
+
difficulty: int | None = None
|
|
56
|
+
# Confirmed against a real account: not always an int (seconds) as the
|
|
57
|
+
# apidoc example showed (2592000) — also seen as a free-form duration
|
|
58
|
+
# string ("1 day").
|
|
59
|
+
estimate_time: int | str | None = None
|
|
60
|
+
duration_days: int | None = None
|
|
61
|
+
terminating_after: int | None = None
|
|
62
|
+
project_id: int | None = None
|
|
63
|
+
campus_id: int | None = None
|
|
64
|
+
cursus_id: int | None = None
|
|
65
|
+
created_at: datetime | None = None
|
|
66
|
+
updated_at: datetime | None = None
|
|
67
|
+
max_people: int | None = None
|
|
68
|
+
is_subscriptable: bool | None = None
|
|
69
|
+
scales: list[ProjectSessionScale] | None = None
|
|
70
|
+
uploads: list[ProjectSessionUpload] | None = None
|
|
71
|
+
team_behaviour: str | None = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class Project(FortyTwoModel):
|
|
75
|
+
id: int
|
|
76
|
+
name: str | None = None
|
|
77
|
+
slug: str | None = None
|
|
78
|
+
difficulty: int | None = None
|
|
79
|
+
description: str | None = None
|
|
80
|
+
parent_id: int | None = None
|
|
81
|
+
parent: ProjectRef | None = None
|
|
82
|
+
children: list[ProjectRef] | None = None
|
|
83
|
+
objectives: list[str] | None = None
|
|
84
|
+
attachments: list[Any] | None = None
|
|
85
|
+
created_at: datetime | None = None
|
|
86
|
+
updated_at: datetime | None = None
|
|
87
|
+
exam: bool | None = None
|
|
88
|
+
cursus: list[Cursus] | None = None
|
|
89
|
+
campus: list[Campus] | None = None
|
|
90
|
+
skills: list[ProjectSkill] | None = None
|
|
91
|
+
videos: list[Any] | None = None
|
|
92
|
+
tags: list[ProjectTag] | None = None
|
|
93
|
+
project_sessions: list[ProjectSession] | None = None
|
|
94
|
+
visible: bool | None = None
|
|
95
|
+
inherited_team: bool | None = None
|
|
96
|
+
position: int | None = None
|
|
97
|
+
has_git: bool | None = None
|
|
98
|
+
has_mark: bool | None = None
|
|
99
|
+
repository: str | None = None
|
|
100
|
+
git_id: int | None = None
|
|
101
|
+
cached_repository_path: str | None = None
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def projects_users(self) -> AsyncQuerySet[ProjectUser] | QuerySet[ProjectUser]:
|
|
105
|
+
"""Assignments of this project (``GET /projects/{id}/projects_users``)."""
|
|
106
|
+
return self._relation("projects_users")
|