Skip to main content

#If0 diskutieren mit

I am writing a script to download a workbook using TSC, modify it using the document API, and then Republish it using TSC. This all works fine, but is re-publishing to the "Default" folder as I am having trouble getting the projectID from the workbook name to pass into the publish step:

 

# Step 3: Download workbook to a temp directory

if len(all_workbooks) == 0:

print("No workbook named {} found.".format(args.workbook_name))

else:

#Start of line to get project id from workbook name, not working

get_projName = source_server.workbooks.get(all_workbooks[0].project_id)

#End of line not working

source_server.workbooks.download(all_workbooks[0].id)

 

#Step4: Use document API to update data connections

curr_wb.datasources[0].connections[0].server = "servername"

curr_wb.datasources[0].connections[0].dbname = "dbname"

curr_wb.datasources[0].connections[0].username = "username"

 

curr_wb.save()

 

#Step5: Publish updated workbook

#would like to pass project id into project_id

curr_wb = TSC.WorkbookItem(name=args.workbook_name, project_id="")

curr_wb = source_server.workbooks.publish(curr_wb, path, mode=TSC.Server.PublishMode.Overwrite, skip_connection_check = True)

2 Antworten
  1. 9. Nov. 2022, 23:47

    @Richard Gazzo​ 

    Hi, I have been working a little in a code that may work for you:

    from tableaudocumentapi import Datasource

    from tableaudocumentapi import Workbook

    from tableaudocumentapi import Connection

    from sys import exit

    import tableauserverclient as TSC

    import pathlib

    import os

     

    # source information

    SOURCE_SERVER_NAME = "https://www.yourserver.com"

    SOURCE_SERVER_USERNAME = "youruser"

    SOURCE_SERVER_PASSWORD = "yourpassword"

    SOURCE_SITE_NAME = ''

    SOURCE_WORKBOOK_NAME = "RestApi"

    SOURCE_DATA_SOURCE_NAME = "Ventas (Superstore_dev)"

     

    # changing data source

    TARGET_DATA_SOURCE_NAME = None

    #If TARGET_DATA_SOURCE_NAME is None, the name would be the same as the SOURCE_DATA_SOURCE_NAME

    #TARGET_DATA_SOURCE_NAME = "Ventas (Superstore_prod)"

    TARGET_DATA_SOURCE_DATABASE = "Superstore_prod"

    TARGET_DATA_SOURCE_SERVER = "yourdatabasehost"

    TARGET_DATA_SOURCE_USER = "yourdatabaseuser"

    TARGET_DATA_SOURCE_PASSWORD = "yourdatabasepassword"

     

    # target server

    TARGET_SERVER_NAME = "https://www.yourdestinationserver.com"

    TARGET_SERVER_USERNAME = "yourdestinationuser"

    TARGET_SERVER_PASSWORD = "yourdestinationpassword"

    TARGET_SITE_NAME = None

    #If TARGET_SITE_NAME is None, then the name will be the same as SOURCE_SITE_NAME

    #TARGET_SITE_NAME = ''

    TARGET_PROJECT_NAME = None

    #If TARGET_PROJECT_NAME is None, then the name will be inherited from workbook project.

    #TARGET_PROJECT_NAME = 'Default'

    TARGET_WORKBOOK_NAME = None

    #If TARGET_WORKBOOK_NAME is None, then the name will be inherited from workbook name.

    #TARGET_WORKBOOK_NAME = "RestApi"

     

     

    source_server = TSC.Server(SOURCE_SERVER_NAME, use_server_version=True)

    source_tableau_auth = TSC.TableauAuth(SOURCE_SERVER_USERNAME, SOURCE_SERVER_PASSWORD, \

    SOURCE_SITE_NAME)

     

    with source_server.auth.sign_in(source_tableau_auth):

    print('Logged in to source server successfully')

     

    req_option = TSC.RequestOptions()

    req_option.filter.add(TSC.Filter(TSC.RequestOptions.Field.Name,

    TSC.RequestOptions.Operator.Equals, SOURCE_WORKBOOK_NAME))

     

    all_workbooks, pagination_item = source_server.workbooks.get(req_option)

     

    ⌗Download workbook to a temp directory

    if len(all_workbooks) == 0:

    print('No workbook named {} found.'.format(SOURCE_WORKBOOK_NAME))

    exit()

    elif len(all_workbooks) >= 2:

    print('Several workbooks named {} found.'.format(SOURCE_WORKBOOK_NAME))

    exit()

    elif len(all_workbooks) == 1:

    tmpdir = "resources"

    isExist = os.path.exists(tmpdir)

    if not isExist:

    # Create a new directory because it does not exist

    os.makedirs(tmpdir)

    print("The new directory is created!")

    try:

    workbook_path = source_server.workbooks.download(all_workbooks[0].id, tmpdir)

    print("workbook_path: '%s' " % (workbook_path,))

    finally:

    print("")

     

    if TARGET_PROJECT_NAME is None:

    TARGET_PROJECT_NAME = all_workbooks[0].project_name

     

    if TARGET_WORKBOOK_NAME is None:

    TARGET_WORKBOOK_NAME = all_workbooks[0].name

    if TARGET_SITE_NAME is None:

    TARGET_SITE_NAME = SOURCE_SITE_NAME

     

    if TARGET_DATA_SOURCE_NAME is None:

    TARGET_DATA_SOURCE_NAME = SOURCE_DATA_SOURCE_NAME

     

    sourceWorkbook = Workbook(workbook_path)

    sourceDataSource = None

    sourceConnection = None

    for tempDataSource in sourceWorkbook.datasources:

    print("name ", tempDataSource.name)

    print("caption ", tempDataSource.caption)

    if tempDataSource.caption == SOURCE_DATA_SOURCE_NAME:

    sourceConnection = tempDataSource.connections[0]

    dataSource = tempDataSource

    break

     

    if sourceConnection is not None:

    sourceConnection.server = TARGET_DATA_SOURCE_SERVER

    sourceConnection.dbname = TARGET_DATA_SOURCE_DATABASE

    sourceConnection.username = TARGET_DATA_SOURCE_USER

    dataSource.caption = TARGET_DATA_SOURCE_NAME

    ⌗save updated workbook

    extension = pathlib.Path(sourceWorkbook.filename).suffix

    print("extension",extension)

    sourceWorkbook.save_as("resources/updated" + extension)

    else:

    print("No Connection with name",SOURCE_DATA_SOURCE_NAME)

    exit()

     

    # publish modified workbook and update credentials

    target_server = TSC.Server(TARGET_SERVER_NAME, use_server_version=True)

    target_tableau_auth = TSC.TableauAuth(TARGET_SERVER_USERNAME, TARGET_SERVER_PASSWORD, \

    TARGET_SITE_NAME)

     

    with target_server.auth.sign_in(target_tableau_auth):

    print('Logged in to target server successfully')

    req_option = TSC.RequestOptions()

    req_option.filter.add(TSC.Filter(TSC.RequestOptions.Field.Name,

    TSC.RequestOptions.Operator.Equals, TARGET_PROJECT_NAME))

    # If destination project is specific this could work, project name must be unique

    dest_projects, pagination_info = target_server.projects.get(req_option)

    if len(dest_projects) == 0:

    print('No project named {} found.'.format(SOURCE_WORKBOOK_NAME))

    exit()

    elif len(dest_projects) >= 2:

    print('Several projects named {} found.'.format(SOURCE_WORKBOOK_NAME))

    exit()

    elif len(dest_projects) == 1:

    try:

    target_project = dest_projects[0]

    finally:

    print("")

    if target_project is not None:

    new_connection_creds = TSC.ConnectionCredentials(name=TARGET_DATA_SOURCE_USER, password=TARGET_DATA_SOURCE_PASSWORD, embed=True, oauth=False)

    new_workbook = TSC.WorkbookItem(name=TARGET_WORKBOOK_NAME, project_id=target_project.id)

    new_workbook = target_server.workbooks.publish(new_workbook, "resources/updated" + extension, mode=TSC.Server.PublishMode.Overwrite, connection_credentials=new_connection_creds)

    print("Successfully copied {0} ({1})".format(new_workbook.name, new_workbook.id))

    else:

    error = "The destination project could not be found."

    raise LookupError(error)

    Hope this works for you

     

    SOURCE_DATA_SOURCE_NAME = "Ventas (Superstore_dev)"

    @Richard Gazzo​ Hi, I have been working a little in a code that may work for you:from tableaudocumentapi import Datasourcefrom tableaudocumentapi import Workbookfrom tableaudocumentapi import Connecti 

     

    If this post resolves the question, would you be so kind to "Select as Best"?. This will help other users find the same answer/resolution and help community keep track of answered questions. Thank you.

     

    Regards,

     

    Diego Martinez

    Tableau Visionary and Forums Ambassador

0/9000

Hi Team,

Hope you're all doing well.

I’ve created a Flex Prompt Template that includes four input parameters. However, there’s now a requirement to pass these inputs dynamically—meaning that not all four inputs will always be provided. In some cases, fewer inputs may be passed, so the remaining ones need to be treated as optional.

Could you please guide me on how to configure the template to handle optional inputs?

Thanks in advance!

2 Antworten
0/9000

The Admin Insights login activity data is commonly two days behind what shows on the Users screen. Additionally the Users screen cannot be downloaded as a .csv file. I did a copy-paste of the Users screen into Excel and used functions on the actual last login dates to get a more accurate picture of user activity. It was a bit of a slog but not an unreasonable task. I would rather use the built-in Insights but it's simply not accurate and not continuously updated. A sample of my data is attached.

 

Thank you in advance.

Adam Russell

8 Antworten
0/9000

H Friends, we are on 2018.2& looking for Tableau server automation Backup Script, that can be scheduled thru windows Task Scheduler for TSM Version.

24 Antworten
0/9000

Hi, 

 

I configured a webhook to send an event (account created) from Amplitude to a Marketing Cloud data extention. But I can't manage to insert the records in my data extention. 

 

Configuration on Amplitude is ok as the events are successfully received in the webhook.

 

I have the following payload :

 

{

  <#if input.user_id??>

  "EventDefinitionKey": "APIEvent-de4d30ac-5191-b5c2-efb2-a533cd294569",

  "grant_type": "client_credentials",

  "client_id": "ltr641qcp13eho9f38rip3uw",

  "client_secret": "VFGRgkC51ojeM6tByQDrbCQo",

  "external_id" : "${input.user_id}",

  </#if>

  "name" : "${input.event_type}",

  "time" : "${input.event_time}",

  "email_root" : "${input.user_properties.email!}",

  "properties" : {

    "email" : "${input.user_properties.email!}"

  }

}

And I created a code resource in SFMC to insert the events records : 

 

<script runat="server" language="javascript">

  Platform.Load("Core", "1");

  

  var jsonpost = Platform.Request.GetPostData();

  var json = Platform.Function.ParseJSON(jsonpost);

  

  var eventDefinitionKey = json.EventDefinitionKey;

  var grantType = json.grant_type;

  var clientId = json.client_id;

  var clientSecret = json.client_secret;

  var externalId = json.external_id;

  var name = json.name;

  var time = json.time;

  var emailRoot = json.email_root;

  var email = json.properties.email;

  

  var dataExtensionName = "TestAmplitudeWebhook";

  

  var deObj = {

    "CustomerKey": dataExtensionName,

    "Name": dataExtensionName,

    "keys": [{

      "Name": "external_id",

      "Value": externalId

    }],

    "values": [{

      "Name": "name",

      "Value": name

    },{

      "Name": "time",

      "Value": time

    },{

      "Name": "email",

      "Value": email

    }]

  };

  

  var data = [deObj];

  var result = Platform.Function.InsertData(data, "Overwrite");

</script>

 

Did someone ever faced a similar issue ?

0/9000

Hello,

So I have a flow published and connected to data sources on Server 1. I have a workbook published on Server 2 that uses that flow (with local copy method). But when I run the update on flow, workbook cant pull updated data. and the connection type says hyper_0.hyper (...), I think it cant be updated because its hyper link connection instead of standard server connection. is there a workaround for this data update issue?

 

And another question also related to this problem, when I extract datasource, I cant publish it to another server, I get an error: This workbook contains a data source that is dependent on a different Tableau Server. only create local copy and then publish works. I suppose extracts cant be published to different servers?

1 Antwort
  1. 31. März 2023, 12:32

    @Nugzari Geladze​ 

    Hi, If understand you have to Tableau Server installs, you use Server 1 to refresh a hyper file to a shared location, that is used by Server 2.

     

    If this is the case, probably the problem is that when Server 1 tries to refresh file, and if Server 2 is using the file, then the file can't be overwrite, because it is blocked by shared use file. A typical example is when you have an Excel file open and you try to delete it. You can't.

     

    The second is as you say, you can't publish a datasource using a flow from one server to another server.

     

    So, what to do? You can use REST API. You could use something like a python code, to read the hyper file from the shared folder and publish as a published datasource to the second server.

     

    Below an example code

    import tableauserverclient as TSC

    from pathlib import Path

     

    # server admin creds

    HOST="https://www.yourserver.com"

    #Use the following to use User and password

    #USER="youruser"

    #PWRD="yourpassword"

     

    #If using PAT use the following

    TOKENNAME="tokenname"

    TOKENID="xuf+yyw==:55h2hkld3wEP"

    #Use "" to default site

    SITE="Entrenamiento"

    #Use "" to default project

    PROJECT_NAME="World Indicators"

    ASYNC = True

    FILE = "Devoluciones.hyper"

    //Data Source Name

    DSNAME ="Devoluciones"

     

     

    server = TSC.Server(HOST, use_server_version=True)

    #Use the following to sign in with user and password

    #tableau_auth = TSC.TableauAuth(USER,PWRD,site=SITE)

     

    #Use the following if using PAT

    tableau_auth = TSC.PersonalAccessTokenAuth(TOKENNAME, TOKENID, site_id=SITE)

     

    PATH_TO_FILE = Path(FILE)

    with server.auth.sign_in(tableau_auth):

    # Define publish mode - Overwrite, Append, or CreateNew

    publish_mode = TSC.Server.PublishMode.Overwrite

    # Get project_id from PROJECT_NAME

    all_projects, pagination_item = server.projects.get()

    for project in TSC.Pager(server.projects):

    if project.name == PROJECT_NAME:

    project_id = project.id

    new_conn_creds = None

    # Create the datasource object with the project_id

    datasource = TSC.DatasourceItem(project_id)

    new_datasource = TSC.DatasourceItem(project_id=project_id,name=DSNAME)

    print(f"Publishing {FILE} to {PROJECT_NAME}...")

    # Publish datasource

    if ASYNC:

    # Async publishing, returns a job_item

    new_job = server.datasources.publish(datasource, PATH_TO_FILE, publish_mode, connection_credentials=new_conn_creds, as_job=ASYNC)

    print("Datasource published asynchronously. Job ID: {0}".format(new_job.id))

    else:

    # Normal publishing, returns a datasource_item

    new_datasource = server.datasources.publish(datasource, PATH_TO_FILE, publish_mode,connection_credentials=new_conn_creds)

    print("Datasource published. Datasource ID: {0}".format(new_datasource.id))

     

    #Don't forget to sign out

    server.auth.sign_out()

    If this post resolves the question, would you be so kind to "Select as Best"?. This will help other users find the same answer/resolution and help community keep track of answered questions. Thank you.

     

    Regards,

     

    Diego Martinez

    Tableau Visionary and Forums Ambassador

0/9000

Created a function in Python to return value based on the comparison.

If I am calling it from Python it is returning the result as expected.

But when I am passing the value from Tableau with Tabpy if comparison not working telling no return value.

Would it possible to get some guidance on it

Attaching the code

Python function

def my_function(X):

    with open("C:\Arijit\Arijit\TGF\Tab_PI\Datedim1.csv", "r") as csv_file:

        csv_reader = csv.reader(csv_file, delimiter=',')

        i=0

        df =[]

        for lines in csv_reader:

            df.insert(i,lines)

            i=i+1

        for j in df:

            ##if datetime.strptime(X, '%d-%m-%Y').date() == datetime.strptime(j[0], '%d-%m-%Y').date():

                if X == int(j[0]):

                    return(int(j[1]))

                 

Tableau function

     SCRIPT_INT("return tabpy.query('testfunc',_arg1)['response']",attr([demodate]))

1 Antwort
  1. 29. Nov. 2020, 07:06

    Please attach your packaged workbook (twbx) so that any solution suggested is relevant and works for you.

0/9000

Hi Guys,

 

I have huge amount of csv files under different projects folder. What I want to do is to set up a project filter first, and then based on this project Python code will scan all the files under this folder. Then I can use this return file lists as another filter. After that, python will open specific csv files based on these two steps filter. The reason to do that is that I don't want to load all the data into tableau one time, it's huge amount of data as I mentioned.

 

I can easily write code in the Python Jupyter Notebook. But it's not easy to complete this in Tableau for me. Hopefully, I can get the idea from you guys. Thank you so much.

 

My code will be like this:

#Code to read all the files under a filtered project

⌗This code is okay in Jupyter notebook, but has error in the tableau, I cannot figure it out why it has error

script_str(

"

import os

Proj = _arg1 # Project filter

Folder = r"C:\Samples\" + Proj

csvfiles = [f for f in oslist(Folder) if f.endswith(".csv")

datefile = [f[:8] for f in csvfiles]

return datefiles

",

attr([Project]))

 

#Code to read a specific file based on csvfiles filter

#The reason to return a value list, because I don't know how to return the whole dataset

#If we can return a dataframe directly, it will great. Otherwise, I need to repeat this step many many time to get the value I want

script_str(

"

import pandas as pd

import os

Proj = _arg1 # Project filter

DT = _arg2 # The csv file filter

Folder = r"C:\Samples\" + Proj

csvfiles = [f for f in oslist(Folder) if f.endswith(".csv")

for item in csvfiles:

     if DT in item:

          df = pd.read_csv(Folder + "//" + item)

return df["Value"].tolist()

",

attr([Project]), attr([Date]))

0/9000

Hi,

I want to connect with different database server dynamically based upon flag or without flag and don't want to use choice connector because we are using database configuration more than 1000 times in our project. if we used choice connector, we need to apply everywhere.

 

if flag is true connect: Oracle database server

if flag is false connect: SQL database server

 

Thank you for help and suggestions.

5 Antworten
0/9000

I am getting below error

 

The following has evaluated to null or missing:

==> pathwayRequirementGroupedUnembeddableResources.pathwayRequirement.availability [in template "layout/rapidtheme/user/consumption/include/consumption-content/course-pathway/downloads.ftl" at line 13, column 55]

 

----

Tip: It's the step after the last dot that caused this error, not those before it.

----

Tip: If the failing expression is known to be legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??

----

 

----

FTL stack trace ("~" means nesting-related):

- Failed at: #assign pathwayRequirementAvailabilit... [in template "layout/rapidtheme/user/consumption/include/consumption-content/course-pathway/downloads.ftl" at line 13, column 13]

- Reached through: #include "/layout/rapidtheme/user/con... [in template "layout/rapidtheme/user/consumption/content-course-pathway-downloads.ftl" at line 5, column 9]

- Reached through: #include path [in template "common/macros.ftl" in macro "include" at line 50, column 9]

- Reached through: @include content [in template "layout/rapidtheme/user/layout.ftl" at line 57, column 45]

----

2 Antworten
0/9000