devrev-Python-SDK 1.0.0__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.
Files changed (45) hide show
  1. devrev/__init__.py +47 -0
  2. devrev/client.py +343 -0
  3. devrev/config.py +180 -0
  4. devrev/exceptions.py +205 -0
  5. devrev/models/__init__.py +499 -0
  6. devrev/models/accounts.py +187 -0
  7. devrev/models/articles.py +109 -0
  8. devrev/models/base.py +147 -0
  9. devrev/models/code_changes.py +103 -0
  10. devrev/models/conversations.py +115 -0
  11. devrev/models/dev_users.py +258 -0
  12. devrev/models/groups.py +140 -0
  13. devrev/models/links.py +107 -0
  14. devrev/models/parts.py +110 -0
  15. devrev/models/rev_users.py +177 -0
  16. devrev/models/slas.py +112 -0
  17. devrev/models/tags.py +90 -0
  18. devrev/models/timeline_entries.py +100 -0
  19. devrev/models/webhooks.py +109 -0
  20. devrev/models/works.py +280 -0
  21. devrev/py.typed +1 -0
  22. devrev/services/__init__.py +74 -0
  23. devrev/services/accounts.py +325 -0
  24. devrev/services/articles.py +80 -0
  25. devrev/services/base.py +234 -0
  26. devrev/services/code_changes.py +80 -0
  27. devrev/services/conversations.py +98 -0
  28. devrev/services/dev_users.py +401 -0
  29. devrev/services/groups.py +103 -0
  30. devrev/services/links.py +68 -0
  31. devrev/services/parts.py +100 -0
  32. devrev/services/rev_users.py +235 -0
  33. devrev/services/slas.py +82 -0
  34. devrev/services/tags.py +80 -0
  35. devrev/services/timeline_entries.py +80 -0
  36. devrev/services/webhooks.py +80 -0
  37. devrev/services/works.py +363 -0
  38. devrev/utils/__init__.py +14 -0
  39. devrev/utils/deprecation.py +49 -0
  40. devrev/utils/http.py +521 -0
  41. devrev/utils/logging.py +139 -0
  42. devrev/utils/pagination.py +155 -0
  43. devrev_python_sdk-1.0.0.dist-info/METADATA +774 -0
  44. devrev_python_sdk-1.0.0.dist-info/RECORD +45 -0
  45. devrev_python_sdk-1.0.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,80 @@
1
+ """Articles service for DevRev SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+
7
+ from devrev.models.articles import (
8
+ Article,
9
+ ArticlesCreateRequest,
10
+ ArticlesCreateResponse,
11
+ ArticlesDeleteRequest,
12
+ ArticlesDeleteResponse,
13
+ ArticlesGetRequest,
14
+ ArticlesGetResponse,
15
+ ArticlesListRequest,
16
+ ArticlesListResponse,
17
+ ArticlesUpdateRequest,
18
+ ArticlesUpdateResponse,
19
+ )
20
+ from devrev.services.base import AsyncBaseService, BaseService
21
+
22
+
23
+ class ArticlesService(BaseService):
24
+ """Service for managing DevRev Articles."""
25
+
26
+ def create(self, request: ArticlesCreateRequest) -> Article:
27
+ """Create a new article."""
28
+ response = self._post("/articles.create", request, ArticlesCreateResponse)
29
+ return response.article
30
+
31
+ def get(self, request: ArticlesGetRequest) -> Article:
32
+ """Get an article by ID."""
33
+ response = self._post("/articles.get", request, ArticlesGetResponse)
34
+ return response.article
35
+
36
+ def list(self, request: ArticlesListRequest | None = None) -> Sequence[Article]:
37
+ """List articles."""
38
+ if request is None:
39
+ request = ArticlesListRequest()
40
+ response = self._post("/articles.list", request, ArticlesListResponse)
41
+ return response.articles
42
+
43
+ def update(self, request: ArticlesUpdateRequest) -> Article:
44
+ """Update an article."""
45
+ response = self._post("/articles.update", request, ArticlesUpdateResponse)
46
+ return response.article
47
+
48
+ def delete(self, request: ArticlesDeleteRequest) -> None:
49
+ """Delete an article."""
50
+ self._post("/articles.delete", request, ArticlesDeleteResponse)
51
+
52
+
53
+ class AsyncArticlesService(AsyncBaseService):
54
+ """Async service for managing DevRev Articles."""
55
+
56
+ async def create(self, request: ArticlesCreateRequest) -> Article:
57
+ """Create a new article."""
58
+ response = await self._post("/articles.create", request, ArticlesCreateResponse)
59
+ return response.article
60
+
61
+ async def get(self, request: ArticlesGetRequest) -> Article:
62
+ """Get an article by ID."""
63
+ response = await self._post("/articles.get", request, ArticlesGetResponse)
64
+ return response.article
65
+
66
+ async def list(self, request: ArticlesListRequest | None = None) -> Sequence[Article]:
67
+ """List articles."""
68
+ if request is None:
69
+ request = ArticlesListRequest()
70
+ response = await self._post("/articles.list", request, ArticlesListResponse)
71
+ return response.articles
72
+
73
+ async def update(self, request: ArticlesUpdateRequest) -> Article:
74
+ """Update an article."""
75
+ response = await self._post("/articles.update", request, ArticlesUpdateResponse)
76
+ return response.article
77
+
78
+ async def delete(self, request: ArticlesDeleteRequest) -> None:
79
+ """Delete an article."""
80
+ await self._post("/articles.delete", request, ArticlesDeleteResponse)
@@ -0,0 +1,234 @@
1
+ """Base service class for DevRev SDK.
2
+
3
+ This module provides the base service class that all API services inherit from.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import logging
9
+ from typing import TYPE_CHECKING, Any, TypeVar, overload
10
+
11
+ from pydantic import BaseModel
12
+
13
+ if TYPE_CHECKING:
14
+ from devrev.utils.http import AsyncHTTPClient, HTTPClient
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ T = TypeVar("T", bound=BaseModel)
19
+
20
+
21
+ class BaseService:
22
+ """Base class for synchronous DevRev API services.
23
+
24
+ Provides common functionality for making API requests
25
+ and parsing responses into Pydantic models.
26
+
27
+ Args:
28
+ http_client: The HTTP client to use for requests
29
+ """
30
+
31
+ def __init__(self, http_client: HTTPClient) -> None:
32
+ """Initialize the service.
33
+
34
+ Args:
35
+ http_client: The HTTP client to use for requests
36
+ """
37
+ self._http = http_client
38
+
39
+ @overload
40
+ def _post(
41
+ self,
42
+ endpoint: str,
43
+ request: BaseModel | None,
44
+ response_type: type[T],
45
+ ) -> T: ...
46
+
47
+ @overload
48
+ def _post(
49
+ self,
50
+ endpoint: str,
51
+ request: BaseModel | None = None,
52
+ response_type: None = None,
53
+ ) -> dict[str, Any]: ...
54
+
55
+ def _post(
56
+ self,
57
+ endpoint: str,
58
+ request: BaseModel | None = None,
59
+ response_type: type[T] | None = None,
60
+ ) -> T | dict[str, Any]:
61
+ """Make a POST request and parse the response.
62
+
63
+ Args:
64
+ endpoint: API endpoint path
65
+ request: Request model to serialize as JSON body
66
+ response_type: Response model type to parse into
67
+
68
+ Returns:
69
+ Parsed response model or raw dict if no response_type
70
+ """
71
+ data = request.model_dump(exclude_none=True, by_alias=True) if request else None
72
+ response = self._http.post(endpoint, data=data)
73
+
74
+ # Handle empty responses (204 No Content or empty body)
75
+ if response.status_code == 204 or not response.content:
76
+ json_data: dict[str, Any] = {}
77
+ else:
78
+ json_data = response.json()
79
+
80
+ if response_type:
81
+ return response_type.model_validate(json_data)
82
+ return json_data
83
+
84
+ @overload
85
+ def _get(
86
+ self,
87
+ endpoint: str,
88
+ params: dict[str, Any] | None,
89
+ response_type: type[T],
90
+ ) -> T: ...
91
+
92
+ @overload
93
+ def _get(
94
+ self,
95
+ endpoint: str,
96
+ params: dict[str, Any] | None = None,
97
+ response_type: None = None,
98
+ ) -> dict[str, Any]: ...
99
+
100
+ def _get(
101
+ self,
102
+ endpoint: str,
103
+ params: dict[str, Any] | None = None,
104
+ response_type: type[T] | None = None,
105
+ ) -> T | dict[str, Any]:
106
+ """Make a GET request and parse the response.
107
+
108
+ Args:
109
+ endpoint: API endpoint path
110
+ params: Query parameters
111
+ response_type: Response model type to parse into
112
+
113
+ Returns:
114
+ Parsed response model or raw dict if no response_type
115
+ """
116
+ response = self._http.get(endpoint, params=params)
117
+
118
+ # Handle empty responses (204 No Content or empty body)
119
+ if response.status_code == 204 or not response.content:
120
+ json_data: dict[str, Any] = {}
121
+ else:
122
+ json_data = response.json()
123
+
124
+ if response_type:
125
+ return response_type.model_validate(json_data)
126
+ return json_data
127
+
128
+
129
+ class AsyncBaseService:
130
+ """Base class for asynchronous DevRev API services.
131
+
132
+ Provides common functionality for making async API requests
133
+ and parsing responses into Pydantic models.
134
+
135
+ Args:
136
+ http_client: The async HTTP client to use for requests
137
+ """
138
+
139
+ def __init__(self, http_client: AsyncHTTPClient) -> None:
140
+ """Initialize the service.
141
+
142
+ Args:
143
+ http_client: The async HTTP client to use for requests
144
+ """
145
+ self._http = http_client
146
+
147
+ @overload
148
+ async def _post(
149
+ self,
150
+ endpoint: str,
151
+ request: BaseModel | None,
152
+ response_type: type[T],
153
+ ) -> T: ...
154
+
155
+ @overload
156
+ async def _post(
157
+ self,
158
+ endpoint: str,
159
+ request: BaseModel | None = None,
160
+ response_type: None = None,
161
+ ) -> dict[str, Any]: ...
162
+
163
+ async def _post(
164
+ self,
165
+ endpoint: str,
166
+ request: BaseModel | None = None,
167
+ response_type: type[T] | None = None,
168
+ ) -> T | dict[str, Any]:
169
+ """Make an async POST request and parse the response.
170
+
171
+ Args:
172
+ endpoint: API endpoint path
173
+ request: Request model to serialize as JSON body
174
+ response_type: Response model type to parse into
175
+
176
+ Returns:
177
+ Parsed response model or raw dict if no response_type
178
+ """
179
+ data = request.model_dump(exclude_none=True, by_alias=True) if request else None
180
+ response = await self._http.post(endpoint, data=data)
181
+
182
+ # Handle empty responses (204 No Content or empty body)
183
+ if response.status_code == 204 or not response.content:
184
+ json_data: dict[str, Any] = {}
185
+ else:
186
+ json_data = response.json()
187
+
188
+ if response_type:
189
+ return response_type.model_validate(json_data)
190
+ return json_data
191
+
192
+ @overload
193
+ async def _get(
194
+ self,
195
+ endpoint: str,
196
+ params: dict[str, Any] | None,
197
+ response_type: type[T],
198
+ ) -> T: ...
199
+
200
+ @overload
201
+ async def _get(
202
+ self,
203
+ endpoint: str,
204
+ params: dict[str, Any] | None = None,
205
+ response_type: None = None,
206
+ ) -> dict[str, Any]: ...
207
+
208
+ async def _get(
209
+ self,
210
+ endpoint: str,
211
+ params: dict[str, Any] | None = None,
212
+ response_type: type[T] | None = None,
213
+ ) -> T | dict[str, Any]:
214
+ """Make an async GET request and parse the response.
215
+
216
+ Args:
217
+ endpoint: API endpoint path
218
+ params: Query parameters
219
+ response_type: Response model type to parse into
220
+
221
+ Returns:
222
+ Parsed response model or raw dict if no response_type
223
+ """
224
+ response = await self._http.get(endpoint, params=params)
225
+
226
+ # Handle empty responses (204 No Content or empty body)
227
+ if response.status_code == 204 or not response.content:
228
+ json_data: dict[str, Any] = {}
229
+ else:
230
+ json_data = response.json()
231
+
232
+ if response_type:
233
+ return response_type.model_validate(json_data)
234
+ return json_data
@@ -0,0 +1,80 @@
1
+ """Code Changes service for DevRev SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+
7
+ from devrev.models.code_changes import (
8
+ CodeChange,
9
+ CodeChangesCreateRequest,
10
+ CodeChangesCreateResponse,
11
+ CodeChangesDeleteRequest,
12
+ CodeChangesDeleteResponse,
13
+ CodeChangesGetRequest,
14
+ CodeChangesGetResponse,
15
+ CodeChangesListRequest,
16
+ CodeChangesListResponse,
17
+ CodeChangesUpdateRequest,
18
+ CodeChangesUpdateResponse,
19
+ )
20
+ from devrev.services.base import AsyncBaseService, BaseService
21
+
22
+
23
+ class CodeChangesService(BaseService):
24
+ """Service for managing DevRev Code Changes."""
25
+
26
+ def create(self, request: CodeChangesCreateRequest) -> CodeChange:
27
+ """Create a new code change."""
28
+ response = self._post("/code-changes.create", request, CodeChangesCreateResponse)
29
+ return response.code_change
30
+
31
+ def get(self, request: CodeChangesGetRequest) -> CodeChange:
32
+ """Get a code change by ID."""
33
+ response = self._post("/code-changes.get", request, CodeChangesGetResponse)
34
+ return response.code_change
35
+
36
+ def list(self, request: CodeChangesListRequest | None = None) -> Sequence[CodeChange]:
37
+ """List code changes."""
38
+ if request is None:
39
+ request = CodeChangesListRequest()
40
+ response = self._post("/code-changes.list", request, CodeChangesListResponse)
41
+ return response.code_changes
42
+
43
+ def update(self, request: CodeChangesUpdateRequest) -> CodeChange:
44
+ """Update a code change."""
45
+ response = self._post("/code-changes.update", request, CodeChangesUpdateResponse)
46
+ return response.code_change
47
+
48
+ def delete(self, request: CodeChangesDeleteRequest) -> None:
49
+ """Delete a code change."""
50
+ self._post("/code-changes.delete", request, CodeChangesDeleteResponse)
51
+
52
+
53
+ class AsyncCodeChangesService(AsyncBaseService):
54
+ """Async service for managing DevRev Code Changes."""
55
+
56
+ async def create(self, request: CodeChangesCreateRequest) -> CodeChange:
57
+ """Create a new code change."""
58
+ response = await self._post("/code-changes.create", request, CodeChangesCreateResponse)
59
+ return response.code_change
60
+
61
+ async def get(self, request: CodeChangesGetRequest) -> CodeChange:
62
+ """Get a code change by ID."""
63
+ response = await self._post("/code-changes.get", request, CodeChangesGetResponse)
64
+ return response.code_change
65
+
66
+ async def list(self, request: CodeChangesListRequest | None = None) -> Sequence[CodeChange]:
67
+ """List code changes."""
68
+ if request is None:
69
+ request = CodeChangesListRequest()
70
+ response = await self._post("/code-changes.list", request, CodeChangesListResponse)
71
+ return response.code_changes
72
+
73
+ async def update(self, request: CodeChangesUpdateRequest) -> CodeChange:
74
+ """Update a code change."""
75
+ response = await self._post("/code-changes.update", request, CodeChangesUpdateResponse)
76
+ return response.code_change
77
+
78
+ async def delete(self, request: CodeChangesDeleteRequest) -> None:
79
+ """Delete a code change."""
80
+ await self._post("/code-changes.delete", request, CodeChangesDeleteResponse)
@@ -0,0 +1,98 @@
1
+ """Conversations service for DevRev SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+
7
+ from devrev.models.conversations import (
8
+ Conversation,
9
+ ConversationsCreateRequest,
10
+ ConversationsCreateResponse,
11
+ ConversationsDeleteRequest,
12
+ ConversationsDeleteResponse,
13
+ ConversationsExportRequest,
14
+ ConversationsExportResponse,
15
+ ConversationsGetRequest,
16
+ ConversationsGetResponse,
17
+ ConversationsListRequest,
18
+ ConversationsListResponse,
19
+ ConversationsUpdateRequest,
20
+ ConversationsUpdateResponse,
21
+ )
22
+ from devrev.services.base import AsyncBaseService, BaseService
23
+
24
+
25
+ class ConversationsService(BaseService):
26
+ """Service for managing DevRev Conversations."""
27
+
28
+ def create(self, request: ConversationsCreateRequest) -> Conversation:
29
+ """Create a new conversation."""
30
+ response = self._post("/conversations.create", request, ConversationsCreateResponse)
31
+ return response.conversation
32
+
33
+ def get(self, request: ConversationsGetRequest) -> Conversation:
34
+ """Get a conversation by ID."""
35
+ response = self._post("/conversations.get", request, ConversationsGetResponse)
36
+ return response.conversation
37
+
38
+ def list(self, request: ConversationsListRequest | None = None) -> Sequence[Conversation]:
39
+ """List conversations."""
40
+ if request is None:
41
+ request = ConversationsListRequest()
42
+ response = self._post("/conversations.list", request, ConversationsListResponse)
43
+ return response.conversations
44
+
45
+ def update(self, request: ConversationsUpdateRequest) -> Conversation:
46
+ """Update a conversation."""
47
+ response = self._post("/conversations.update", request, ConversationsUpdateResponse)
48
+ return response.conversation
49
+
50
+ def delete(self, request: ConversationsDeleteRequest) -> None:
51
+ """Delete a conversation."""
52
+ self._post("/conversations.delete", request, ConversationsDeleteResponse)
53
+
54
+ def export(self, request: ConversationsExportRequest | None = None) -> Sequence[Conversation]:
55
+ """Export conversations."""
56
+ if request is None:
57
+ request = ConversationsExportRequest()
58
+ response = self._post("/conversations.export", request, ConversationsExportResponse)
59
+ return response.conversations
60
+
61
+
62
+ class AsyncConversationsService(AsyncBaseService):
63
+ """Async service for managing DevRev Conversations."""
64
+
65
+ async def create(self, request: ConversationsCreateRequest) -> Conversation:
66
+ """Create a new conversation."""
67
+ response = await self._post("/conversations.create", request, ConversationsCreateResponse)
68
+ return response.conversation
69
+
70
+ async def get(self, request: ConversationsGetRequest) -> Conversation:
71
+ """Get a conversation by ID."""
72
+ response = await self._post("/conversations.get", request, ConversationsGetResponse)
73
+ return response.conversation
74
+
75
+ async def list(self, request: ConversationsListRequest | None = None) -> Sequence[Conversation]:
76
+ """List conversations."""
77
+ if request is None:
78
+ request = ConversationsListRequest()
79
+ response = await self._post("/conversations.list", request, ConversationsListResponse)
80
+ return response.conversations
81
+
82
+ async def update(self, request: ConversationsUpdateRequest) -> Conversation:
83
+ """Update a conversation."""
84
+ response = await self._post("/conversations.update", request, ConversationsUpdateResponse)
85
+ return response.conversation
86
+
87
+ async def delete(self, request: ConversationsDeleteRequest) -> None:
88
+ """Delete a conversation."""
89
+ await self._post("/conversations.delete", request, ConversationsDeleteResponse)
90
+
91
+ async def export(
92
+ self, request: ConversationsExportRequest | None = None
93
+ ) -> Sequence[Conversation]:
94
+ """Export conversations."""
95
+ if request is None:
96
+ request = ConversationsExportRequest()
97
+ response = await self._post("/conversations.export", request, ConversationsExportResponse)
98
+ return response.conversations