Downloading a PDF version of your dashboard is great and is very easy to do via the Looker UI. In this article, we make use of the Looker API (and the python SDK client) to do this.
Authenticate into the Looker API.
import looker
base_url = 'https://learn.looker.com:19999/api/3.0'
client_id = ''
client_secret = ''
# instantiate Auth API
unauthenticated_client = looker.ApiClient(base_url)
unauthenticated_authApi = looker.ApiAuthApi(unauthenticated=_client)
# authenticate client
token = unauthenticated_authApi.login(client_id=client_id, client_secret=client_secret)
client = looker.ApiClient(base_url, 'Authorization', 'token ' + token.access_token)
Create a new task to render the desired dashboard to a PDF using the create_dashboard_render_task endpoint. Please take note of the format of the dashboard_filters, which is a string and expects the filters in query URL format. e.g.: "My Filter=New York&My Other Filter=Brooklyn"
.
# instantiate render task API
renderTask = looker.RenderTaskApi(api_client=client)
height = 842
width = 595
output_format = 'pdf'
dashboard_id = 241
body = {
"dashboard_style": "tiled",
"dashboard_filters": {
"Created Date=12 months ago for 12 months"
}
}
# fire a render task and get its ID
task_response = renderTask.create_dashboard_render_task(dashboard_id, output_format, body, width, height)
task_id = task_response.id
###Step 3:
Use the render_task(id) endpoint to confirm the the render task has finished. Consequently, we can get the produced document using the render_task_results endpoint as follows:
# get the produced results
results = renderTask.render_task_results(task_id, _preload_content = False)
data = results.data
# write it to PDF
with open('output.pdf', 'wb+') as f:
f.write(data)
PS: the _preload_content = false
parameter is used to tell Python not to parse the body of the response as text.
I am not able to locate any Looker Python SDK which has a valid reference to looker.ApiClient.
Can you pass on the location where to download this this Looker Python SDK?
(edit)
Perhaps I misunderstood. Looks like this should be generated based off this article
The Looker API is a collection of “RESTful” operations that enables you to tap into the power of the Looker data platform in your own applications. The Looker API can be invoked using plain old HTTP(S) requests. Any development tool, language, or application that can make HTTP requests and ingest JSON responses should be able to use the Looker API. Web geeks who live and breathe HTTP and/or AJAX XHR will feel at home using just the “raw” Looker API HTTP URL endpoints. GET, POST, PUT, PATCH, DEL…
I’m not all that familiar with swagger, but it’s confusing to me why this client would have to be generated. Especially considering all the dependencies required in order to get it done.
For now I’m going to attempt to interact with the API directly via http, instead.
Hi evan,
As you surmised, we don’t currently have a ready-made Python client SDK package to access the Looker API available for download. You can generate a Python client SDK from the Looker API swagger metadata, as covered in the article you linked.
This does introduce some additional steps that you, our customers, have to go through to get started using the Looker API, and for that I apologize. The swagger codegen step does allow a wide variety of programming languages to access the Looker REST API without any additional effort from us.
Some folks who are comfortable making HTTP REST requests skip the whole SDK step and just write their code to make HTTP requests to the Looker API URLs directly. The downside to that is you don’t get the data types built for you, and you have to think in terms of HTTP requests all the time. The Swagger generated client-SDKs for the Looker API offer the convenience of accessing the Looker API like a function call library so you don’t have to get down and dirty with HTTP.
Providing pre-packaged Looker client SDK downloads is high on my personal wish list, but until I can find a couple of free weekends I’m not likely to make much progress on this front. 😒
If/when we do offer pre-packaged client SDKs for the Looker API, it will definitely be announced in an article here on this forum. Watch this space! 😉
Sincerely,
-Danny
Can this be done with the Ruby SDK?
@mikeghen1 Yes, the Looker client SDK for Ruby can download PDFs. https://rubygems.org/gems/looker-sdk
-Danny
Thanks, I found the gem already.
I don’t see any documentation on how to use the SDK to do that. Is there documentation for how to use that gem to do things other than manage users?
Hi @mikeghen1,
Here is our API doc on how to create a render task for a dashboard. But, I have played with this before and here is an example where I create a .png file for a look
#!/usr/bin/env ruby
require 'looker-sdk'
sdk = LookerSDK::Client.new(
:client_id => ENV['API_ID'],
:client_secret => ENV['API_KEY'],
:api_endpoint => "https://self-signed.looker.com:19999/api/3.0",
:connection_options => {:ssl => {:verify => false}}
)
png = sdk.create_look_render_task(164, "png", {}, {:query => {:width => 1000, :height => 1000}})
id = png[:id]
until sdk.render_task(id)[:status] == 'success' do
end
results = sdk.render_task_results(id)
File.open('look.png', 'w') { |file| file.write(results) }
As you can see, we first have to create a render task. Then, we have to wait until that task is completed which is what we do here:
until sdk.render_task(id)[:status] == 'success' do
end
Then, once it returns true, we get the results, store it in a variable, and save it to a file. Let me know if this helps! And of course, you will have to make some changes to your ruby script.
Cheers,
Vincent
Thanks Vincent!
I followed the instructions to generate the PDF with Python and got this error:
Traceback (most recent call last):
File "generate_pdf.py", line 38, in <module>
results = renderTask.render_task_results(task_id, _preload_content=False)
File "/Users/mikeghen/Documents/REDACTED/render_task_api.py", line 561, in render_task_results
" to method render_task_results" % key
TypeError: Got an unexpected keyword argument '_preload_content' to method render_task_results
I generated my Python looker package using the instructions provided here: Generating Client SDKs for the Looker API. (Doing that was a pain 😩 I don’t understand why Looker only provides a Ruby SDK) I confirmed it worked with a few other API calls before I tried to do this PDF, render task thing.
When I just remove _preload_content
I get:
Traceback (most recent call last):
File "generate_pdf.py", line 46, in <module>
data = results.data
AttributeError: 'str' object has no attribute 'data'
Looks like if I just pass results
rather than results.data
this works out OK without _preload_content
:
results = renderTask.render_task_results(task_id)
# write it to PDF
with open('output.pdf', 'wb+') as f:
f.write(results)
I also got an error when trying to supply a _preload_content
argument to render_task_results
.
In order to get PDF downloads working using the Swagger-generated Python SDK, I had to do the following:
Using Python 3.x you’ll see these line in the Swagger-generated rest.py file:
168 # In the python 3, the response.data is bytes.
169 # we need to decode it to string.
170 if sys.version_info > (3,):
171 r.data = r.data.decode('utf8')
You’ll need to do something about that when downloading the PDF results, or else your API client will try to convert it to text.
My solution was to add a decode
parameter to the RESTClientObject.request method, setting the default value to True
, so now the decode condition looks like this:
153 # In the python 3, the response.data is bytes.
154 # we need to decode it to string.
155 if sys.version_info > (3,) and decode:
156 r.data = r.data.decode('utf8')
I made similar updates to the wrapped calls to the REST client in api_client.py
.
You need to make sure that you bypass deserialization of the data in the __call_api method in api_client.py
:
146 # deserialize response data
147 if decode:
148 if response_type:
149 deserialized_data = self.deserialize(response_data, response_type)
150 else:
151 deserialized_data = None
152 else:
153 deserialized_data = response_data.data
Finally in apis/render_task_api.py
, you can update the api call like this:
609 response = self.api_client.call_api(resource_path, 'GET',
610 path_params,
611 query_params,
612 header_params,
613 body=body_params,
614 post_params=form_params,
615 files=local_var_files,
616 response_type='str',
617 auth_settings=auth_settings,
618 decode=False,
619 callback=params.get('callback'))
Here’s a gist that includes the affected files: https://gist.github.com/mpatek/316cccf6ec15721c8f60343e3b5deed7
Note: if width and height parameters there are wrong, the PDF may render super funky
Are we going to support Expand Tables as part of API , That is a great option to have if we are generating large number of PDF’s.
If we fetch PNG from look, how will look gets refreshed automatically without opening it ?
I want to generate PNG every 2 hours
Hi Guys,
There is any way to pass parameters to be used by the report data source, to return dynamic results, depending on that parameters?
I have a report configured with a datasource that receives parameters, that will be used as parameters in a DB SP call.
In the Looker API documentation, for the download pdf, I did not see nothing related with this.
Can anyone help me?
Many thanks