Workiva Scripting and end of support for Python 3.9
To keep your automations future‑proof, Workiva is introducing support for Python 3.13, along with a script‑level setting that lets you choose the runtime version for each script. This guide explains how to move safely from 3.9 to 3.13, what to test, and how to roll out changes with minimal disruption.
Until October 2025, Workiva Scripting relied on the official Python 3.9 release from the Python Software Foundation, which has now reached end of life and no longer receives security updates or bug fixes.
In response to this change, Workiva Scripting has transitioned to use the Amazon Linux 2023 (AL2023) image, which provides its own builds of Python 3.9 and 3.13. This change ensures that Python 3.9 receives ongoing security patches and maintenance through Amazon’s update cycle, even though the upstream Python release is no longer patched by the open-source community.
As a result of this transition, Workiva Scripting will continue to support running scripts securely on Python 3.9 until October 2026.
Who should think about this migration? Anyone currently running Workiva Scripting automations on Python 3.9—whether triggered manually, from Chains, or via Integrated Automations.
What if I do nothing? Your scripts remain secure through AL2023 patches until October 2026, but migration is recommended to align with the latest supported runtime (3.13).
For more background about end-of-life timelines and supported versions, review the official Python release status webpage.
How Workiva is supporting this change
Workiva is rolling out an update to give developers control over which Python runtime their scripts use. This update will bring the following changes:
- Python 3.13 support – All new scripts will default to Python 3.13, the latest stable version.
- Runtime configuration per script – Each script will now let you choose the Python runtime version (3.9 or 3.13) the script will use.
- Backward compatibility – All existing scripts will continue to use Python 3.9 until you update them.
- Editor & API support – You’ll be able to set or update the runtime directly in the Workiva Script Editor or via the Scripting API.
This ensures you can migrate on your own timeline, test safely, and only switch production scripts when you’re confident they’re ready.
Timeline for this changeover
To help you plan, here’s the rollout schedule:
- Python 3.13 available in Workiva (September 2025) – All customers can configure scripts to run on Python 3.9 or Python 3.13 using the Scripting API or the Scripting Editor.
- Python 3.9 end of life (October 2025) – Official Python community support ends. Workiva continues support via AL2023 through October 2026, but migration is highly recommended.
- October 2026 – Workiva plans to end support for Python 3.9 in October 2026, after which all scripts will run on Python 3.13.
You should begin testing scripts on Python 3.13 as soon as possible while keeping production on 3.9 only temporarily. Once you are comfortable using Python 3.13, switch your production scripts over to the Python 3.13 runtime without delay.
Switching a script to Python 3.13
Our recommended rollout pattern: create a copy, update the version, test, then promote. This minimizes risk to production and lets you keep run history if you need it.
Step 1 — Make a copy
- In Workiva, make a copy of your production script.
The copy will still be set to Python 3.9. - Set the runtime for the copy to Python 3.13.
Step 2 — Test and adapt the copy
- Run the copy in a safe/test context.
- Fix any breaking changes (see “Common issues & fixes”).
- Validate outputs, side‑effects, and performance.
Step 3 — Change to 3.13 (two options)
Option A — This will keep the production run history
- Push the updated code from the copy back to the original script through copy-and-paste.
- Change the original script’s runtime to Python 3.13.
- Re‑run your tests, then resume normal scheduling/triggers on the original.
- (Optional) Archive or retire the copy.
Option B — This will not keep the production run history
- Change the production trigger (that is, the Chains trigger) to point from the original script to the copy script.
- The copy becomes the new production script (running on Python 3.13).
- (Optional) Archive or retire the original.
Call to action: Whichever option you choose, move all your active scripts to Python 3.13 by October 2025.
Update the Python runtime version
Using the Scripting API
-
Determine the script’s runtime.
GET /v1/scripts/{script_id}Check the value for
runtimein the response. -
Update the script to Python 3.13.
PATCH /v1/scripts/{script_id} Content-Type: application/json [{ "op": "replace", "path": "/runtime", "value": "python3.13" }]
For more details, see the Scripting Prototype API docs.
Example: Changing and reading the Python runtime version
The following sample code shows how to update a script’s runtime version (3.9 or 3.13) using the Scripting API, and how to confirm the version currently configured.
import os
import requests
CLIENT_ID = os.environ.get("CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
SCRIPT_ID = os.environ.get("SCRIPT_ID")
VERSION = os.environ.get("VERSION")
#VERSION = "python3.9"
#VERSION = "python3.13"
SCRIPTS_V1_URL = "https://api.app.wdesk.com/prototype/platform/scripts"
AUTH_URL = "https://api.app.wdesk.com/iam/v1/oauth2/token"
def change_version(clientId, clientSecret, scriptId, version):
auth_header = get_auth_header(clientId, clientSecret)
# Change Python Version
req_body = [
{
"op": "replace",
"path": "/runtime",
"value": version
}
]
resp = requests.patch(
f"{SCRIPTS_V1_URL}/{scriptId}", json=req_body, headers=auth_header
)
name = resp.json().get("name")
new_version = resp.json().get("runtime")
print("Python version for '" + name + "' script changed to: " + new_version.replace("python", ""))
def read_version(client_id, client_secret):
auth_header = get_auth_header(client_id, client_secret)
# read Python Version
resp = requests.get(
f"{SCRIPTS_V1_URL}/{SCRIPT_ID}", headers=auth_header
)
name = resp.json().get("name")
configured_version = resp.json().get("runtime")
print("Python version for '" + name + "' script: " + configured_version.replace("python", ""))
# Fetches the auth headers for a given client id and secret
def get_auth_header(client_id, client_secret):
token_headers = {"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"}
data_field = (
f"client_id={client_id}&client_secret={client_secret}"
f"&grant_type=client_credentials"
)
auth_resp = requests.post(f"{AUTH_URL}", data=data_field, headers=token_headers)
auth_json = auth_resp.json()
bearer_token = "Bearer " + auth_json.get("access_token")
return {"Authorization": bearer_token}
change_version(CLIENT_ID, CLIENT_SECRET, SCRIPT_ID, VERSION)
#read_version(CLIENT_ID, CLIENT_SECRET)Using the Scripting Editor
With the Scripting Editor you’ll be able to configure the runtime directly in the UI. A new dropdown is available under Properties → Runtime Version where you can select between Python 3.9 and Python 3.13.
To update a script in the Editor:
- Open the script in the Scripting Editor.
- Go to the Properties panel on the right.
- Under Runtime Version, select Python 3.13 from the dropdown.
- Save your changes.
- Run the script in a safe/test environment before promoting to production.
Tips
- Ensure that any third-party packages in your scripts are compatible with Python 3.13.
- Update any pinned package versions in your
requirements.txtfile (for example, unlike in Python 3.9,requests==2.28is not needed in 3.13). - Read the official Python documentation for details regarding the major changes in Python versions 3.10, 3.11, 3.12, and 3.13, including:
- Structural pattern matching, f-string updates, improved error messages
- Significant performance improvements (function calls, string operations, memory management, JSON serialization/deserialization)
- Deprecation of packages and certain package parameters removed (
cgi,cgitb,distutils, etc. have been deprecated; theasyncio"loop" parameter removed)
Common migration issues & fixes in moving from 3.9 to 3.13
Here are some common issues you may face when moving scripts from Python 3.9 to 3.13, along with suggested fixes for them:
-
Third‑party libraries – Some packages may not yet support Python 3.13.
- Fix: Upgrade to the latest compatible version, or replace with an alternative. Test any pinned requirements carefully. You can check support for your libraries at pyreadiness.org/3.13, and review the "Supported scripting libraries and dependencies" help article for more information.
-
Requests library version – The
requestslibrary is the most common third‑party library in Workiva Scripting. In early releases of Python 3.9, scripts will break withrequestsversion 2.30.0 or newer. Once you migrate to Python 3.13, you can use the latest versions ofrequestswithout issues. -
Python 3.13 has differences in string and bytes handling – Stricter type checks can surface hidden issues.
-
Fix: Check for code that mixes
strandbytesand ensure explicit encoding/decoding.
-
Fix: Check for code that mixes
-
Datetime & timezone behavior – Python 3.13 has differences in the
zoneinfolibrary and stricter parsing.- Fix: Test all date/time logic, especially formatting and timezone conversions.
-
JSON serialization – Some objects may fail to serialize due to stricter rules.
-
Fix: Ensure custom objects are converted before
json.dumps, or use default encoders.
-
Fix: Ensure custom objects are converted before
-
Deprecated APIs – Some Python
stdlibfunctions (for example,asyncio.get_event_loop,distutils, and certain locale APIs) deprecated in Python 3.9 have been removed.- Fix: Update code to use supported alternatives.
-
Performance changes – Loops and async tasks may behave differently.
- Fix: Run load tests on critical paths; update concurrency logic if needed.
Tip: Always test copies of your production scripts first. Fixes applied in a controlled test environment reduce risk of production issues.
What’s new in Python 3.13
Here are a few change highlights for Python 3.13:
- Improved interactive interpreter – Multi‑line editing, colors, and colorized tracebacks.
- Experimental free‑threaded build mode – Allows true parallel threads (no GIL) on some platforms.
- Experimental JIT – Early groundwork for performance improvements.
-
Better debugging tools –
locals()mutations now work with well‑defined semantics. - New memory allocator – Modified mimalloc included and enabled by default if supported.
- Smaller files – Docstrings strip leading whitespace, reducing memory use and .pyc file sizes.
-
New dbm backend – Uses
dbm.sqlite3by default. - Platform updates – macOS minimum 10.13, iOS/Android Tier 3, WASI Tier 2.
- Typing improvements – Type defaults, narrowing, read‑only items, and deprecation annotations.
-
Removals – Deprecated modules removed (for example,
cgi,telnetlib,imghdr,lib2to3, etc.).
For the full release notes, see Python.org's "What’s New in Python 3.13".
If you’d like to review the specific changes introduced between 3.9 and 3.13, see:
FAQs
Q: Do I need to migrate all my scripts right away?
No. Begin testing scripts on Python 3.13 now and keep production on 3.9 only temporarily. All scripts must be migrated to Python 3.13 before October 2026.
Q: Will my existing scripts break automatically when Python 3.9 reaches end of life?
No. Workiva Scripting will rely on Amazon’s Python 3.9 version under Amazon Linux 2023 (AL2023), which continues to receive security patches, until October 2026. Your scripts will not be impacted by the official Python 3.9 end of life.
Q: Can I test scripts on 3.13 while keeping production on 3.9?
Yes. Create a copy of your script and update it to run on Python 3.13 for testing. Fix any issues in the copy before promoting it to production. To avoid losing compatibility, keep separate versions—one for 3.9 and one for 3.13—so you can easily switch between them if needed.
Q: Will the Scripting Editor support changing the runtime?
Yes. Editor support for Python 3.13 will be available at the same time as API support in September 2025
Q: Where can I learn more about library support?
Check pyreadiness.org/3.13 and the "Supported scripting libraries and dependencies" Workiva help article.
Q: What happens to my historical run data if I switch scripts?
If you overwrite the original script, you keep the run history. If you point triggers to a copy, the original’s run history will remain with the old script.
Q: What happens if I don’t migrate by October 2026?
Your scripts will automatically transition to Python 3.13 after October 2026, when Workiva discontinues support for running scripts on Python 3.9 under AL2023. To avoid disruption, you should test and migrate scripts to Python 3.13 well before October 2026.
Q: Do I need to change my Chains or Integrated Automations when migrating?
No. Your Chains and Integrated Automations will continue to run as expected, as long as the underlying scripts are updated to Python 3.13. The main step is ensuring the script itself is migrated.
Q: Can I roll back a script from Python 3.13 to 3.9 if issues occur?
Users can switch a script’s runtime back to Python 3.9 temporarily, but any code changes made to adapt for Python 3.13 won’t be reverted automatically. You would need to manually adjust the script to make it compatible with 3.9 again. A better approach is to maintain separate copies—one adapted for Python 3.9 and another for Python 3.13—so you can switch between versions safely if issues arise.