Python gives you the ability to write a bit of code and the call that code as a function. You can call the function from within the same script where the function is defined, or you can save the function in a separate script and then import the function inside of other scripts.
Writing and calling functions is a key component of the Don’t Repeat Yourself (DRY) principle of software development. Creating a function in a single script and calling that function from other scripts is preferable to performing copypasta of the same bit of code throughout several scripts. When a function lives in a single script, it only needs to be updated in that one place when it inevitably needs updating.
While Python functions can perform isolated tasks, my typical use cases send values into the function and receive a value returned from the function. In this example, I’ll import a Python function used to refresh an access token required to authenticate to a remote API endpoint. I’ll pass other tokens required to refresh the access token into the function, and the function will return the refreshed access token back to the calling script.
The Function
The names of the script & function especially matter as we parse through the code. We’ve created a Python script called RefreshBlubrryAccessToken.py. In that script, we define a function called fetchtoken.
The fetchtoken function expects three inputs to be passed to it–clientid, clientsecret, and refreshtoken. While the name of the function—fetchtoken–matters because we’re going to be calling it in another script, the names of the variables used to assign the input values to don’t matter in the same way. Variables don’t live outside of the function in which they are created.
The function uses the requests library to make an refresh access token API call to Blubrry, using clientid, clientsecret, and refreshtoken to authenticate. The response to our HTTP POST API call is a JSON payload, and the key value in that payload we care about most is the ‘access_token’. This value is returned as the value stored in variable accessToken.
# RefreshBlubrryAccessToken.py
import requests
def fetchtoken(clientid, clientsecret, refreshtoken):
# From Blubrry's docs, this is how you call for a new access token.
# https://blubrry.com/developer/api/oauth-2/
# Use the Refresh token API call to obtain a new access token
# curl "https://api.blubrry.com/oauth2/token"
# -u clientId:clientSecret
# -d grant_type=refresh_token
# -d refresh_token=refreshToken
baseURL = 'https://api.blubrry.com/'
apiURL = 'oauth2/token'
apiCall = baseURL + apiURL
apiCallData = {
'grant_type': 'refresh_token',
'refresh_token': refreshtoken
}
responseFromBlubrry = requests.post(
apiCall,
auth=(clientid, clientsecret),
data=apiCallData
)
accessToken = responseFromBlubrry.json()['access_token']
return accessToken
This function is simplified for illustration purposes. In real life, we wouldn’t assume we’re getting back a valid access token. Instead, we’d check for error codes we might have gotten back instead and handled them appropriately. Think of this code as proof of concept and not production ready.
Using The Function
Remember how we named the function above RefreshBlubrryAccessToken.py? In this example, that script file lives in the same directory as this other script that’s calling it. Therefore, when we say “import RefreshBlubrryAccessToken“, the file will be found since Python includes adjacent files in its import search scope.
The values BLUBRRY_CLIENT_ID, BLUBRRY_CLIENT_SECRET, and BLUBRRY_REFRESH_TOKEN were passed into this script from the local operating system environment.
With the function imported and key variables assigned their values, we’re set to invoke the function. The magic happens in the final line of the script accessToken = RefreshBlubrryAccessToken.fetchtoken(clientID, clientSecret, refreshToken). Here’s what that line does.
- Creates a variable called accessToken. The value of accessToken will be set to the value returned by the function RefreshBlubrryAccessToken.fetchtoken. If you review the function code above, that’s the line at the bottom of the script return accessToken.
- Invokes the function RefreshBlubrryAccessToken.fetchtoken. We imported RefreshBlubrryAccessToken at the top, right? And fetchtoken is the name of a function we define in RefreshBlubrryAccessToken.
- Passes the values of clientID, clientSecret, and refreshToken to the function as we invoke it. In this example, the function uses these input values as the credentials to the Blubrry API endpoint.
- Assigned the value returned by the function to accessToken. If all went well with our function, that means we now have an access token we can use to make calls to other API endpoints in the wonderful world of Blubrry.
import os
import RefreshBlubrryAccessToken
clientID = os.environ["BLUBRRY_CLIENT_ID"]
clientSecret = os.environ["BLUBRRY_CLIENT_SECRET"]
refreshToken = os.environ["BLUBRRY_REFRESH_TOKEN"]
accessToken = RefreshBlubrryAccessToken.fetchtoken(clientID, clientSecret, refreshToken)
Although both the function’s code and the code of the script calling the function both use the same variable names of clientID, clientSecret, refreshToken, and accessToken, those variable names do not have to be the same in both scripts. Python variables have a regional scope. I kept the variable names the same for readability.
Why Bother Passing Credentials, Anyway?
You might wonder why I didn’t embed the credentials into the function itself. Why bother with passing the credentials from the calling script into the function? In my case as a relative n00b to Python, I ran into an issue with the function being called not knowing what the operating system environment variables were. Rather than digging more deeply into variable scopes to grok how Python functions are made aware (or not) of environment variables, I opted just to pass the credentials through from a calling script.
That is, I strongly suspect there’s a way for a called function to see OS environment variables that have been set. Or if not, that there’s some other appropriate way to solve what must be a common problem. However, I got bogged down trying to make sense of it. In the spirit of getting something done, I chose to pass the environment variables in from the calling script.
Upon reflection, this choice seemed like a good solution anyway. While my current use case is supporting a single client with a single Blubrry account, what if I wanted to use the function to support multiple clients with multiple accounts and credential sets? Passing credentials through to the function feels like an appropriate solution in that context.
For More Information
Python 3 Language Reference–5. The Import System
Python Scope – W3 Schools