Python SNC (ServiceNow) API
PySNC is a Python interface for the ServiceNow REST and Table APIs, designed to mimic the familiar GlideRecord interface with Pythonic support. It provides robust features for interacting with ServiceNow instances, including synchronous and asynchronous operations, OAuth 2.0 Client Credentials Grant Flow, mTLS support, and built-in retry mechanisms for common error codes. The library is actively maintained with a positive release cadence.
Common errors
-
AttributeError: 'GlideRecord' object has no attribute 'addQuery'
cause Attempting to use camelCase method names (like in ServiceNow JavaScript) instead of Pythonic snake_case.fixChange method calls to snake_case, e.g., `gr.add_query()` instead of `gr.addQuery()`, `gr.get_value()` instead of `gr.getValue()`. -
TypeError: 'NoneType' object has no attribute 'GlideRecord' or 'NoneType' object is not callable
cause The `ServiceNowClient` object failed to initialize or authenticate, returning `None` or an invalid object, then subsequent calls fail.fixVerify the ServiceNow instance URL (`SN_INSTANCE`) and ensure that authentication credentials (username/password or OAuth details) are correct and that the user has the necessary API roles. Check for network connectivity issues. -
RuntimeWarning: 'GlideRecord' object is not rewindable. Iteration can only occur once.
cause A `GlideRecord` object that was initialized with `rewindable=False` (or after `gr.next()` has been called to exhaust results) is being iterated a second time.fixIf multiple iterations are needed, ensure `GlideRecord` is created with `rewindable=True` (which is the default behavior). If using `gr.next()`, call `gr.rewind()` before starting a new iteration. Pythonic `for` loops handle this more gracefully. -
Unexpectedly, all records in the table were updated instead of just the queried ones using update_multiple().
cause Directly setting a field property (`gr.field = 'value'`) before calling `update_multiple()` instead of using the `set_value()` method.fixAlways use `gr.set_value('field_name', 'new_value')` when preparing a `GlideRecord` object for `update_multiple()` to ensure the update applies only to records matching the query.
Warnings
- gotcha When iterating a `GlideRecord` using the traditional `gr.next()` method, you must call `gr.rewind()` if you wish to iterate a second time over the same result set. Pythonic iteration (e.g., `for record in gr:`) handles this automatically and is generally preferred.
- gotcha For optimal performance, explicitly set `GlideRecord.fields` to retrieve only the necessary columns and tune `batch_size` based on your instance's configuration and API usage. Retrieving all fields or very large batches can impact performance.
- breaking Versions prior to 1.1.9 contained a bug where `GlideRecord.changes()` could incorrectly return `False` when multiple modifications were made to a record, leading to missed updates or incorrect state detection.
- gotcha Unlike ServiceNow's native JavaScript APIs which use camelCase (e.g., `addQuery`), `pysnc` adheres to Python's PEP 8 guidelines, using snake_case for method names (e.g., `add_query`). Using incorrect casing will result in `AttributeError`.
- breaking Users of `pip >= 24` experienced installation or runtime issues with older versions of `pysnc` due to dependency resolution changes. This was addressed in `pysnc` 1.1.7.
- gotcha When using `GlideRecord.update_multiple()`, setting field values directly as properties (e.g., `gr.state = '10'`) can lead to unintended updates across all records in the table. Always use `gr.set_value('field_name', 'new_value')` for field assignments before calling `update_multiple()` to ensure only queried records are affected.
Install
-
pip install pysnc -
pip install pysnc[asyncio]
Imports
- ServiceNowClient
import pysnc
from pysnc import ServiceNowClient
- AsyncServiceNowClient
from pysnc.asyncio import AsyncServiceNowClient
- ServiceNowPasswordGrantFlow
from pysnc.oauth2 import ServiceNowPasswordGrantFlow
Quickstart
import os
from pysnc import ServiceNowClient
# Configure environment variables for secure access
SN_INSTANCE = os.environ.get('SN_INSTANCE', 'your_instance.service-now.com')
SN_USERNAME = os.environ.get('SN_USERNAME', 'your_username')
SN_PASSWORD = os.environ.get('SN_PASSWORD', 'your_password')
if not all([SN_INSTANCE, SN_USERNAME, SN_PASSWORD]):
print("Please set SN_INSTANCE, SN_USERNAME, and SN_PASSWORD environment variables.")
exit(1)
try:
# Initialize the ServiceNow client with basic authentication
client = ServiceNowClient(SN_INSTANCE, (SN_USERNAME, SN_PASSWORD))
# Create a GlideRecord object for the 'incident' table
gr = client.GlideRecord('incident')
# Add a query condition (e.g., active incidents)
gr.add_query('active', 'true')
gr.add_limit(5) # Limit results for demonstration
# Execute the query
gr.query()
# Iterate through the results (Pythonic iteration is recommended)
print(f"Found {gr.get_row_count()} active incidents:")
for record in gr:
print(f" Incident Number: {record.number}, Short Description: {record.short_description}")
# Example of getting a single record by sys_id
if gr.get_row_count() > 0:
first_sys_id = gr.next().sys_id # Using .next() here for specific record access
single_record = client.GlideRecord('incident')
if single_record.get(first_sys_id):
print(f"\nRetrieved single incident: {single_record.number}")
except Exception as e:
print(f"An error occurred: {e}")