pumpwood_communication.microservice_abc.simple

Facilitate communication with Pumpowood backend.

This packages facilitates the communication with end-points with Pumpwood pattern and helps with authentication.

Source-code at Github:
https://github.com/Murabei-OpenSource-Codes/pumpwood-communication

 1"""
 2Facilitate communication with Pumpowood backend.
 3
 4This packages facilitates the communication with end-points with Pumpwood
 5pattern and helps with authentication.
 6
 7Source-code at Github:<br>
 8https://github.com/Murabei-OpenSource-Codes/pumpwood-communication
 9"""
10
11__docformat__ = "google"
12from .batch import ABCSimpleBatchMicroservice
13from .permission import ABCPermissionMicroservice
14from .retrieve import ABCSimpleRetriveMicroservice
15from .delete import ABCSimpleDeleteMicroservice
16from .save import ABCSimpleSaveMicroservice
17
18__all__ = [
19    ABCSimpleBatchMicroservice, ABCPermissionMicroservice,
20    ABCSimpleRetriveMicroservice, ABCSimpleDeleteMicroservice,
21    ABCSimpleSaveMicroservice]
class ABCSimpleBatchMicroservice(abc.ABC, pumpwood_communication.microservice_abc.base.base.PumpWoodMicroServiceBase):
10class ABCSimpleBatchMicroservice(ABC, PumpWoodMicroServiceBase):
11    """Abstract class for batch end-points."""
12
13    @staticmethod
14    def _build_aggregate_url(model_class: str):
15        return "rest/%s/aggregate/" % (model_class.lower(),)
16
17    def aggregate(self, model_class: str, group_by: List[str], agg: dict,
18                  filter_dict: dict = {}, exclude_dict: dict = {},
19                  order_by: List[str] = [], auth_header: dict = None,
20                  limit: int = None) -> pd.DataFrame:
21        """Save a list of objects with one request.
22
23        Args:
24            model_class (str):
25                Model class of the end-point that will be aggregated.
26            group_by (List[str]):
27                List of the fields that will be used on aggregation as
28                group by.
29            agg (dict):
30                A dictionary with dictionary itens as `field` and `function`
31                specifing the field that will be aggregated using a function.
32            filter_dict (dict):
33                Filter that will be applied before the aggregation.
34            exclude_dict (dict):
35                Exclude clause that will be applied before the aggregation.
36            order_by (list):
37                Ordenation acording to grouping elements. It can be used
38                fields created as keys of agg dictinary.
39            auth_header (dict):
40                Authentication header used to impersonation of user.
41            limit (int):
42                Limit number of returned row at aggregation query.
43
44        Returns:
45            Return a DataFrame with aggregation results.
46        """
47        url_str = self._build_aggregate_url(model_class=model_class)
48        data = {
49            'agg': agg, 'group_by': group_by, 'filter_dict': filter_dict,
50            'exclude_dict': exclude_dict, 'order_by': order_by,
51            'limit': limit}
52        return self.request_post(
53            url=url_str, data=data, auth_header=auth_header)

Abstract class for batch end-points.

def aggregate( self, model_class: str, group_by: List[str], agg: dict, filter_dict: dict = {}, exclude_dict: dict = {}, order_by: List[str] = [], auth_header: dict = None, limit: int = None) -> pandas.core.frame.DataFrame:
17    def aggregate(self, model_class: str, group_by: List[str], agg: dict,
18                  filter_dict: dict = {}, exclude_dict: dict = {},
19                  order_by: List[str] = [], auth_header: dict = None,
20                  limit: int = None) -> pd.DataFrame:
21        """Save a list of objects with one request.
22
23        Args:
24            model_class (str):
25                Model class of the end-point that will be aggregated.
26            group_by (List[str]):
27                List of the fields that will be used on aggregation as
28                group by.
29            agg (dict):
30                A dictionary with dictionary itens as `field` and `function`
31                specifing the field that will be aggregated using a function.
32            filter_dict (dict):
33                Filter that will be applied before the aggregation.
34            exclude_dict (dict):
35                Exclude clause that will be applied before the aggregation.
36            order_by (list):
37                Ordenation acording to grouping elements. It can be used
38                fields created as keys of agg dictinary.
39            auth_header (dict):
40                Authentication header used to impersonation of user.
41            limit (int):
42                Limit number of returned row at aggregation query.
43
44        Returns:
45            Return a DataFrame with aggregation results.
46        """
47        url_str = self._build_aggregate_url(model_class=model_class)
48        data = {
49            'agg': agg, 'group_by': group_by, 'filter_dict': filter_dict,
50            'exclude_dict': exclude_dict, 'order_by': order_by,
51            'limit': limit}
52        return self.request_post(
53            url=url_str, data=data, auth_header=auth_header)

Save a list of objects with one request.

Arguments:
  • model_class (str): Model class of the end-point that will be aggregated.
  • group_by (List[str]): List of the fields that will be used on aggregation as group by.
  • agg (dict): A dictionary with dictionary itens as field and function specifing the field that will be aggregated using a function.
  • filter_dict (dict): Filter that will be applied before the aggregation.
  • exclude_dict (dict): Exclude clause that will be applied before the aggregation.
  • order_by (list): Ordenation acording to grouping elements. It can be used fields created as keys of agg dictinary.
  • auth_header (dict): Authentication header used to impersonation of user.
  • limit (int): Limit number of returned row at aggregation query.
Returns:

Return a DataFrame with aggregation results.

class ABCPermissionMicroservice(abc.ABC, pumpwood_communication.microservice_abc.base.base.PumpWoodMicroServiceBase):
 9class ABCPermissionMicroservice(ABC, PumpWoodMicroServiceBase):
10    """Abstract class for permission checking at pumpwood."""
11
12    def check_if_logged(self, auth_header: dict = None) -> bool:
13        """Check if user is logged.
14
15        Args:
16            auth_header (dict): = None
17                AuthHeader to substitute the microservice original at
18                request. If not passed, microservice object auth_header
19                will be used.
20
21        Returns:
22            Return True if auth_header is looged and False if not
23        """
24        try:
25            check = self.request_get(
26                url="rest/registration/check/",
27                auth_header=auth_header)
28        except PumpWoodUnauthorized:
29            return False
30        return check
31
32    def get_user_info(self, auth_header: dict = None) -> dict:
33        """Get user info.
34
35        Args:
36            auth_header (dict): = None
37                AuthHeader to substitute the microservice original at
38                request. If not passed, microservice object auth_header
39                will be used.
40
41        Returns:
42            A serialized user object with information of the logged user.
43        """
44        user_info = self.request_get(
45            url="rest/registration/retrieveauthenticateduser/",
46            auth_header=auth_header)
47        return user_info
48
49    def check_permission(self, model_class: str, end_point: str,
50                         extra_arg: str = None, allow_service_user: str = None,
51                         allow_external: str = None, auth_header: dict = None,
52                         ) -> dict:
53        """Get user info.
54
55        Args:
56            model_class (str):
57                Model class associated to be checked for access.
58            end_point (str):
59                Name of the end-point that will be checked for permission. Ex.:
60                retrieve, save, list, list-without-pag, ...
61            extra_arg (str):
62                Used on some end-points. On action end-point it is reponsible
63                for setting the action associated with the call.
64            allow_service_user: str = None:
65
66            allow_external: str = None:
67
68            auth_header (dict):
69                AuthHeader to substitute the microservice original at
70                request. If not passed, microservice object auth_header
71                will be used.
72
73        Returns:
74            A serialized user object with information of the logged user.
75        """
76        # user_info = self.request_post(
77        #     url="rest/registration/check/",
78        #     payload={
79        #         'end_point': end_point,
80        #         'first_arg': first_arg,
81        #         'second_arg': second_arg,
82        #         'api_config_allow': api_config_allow,
83        #         'api_config_deny': api_config_deny},
84        #     auth_header=auth_header, timeout=self.default_timeout)
85        # return user_info
86        return True

Abstract class for permission checking at pumpwood.

def check_if_logged(self, auth_header: dict = None) -> bool:
12    def check_if_logged(self, auth_header: dict = None) -> bool:
13        """Check if user is logged.
14
15        Args:
16            auth_header (dict): = None
17                AuthHeader to substitute the microservice original at
18                request. If not passed, microservice object auth_header
19                will be used.
20
21        Returns:
22            Return True if auth_header is looged and False if not
23        """
24        try:
25            check = self.request_get(
26                url="rest/registration/check/",
27                auth_header=auth_header)
28        except PumpWoodUnauthorized:
29            return False
30        return check

Check if user is logged.

Arguments:
  • auth_header (dict): = None AuthHeader to substitute the microservice original at request. If not passed, microservice object auth_header will be used.
Returns:

Return True if auth_header is looged and False if not

def get_user_info(self, auth_header: dict = None) -> dict:
32    def get_user_info(self, auth_header: dict = None) -> dict:
33        """Get user info.
34
35        Args:
36            auth_header (dict): = None
37                AuthHeader to substitute the microservice original at
38                request. If not passed, microservice object auth_header
39                will be used.
40
41        Returns:
42            A serialized user object with information of the logged user.
43        """
44        user_info = self.request_get(
45            url="rest/registration/retrieveauthenticateduser/",
46            auth_header=auth_header)
47        return user_info

Get user info.

Arguments:
  • auth_header (dict): = None AuthHeader to substitute the microservice original at request. If not passed, microservice object auth_header will be used.
Returns:

A serialized user object with information of the logged user.

def check_permission( self, model_class: str, end_point: str, extra_arg: str = None, allow_service_user: str = None, allow_external: str = None, auth_header: dict = None) -> dict:
49    def check_permission(self, model_class: str, end_point: str,
50                         extra_arg: str = None, allow_service_user: str = None,
51                         allow_external: str = None, auth_header: dict = None,
52                         ) -> dict:
53        """Get user info.
54
55        Args:
56            model_class (str):
57                Model class associated to be checked for access.
58            end_point (str):
59                Name of the end-point that will be checked for permission. Ex.:
60                retrieve, save, list, list-without-pag, ...
61            extra_arg (str):
62                Used on some end-points. On action end-point it is reponsible
63                for setting the action associated with the call.
64            allow_service_user: str = None:
65
66            allow_external: str = None:
67
68            auth_header (dict):
69                AuthHeader to substitute the microservice original at
70                request. If not passed, microservice object auth_header
71                will be used.
72
73        Returns:
74            A serialized user object with information of the logged user.
75        """
76        # user_info = self.request_post(
77        #     url="rest/registration/check/",
78        #     payload={
79        #         'end_point': end_point,
80        #         'first_arg': first_arg,
81        #         'second_arg': second_arg,
82        #         'api_config_allow': api_config_allow,
83        #         'api_config_deny': api_config_deny},
84        #     auth_header=auth_header, timeout=self.default_timeout)
85        # return user_info
86        return True

Get user info.

Arguments:
  • model_class (str): Model class associated to be checked for access.
  • end_point (str): Name of the end-point that will be checked for permission. Ex.: retrieve, save, list, list-without-pag, ...
  • extra_arg (str): Used on some end-points. On action end-point it is reponsible for setting the action associated with the call.
  • allow_service_user: str = None:
  • allow_external: str = None:
  • auth_header (dict): AuthHeader to substitute the microservice original at request. If not passed, microservice object auth_header will be used.
Returns:

A serialized user object with information of the logged user.

class ABCSimpleRetriveMicroservice(abc.ABC, pumpwood_communication.microservice_abc.base.base.PumpWoodMicroServiceBase):
 12class ABCSimpleRetriveMicroservice(ABC, PumpWoodMicroServiceBase):
 13    """Abstract class for parallel calls at Pumpwood end-points."""
 14
 15    @staticmethod
 16    def _build_list_one_url(model_class, pk):
 17        return "rest/%s/retrieve/%s/" % (model_class.lower(), pk)
 18
 19    def list_one(self, model_class: str, pk: int, fields: list = None,
 20                 default_fields: bool = True, foreign_key_fields: bool = False,
 21                 related_fields: bool = False, auth_header: dict = None,
 22                 use_disk_cache: bool = False,
 23                 disk_cache_expire: int = None) -> dict:
 24        """Retrieve an object using list serializer (simple).
 25
 26        **# DEPRECTED #** It is the same as retrieve using
 27        `default_fields: bool = True`, if possible migrate to retrieve
 28        function.
 29
 30        Args:
 31            model_class:
 32                Model class of the end-point
 33            pk:
 34                Object pk
 35            auth_header:
 36                Auth header to substitute the microservice original
 37                at the request (user impersonation).
 38            fields:
 39                Set the fields to be returned by the list end-point.
 40            default_fields:
 41                Boolean, if true and fields arguments None will return the
 42                default fields set for list by the backend.
 43            foreign_key_fields:
 44                Return forenging key objects. It will return the fk
 45                corresponding object. Ex: `created_by_id` reference to
 46                a user `model_class` the correspondent to User will be
 47                returned at `created_by`.
 48            related_fields:
 49                Return related fields objects. Related field objects are
 50                objects that have a forenging key associated with this
 51                model_class, results will be returned as a list of
 52                dictionaries usually in a field with `_set` at end.
 53                Returning related_fields consume backend resorces, use
 54                carefully.
 55            use_disk_cache (bool):
 56                If set true, get request will use local cache to reduce
 57                the requests to the backend.
 58            disk_cache_expire (int):
 59                Time in seconds to expire the cache, it None it will
 60                use de default set be PumpwoodCache.
 61
 62        Returns:
 63            Return object with the correspondent pk.
 64
 65        Raises:
 66            PumpWoodObjectDoesNotExist:
 67                If pk not found on database.
 68        """
 69        url_str = self._build_list_one_url(model_class, pk)
 70        return self.request_get(
 71            url=url_str, parameters={
 72                "fields": fields, "default_fields": default_fields,
 73                "foreign_key_fields": foreign_key_fields,
 74                "related_fields": related_fields},
 75            auth_header=auth_header, use_disk_cache=use_disk_cache,
 76            disk_cache_expire=disk_cache_expire)
 77
 78    @staticmethod
 79    def _build_retrieve_url(model_class: str, pk: int):
 80        return "rest/%s/retrieve/%s/" % (model_class.lower(), pk)
 81
 82    def retrieve(self, model_class: str, pk: int,
 83                 default_fields: bool = False,
 84                 foreign_key_fields: bool = False,
 85                 related_fields: bool = False,
 86                 fields: list = None,
 87                 auth_header: dict = None,
 88                 use_disk_cache: bool = False,
 89                 disk_cache_expire: int = None) -> dict:
 90        """Retrieve an object from PumpWood.
 91
 92        Function to get object serialized by retrieve end-point
 93        (more detailed data).
 94
 95        Args:
 96            model_class:
 97                Model class of the end-point
 98            pk:
 99                Object pk
100            auth_header:
101                Auth header to substitute the microservice original
102                at the request (user impersonation).
103            fields:
104                Set the fields to be returned by the list end-point.
105            default_fields:
106                Boolean, if true and fields arguments None will return the
107                default fields set for list by the backend.
108            foreign_key_fields:
109                Return forenging key objects. It will return the fk
110                corresponding object. Ex: `created_by_id` reference to
111                a user `model_class` the correspondent to User will be
112                returned at `created_by`.
113            related_fields:
114                Return related fields objects. Related field objects are
115                objects that have a forenging key associated with this
116                model_class, results will be returned as a list of
117                dictionaries usually in a field with `_set` at end.
118                Returning related_fields consume backend resorces, use
119                carefully.
120            use_disk_cache (bool):
121                If set true, get request will use local cache to reduce
122                the requests to the backend.
123            disk_cache_expire (int):
124                Time in seconds to expire the cache, it None it will
125                use de default set be PumpwoodCache.
126
127        Returns:
128            Return object with the correspondent pk.
129
130        Raises:
131            PumpWoodObjectDoesNotExist:
132                If pk not found on database.
133        """
134        url_str = self._build_retrieve_url(model_class=model_class, pk=pk)
135        return self.request_get(
136            url=url_str, parameters={
137                "fields": fields, "default_fields": default_fields,
138                "foreign_key_fields": foreign_key_fields,
139                "related_fields": related_fields},
140            auth_header=auth_header, use_disk_cache=use_disk_cache,
141            disk_cache_expire=disk_cache_expire)
142
143    @staticmethod
144    def _build_retrieve_file_url(model_class: str, pk: int):
145        return "rest/%s/retrieve-file/%s/" % (model_class.lower(), pk)
146
147    def retrieve_file(self, model_class: str, pk: int, file_field: str,
148                      auth_header: dict = None, save_file: bool = True,
149                      save_path: str = "./", file_name: str = None,
150                      if_exists: str = "fail") -> any:
151        """Retrieve a file from PumpWood.
152
153        This function will retrieve file as a single request, depending on the
154        size of the files it would be preferred to use streaming end-point.
155
156        Args:
157            model_class:
158                Class of the model to retrieve file.
159            pk:
160                Pk of the object associeted file.
161            file_field:
162                Field of the file to be downloaded.
163            auth_header:
164                Dictionary containing the auth header.
165            save_file:
166                If data is to be saved as file or return get
167                response.
168            save_path:
169                Path of the directory to save file.
170            file_name:
171                Name of the file, if None it will have same name as
172                saved in PumpWood.
173            if_exists:
174                Values must be in {'fail', 'change_name', 'overwrite', 'skip'}.
175                Set what to do if there is a file with same name. Skip
176                will not download file if there is already with same
177                os.path.join(save_path, file_name), file_name must be set
178                for skip argument.
179            auth_header:
180                Auth header to substitute the microservice original
181                at the request (user impersonation).
182
183        Returns:
184            May return the file name if save_file=True; If false will return
185            a dictonary with keys `filename` with original file name and
186            `content` with binary data of file content.
187
188        Raises:
189            PumpWoodForbidden:
190                'storage_object attribute not set for view, file operations
191                are disable'. This indicates that storage for this backend
192                was not configured, so it is not possible to make storage
193                operations,
194            PumpWoodForbidden:
195                'file_field must be set on self.file_fields dictionary'. This
196                indicates that the `file_field` parameter is not listed as
197                a file field on the backend.
198            PumpWoodObjectDoesNotExist:
199                'field [{}] not found or null at object'. This indicates that
200                the file field requested is not present on object fields.
201            PumpWoodObjectDoesNotExist:
202                'Object not found in storage [{}]'. This indicates that the
203                file associated with file_field is not avaiable at the
204                storage. This should not ocorrur, it might have a manual
205                update at the model_class table or manual removal/rename of
206                files on storage.
207        """
208        if if_exists not in ["fail", "change_name", "overwrite", "skip"]:
209            raise PumpWoodException(
210                "if_exists must be in ['fail', 'change_name', 'overwrite', "
211                "'skip']")
212
213        if file_name is not None and if_exists == 'skip':
214            file_path = os.path.join(save_path, file_name)
215            is_file_already = os.path.isfile(file_path)
216            if is_file_already:
217                print("skiping file already exists: ", file_path)
218                return file_path
219
220        url_str = self._build_retrieve_file_url(model_class=model_class, pk=pk)
221        file_response = self.request_get(
222            url=url_str, parameters={"file-field": file_field},
223            auth_header=auth_header)
224        if not save_file:
225            return file_response
226
227        if not os.path.exists(save_path):
228            raise PumpWoodException(
229                "Path to save retrieved file [{}] does not exist".format(
230                    save_path))
231
232        file_name = secure_filename(file_name or file_response["filename"])
233        file_path = os.path.join(save_path, file_name)
234        is_file_already = os.path.isfile(file_path)
235        if is_file_already:
236            if if_exists == "change_name":
237                filename, file_extension = os.path.splitext(file_path)
238                too_many_tries = True
239                for i in range(10):
240                    new_path = "{filename}__{count}{extension}".format(
241                        filename=filename, count=i,
242                        extension=file_extension)
243                    if not os.path.isfile(new_path):
244                        file_path = new_path
245                        too_many_tries = False
246                        break
247                if too_many_tries:
248                    raise PumpWoodException(
249                        ("Too many tries to find a not used file name." +
250                         " file_path[{}]".format(file_path)))
251
252            elif if_exists == "fail":
253                raise PumpWoodException(
254                    ("if_exists set as 'fail' and there is a file with same" +
255                     "name. file_path [{}]").format(file_path))
256
257        with open(file_path, "wb") as file:
258            file.write(file_response["content"])
259        return file_path
260
261    @staticmethod
262    def _build_retrieve_file_straming_url(model_class: str, pk: int):
263        return "rest/%s/retrieve-file-streaming/%s/" % (
264            model_class.lower(), pk)
265
266    def retrieve_streaming_file(self, model_class: str, pk: int,
267                                file_field: str, file_name: str,
268                                auth_header: dict = None,
269                                save_path: str = "./",
270                                if_exists: str = "fail"):
271        """Retrieve a file from PumpWood using streaming to retrieve content.
272
273        This funcion uses file streaming to retrieve file content, it should be
274        prefered when dealing with large (bigger than 10Mb) files transfer.
275        Using this end-point the file is not loaded on backend memory content
276        is transfered by chucks that are read at the storage and transfered
277        to user.
278
279        It will necessarily save the content as a file, there is not the
280        possibility of retrieving the content directly from request.
281
282        Args:
283            model_class:
284                Class of the model to retrieve file.
285            pk:
286                Pk of the object associeted file.
287            file_field:
288                Field of the file to be downloaded.
289            auth_header:
290                Dictionary containing the auth header.
291            save_path:
292                Path of the directory to save file.
293            file_name:
294                Name of the file, if None it will have same name as
295                saved in PumpWood.
296            if_exists:
297                Values must be in {'fail', 'change_name', 'overwrite'}.
298                Set what to do if there is a file with same name.
299            auth_header:
300                Auth header to substitute the microservice original
301                at the request (user impersonation).
302
303        Returns:
304            Returns the file path that recived the file content.
305
306        Raises:
307            PumpWoodForbidden:
308                'storage_object attribute not set for view, file operations
309                are disable'. This indicates that storage for this backend
310                was not configured, so it is not possible to make storage
311                operations,
312            PumpWoodForbidden:
313                'file_field must be set on self.file_fields dictionary'. This
314                indicates that the `file_field` parameter is not listed as
315                a file field on the backend.
316            PumpWoodObjectDoesNotExist:
317                'field [{}] not found or null at object'. This indicates that
318                the file field requested is not present on object fields.
319            PumpWoodObjectDoesNotExist:
320                'Object not found in storage [{}]'. This indicates that the
321                file associated with file_field is not avaiable at the
322                storage. This should not ocorrur, it might have a manual
323                update at the model_class table or manual removal/rename of
324                files on storage.
325        """
326        request_header = self._check__auth_header(auth_header)
327
328        # begin Args check
329        if if_exists not in ["fail", "change_name", "overwrite"]:
330            raise PumpWoodException(
331                "if_exists must be in ['fail', 'change_name', 'overwrite']")
332
333        if not os.path.exists(save_path):
334            raise PumpWoodException(
335                "Path to save retrieved file [{}] does not exist".format(
336                    save_path))
337        # end Args check
338
339        file_path = os.path.join(save_path, file_name)
340        if os.path.isfile(file_path) and if_exists == "change_name":
341            filename, file_extension = os.path.splitext(file_path)
342            too_many_tries = False
343            for i in range(10):
344                new_path = "{filename}__{count}{extension}".format(
345                    filename=filename, count=i,
346                    extension=file_extension)
347                if not os.path.isfile(new_path):
348                    file_path = new_path
349                    too_many_tries = True
350                    break
351            if not too_many_tries:
352                raise PumpWoodException(
353                    ("Too many tries to find a not used file name." +
354                     " file_path[{}]".format(file_path)))
355
356        if os.path.isfile(file_path) and if_exists == "fail":
357            raise PumpWoodException(
358                ("if_exists set as 'fail' and there is a file with same" +
359                 "name. file_path [{}]").format(file_path))
360
361        url_str = self._build_retrieve_file_straming_url(
362            model_class=model_class, pk=pk)
363
364        get_url = self.server_url + url_str
365        with requests.get(
366                get_url, verify=self.verify_ssl, headers=request_header,
367                params={"file-field": file_field},
368                timeout=self.default_timeout) as response:
369            self.error_handler(response)
370            with open(file_path, 'wb') as f:
371                for chunk in response.iter_content(chunk_size=8192):
372                    if chunk:
373                        f.write(chunk)
374        return file_path

Abstract class for parallel calls at Pumpwood end-points.

def list_one( self, model_class: str, pk: int, fields: list = None, default_fields: bool = True, foreign_key_fields: bool = False, related_fields: bool = False, auth_header: dict = None, use_disk_cache: bool = False, disk_cache_expire: int = None) -> dict:
19    def list_one(self, model_class: str, pk: int, fields: list = None,
20                 default_fields: bool = True, foreign_key_fields: bool = False,
21                 related_fields: bool = False, auth_header: dict = None,
22                 use_disk_cache: bool = False,
23                 disk_cache_expire: int = None) -> dict:
24        """Retrieve an object using list serializer (simple).
25
26        **# DEPRECTED #** It is the same as retrieve using
27        `default_fields: bool = True`, if possible migrate to retrieve
28        function.
29
30        Args:
31            model_class:
32                Model class of the end-point
33            pk:
34                Object pk
35            auth_header:
36                Auth header to substitute the microservice original
37                at the request (user impersonation).
38            fields:
39                Set the fields to be returned by the list end-point.
40            default_fields:
41                Boolean, if true and fields arguments None will return the
42                default fields set for list by the backend.
43            foreign_key_fields:
44                Return forenging key objects. It will return the fk
45                corresponding object. Ex: `created_by_id` reference to
46                a user `model_class` the correspondent to User will be
47                returned at `created_by`.
48            related_fields:
49                Return related fields objects. Related field objects are
50                objects that have a forenging key associated with this
51                model_class, results will be returned as a list of
52                dictionaries usually in a field with `_set` at end.
53                Returning related_fields consume backend resorces, use
54                carefully.
55            use_disk_cache (bool):
56                If set true, get request will use local cache to reduce
57                the requests to the backend.
58            disk_cache_expire (int):
59                Time in seconds to expire the cache, it None it will
60                use de default set be PumpwoodCache.
61
62        Returns:
63            Return object with the correspondent pk.
64
65        Raises:
66            PumpWoodObjectDoesNotExist:
67                If pk not found on database.
68        """
69        url_str = self._build_list_one_url(model_class, pk)
70        return self.request_get(
71            url=url_str, parameters={
72                "fields": fields, "default_fields": default_fields,
73                "foreign_key_fields": foreign_key_fields,
74                "related_fields": related_fields},
75            auth_header=auth_header, use_disk_cache=use_disk_cache,
76            disk_cache_expire=disk_cache_expire)

Retrieve an object using list serializer (simple).

# DEPRECTED # It is the same as retrieve using default_fields: bool = True, if possible migrate to retrieve function.

Arguments:
  • model_class: Model class of the end-point
  • pk: Object pk
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
  • fields: Set the fields to be returned by the list end-point.
  • default_fields: Boolean, if true and fields arguments None will return the default fields set for list by the backend.
  • foreign_key_fields: Return forenging key objects. It will return the fk corresponding object. Ex: created_by_id reference to a user model_class the correspondent to User will be returned at created_by.
  • related_fields: Return related fields objects. Related field objects are objects that have a forenging key associated with this model_class, results will be returned as a list of dictionaries usually in a field with _set at end. Returning related_fields consume backend resorces, use carefully.
  • use_disk_cache (bool): If set true, get request will use local cache to reduce the requests to the backend.
  • disk_cache_expire (int): Time in seconds to expire the cache, it None it will use de default set be PumpwoodCache.
Returns:

Return object with the correspondent pk.

Raises:
  • PumpWoodObjectDoesNotExist: If pk not found on database.
def retrieve( self, model_class: str, pk: int, default_fields: bool = False, foreign_key_fields: bool = False, related_fields: bool = False, fields: list = None, auth_header: dict = None, use_disk_cache: bool = False, disk_cache_expire: int = None) -> dict:
 82    def retrieve(self, model_class: str, pk: int,
 83                 default_fields: bool = False,
 84                 foreign_key_fields: bool = False,
 85                 related_fields: bool = False,
 86                 fields: list = None,
 87                 auth_header: dict = None,
 88                 use_disk_cache: bool = False,
 89                 disk_cache_expire: int = None) -> dict:
 90        """Retrieve an object from PumpWood.
 91
 92        Function to get object serialized by retrieve end-point
 93        (more detailed data).
 94
 95        Args:
 96            model_class:
 97                Model class of the end-point
 98            pk:
 99                Object pk
100            auth_header:
101                Auth header to substitute the microservice original
102                at the request (user impersonation).
103            fields:
104                Set the fields to be returned by the list end-point.
105            default_fields:
106                Boolean, if true and fields arguments None will return the
107                default fields set for list by the backend.
108            foreign_key_fields:
109                Return forenging key objects. It will return the fk
110                corresponding object. Ex: `created_by_id` reference to
111                a user `model_class` the correspondent to User will be
112                returned at `created_by`.
113            related_fields:
114                Return related fields objects. Related field objects are
115                objects that have a forenging key associated with this
116                model_class, results will be returned as a list of
117                dictionaries usually in a field with `_set` at end.
118                Returning related_fields consume backend resorces, use
119                carefully.
120            use_disk_cache (bool):
121                If set true, get request will use local cache to reduce
122                the requests to the backend.
123            disk_cache_expire (int):
124                Time in seconds to expire the cache, it None it will
125                use de default set be PumpwoodCache.
126
127        Returns:
128            Return object with the correspondent pk.
129
130        Raises:
131            PumpWoodObjectDoesNotExist:
132                If pk not found on database.
133        """
134        url_str = self._build_retrieve_url(model_class=model_class, pk=pk)
135        return self.request_get(
136            url=url_str, parameters={
137                "fields": fields, "default_fields": default_fields,
138                "foreign_key_fields": foreign_key_fields,
139                "related_fields": related_fields},
140            auth_header=auth_header, use_disk_cache=use_disk_cache,
141            disk_cache_expire=disk_cache_expire)

Retrieve an object from PumpWood.

Function to get object serialized by retrieve end-point (more detailed data).

Arguments:
  • model_class: Model class of the end-point
  • pk: Object pk
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
  • fields: Set the fields to be returned by the list end-point.
  • default_fields: Boolean, if true and fields arguments None will return the default fields set for list by the backend.
  • foreign_key_fields: Return forenging key objects. It will return the fk corresponding object. Ex: created_by_id reference to a user model_class the correspondent to User will be returned at created_by.
  • related_fields: Return related fields objects. Related field objects are objects that have a forenging key associated with this model_class, results will be returned as a list of dictionaries usually in a field with _set at end. Returning related_fields consume backend resorces, use carefully.
  • use_disk_cache (bool): If set true, get request will use local cache to reduce the requests to the backend.
  • disk_cache_expire (int): Time in seconds to expire the cache, it None it will use de default set be PumpwoodCache.
Returns:

Return object with the correspondent pk.

Raises:
  • PumpWoodObjectDoesNotExist: If pk not found on database.
def retrieve_file( self, model_class: str, pk: int, file_field: str, auth_header: dict = None, save_file: bool = True, save_path: str = './', file_name: str = None, if_exists: str = 'fail') -> <built-in function any>:
147    def retrieve_file(self, model_class: str, pk: int, file_field: str,
148                      auth_header: dict = None, save_file: bool = True,
149                      save_path: str = "./", file_name: str = None,
150                      if_exists: str = "fail") -> any:
151        """Retrieve a file from PumpWood.
152
153        This function will retrieve file as a single request, depending on the
154        size of the files it would be preferred to use streaming end-point.
155
156        Args:
157            model_class:
158                Class of the model to retrieve file.
159            pk:
160                Pk of the object associeted file.
161            file_field:
162                Field of the file to be downloaded.
163            auth_header:
164                Dictionary containing the auth header.
165            save_file:
166                If data is to be saved as file or return get
167                response.
168            save_path:
169                Path of the directory to save file.
170            file_name:
171                Name of the file, if None it will have same name as
172                saved in PumpWood.
173            if_exists:
174                Values must be in {'fail', 'change_name', 'overwrite', 'skip'}.
175                Set what to do if there is a file with same name. Skip
176                will not download file if there is already with same
177                os.path.join(save_path, file_name), file_name must be set
178                for skip argument.
179            auth_header:
180                Auth header to substitute the microservice original
181                at the request (user impersonation).
182
183        Returns:
184            May return the file name if save_file=True; If false will return
185            a dictonary with keys `filename` with original file name and
186            `content` with binary data of file content.
187
188        Raises:
189            PumpWoodForbidden:
190                'storage_object attribute not set for view, file operations
191                are disable'. This indicates that storage for this backend
192                was not configured, so it is not possible to make storage
193                operations,
194            PumpWoodForbidden:
195                'file_field must be set on self.file_fields dictionary'. This
196                indicates that the `file_field` parameter is not listed as
197                a file field on the backend.
198            PumpWoodObjectDoesNotExist:
199                'field [{}] not found or null at object'. This indicates that
200                the file field requested is not present on object fields.
201            PumpWoodObjectDoesNotExist:
202                'Object not found in storage [{}]'. This indicates that the
203                file associated with file_field is not avaiable at the
204                storage. This should not ocorrur, it might have a manual
205                update at the model_class table or manual removal/rename of
206                files on storage.
207        """
208        if if_exists not in ["fail", "change_name", "overwrite", "skip"]:
209            raise PumpWoodException(
210                "if_exists must be in ['fail', 'change_name', 'overwrite', "
211                "'skip']")
212
213        if file_name is not None and if_exists == 'skip':
214            file_path = os.path.join(save_path, file_name)
215            is_file_already = os.path.isfile(file_path)
216            if is_file_already:
217                print("skiping file already exists: ", file_path)
218                return file_path
219
220        url_str = self._build_retrieve_file_url(model_class=model_class, pk=pk)
221        file_response = self.request_get(
222            url=url_str, parameters={"file-field": file_field},
223            auth_header=auth_header)
224        if not save_file:
225            return file_response
226
227        if not os.path.exists(save_path):
228            raise PumpWoodException(
229                "Path to save retrieved file [{}] does not exist".format(
230                    save_path))
231
232        file_name = secure_filename(file_name or file_response["filename"])
233        file_path = os.path.join(save_path, file_name)
234        is_file_already = os.path.isfile(file_path)
235        if is_file_already:
236            if if_exists == "change_name":
237                filename, file_extension = os.path.splitext(file_path)
238                too_many_tries = True
239                for i in range(10):
240                    new_path = "{filename}__{count}{extension}".format(
241                        filename=filename, count=i,
242                        extension=file_extension)
243                    if not os.path.isfile(new_path):
244                        file_path = new_path
245                        too_many_tries = False
246                        break
247                if too_many_tries:
248                    raise PumpWoodException(
249                        ("Too many tries to find a not used file name." +
250                         " file_path[{}]".format(file_path)))
251
252            elif if_exists == "fail":
253                raise PumpWoodException(
254                    ("if_exists set as 'fail' and there is a file with same" +
255                     "name. file_path [{}]").format(file_path))
256
257        with open(file_path, "wb") as file:
258            file.write(file_response["content"])
259        return file_path

Retrieve a file from PumpWood.

This function will retrieve file as a single request, depending on the size of the files it would be preferred to use streaming end-point.

Arguments:
  • model_class: Class of the model to retrieve file.
  • pk: Pk of the object associeted file.
  • file_field: Field of the file to be downloaded.
  • auth_header: Dictionary containing the auth header.
  • save_file: If data is to be saved as file or return get response.
  • save_path: Path of the directory to save file.
  • file_name: Name of the file, if None it will have same name as saved in PumpWood.
  • if_exists: Values must be in {'fail', 'change_name', 'overwrite', 'skip'}. Set what to do if there is a file with same name. Skip will not download file if there is already with same os.path.join(save_path, file_name), file_name must be set for skip argument.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
Returns:

May return the file name if save_file=True; If false will return a dictonary with keys filename with original file name and content with binary data of file content.

Raises:
  • PumpWoodForbidden: 'storage_object attribute not set for view, file operations are disable'. This indicates that storage for this backend was not configured, so it is not possible to make storage operations,
  • PumpWoodForbidden: 'file_field must be set on self.file_fields dictionary'. This indicates that the file_field parameter is not listed as a file field on the backend.
  • PumpWoodObjectDoesNotExist: 'field [{}] not found or null at object'. This indicates that the file field requested is not present on object fields.
  • PumpWoodObjectDoesNotExist: 'Object not found in storage [{}]'. This indicates that the file associated with file_field is not avaiable at the storage. This should not ocorrur, it might have a manual update at the model_class table or manual removal/rename of files on storage.
def retrieve_streaming_file( self, model_class: str, pk: int, file_field: str, file_name: str, auth_header: dict = None, save_path: str = './', if_exists: str = 'fail'):
266    def retrieve_streaming_file(self, model_class: str, pk: int,
267                                file_field: str, file_name: str,
268                                auth_header: dict = None,
269                                save_path: str = "./",
270                                if_exists: str = "fail"):
271        """Retrieve a file from PumpWood using streaming to retrieve content.
272
273        This funcion uses file streaming to retrieve file content, it should be
274        prefered when dealing with large (bigger than 10Mb) files transfer.
275        Using this end-point the file is not loaded on backend memory content
276        is transfered by chucks that are read at the storage and transfered
277        to user.
278
279        It will necessarily save the content as a file, there is not the
280        possibility of retrieving the content directly from request.
281
282        Args:
283            model_class:
284                Class of the model to retrieve file.
285            pk:
286                Pk of the object associeted file.
287            file_field:
288                Field of the file to be downloaded.
289            auth_header:
290                Dictionary containing the auth header.
291            save_path:
292                Path of the directory to save file.
293            file_name:
294                Name of the file, if None it will have same name as
295                saved in PumpWood.
296            if_exists:
297                Values must be in {'fail', 'change_name', 'overwrite'}.
298                Set what to do if there is a file with same name.
299            auth_header:
300                Auth header to substitute the microservice original
301                at the request (user impersonation).
302
303        Returns:
304            Returns the file path that recived the file content.
305
306        Raises:
307            PumpWoodForbidden:
308                'storage_object attribute not set for view, file operations
309                are disable'. This indicates that storage for this backend
310                was not configured, so it is not possible to make storage
311                operations,
312            PumpWoodForbidden:
313                'file_field must be set on self.file_fields dictionary'. This
314                indicates that the `file_field` parameter is not listed as
315                a file field on the backend.
316            PumpWoodObjectDoesNotExist:
317                'field [{}] not found or null at object'. This indicates that
318                the file field requested is not present on object fields.
319            PumpWoodObjectDoesNotExist:
320                'Object not found in storage [{}]'. This indicates that the
321                file associated with file_field is not avaiable at the
322                storage. This should not ocorrur, it might have a manual
323                update at the model_class table or manual removal/rename of
324                files on storage.
325        """
326        request_header = self._check__auth_header(auth_header)
327
328        # begin Args check
329        if if_exists not in ["fail", "change_name", "overwrite"]:
330            raise PumpWoodException(
331                "if_exists must be in ['fail', 'change_name', 'overwrite']")
332
333        if not os.path.exists(save_path):
334            raise PumpWoodException(
335                "Path to save retrieved file [{}] does not exist".format(
336                    save_path))
337        # end Args check
338
339        file_path = os.path.join(save_path, file_name)
340        if os.path.isfile(file_path) and if_exists == "change_name":
341            filename, file_extension = os.path.splitext(file_path)
342            too_many_tries = False
343            for i in range(10):
344                new_path = "{filename}__{count}{extension}".format(
345                    filename=filename, count=i,
346                    extension=file_extension)
347                if not os.path.isfile(new_path):
348                    file_path = new_path
349                    too_many_tries = True
350                    break
351            if not too_many_tries:
352                raise PumpWoodException(
353                    ("Too many tries to find a not used file name." +
354                     " file_path[{}]".format(file_path)))
355
356        if os.path.isfile(file_path) and if_exists == "fail":
357            raise PumpWoodException(
358                ("if_exists set as 'fail' and there is a file with same" +
359                 "name. file_path [{}]").format(file_path))
360
361        url_str = self._build_retrieve_file_straming_url(
362            model_class=model_class, pk=pk)
363
364        get_url = self.server_url + url_str
365        with requests.get(
366                get_url, verify=self.verify_ssl, headers=request_header,
367                params={"file-field": file_field},
368                timeout=self.default_timeout) as response:
369            self.error_handler(response)
370            with open(file_path, 'wb') as f:
371                for chunk in response.iter_content(chunk_size=8192):
372                    if chunk:
373                        f.write(chunk)
374        return file_path

Retrieve a file from PumpWood using streaming to retrieve content.

This funcion uses file streaming to retrieve file content, it should be prefered when dealing with large (bigger than 10Mb) files transfer. Using this end-point the file is not loaded on backend memory content is transfered by chucks that are read at the storage and transfered to user.

It will necessarily save the content as a file, there is not the possibility of retrieving the content directly from request.

Arguments:
  • model_class: Class of the model to retrieve file.
  • pk: Pk of the object associeted file.
  • file_field: Field of the file to be downloaded.
  • auth_header: Dictionary containing the auth header.
  • save_path: Path of the directory to save file.
  • file_name: Name of the file, if None it will have same name as saved in PumpWood.
  • if_exists: Values must be in {'fail', 'change_name', 'overwrite'}. Set what to do if there is a file with same name.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
Returns:

Returns the file path that recived the file content.

Raises:
  • PumpWoodForbidden: 'storage_object attribute not set for view, file operations are disable'. This indicates that storage for this backend was not configured, so it is not possible to make storage operations,
  • PumpWoodForbidden: 'file_field must be set on self.file_fields dictionary'. This indicates that the file_field parameter is not listed as a file field on the backend.
  • PumpWoodObjectDoesNotExist: 'field [{}] not found or null at object'. This indicates that the file field requested is not present on object fields.
  • PumpWoodObjectDoesNotExist: 'Object not found in storage [{}]'. This indicates that the file associated with file_field is not avaiable at the storage. This should not ocorrur, it might have a manual update at the model_class table or manual removal/rename of files on storage.
class ABCSimpleDeleteMicroservice(abc.ABC, pumpwood_communication.microservice_abc.base.base.PumpWoodMicroServiceBase):
  8class ABCSimpleDeleteMicroservice(ABC, PumpWoodMicroServiceBase):
  9    """Abstract class for calls at Pumpwood delete end-points."""
 10
 11    @staticmethod
 12    def _build_delete_request_url(model_class, pk):
 13        return "rest/%s/delete/%s/" % (model_class.lower(), pk)
 14
 15    def delete(self, model_class: str, pk: int,
 16               auth_header: dict = None) -> dict:
 17        """Send delete request to a PumpWood object.
 18
 19        Delete (or whatever the PumpWood system have been implemented) the
 20        object with the specified pk.
 21
 22        Args:
 23            model_class:
 24                Model class to delete the object
 25            pk:
 26                Object pk to be deleted (or whatever the PumpWood system
 27                have been implemented). Some model_class with 'deleted' field
 28                does not remove the entry, it will flag deleted=True at this
 29                cases. Model class with delete=True will be not retrieved
 30                by default on `list` and `list_without_pag` end-points.
 31            auth_header:
 32                Auth header to substitute the microservice original
 33                at the request (user impersonation).
 34
 35        Returns:
 36            Returns delete object.
 37
 38        Raises:
 39            PumpWoodObjectDoesNotExist:
 40                'Requested object {model_class}[{pk}] not found.' This
 41                indicates that the pk was not found in database.
 42        """
 43        url_str = self._build_delete_request_url(model_class, pk)
 44        return self.request_delete(url=url_str, auth_header=auth_header)
 45
 46    @staticmethod
 47    def _build_remove_file_field(model_class, pk):
 48        return "rest/%s/remove-file-field/%s/" % (model_class.lower(), pk)
 49
 50    def delete_file(self, model_class: str, pk: int, file_field: str,
 51                    auth_header: dict = None) -> bool:
 52        """Send delete request to a PumpWood object.
 53
 54        Delete (or whatever the PumpWood system have been implemented) the
 55        object with the specified pk.
 56
 57        At previous versions this function was `remove_file_field`. An alias
 58        is created for backward compatibility.
 59
 60        Args:
 61            model_class:
 62                Model class to delete the object
 63            pk:
 64                Object pk to be deleted (or whatever the PumpWood system
 65                have been implemented).
 66            file_field:
 67                File field to be removed from storage.
 68            auth_header:
 69                Auth header to substitute the microservice original
 70                at the request (user impersonation).
 71
 72        Returns:
 73            Return True is file was successful removed
 74
 75        Raises:
 76            PumpWoodForbidden:
 77                'storage_object attribute not set for view, file operations
 78                are disable'. This indicates that storage_object is not
 79                associated with view, not allowing it to make storage
 80                operations.
 81            PumpWoodForbidden:
 82                'file_field must be set on self.file_fields dictionary.'.
 83                This indicates that the `file_field` was not set as a file
 84                field on the backend.
 85            PumpWoodObjectDoesNotExist:
 86                'File does not exist. File field [{}] is set as None'.
 87                This indicates that the object does not exists on storage,
 88                it should not occur. It might have been some manual update
 89                of the database or at the storage level.
 90        """
 91        url_str = self._build_remove_file_field(model_class, pk)
 92        return self.request_delete(
 93            url=url_str, auth_header=auth_header,
 94            parameters={"file-field": file_field})
 95
 96    # Create an alias for backward compatibility.
 97    remove_file_field = delete_file
 98
 99    @staticmethod
100    def _build_delete_many_request_url(model_class):
101        return "rest/%s/delete/" % (model_class.lower(), )
102
103    def delete_many(self, model_class: str, filter_dict: dict = {},
104                    exclude_dict: dict = {}, auth_header: dict = None) -> bool:
105        """Remove many objects using query to retrict removal.
106
107        CAUTION It is not possible to undo this operation, model_class
108        this deleted field will be removed from database when using this
109        end-point, different from using delete end-point.
110
111        Args:
112            model_class:
113                Model class to delete the object
114            filter_dict:
115                Dictionary to make filter query.
116            exclude_dict:
117                Dictionary to make exclude query.
118            auth_header:
119                Auth header to substitute the microservice original
120                at the request (user impersonation).
121
122        Returns:
123            True if delete is ok.
124
125        Raises:
126            PumpWoodObjectDeleteException:
127                Raises error if there is any error when commiting object
128                deletion on database.
129        """
130        url_str = self._build_delete_many_request_url(model_class)
131        return self.request_post(
132            url=url_str,
133            data={'filter_dict': filter_dict, 'exclude_dict': exclude_dict},
134            auth_header=auth_header)

Abstract class for calls at Pumpwood delete end-points.

def delete(self, model_class: str, pk: int, auth_header: dict = None) -> dict:
15    def delete(self, model_class: str, pk: int,
16               auth_header: dict = None) -> dict:
17        """Send delete request to a PumpWood object.
18
19        Delete (or whatever the PumpWood system have been implemented) the
20        object with the specified pk.
21
22        Args:
23            model_class:
24                Model class to delete the object
25            pk:
26                Object pk to be deleted (or whatever the PumpWood system
27                have been implemented). Some model_class with 'deleted' field
28                does not remove the entry, it will flag deleted=True at this
29                cases. Model class with delete=True will be not retrieved
30                by default on `list` and `list_without_pag` end-points.
31            auth_header:
32                Auth header to substitute the microservice original
33                at the request (user impersonation).
34
35        Returns:
36            Returns delete object.
37
38        Raises:
39            PumpWoodObjectDoesNotExist:
40                'Requested object {model_class}[{pk}] not found.' This
41                indicates that the pk was not found in database.
42        """
43        url_str = self._build_delete_request_url(model_class, pk)
44        return self.request_delete(url=url_str, auth_header=auth_header)

Send delete request to a PumpWood object.

Delete (or whatever the PumpWood system have been implemented) the object with the specified pk.

Arguments:
  • model_class: Model class to delete the object
  • pk: Object pk to be deleted (or whatever the PumpWood system have been implemented). Some model_class with 'deleted' field does not remove the entry, it will flag deleted=True at this cases. Model class with delete=True will be not retrieved by default on list and list_without_pag end-points.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
Returns:

Returns delete object.

Raises:
  • PumpWoodObjectDoesNotExist: 'Requested object {model_class}[{pk}] not found.' This indicates that the pk was not found in database.
def delete_file( self, model_class: str, pk: int, file_field: str, auth_header: dict = None) -> bool:
50    def delete_file(self, model_class: str, pk: int, file_field: str,
51                    auth_header: dict = None) -> bool:
52        """Send delete request to a PumpWood object.
53
54        Delete (or whatever the PumpWood system have been implemented) the
55        object with the specified pk.
56
57        At previous versions this function was `remove_file_field`. An alias
58        is created for backward compatibility.
59
60        Args:
61            model_class:
62                Model class to delete the object
63            pk:
64                Object pk to be deleted (or whatever the PumpWood system
65                have been implemented).
66            file_field:
67                File field to be removed from storage.
68            auth_header:
69                Auth header to substitute the microservice original
70                at the request (user impersonation).
71
72        Returns:
73            Return True is file was successful removed
74
75        Raises:
76            PumpWoodForbidden:
77                'storage_object attribute not set for view, file operations
78                are disable'. This indicates that storage_object is not
79                associated with view, not allowing it to make storage
80                operations.
81            PumpWoodForbidden:
82                'file_field must be set on self.file_fields dictionary.'.
83                This indicates that the `file_field` was not set as a file
84                field on the backend.
85            PumpWoodObjectDoesNotExist:
86                'File does not exist. File field [{}] is set as None'.
87                This indicates that the object does not exists on storage,
88                it should not occur. It might have been some manual update
89                of the database or at the storage level.
90        """
91        url_str = self._build_remove_file_field(model_class, pk)
92        return self.request_delete(
93            url=url_str, auth_header=auth_header,
94            parameters={"file-field": file_field})

Send delete request to a PumpWood object.

Delete (or whatever the PumpWood system have been implemented) the object with the specified pk.

At previous versions this function was remove_file_field. An alias is created for backward compatibility.

Arguments:
  • model_class: Model class to delete the object
  • pk: Object pk to be deleted (or whatever the PumpWood system have been implemented).
  • file_field: File field to be removed from storage.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
Returns:

Return True is file was successful removed

Raises:
  • PumpWoodForbidden: 'storage_object attribute not set for view, file operations are disable'. This indicates that storage_object is not associated with view, not allowing it to make storage operations.
  • PumpWoodForbidden: 'file_field must be set on self.file_fields dictionary.'. This indicates that the file_field was not set as a file field on the backend.
  • PumpWoodObjectDoesNotExist: 'File does not exist. File field [{}] is set as None'. This indicates that the object does not exists on storage, it should not occur. It might have been some manual update of the database or at the storage level.
def remove_file_field( self, model_class: str, pk: int, file_field: str, auth_header: dict = None) -> bool:
50    def delete_file(self, model_class: str, pk: int, file_field: str,
51                    auth_header: dict = None) -> bool:
52        """Send delete request to a PumpWood object.
53
54        Delete (or whatever the PumpWood system have been implemented) the
55        object with the specified pk.
56
57        At previous versions this function was `remove_file_field`. An alias
58        is created for backward compatibility.
59
60        Args:
61            model_class:
62                Model class to delete the object
63            pk:
64                Object pk to be deleted (or whatever the PumpWood system
65                have been implemented).
66            file_field:
67                File field to be removed from storage.
68            auth_header:
69                Auth header to substitute the microservice original
70                at the request (user impersonation).
71
72        Returns:
73            Return True is file was successful removed
74
75        Raises:
76            PumpWoodForbidden:
77                'storage_object attribute not set for view, file operations
78                are disable'. This indicates that storage_object is not
79                associated with view, not allowing it to make storage
80                operations.
81            PumpWoodForbidden:
82                'file_field must be set on self.file_fields dictionary.'.
83                This indicates that the `file_field` was not set as a file
84                field on the backend.
85            PumpWoodObjectDoesNotExist:
86                'File does not exist. File field [{}] is set as None'.
87                This indicates that the object does not exists on storage,
88                it should not occur. It might have been some manual update
89                of the database or at the storage level.
90        """
91        url_str = self._build_remove_file_field(model_class, pk)
92        return self.request_delete(
93            url=url_str, auth_header=auth_header,
94            parameters={"file-field": file_field})

Send delete request to a PumpWood object.

Delete (or whatever the PumpWood system have been implemented) the object with the specified pk.

At previous versions this function was remove_file_field. An alias is created for backward compatibility.

Arguments:
  • model_class: Model class to delete the object
  • pk: Object pk to be deleted (or whatever the PumpWood system have been implemented).
  • file_field: File field to be removed from storage.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
Returns:

Return True is file was successful removed

Raises:
  • PumpWoodForbidden: 'storage_object attribute not set for view, file operations are disable'. This indicates that storage_object is not associated with view, not allowing it to make storage operations.
  • PumpWoodForbidden: 'file_field must be set on self.file_fields dictionary.'. This indicates that the file_field was not set as a file field on the backend.
  • PumpWoodObjectDoesNotExist: 'File does not exist. File field [{}] is set as None'. This indicates that the object does not exists on storage, it should not occur. It might have been some manual update of the database or at the storage level.
def delete_many( self, model_class: str, filter_dict: dict = {}, exclude_dict: dict = {}, auth_header: dict = None) -> bool:
103    def delete_many(self, model_class: str, filter_dict: dict = {},
104                    exclude_dict: dict = {}, auth_header: dict = None) -> bool:
105        """Remove many objects using query to retrict removal.
106
107        CAUTION It is not possible to undo this operation, model_class
108        this deleted field will be removed from database when using this
109        end-point, different from using delete end-point.
110
111        Args:
112            model_class:
113                Model class to delete the object
114            filter_dict:
115                Dictionary to make filter query.
116            exclude_dict:
117                Dictionary to make exclude query.
118            auth_header:
119                Auth header to substitute the microservice original
120                at the request (user impersonation).
121
122        Returns:
123            True if delete is ok.
124
125        Raises:
126            PumpWoodObjectDeleteException:
127                Raises error if there is any error when commiting object
128                deletion on database.
129        """
130        url_str = self._build_delete_many_request_url(model_class)
131        return self.request_post(
132            url=url_str,
133            data={'filter_dict': filter_dict, 'exclude_dict': exclude_dict},
134            auth_header=auth_header)

Remove many objects using query to retrict removal.

CAUTION It is not possible to undo this operation, model_class this deleted field will be removed from database when using this end-point, different from using delete end-point.

Arguments:
  • model_class: Model class to delete the object
  • filter_dict: Dictionary to make filter query.
  • exclude_dict: Dictionary to make exclude query.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
Returns:

True if delete is ok.

Raises:
  • PumpWoodObjectDeleteException: Raises error if there is any error when commiting object deletion on database.
class ABCSimpleSaveMicroservice(abc.ABC, pumpwood_communication.microservice_abc.base.base.PumpWoodMicroServiceBase):
 12class ABCSimpleSaveMicroservice(ABC, PumpWoodMicroServiceBase):
 13    """Abstract class for parallel calls at Pumpwood end-points."""
 14
 15    @staticmethod
 16    def _build_save_url(model_class):
 17        return "rest/%s/save/" % (model_class.lower())
 18
 19    def save(self, obj_dict, files: dict = None, auth_header: dict = None,
 20             fields: list = None, default_fields: bool = False,
 21             foreign_key_fields: bool = False,
 22             related_fields: bool = False) -> dict:
 23        """Save or Update a new object.
 24
 25        Function to save or update a new model_class object. If obj_dict['pk']
 26        is None or not defined a new object will be created. The obj
 27        model class is defided at obj_dict['model_class'] and if not defined an
 28        PumpWoodObjectSavingException will be raised.
 29
 30        If files argument is set, request will be transfered using a multipart
 31        request file files mapping file key to file field on backend.
 32
 33        Args:
 34            obj_dict:
 35                Model data dictionary. It must have 'model_class'
 36                key and if 'pk' key is not defined a new object will
 37                be created, else object with pk will be updated.
 38            files:
 39                A dictionary of files to be added to as a multi-part
 40                post request. File must be passed as a file object with read
 41                bytes.
 42            auth_header:
 43                Auth header to substitute the microservice original
 44                at the request (user impersonation).
 45            fields:
 46                Set the fields to be returned by the list end-point.
 47            default_fields:
 48                Boolean, if true and fields arguments None will return the
 49                default fields set for list by the backend.
 50            foreign_key_fields:
 51                Return forenging key objects. It will return the fk
 52                corresponding object. Ex: `created_by_id` reference to
 53                a user `model_class` the correspondent to User will be
 54                returned at `created_by`.
 55            related_fields:
 56                Return related fields objects. Related field objects are
 57                objects that have a forenging key associated with this
 58                model_class, results will be returned as a list of
 59                dictionaries usually in a field with `_set` at end.
 60                Returning related_fields consume backend resorces, use
 61                carefully.
 62
 63        Returns:
 64            Return updated/created object data.
 65
 66        Raises:
 67            PumpWoodObjectSavingException:
 68                'To save an object obj_dict must have model_class defined.'
 69                This indicates that the obj_dict must have key `model_class`
 70                indicating model class of the object that will be
 71                updated/created.
 72            PumpWoodObjectDoesNotExist:
 73                'Requested object {model_class}[{pk}] not found.'. This
 74                indicates that the pk passed on obj_dict was not found on
 75                backend database.
 76            PumpWoodIntegrityError:
 77                Error raised when IntegrityError is raised on database. This
 78                might ocorrur when saving objects that does not respect
 79                uniqueness restriction on database or other IntegrityError
 80                like removal of foreign keys with related data.
 81            PumpWoodObjectSavingException:
 82                Return error at object validation on de-serializing the
 83                object or files with unexpected extensions.
 84        """
 85        model_class = obj_dict.get('model_class')
 86        if model_class is None:
 87            raise PumpWoodObjectSavingException(
 88                'To save an object obj_dict must have model_class defined.')
 89
 90        url_str = self._build_save_url(model_class)
 91        parameters = {
 92            "fields": fields, "default_fields": default_fields,
 93            "foreign_key_fields": foreign_key_fields,
 94            "related_fields": related_fields}
 95        return self.request_post(
 96            url=url_str, data=obj_dict, parameters=parameters, files=files,
 97            auth_header=auth_header)
 98
 99    @staticmethod
100    def _build_save_streaming_file_url(model_class, pk):
101        return "rest/{model_class}/save-file-streaming/{pk}/".format(
102            model_class=model_class.lower(), pk=pk)
103
104    def save_streaming_file(self, model_class: str, pk: int, file_field: str,
105                            file: io.BufferedReader, file_name: str = None,
106                            auth_header: dict = None,
107                            fields: list = None, default_fields: bool = False,
108                            foreign_key_fields: bool = False,
109                            related_fields: bool = False) -> str:
110        """Stream file to PumpWood.
111
112        Use streaming to transfer a file content to Pumpwood storage, this
113        end-point is prefered when transmiting files bigger than 10Mb. It
114        is necessary to have the object created before the file transfer.
115
116        Args:
117            model_class:
118                Model class of the object.
119            pk:
120                pk of the object.
121            file_field:
122                File field that will receive file stream.
123            file:
124                File to upload as a file object with read bytes option.
125            auth_header:
126                Auth header to substitute the microservice original
127                at the request (user impersonation).
128            file_name:
129                Name of the file, if not set it will be saved as
130                {pk}__{file_field}.{extension at permited extension}
131            fields:
132                Set the fields to be returned by the list end-point.
133            default_fields:
134                Boolean, if true and fields arguments None will return the
135                default fields set for list by the backend.
136            foreign_key_fields:
137                Return forenging key objects. It will return the fk
138                corresponding object. Ex: `created_by_id` reference to
139                a user `model_class` the correspondent to User will be
140                returned at `created_by`.
141            related_fields:
142                Return related fields objects. Related field objects are
143                objects that have a forenging key associated with this
144                model_class, results will be returned as a list of
145                dictionaries usually in a field with `_set` at end.
146                Returning related_fields consume backend resorces, use
147                carefully.
148
149        Returns:
150            Return the file name associated with data at the storage.
151
152        Raises:
153            PumpWoodForbidden:
154                'file_field must be set on self.file_fields dictionary'. This
155                indicates that the `file_field` passed is not associated
156                with a file field on the backend.
157            PumpWoodException:
158                'Saved bytes in streaming [{}] differ from file bytes [{}].'.
159                This indicates that there was an error when transfering data
160                to storage, the file bytes and transfered bytes does not
161                match.
162        """
163        request_header = self._check__auth_header(auth_header=auth_header)
164        request_header["Content-Type"] = "application/octet-stream"
165        post_url = self.server_url + self._build_save_streaming_file_url(
166            model_class=model_class, pk=pk)
167
168        parameters = {
169            "fields": fields, "default_fields": default_fields,
170            "foreign_key_fields": foreign_key_fields,
171            "related_fields": related_fields, "file_field": file_field}
172        if file_name is not None:
173            parameters["file_name"] = file_name
174
175        response = requests.post(
176            url=post_url, data=file, params=parameters,
177            verify=self.verify_ssl, headers=request_header, stream=True,
178            timeout=self.default_timeout)
179
180        file_last_bite = file.tell()
181        self.error_handler(response)
182        json_response = self.angular_json(response)
183
184        if file_last_bite != json_response["bytes_uploaded"]:
185            template = (
186                "Saved bytes in streaming [{}] differ from file " +
187                "bites [{}].")
188            raise PumpWoodException(
189                    template.format(
190                        json_response["bytes_uploaded"], file_last_bite))
191        return json_response["file_path"]

Abstract class for parallel calls at Pumpwood end-points.

def save( self, obj_dict, files: dict = None, auth_header: dict = None, fields: list = None, default_fields: bool = False, foreign_key_fields: bool = False, related_fields: bool = False) -> dict:
19    def save(self, obj_dict, files: dict = None, auth_header: dict = None,
20             fields: list = None, default_fields: bool = False,
21             foreign_key_fields: bool = False,
22             related_fields: bool = False) -> dict:
23        """Save or Update a new object.
24
25        Function to save or update a new model_class object. If obj_dict['pk']
26        is None or not defined a new object will be created. The obj
27        model class is defided at obj_dict['model_class'] and if not defined an
28        PumpWoodObjectSavingException will be raised.
29
30        If files argument is set, request will be transfered using a multipart
31        request file files mapping file key to file field on backend.
32
33        Args:
34            obj_dict:
35                Model data dictionary. It must have 'model_class'
36                key and if 'pk' key is not defined a new object will
37                be created, else object with pk will be updated.
38            files:
39                A dictionary of files to be added to as a multi-part
40                post request. File must be passed as a file object with read
41                bytes.
42            auth_header:
43                Auth header to substitute the microservice original
44                at the request (user impersonation).
45            fields:
46                Set the fields to be returned by the list end-point.
47            default_fields:
48                Boolean, if true and fields arguments None will return the
49                default fields set for list by the backend.
50            foreign_key_fields:
51                Return forenging key objects. It will return the fk
52                corresponding object. Ex: `created_by_id` reference to
53                a user `model_class` the correspondent to User will be
54                returned at `created_by`.
55            related_fields:
56                Return related fields objects. Related field objects are
57                objects that have a forenging key associated with this
58                model_class, results will be returned as a list of
59                dictionaries usually in a field with `_set` at end.
60                Returning related_fields consume backend resorces, use
61                carefully.
62
63        Returns:
64            Return updated/created object data.
65
66        Raises:
67            PumpWoodObjectSavingException:
68                'To save an object obj_dict must have model_class defined.'
69                This indicates that the obj_dict must have key `model_class`
70                indicating model class of the object that will be
71                updated/created.
72            PumpWoodObjectDoesNotExist:
73                'Requested object {model_class}[{pk}] not found.'. This
74                indicates that the pk passed on obj_dict was not found on
75                backend database.
76            PumpWoodIntegrityError:
77                Error raised when IntegrityError is raised on database. This
78                might ocorrur when saving objects that does not respect
79                uniqueness restriction on database or other IntegrityError
80                like removal of foreign keys with related data.
81            PumpWoodObjectSavingException:
82                Return error at object validation on de-serializing the
83                object or files with unexpected extensions.
84        """
85        model_class = obj_dict.get('model_class')
86        if model_class is None:
87            raise PumpWoodObjectSavingException(
88                'To save an object obj_dict must have model_class defined.')
89
90        url_str = self._build_save_url(model_class)
91        parameters = {
92            "fields": fields, "default_fields": default_fields,
93            "foreign_key_fields": foreign_key_fields,
94            "related_fields": related_fields}
95        return self.request_post(
96            url=url_str, data=obj_dict, parameters=parameters, files=files,
97            auth_header=auth_header)

Save or Update a new object.

Function to save or update a new model_class object. If obj_dict['pk'] is None or not defined a new object will be created. The obj model class is defided at obj_dict['model_class'] and if not defined an PumpWoodObjectSavingException will be raised.

If files argument is set, request will be transfered using a multipart request file files mapping file key to file field on backend.

Arguments:
  • obj_dict: Model data dictionary. It must have 'model_class' key and if 'pk' key is not defined a new object will be created, else object with pk will be updated.
  • files: A dictionary of files to be added to as a multi-part post request. File must be passed as a file object with read bytes.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
  • fields: Set the fields to be returned by the list end-point.
  • default_fields: Boolean, if true and fields arguments None will return the default fields set for list by the backend.
  • foreign_key_fields: Return forenging key objects. It will return the fk corresponding object. Ex: created_by_id reference to a user model_class the correspondent to User will be returned at created_by.
  • related_fields: Return related fields objects. Related field objects are objects that have a forenging key associated with this model_class, results will be returned as a list of dictionaries usually in a field with _set at end. Returning related_fields consume backend resorces, use carefully.
Returns:

Return updated/created object data.

Raises:
  • PumpWoodObjectSavingException: 'To save an object obj_dict must have model_class defined.' This indicates that the obj_dict must have key model_class indicating model class of the object that will be updated/created.
  • PumpWoodObjectDoesNotExist: 'Requested object {model_class}[{pk}] not found.'. This indicates that the pk passed on obj_dict was not found on backend database.
  • PumpWoodIntegrityError: Error raised when IntegrityError is raised on database. This might ocorrur when saving objects that does not respect uniqueness restriction on database or other IntegrityError like removal of foreign keys with related data.
  • PumpWoodObjectSavingException: Return error at object validation on de-serializing the object or files with unexpected extensions.
def save_streaming_file( self, model_class: str, pk: int, file_field: str, file: _io.BufferedReader, file_name: str = None, auth_header: dict = None, fields: list = None, default_fields: bool = False, foreign_key_fields: bool = False, related_fields: bool = False) -> str:
104    def save_streaming_file(self, model_class: str, pk: int, file_field: str,
105                            file: io.BufferedReader, file_name: str = None,
106                            auth_header: dict = None,
107                            fields: list = None, default_fields: bool = False,
108                            foreign_key_fields: bool = False,
109                            related_fields: bool = False) -> str:
110        """Stream file to PumpWood.
111
112        Use streaming to transfer a file content to Pumpwood storage, this
113        end-point is prefered when transmiting files bigger than 10Mb. It
114        is necessary to have the object created before the file transfer.
115
116        Args:
117            model_class:
118                Model class of the object.
119            pk:
120                pk of the object.
121            file_field:
122                File field that will receive file stream.
123            file:
124                File to upload as a file object with read bytes option.
125            auth_header:
126                Auth header to substitute the microservice original
127                at the request (user impersonation).
128            file_name:
129                Name of the file, if not set it will be saved as
130                {pk}__{file_field}.{extension at permited extension}
131            fields:
132                Set the fields to be returned by the list end-point.
133            default_fields:
134                Boolean, if true and fields arguments None will return the
135                default fields set for list by the backend.
136            foreign_key_fields:
137                Return forenging key objects. It will return the fk
138                corresponding object. Ex: `created_by_id` reference to
139                a user `model_class` the correspondent to User will be
140                returned at `created_by`.
141            related_fields:
142                Return related fields objects. Related field objects are
143                objects that have a forenging key associated with this
144                model_class, results will be returned as a list of
145                dictionaries usually in a field with `_set` at end.
146                Returning related_fields consume backend resorces, use
147                carefully.
148
149        Returns:
150            Return the file name associated with data at the storage.
151
152        Raises:
153            PumpWoodForbidden:
154                'file_field must be set on self.file_fields dictionary'. This
155                indicates that the `file_field` passed is not associated
156                with a file field on the backend.
157            PumpWoodException:
158                'Saved bytes in streaming [{}] differ from file bytes [{}].'.
159                This indicates that there was an error when transfering data
160                to storage, the file bytes and transfered bytes does not
161                match.
162        """
163        request_header = self._check__auth_header(auth_header=auth_header)
164        request_header["Content-Type"] = "application/octet-stream"
165        post_url = self.server_url + self._build_save_streaming_file_url(
166            model_class=model_class, pk=pk)
167
168        parameters = {
169            "fields": fields, "default_fields": default_fields,
170            "foreign_key_fields": foreign_key_fields,
171            "related_fields": related_fields, "file_field": file_field}
172        if file_name is not None:
173            parameters["file_name"] = file_name
174
175        response = requests.post(
176            url=post_url, data=file, params=parameters,
177            verify=self.verify_ssl, headers=request_header, stream=True,
178            timeout=self.default_timeout)
179
180        file_last_bite = file.tell()
181        self.error_handler(response)
182        json_response = self.angular_json(response)
183
184        if file_last_bite != json_response["bytes_uploaded"]:
185            template = (
186                "Saved bytes in streaming [{}] differ from file " +
187                "bites [{}].")
188            raise PumpWoodException(
189                    template.format(
190                        json_response["bytes_uploaded"], file_last_bite))
191        return json_response["file_path"]

Stream file to PumpWood.

Use streaming to transfer a file content to Pumpwood storage, this end-point is prefered when transmiting files bigger than 10Mb. It is necessary to have the object created before the file transfer.

Arguments:
  • model_class: Model class of the object.
  • pk: pk of the object.
  • file_field: File field that will receive file stream.
  • file: File to upload as a file object with read bytes option.
  • auth_header: Auth header to substitute the microservice original at the request (user impersonation).
  • file_name: Name of the file, if not set it will be saved as {pk}__{file_field}.{extension at permited extension}
  • fields: Set the fields to be returned by the list end-point.
  • default_fields: Boolean, if true and fields arguments None will return the default fields set for list by the backend.
  • foreign_key_fields: Return forenging key objects. It will return the fk corresponding object. Ex: created_by_id reference to a user model_class the correspondent to User will be returned at created_by.
  • related_fields: Return related fields objects. Related field objects are objects that have a forenging key associated with this model_class, results will be returned as a list of dictionaries usually in a field with _set at end. Returning related_fields consume backend resorces, use carefully.
Returns:

Return the file name associated with data at the storage.

Raises:
  • PumpWoodForbidden: 'file_field must be set on self.file_fields dictionary'. This indicates that the file_field passed is not associated with a file field on the backend.
  • PumpWoodException: 'Saved bytes in streaming [{}] differ from file bytes [{}].'. This indicates that there was an error when transfering data to storage, the file bytes and transfered bytes does not match.