tableau / server-client-python

A Python library for the Tableau Server REST API
https://tableau.github.io/server-client-python/
MIT License
655 stars 420 forks source link

AttributeError: 'NoneType' object has no attribute 'id' #1363

Closed naresh251 closed 5 months ago

naresh251 commented 5 months ago

Describe the bug A clear and concise description of what the bug is.

Versions Details of your environment, including:

To Reproduce Steps to reproduce the behavior. Please include a code snippet where possible.

# Name of the data source in tableau
datasource = sys.argv[1]

tableau_auth = tsc.PersonalAccessTokenAuth(
    token_name=personal_access_token_name,
    personal_access_token=personal_access_token_secret,
    site_id=site
)
server = tsc.Server(tableau_server, use_server_version=True)
server.auth.sign_in(tableau_auth)

# Get datasource id from datasource name
req_option = tsc.RequestOptions(pagesize=1000)
req_option.filter.update([tsc.Filter(tsc.RequestOptions.Field.Name, tsc.RequestOptions.Operator.Equals, datasource)])
all_datasources = list(tsc.Pager(server.datasources, req_option))

datasource_id = all_datasources[0].id

# Get 1000 tasks and then filter for only extract tasks under the datasource id of interest
# I don't believe you can filter tasks
all_extracts = list(tsc.Pager(server.tasks, tsc.RequestOptions(pagesize=1000)))

# The task type for incremental extracts is 'IncrementExtractTask' and full extracts is 'extractRefresh'
# The task type for incremental exrracts via Bridges is 'IncrementExtractViaBridgeTask'
extracts = [i for i in all_extracts if (i.target.id == datasource_id) and ('IncrementExtractViaBridgeTask' == i.task_type)]

incremental_extract_obj = extracts[0]

# Trigger the incremental extract associated with the datasource
update_xml = server.tasks.run(incremental_extract_obj)
job_id = xmltodict.parse(update_xml)['tsResponse']['job']['@id']
print(f"Refresh extract job {job_id} created")

Results What are the results or error messages received?

D:\Python38>python.exe D:\Refresh-Scripts\TableauExtractIncRefTrigScript.py Tab_AggSCMDownload_V
Traceback (most recent call last):
  File "D:\Refresh-Scripts\TableauExtractIncRefTrigScript.py", line 35, in <module>
    extracts = [i for i in all_extracts if (i.target.id == datasource_id) and ('IncrementExtractViaBridgeTask' == i.task_type)]
  File "D:\Refresh-Scripts\TableauExtractIncRefTrigScript.py", line 35, in <listcomp>
    extracts = [i for i in all_extracts if (i.target.id == datasource_id) and ('IncrementExtractViaBridgeTask' == i.task_type)]
AttributeError: 'NoneType' object has no attribute 'id'
jorwoods commented 5 months ago

Hey @naresh251. I think you missed adding the backticks to make your code render as code in the issue. That said, I have a few thoughts on your issue:

Can you try changing: extracts = [i for i in all_extracts if (i.target.id == datasource_id) and ('IncrementExtractViaBridgeTask' == i.task_type)]

to

extracts = [i for i in all_extracts if ('IncrementExtractViaBridgeTask' == i.task_type) and (i.target.id == datasource_id)]

Python implicitly does short-circuit evaluation, so if the first condition is False it never evaluates the second. In the code you provided, it is checking if the target.id == datasource_id before it checks if the task type is 'IncrementExtractViaBridgeTask'. By flipping the conditions around, it will check if the task type is correct before it tries to compare the target id, which may eliminate that NoneType error.

naresh251 commented 5 months ago

hey @jorwoods thanks for checking. Issue got fixed by condition i.target is not None.

extracts = [i for i in all_extracts if (i.target is not None and i.target.id == datasource_id) and ('IncrementExtractViaBridgeTask' == i.task_type)]

bcantoni commented 5 months ago

Closed as solved based on discussion above.