Coretex
network_object.py
1 # Copyright (C) 2023 Coretex LLC
2 
3 # This file is part of Coretex.ai
4 
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
17 
18 from typing import Optional, Any, Dict, List
19 from typing_extensions import Self
20 
21 import inflection
22 
23 from .network_manager import networkManager
24 from .network_response import NetworkRequestError
25 from ..codable import Codable
26 
27 
28 DEFAULT_PAGE_SIZE = 100
29 
30 
32 
33  """
34  Base class for every Coretex.ai entity representation in Python
35 
36  Properties
37  ----------
38  id : int
39  id of object
40  isDeleted : bool
41  boolean value that represents if object will be shown or not
42  """
43 
44  id: int
45  isDeleted: bool
46 
47  # Required init
48  def __init__(self) -> None:
49  pass
50 
51  @classmethod
52  def _endpoint(cls) -> str:
53  """
54  Maps the entity endpoint to overriden value, else
55  it uses inflection.underscode on the class name for endpoint
56 
57  Returns
58  -------
59  str -> Coretex.ai object endpoint for a given class
60  """
61 
62  return inflection.underscore(cls.__name__)
63 
64  def entityUrl(self) -> str:
65  """
66  Maps the entity url to the frontend page url
67 
68  Returns
69  -------
70  str -> The URL path on Coretex for the entity.
71  """
72 
73  return f"{type(self).__name__.lower()}/{self.id}"
74 
75  def __eq__(self, __o: object) -> bool:
76  """
77  Checks if the NetworkObjects which have id property
78  defined are equal
79 
80  Parameter
81  ---------
82  __o : object
83  object to which we are comparing self
84 
85  Returns
86  -------
87  bool -> True if ids are present and equal, False in any other case
88  """
89 
90  # check if object parent class matches
91  if isinstance(__o, NetworkObject):
92  return self.idid == __o.id
93 
94  return NotImplemented
95 
96  def __hash__(self) -> int:
97  """
98  Calculates hash of the object in a non-randomized manner
99 
100  Returns
101  -------
102  int -> hash of all the items defined on the self.__dict__ object
103  """
104 
105  return hash(tuple(sorted(self.__dict__.items())))
106 
107  def refresh(self, jsonObject: Optional[Dict[str, Any]] = None) -> bool:
108  """
109  Updates objects fields to a provided value if set, otherwise
110  fetches the object from the API and updates the values
111  using the fetched object
112 
113  Parameters
114  ----------
115  jsonObject : Optional[Dict[str, Any]]
116  A serialized json object to which the values should be updated, if provided
117 
118  Returns
119  -------
120  bool -> True if the update was successful, False otherwise
121  """
122 
123  # Update from json if it exists
124  if jsonObject is not None:
125  self._updateFields_updateFields(jsonObject)
126  return True
127 
128  # Fetch from server otherwise
129  try:
130  obj = self.__class__.fetchById(self.idid)
131  except NetworkRequestError:
132  return False
133 
134  for key, value in obj.__dict__.items():
135  self.__dict__[key] = value
136 
137  return True
138 
139  def update(self, **kwargs: Any) -> bool:
140  """
141  Sends a PUT request to Coretex backend
142 
143  Parameters
144  ----------
145  **kwargs : Dict[str, Any]
146  parameters which will be sent as request body
147 
148  Returns
149  -------
150  bool -> True if request was successful, False otherwise
151  """
152 
153  if self.isDeleted:
154  return False
155 
156  endpoint = f"{self._endpoint()}/{self.id}"
157  return not networkManager.put(endpoint, kwargs).hasFailed()
158 
159  def delete(self) -> bool:
160  """
161  Sends a DELETE request to Coretex backend
162 
163  Returns
164  -------
165  bool -> True if request was successful, False otherwise
166  """
167 
168  if self.isDeleted:
169  return False
170 
171  endpoint = f"{self._endpoint()}/{self.id}"
172  return not networkManager.delete(endpoint).hasFailed()
173 
174  @classmethod
175  def create(cls, **kwargs: Any) -> Self:
176  """
177  Creates the entity linked to this class on Coretex backend
178 
179  Parameters
180  ----------
181  **kwargs : Dict[str, Any]
182  parameters which will be sent as request body
183 
184  Returns
185  -------
186  Self -> created object if request was successful
187 
188  Raises
189  ------
190  NetworkRequestError -> If the request for creating failed
191  """
192 
193  response = networkManager.post(cls._endpoint_endpoint(), kwargs)
194  if response.hasFailed():
195  raise NetworkRequestError(response, f">> [Coretex] Failed to create \"{cls.__name__}\" with parameters \"{kwargs}\"")
196 
197  return cls.decodedecode(response.getJson(dict))
198 
199  @classmethod
200  def fetchAll(cls, **kwargs: Any) -> List[Self]:
201  """
202  Fetches all entities from Coretex backend which match
203  the given predicate
204 
205  Parameters
206  ----------
207  **kwargs : Optional[Dict[str, Any]]
208  query parameters (predicate) which will be appended to URL
209 
210  Returns
211  -------
212  List[Self] -> list of all fetched entities
213 
214  Raises
215  ------
216  NetworkRequestError -> If the request for fetching failed
217  """
218 
219  if "page_size" not in kwargs:
220  kwargs["page_size"] = DEFAULT_PAGE_SIZE
221 
222  response = networkManager.get(cls._endpoint_endpoint(), kwargs)
223  if response.hasFailed():
224  raise NetworkRequestError(response, f"Failed to fetch \"{cls.__name__}\" with parameters \"{kwargs}\"")
225 
226  objects: List[Self] = []
227 
228  for obj in response.getJson(list):
229  objects.append(cls.decodedecode(obj))
230 
231  return objects
232 
233  @classmethod
234  def fetchOne(cls, **kwargs: Any) -> Self:
235  """
236  Fetches one entity from Coretex backend which matches
237  the given predicate
238 
239  Parameters
240  ----------
241  **kwargs : Optional[Dict[str, Any]]
242  query parameters (predicate) which will be appended to URL
243 
244  Returns
245  -------
246  Self -> fetched entity
247 
248  Raises
249  ------
250  NetworkRequestError -> If the request for fetching failed
251  ValueError -> If no object was fetched
252  """
253 
254  kwargs["page_size"] = 1
255  result = cls.fetchAllfetchAll(**kwargs)
256 
257  if len(result) == 0:
258  raise ValueError(f"Failed to fetch \"{cls.__name__}\" with parameters \"{kwargs}\"")
259 
260  return result[0]
261 
262  @classmethod
263  def fetchById(cls, objectId: int, **kwargs: Any) -> Self:
264  """
265  Fetches a single entity with the matching id
266 
267  Parameters
268  ----------
269  objectId : int
270  id of the object which is fetched
271  **kwargs : Optional[Dict[str, Any]]
272  query parameters (predicate) which will be appended to URL
273 
274  Returns
275  -------
276  Optional[Self] -> fetched object if request was successful, None otherwise
277 
278  Raises
279  ------
280  NetworkRequestError -> If the request for fetching failed
281  """
282 
283  if "page_size" not in kwargs:
284  kwargs["page_size"] = DEFAULT_PAGE_SIZE
285 
286  response = networkManager.get(f"{cls._endpoint()}/{objectId}", kwargs)
287 
288  if response.hasFailed():
289  raise NetworkRequestError(response, f"Failed to fetch \"{cls.__name__}\" with ID \"{objectId}\"")
290 
291  return cls.decodedecode(response.getJson(dict))
Self decode(cls, Dict[str, Any] encodedObject)
Definition: codable.py:239
None _updateFields(self, Dict[str, Any] encodedObject)
Definition: codable.py:210
Self fetchById(cls, int objectId, **Any kwargs)
bool refresh(self, Optional[Dict[str, Any]] jsonObject=None)