demisto / demisto-py

Demisto Client for Python
Apache License 2.0
70 stars 41 forks source link

TypeError: a bytes-like object is required, not 'str' in `download_file` function. #117

Closed guin0x closed 11 months ago

guin0x commented 1 year ago

Description

When using the api_instance.download_file() function I get the following error: TypeError: a bytes-like object is required, not 'str'

However, according to the docs, the input of download_file should be a string.

The full error trace is:

TypeError                                 Traceback (most recent call last)
Cell In[13], line 1
----> 1 api_instance.download_file(entryid = incidents_csv)

File ~/.local/lib/python3.10/site-packages/demisto_client/demisto_api/api/default_api.py:1792, in DefaultApi.download_file(self, entryid, **kwargs)
   1790     return self.download_file_with_http_info(entryid, **kwargs)  # noqa: E501
   1791 else:
-> 1792     (data) = self.download_file_with_http_info(entryid, **kwargs)  # noqa: E501
   1793     return data

File ~/.local/lib/python3.10/site-packages/demisto_client/demisto_api/api/default_api.py:1856, in DefaultApi.download_file_with_http_info(self, entryid, **kwargs)
   1853 # Authentication setting
   1854 auth_settings = ['api_key', 'csrf_token', 'x-xdr-auth-id']  # noqa: E501
-> 1856 return self.api_client.call_api(
   1857     '/entry/download/{entryid}', 'GET',
   1858     path_params,
   1859     query_params,
   1860     header_params,
   1861     body=body_params,
   1862     post_params=form_params,
   1863     files=local_var_files,
   1864     response_type='file',  # noqa: E501
   1865     auth_settings=auth_settings,
   1866     async_req=params.get('async_req'),
   1867     _return_http_data_only=params.get('_return_http_data_only'),
   1868     _preload_content=params.get('_preload_content', True),
   1869     _request_timeout=params.get('_request_timeout'),
   1870     collection_formats=collection_formats)

File ~/.local/lib/python3.10/site-packages/demisto_client/demisto_api/api_client.py:331, in ApiClient.call_api(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, async_req, _return_http_data_only, collection_formats, _preload_content, _request_timeout)
    294 """Makes the HTTP request (synchronous) and returns deserialized data.
    295 
    296 To make an async request, set the async_req parameter.
   (...)
    328     then the method will return the response directly.
    329 """
    330 if not async_req:
--> 331     return self.__call_api(resource_path, method,
    332                            path_params, query_params, header_params,
    333                            body, post_params, files,
    334                            response_type, auth_settings,
    335                            _return_http_data_only, collection_formats,
    336                            _preload_content, _request_timeout)
    337 else:
    338     thread = self.pool.apply_async(self.__call_api, (resource_path,
    339                                    method, path_params, query_params,
    340                                    header_params, body,
   (...)
    344                                    collection_formats,
    345                                    _preload_content, _request_timeout))

File ~/.local/lib/python3.10/site-packages/demisto_client/demisto_api/api_client.py:171, in ApiClient.__call_api(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)
    168 if _preload_content:
    169     # deserialize response data
    170     if response_type:
--> 171         return_data = self.deserialize(response_data, response_type)
    172     else:
    173         return_data = None

File ~/.local/lib/python3.10/site-packages/demisto_client/demisto_api/api_client.py:235, in ApiClient.deserialize(self, response, response_type)
    232 # handle file downloading
    233 # save response body into a tmp file and return the instance
    234 if response_type == "file":
--> 235     return self.__deserialize_file(response)
    237 # fetch data from response object
    238 try:

File ~/.local/lib/python3.10/site-packages/demisto_client/demisto_api/api_client.py:543, in ApiClient.__deserialize_file(self, response)
    540     path = os.path.join(os.path.dirname(path), filename)
    542 with open(path, "wb") as f:
--> 543     f.write(response.data)
    545 return path

TypeError: a bytes-like object is required, not 'str'

To Reproduce Steps to reproduce the behavior:

import demisto_client.demisto_api
from demisto_client.demisto_api.rest import ApiException
from pprint import pprint

api_key = 'XXX'
base_url = 'XXX'

api_instance = demisto_client.configure(base_url=base_url, api_key=api_key, verify_ssl=False)
filter = demisto_client.demisto_api.SearchIncidentsData()
inc_filter = demisto_client.demisto_api.IncidentFilter()
inc_filter.query='status: Active'
filter.filter = inc_filter

update_data_batch = demisto_client.demisto_api.UpdateDataBatch()
update_data_batch.filter = inc_filter

incidents_csv = api_instance.export_incidents_to_csv_batch(update_data_batch = update_data_batch)
api_instance.download_file(entryid = incidents_csv)

Expected behavior I would expect to download the .csv file with the incidents I want.

DeanArbel commented 1 year ago

This issue is being tracked internally at https://jira-hq.paloaltonetworks.local/browse/CIAC-8348. We'll post an update here once it's handled.

MosheEichler commented 11 months ago

Hey @guin0x the issue fixed, can you please confirm?

guin0x commented 11 months ago

I'm still facing the same issue. Maybe I'm doing something wrong?

I'm still doing the same as I mentioned before, and I get the same error (TypeError: a bytes-like object is required, not 'str') in the last line api_instance.download_file(entryid = incidents_csv).

Below the entire code.

import demisto_client.demisto_api
from demisto_client.demisto_api.rest import ApiException
from pprint import pprint

api_key = 'XXX'
base_url = 'XXX'

api_instance = demisto_client.configure(base_url=base_url, api_key=api_key, verify_ssl=False)
filter = demisto_client.demisto_api.SearchIncidentsData()
inc_filter = demisto_client.demisto_api.IncidentFilter()
inc_filter.query='status: Active'
filter.filter = inc_filter

update_data_batch = demisto_client.demisto_api.UpdateDataBatch()
update_data_batch.filter = inc_filter

incidents_csv = api_instance.export_incidents_to_csv_batch(update_data_batch = update_data_batch)
api_instance.download_file(entryid = incidents_csv)
MosheEichler commented 11 months ago

@guin0x Hey Please update the demisto-py version to the latest (3.2.12) And test the following code:

import demisto_client.demisto_api

host = '<your host>'
api_key = '<your api-key>'

api_instance = demisto_client.configure(base_url=host, api_key=api_key)
inc_filter = demisto_client.demisto_api.IncidentFilter()
inc_filter.query = 'status: "Active"'

update_data_batch = demisto_client.demisto_api.UpdateDataBatch(filter=inc_filter, all=True, columns=['id', 'name', 'status'])
api_response = api_instance.export_incidents_to_csv_batch(update_data_batch=update_data_batch)
print(api_response)
guin0x commented 11 months ago

hi @MosheEichler,

I upgraded demisto-py to 3.2.12 and the issue seems to be resolved.

Please note that, originally, running the code you proposed in your previous answer wouldn't raise any errors since the error was related to the download_file() function, and not with the export_incidents_to_csv_batch().

Nonetheless, now no error was raised. Thank you :)

I'm wondering though, for example, in your example above, api_response would be the name of a .csv file; then I'm trying to use the download_file() function to download that .csv file, but then if I try:

api_instance.download_file(entryid = api_response), I get something like /tmp/tmpdxj6q24x

did I misunderstand how to use download_file() and export_incidents_to_csv_batch()?

MosheEichler commented 11 months ago

The download_file function does not expect a file name as a parameter, but an etryId, which can be found in the warroom For example:

Screenshot 2023-09-26 at 16 49 14
guin0x commented 11 months ago

ahh... great, thanks a lot! I still have a few questions I'll park them here:

1) How can I download the .csv that was exported with export_incidents_to_csv_batch()? 2) If I use the download_file() to download some incident that I got the ID from the war room, I still get as an output some path so some tmp; 3) I have also tried using the get_incident_as_csv but it didn't work..

So far, the best solution to download all the incidents is with search_incidents and then write it to some file, I'm just trying to find any alternative to download a bunch of incidents, that's why I started looking into the download_file function.. could you maybe point me somewhere I can find this info?

Thank you.

MosheEichler commented 11 months ago

Hey @guin0x

  1. export_incidents_to_csv_batch() just export the incidents to a csv file in order to download this file to your computer you should use the get_incident_as_csv() function. something like this:
    
    import demisto_client

api_key = host =

api_instance = demisto_client.configure(base_url=host, api_key=api_key) inc_filter = demisto_client.demisto_api.IncidentFilter() inc_filter.query = 'status: "Active"'

update_data_batch = demisto_client.demisto_api.UpdateDataBatch(filter=inc_filter, all=True, columns=['id', 'name', 'status'])

csv_id = api_instance.export_incidents_to_csv_batch(update_data_batch=update_data_batch) api_response = api_instance.get_incident_as_csv(csv_id) print(api_response) # this is the path to the downloaded file on your computer.


2. The `download_file()` function is not related to an incident, this function is for downloading files form the war room to your computer by giving the **`entry_id`** of the file.
3. See the example above how I used the function it works for me.

Please contact your customer success representative if you have any further questions