Suppose you have a nice dataset, that you would like to use in a tableau dashboard/workbook.  

There's basically two ways to proceed:  
- Export your dataset as a hyper-file, and publish it on the tableau server  
- Write your data into the reportingDB, and link the workbook either directly to the table, or use an extract

To publish a dataset on the server for the first time, do the following

Suppose your dataset is stored in a pd.DataFrame called "df"
```python
import pandas as pd

data = {
    'report_date': pd.to_datetime(['2024-01-01', '2024-01-02']),
    'isrc': ['USRC19401295', 'GBARL9300135'],
    'country_code': ['US', 'FI'],
    'num_streams': [100, 200],
    'avg_stream_duration_seconds': [150.5, 200.75],
    'is_local_track': [True, False],
}

df = pd.DataFrame(data)
```

To ensure that your datasource has the desired data types for each column, it's good practice to manually declare the data types of each column in your dataset like so
```python
from tableauhyperapi import TableDefinition, SqlType

hyperSchema = [
    TableDefinition.Column('report_date', SqlType.date()), # For date columns, use the date -type
    TableDefinition.Column('isrc', SqlType.text()), # For character columns, use the text -type
    TableDefinition.Column('country_code', SqlType.text()),
    TableDefinition.Column('num_streams', SqlType.big_int()), # For integer columns, use the big_int -type
    TableDefinition.Column('avg_stream_duration_seconds', SqlType.double()), # For float columns, use the double -type
    TableDefinition.Column('is_local_track', SqlType.bool()), # For boolean columns, use the bool -type
]
```

For details on the data types, you can refer to [the tableau documentation](https://tableau.github.io/hyper-db/lang_docs/py/_modules/tableauhyperapi/sqltype.html)

However, you can also use our built-in hyperSchema generator, that aims to infer the correct data type based on the content of the columns in the dataframe.  
In this case, the script will print out the inferred data types for each column, so make sure these are what you expect!

You can call the generate_hyper_schema function either directly, or simply omit the hyperSchema argument from the write_hyper function, in which case the hyper schema will be generated in the function scope.
```python
hyperSchema = tableau.generate_hyper_schema(df)
```

You are now basically ready to write your data as a hyper file.  
Note that you should pick a descriptive name for your data, since **this is what the data source will be named on the server!**
```python
file_path = './path/to/your/directory/name_of_dataset.hyper'

# If you already defined your hyperschema either manually, or by calling generate_hyper_schema, pass it as an argument
tableau.write_hyper(data, file_path, hyperSchema)

# If not, just omit the variable
tableau.write_hyper(data, file_path)

# If you also wish to be able to work with the hyper using Alteryx, use the following naming conventions
tableau.write_hyper(data, file_path, schemaName='public', tableName='table1')

```

Now the hyper file is ready to be uploaded on the server.  
At this point, you'll probably want to check the ID of the project where you want the datasource to be stored.
```python
tableau.print_project_ids('int_mktng')
```

Now that you know the correct project ID, you can publish your datasource on the server:
```python
datasource_id = tableau.new_datasource(site='int_mktng', project_id='e6d1af34-b15d-490f-a972-cbabcb8e7cf1', filepath=file_path)
```

It's that simple!  
The operation returns and prints out the ID of your newly created datasource. **However**, if you have a massive data set and you're pusblishing the data source asynchronously with the argument asjob=True, the ID returned and printed by the function is incorrect!

In such case, or if you simply forget to capture the ID, you can also check the names and IDs of all data sources on a site by running:
```python
tableau.print_datasource_ids('int_mktng')
```

When it comes time to update your datasource, you can do so by running:
```python
tableau.write_hyper(data, file_path, hyperSchema)
tableau.publish_hyper(file_path, 'your_data_source_id_here', 'int_mktng')
```

If you have datasources that are extracts of ReportingDB tables, you can update them programmatically:
```python
data_source_dict = {
    'name_of_data_source_1': 'id_of_data_source_1'
    'name_of_data_source_2': 'id_of_data_source_2'
}

tableau.refresh_extracts(data_source_dict, site='int_mktng')
```

And there you go, working with tableu has never been easier!
