Anaplan API 2.0 Python Library

I recently posted a Python library for version 1.3 of our API. With the GA announcment of API 2.0, I'm sharing a new library that works with these endpoints. Like the previous library, it does support certificate authentication, however it requires the private key in a particular format (documented in the code, and below).

I'm pleased to announce, the use of Java keystore is now supported.

Note: While all of these scripts have been tested and found to be fully functional, due to the vast amount of potential use cases, Anaplan does not explicitly support custom scripts built by our customers. This article is for information only and does not suggest any future product direction. This library is a work in progress, and will be updated with new features once they have been tested.

 

Getting Started

The attached Python library serves as a wrapper for interacting with the Anaplan API. This article will explain how you can use the library automate many of the requests that are available in our Apiary, which can be found at https://anaplanbulkapi20.docs.apiary.io/#.

This article assumes you have the requests and M2Crypto modules installed as well as the Python 3.7. Please make sure you are installing these modules with Python 3, and not for an older version of Python. For more information on these modules, please see their respective websites:

  • Python 
    (If you are using a Python version older or newer than 3.7 we cannot guarantee validity of the article) 
  • Requests 
  • M2Crypto

Note: Please read the comments at the top of every script before use, as they more thoroughly detail the assumptions that each script makes.

Gathering the Necessary Information

In order to use this library, the following information is required:

  • Anaplan model ID
  • Anaplan workspace ID
  • Anaplan action ID
  • CA certificate key-pair (private key and public certificate), or username and password

There are two ways to obtain the model and workspace IDs:

  1. While the model is open, go Help>About: Help Menu.png
  2. Select the workspace and model IDs from the URL: URL.png

Authentication

Every API request is required to supply valid authentication. There are two (2) ways to authenticate:

  1. Certificate Authentication
  2. Basic Authentication

For full details about CA certificates, please refer to our Anapedia article.

Basic authentication uses your Anaplan username and password.

To create a connection with this library, define the authentication type and details, and the Anaplan workspace and model IDs:

Certificate Files:

conn = AnaplanConnection(anaplan.generate_authorization("Certificate","<path to private key>", "<path to public certificate>"), "<workspace ID>", "<model ID>")

Basic:

conn = AnaplanConnection(anaplan.generate_authorization("Basic","<Anaplan username>", "<Anaplan password>"), "<workspace ID>", "<model ID>") 

 Java Keystore:

from anaplan_auth import get_keystore_pair

key_pair=get_keystore_pair('/Users/jessewilson/Documents/Certificates/my_keystore.jks', '<passphrase>', '<key alias>', '<key passphrase>')
privKey=key_pair[0]
pubCert=key_pair[1]
    
#Instantiate AnaplanConnection without workspace or model IDs
conn = AnaplanConnection(anaplan.generate_authorization("Certificate", privKey, pubCert), "", "")

Note: In the above code, you must import the get_keystore_pair method from the anaplan_auth module in order to pull the private key and public certificate details from the keystore.

Getting Anaplan Resource Information

You can use this library to get the necessary file or action IDs. This library builds a Python key-value dictionary, which you can search to obtain the desired information:

Example:

list_of_files = anaplan.get_list(conn, "files")
files_dict = anaplan_resource_dictionary.build_id_dict(list_of_files)

This code will build a dictionary, with the file name as the key. The following code will return the ID of the file:

users_file_id = anaplan_resource_dictionary.get_id(files_dict, "file name")
print(users_file_id)

To build a dictionary of other resources, replace "files" with the desired resource: actions, exports, imports, processes. You can use this functionality to easily refer to objects (workspace, model, action, file) by name, rather than ID.

Example:

#Fetch the name of the process to run
process=input("Enter name of process to run: ")

start = datetime.utcnow()
with open('/Users/jessewilson/Desktop/Test results.txt', 'w+') as file:
        file.write(anaplan.execute_action(conn, str(ard.get_id(ard.build_id_dict(anaplan.get_list(conn, "processes"), "processes"), process)), 1))
        file.close()
end = datetime.utcnow()

The code above prompts for a process name, queries the Anaplan model for a list of processes, builds a key-value dictionary based on the resource name, then searches that dictionary for the user-provided name, and executes the action, and writes the results to a local file.

Uploads

You can upload a file of any size, and define a chunk size up to 50mb. The library loops through the file or memory buffer, reading chunks of the specified size and uploading to the Anaplan model.
Flat file: 

upload = anaplan.file_upload(conn, "<file ID>", <chunkSize (1-50)>, "<path to file>")

"Streamed" file:

with open('/Users/jessewilson/Documents/countries.csv', "rt") as f:
        buf=f.read()
    f.close()    
print(anaplan.stream_upload(conn, "113000000000", buf))
print(anaplan.stream_upload(conn, "113000000000", "", complete=True))

The above code reads a flat file and saves the data to a  buffer (this can be replaced with any data source, it does not necessarily need to read from a file). This data is then passed to the "streaming" upload method. This method does not accept the chunk size input, instead, it simply ensures that the data in the buffer is less than 50mb before uploading. You are responsible for ensuring that the data you've extracted is appropriately split. Once you've finished uploading the data, you must make one final call to mark the file as complete and ready for use by Anaplan actions.

Executing Actions

You can run any Anaplan action with this script, and define a number of times to retry the request if there's a problem. In order to execute an Anaplan action, the ID is required. To execute, all that is required is the following:

run_job = execute_action(conn, "<action ID>", "<retryCount>")
print(run_job)

This will run the desired action, loop until complete, then print the results to the screen. If failure dump(s) exits, this will also be returned.

Example output:

Process action 112000000082 completed. Failure: True
Process action 112000000079 completed. Failure: True

Details:
hierarchyName
Worker Report
successRowCount
0
successCreateCount
0
successUpdateCount
0
warningsRowCount
435
warningsCreateCount
0
warningsUpdateCount
435
failedCount
4
ignoredCount
0
totalRowCount
439
totalCreateCount
0
totalUpdateCount
435
invalidCount
4
updatedCount
435
renamedCount
435
createdCount
0
lineItemName
Code
rowCount
0
ignoredCount
435

Failure dump(s):
Error dump for 112000000082
"_Status_","Employees","Parent","Code","Prop1","Prop2","_Line_","_Error_1_"
"E","Test User 2","All employees","","101.1a","1.0","2","Error parsing key for this row; no values"
"W","Jesse Wilson","All employees","a004100000HnINpAAN","","0.0","3","Invalid parent"
"W","Alec","All employees","a004100000HnINzAAN","","0.0","4","Invalid parent"
"E","Alec 2","All employees","","","0.0","5","Error parsing key for this row; no values"
"W","Test 2","All employees","a004100000HnIO9AAN","","0.0","6","Invalid parent"
"E","Jesse Wilson - To Delete","All employees","","","0.0","7","Error parsing key for this row; no values"
"W","#1725","All employees","69001","","0.0","8","Invalid parent"
[...]
"W","#2156","All employees","21001","","0.0","439","Invalid parent"
"E","All employees","","","","","440","Error parsing key for this row; no values"
Error dump for 112000000079
"Worker Report","Code","Value 1","_Line_","_Error_1_"
"Jesse Wilson","a004100000HnINpAAN","0","434","Item not located in Worker Report list: Jesse Wilson"
"Alec","a004100000HnINzAAN","0","435","Item not located in Worker Report list: Alec"
"Test 2","a004100000HnIO9AAN","0","436","Item not located in Worker Report list: Test 2

Downloading a File

If the above code is used to execute an export action, the fill will not be downloaded automatically. To get this file, use the following:

download = get_file(conn, "<file ID>", "<path to local file>")
print(download)

This will save the file to the desired location on the local machine (or mounted network share folder) and alert you once the download is complete, or warn you if there is an error.

Get Available Workspaces and Models

API 2.0 introduced a new means of fetching the workspaces and models available to a given user. You can use this library to build a key-value dictionary (as above) for these resources.

#Instantiate AnaplanConnection without workspace or model IDs
conn = AnaplanConnection(anaplan.generate_authorization("Certificate", privKey, pubCert), "", "")
    
#Setting session variables
uid = anaplan.get_user_id(conn)
    
#Fetch models and workspaces the account may access
workspaces = ard.build_id_dict(anaplan.get_workspaces(conn, uid), "workspaces")
models = ard.build_id_dict(anaplan.get_models(conn, uid), "models")
    
#Select workspace and model to use
while True:
        workspace_name=input("Enter workspace name to use (Enter ? to list available workspaces): ")
        if workspace_name == '?':
            for key in workspaces:
                print(key)
        else:
            break
    
while True:
        model_name=input("Enter model name to use (Enter ? to list available models): ")
        if model_name == '?':
            for key in models:
                print(key)
        else:
            break
    
#Extract workspace and model IDs from dictionaries
workspace_id = ard.get_id(workspaces, workspace_name)
model_id = ard.get_id(models, model_name)
    
#Updating AnaplanConnection object
conn.modelGuid=model_id
conn.workspaceGuid=workspace_id

The above code will create an AnaplanConnection instance with only the user authentication defined. It queries the API to return the ID of the user in question, then queries for the available workspaces and models, and builds a dictionary with these results. You can then enter the name of the workspace and model you wish to use (or print to screen all available), then finally update the AnaplanConnection instance to be used in all future requests.

Attachments
Labels (2)
Contributors