tableau / server-client-python

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

"Publish Flow" will fail #815

Closed bugcity closed 8 months ago

bugcity commented 3 years ago

The request body made by TSC is different from the specification of the Publish Flow REST API. Unlike that of the data source, connections is not a child element of flow. Because the flow request is created in the same method as the data source request.

The Publish Flow REST API has the following specification.

<tsRequest>
    <flow name="flow-name" >
        <project id="project-id" />
    </flow>
    <connections>
        <connection id="abc"
            password="connection-password"
            username="connection username"
            embed="embed-flag">
        <connectionCredentials
            name="connection-username"
            password="connection-password"
            embed="embed-flag" />
        </connection>
    </connections>
</tsRequest>

The Publish Data Source REST API has the following specification.

<tsRequest>
    <datasource name="datasource-name"
    useRemoteQueryAgent="use-remote-query-agent-flag"
    description="datasource-description">
        <connectionCredentials name="connection-username"
         password="connection-password"
            embed="embed-flag" />
        <project id="project-id" />
          <askData enablement="ask-data-enablement"/>
  </datasource>
</tsRequest>
jacalata commented 3 years ago

I haven't checked but I suspect this is fixed by @jorwoods recent work.

jorwoods commented 3 years ago

I had not made any functional changes to how flow items get published to server. However, I did this morning test it both ways with the connections element being a sub element to flow and a sub element to tsRequest, and both routes failed for me.

jorwoods commented 2 years ago

@jacalata I tried this again. Publishing flows returns an XML error if the connection element is a sub element to the flow element.

So, it seems like this is wrong: https://github.com/tableau/server-client-python/blob/9ec60ac573792f8809b7f74a2bae4b04a2f06a1a/tableauserverclient/server/request_factory.py#L320

But if I try changing it to connections_element = ET.SubElement(xml_request, "connections"), I get a different ServerResponseError.

I tried publishing the superstore demo from Prep Builder 2022.1. Interrogating the vizportal logs, I see

2022-05-24 21:12:32.905 -0500 (Finance,jorwoods,z5pvoR84SuqGzQvqNLkuMg,Yo2QkP2EcUAJGy3JSyuxkwAAAr0,0:1985378a:180e2ee37c3:-bdb) catalina-exec-22 vizportal: ERROR com.tableausoftware.api.rest.util.RestApiControllerAdvice - There was a problem publishing the file 'Superstore TSC publish test'.: com.tableausoftware.api.rest.exceptions.BadRequestRestException: java.lang.NullPointerException com.tableausoftware.api.rest.exceptions.BadRequestRestException: java.lang.NullPointerException

Example code follows:

from getpass import getpass, getuser
from pathlib import Path
import tableauserverclient as TSC

server = TSC.Server("https://localhost/")
auth = TSC.models.tableau_auth.TableauAuth(getuser(), getpass())
server.auth.sign_in(auth)

flow_file = Path.home() /  "Documents" / "My Tableau Prep Repository" / "Flows" / "Superstore.tflx"

project = server.projects.filter(name="Default")[0]
flow = TSC.models.flow_item.FlowItem(project_id=project.id, "Superstore TSC publish test")

server.flows.publish(
    flow,
    file_path=str(flow_file),
    mode=server.PublishMode.Overwrite
)