Coretex
file_data.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, Tuple, Union, BinaryIO
19 from typing_extensions import Self
20 from pathlib import Path
21 from contextlib import ExitStack
22 
23 from ..utils import guessMimeType
24 
25 
26 class FileData:
27 
28  """
29  Class which describes file which will be uploaded
30  using NetworkManager.genericUpload function.
31  To upload a file either its "filePath" or "fileBytes"
32  must be set, otherwise it will raise an exception.
33  "filePath" will upload the file from the specified path, while
34  "fileBytes" will upload the file directly from the memory.
35  If both parameters have value "fileBytes" will be used.
36 
37  Objects of this class should not be instantiated directly,
38  use either "FileData.createFromPath" or "FileData.createFromBytes"
39  to instantiate the object.
40 
41  Properties
42  ----------
43  parameterName : str
44  Name of the form-data parameter
45  fileName : str
46  Name of the file which will be uploaded
47  mimeType : str
48  Mime type of the file which will be uploaded
49  filePath : Optional[str]
50  Path to the file which will be uploaded
51  fileBytes : Optional[bytes]
52  Bytes of the file which will be uploaded
53  """
54 
55  def __init__(
56  self,
57  parameterName: str,
58  fileName: str,
59  mimeType: str,
60  filePath: Optional[Path] = None,
61  fileBytes: Optional[bytes] = None
62  ) -> None:
63 
64  if filePath is None and fileBytes is None:
65  raise ValueError(">> [Coretex] Either \"filePath\" or \"fileData\" have to provided for file upload. \"fileData\" will be used if both are provided")
66 
67  self.parameterNameparameterName = parameterName
68  self.fileNamefileName = fileName
69  self.mimeTypemimeType = mimeType
70  self.filePathfilePath = filePath
71  self.fileBytesfileBytes = fileBytes
72 
73  @classmethod
75  cls,
76  parameterName: str,
77  filePath: Union[Path, str],
78  fileName: Optional[str] = None,
79  mimeType: Optional[str] = None
80  ) -> Self:
81 
82  """
83  Creates "FileData" object from the specified file path. Use
84  this function if you want to upload a file directly from path.
85 
86  Parameters
87  ----------
88  parameterName : str
89  Name of the form-data parameter
90  filePath : Union[Path, str]
91  Path to the file which will be uploaded
92  fileName : Optional[str]
93  Name of the file which will be uploaded, if None it will
94  be extracted from the "filePath" parameter
95  mimeType : Optional[str]
96  Mime type of the file which will be uploaded, if None it will
97  be guessed. If it is not possible to guess an exception will be
98  raised. In that case provide the mime type manually.
99 
100  Returns
101  -------
102  Self -> on object which describes how a path should be uploaded from path
103 
104  Raises
105  ------
106  ValueError -> if "filePath" is not a valid file
107  """
108 
109  if isinstance(filePath, str):
110  filePath = Path(filePath)
111 
112  if not filePath.is_file():
113  raise ValueError(">> [Coretex] \"filePath\" is not a valid file")
114 
115  if fileName is None:
116  fileName = filePath.stem
117 
118  if mimeType is None:
119  mimeType = guessMimeType(filePath)
120 
121  return cls(parameterName, fileName, mimeType, filePath = filePath)
122 
123  @classmethod
125  cls,
126  parameterName: str,
127  fileBytes: bytes,
128  fileName: str,
129  mimeType: Optional[str] = None
130  ) -> Self:
131 
132  """
133  Creates "FileData" object from the provided bytes. Use this
134  function if you want to upload a file directly from memory.
135 
136  Parameters
137  ----------
138  parameterName : str
139  Name of the form-data parameter
140  fileBytes : bytes
141  Bytes of the file which will be uploaded
142  fileName : str
143  Name of the file which will be uploaded, if None it will
144  be extracted from the "filePath" parameter
145  mimeType : Optional[str]
146  Mime type of the file which will be uploaded, if None it will
147  be set to "application/octet-stream".
148 
149  Returns
150  -------
151  Self -> on object which describes how a path should be uploaded from memory
152  """
153 
154  if mimeType is None:
155  mimeType = "application/octet-stream"
156 
157  return cls(parameterName, fileName, mimeType, fileBytes = fileBytes)
158 
159  def __getFileData(self, exitStack: ExitStack) -> Union[bytes, BinaryIO]:
160  if self.fileBytesfileBytes is not None:
161  return self.fileBytesfileBytes
162 
163  if self.filePathfilePath is not None:
164  return exitStack.enter_context(self.filePathfilePath.open("rb"))
165 
166  raise ValueError(">> [Coretex] Either \"filePath\" or \"fileData\" have to provided for file upload. \"fileData\" will be used if both are provided")
167 
168  def prepareForUpload(self, exitStack: ExitStack) -> Tuple[str, Tuple[str, Union[bytes, BinaryIO], str]]:
169  """
170  Converts the "FileData" object into a format which can be used
171  by the requests library for uploading files.
172 
173  Parameters
174  ----------
175  exitStack : ExitStack
176  Context stack which contains the context of files
177  opened by the "FileData" object. Used to join multiple file
178  contexts, so if one raises an exception all the files will
179  properly get closed.
180 
181  Returns
182  -------
183  Tuple[str, Tuple[str, Any, str]] -> Format accepted by the requests
184  library for uploading files.
185  """
186 
187  return self.parameterNameparameterName, (self.fileNamefileName, self.__getFileData__getFileData(exitStack), self.mimeTypemimeType)
Union[bytes, BinaryIO] __getFileData(self, ExitStack exitStack)
Definition: file_data.py:159
Self createFromPath(cls, str parameterName, Union[Path, str] filePath, Optional[str] fileName=None, Optional[str] mimeType=None)
Definition: file_data.py:80
Self createFromBytes(cls, str parameterName, bytes fileBytes, str fileName, Optional[str] mimeType=None)
Definition: file_data.py:130
Tuple[str, Tuple[str, Union[bytes, BinaryIO], str]] prepareForUpload(self, ExitStack exitStack)
Definition: file_data.py:168