{"id":9239,"library":"pysnc","title":"Python SNC (ServiceNow) API","description":"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.","status":"active","version":"1.2.1","language":"en","source_language":"en","source_url":"https://github.com/ServiceNow/PySNC","tags":["ServiceNow","REST API","GlideRecord","ITSM","automation","asyncio","OAuth2"],"install":[{"cmd":"pip install pysnc","lang":"bash","label":"Basic installation"},{"cmd":"pip install pysnc[asyncio]","lang":"bash","label":"With async support"}],"dependencies":[],"imports":[{"note":"The primary synchronous client for interacting with ServiceNow.","wrong":"import pysnc","symbol":"ServiceNowClient","correct":"from pysnc import ServiceNowClient"},{"note":"Used for asynchronous operations, requires `pysnc[asyncio]` installation.","symbol":"AsyncServiceNowClient","correct":"from pysnc.asyncio import AsyncServiceNowClient"},{"note":"One of several OAuth2 authentication flows available, alongside ClientCredentialsGrantFlow.","symbol":"ServiceNowPasswordGrantFlow","correct":"from pysnc.oauth2 import ServiceNowPasswordGrantFlow"}],"quickstart":{"code":"import os\nfrom pysnc import ServiceNowClient\n\n# Configure environment variables for secure access\nSN_INSTANCE = os.environ.get('SN_INSTANCE', 'your_instance.service-now.com')\nSN_USERNAME = os.environ.get('SN_USERNAME', 'your_username')\nSN_PASSWORD = os.environ.get('SN_PASSWORD', 'your_password')\n\nif not all([SN_INSTANCE, SN_USERNAME, SN_PASSWORD]):\n    print(\"Please set SN_INSTANCE, SN_USERNAME, and SN_PASSWORD environment variables.\")\n    exit(1)\n\ntry:\n    # Initialize the ServiceNow client with basic authentication\n    client = ServiceNowClient(SN_INSTANCE, (SN_USERNAME, SN_PASSWORD))\n\n    # Create a GlideRecord object for the 'incident' table\n    gr = client.GlideRecord('incident')\n\n    # Add a query condition (e.g., active incidents)\n    gr.add_query('active', 'true')\n    gr.add_limit(5) # Limit results for demonstration\n\n    # Execute the query\n    gr.query()\n\n    # Iterate through the results (Pythonic iteration is recommended)\n    print(f\"Found {gr.get_row_count()} active incidents:\")\n    for record in gr:\n        print(f\"  Incident Number: {record.number}, Short Description: {record.short_description}\")\n\n    # Example of getting a single record by sys_id\n    if gr.get_row_count() > 0:\n        first_sys_id = gr.next().sys_id # Using .next() here for specific record access\n        single_record = client.GlideRecord('incident')\n        if single_record.get(first_sys_id):\n            print(f\"\\nRetrieved single incident: {single_record.number}\")\n\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")","lang":"python","description":"This quickstart demonstrates how to initialize the `ServiceNowClient` using environment variables for credentials, create a `GlideRecord` object, add a query, execute it, and iterate through the results. It also shows how to fetch a single record by its `sys_id`."},"warnings":[{"fix":"Use `for record in gr:` for iteration. If using `gr.next()`, call `gr.rewind()` before re-iterating.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Before `gr.query()`, set `gr.fields = 'field1,field2,sys_id'`. Adjust `client.GlideRecord('table', batch_size=X)` as needed.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Upgrade `pysnc` to version 1.1.9 or later to ensure `GlideRecord.changes()` functions correctly.","message":"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.","severity":"breaking","affected_versions":"<1.1.9"},{"fix":"Always use snake_case for `pysnc` method calls, such as `gr.add_query()`, `gr.get_value()`, `gr.update_multiple()`.","message":"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`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure you are using `pysnc` version 1.1.7 or newer.","message":"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.","severity":"breaking","affected_versions":"<1.1.7 with pip >= 24"},{"fix":"Replace `gr.field = 'value'` with `gr.set_value('field', 'value')` when preparing for `update_multiple()` operations.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Change method calls to snake_case, e.g., `gr.add_query()` instead of `gr.addQuery()`, `gr.get_value()` instead of `gr.getValue()`.","cause":"Attempting to use camelCase method names (like in ServiceNow JavaScript) instead of Pythonic snake_case.","error":"AttributeError: 'GlideRecord' object has no attribute 'addQuery'"},{"fix":"Verify 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.","cause":"The `ServiceNowClient` object failed to initialize or authenticate, returning `None` or an invalid object, then subsequent calls fail.","error":"TypeError: 'NoneType' object has no attribute 'GlideRecord' or 'NoneType' object is not callable"},{"fix":"If 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.","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.","error":"RuntimeWarning: 'GlideRecord' object is not rewindable. Iteration can only occur once."},{"fix":"Always 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.","cause":"Directly setting a field property (`gr.field = 'value'`) before calling `update_multiple()` instead of using the `set_value()` method.","error":"Unexpectedly, all records in the table were updated instead of just the queried ones using update_multiple()."}]}