Skip to main content

GitHub Actions CI PyPI - License PyPI - Version PyPI - Wheel Supported Versions

Sppyte

A tiny, explicit Python helper for working with SharePoint site in Python using legacy SharePoint REST endpoints using NTLM authentication. Sppyte1 keeps a very thin abstraction so you can reason about the underlying HTTP calls without surprises.

⚠️ This client uses NTLM (requests-ntlm) and is best suited for SharePoint on-prem or environments where NTLM is configured. SharePoint Online typically uses different auth flows.

Table of Contents

Features

  • Simple Site connection with NTLM auth and automatic form digest retrieval.
  • List helper to:
    • Add / update / delete items
    • Use OData params to control item responses
    • Add attachments to items
  • Library helper to:
    • Add / delete folders
    • Upload / download / delete documents
    • List folder contents and control output with OData params
  • Access other SharePoint REST service endpoints as needed

Installation

pip install sppyte

Quickstart

from sppyte import Site

HOST = "https://sharepoint.example.com"
SITE = "/sites/parrots" # relative path
USER = "norwegian"
PASS = "••••••••"

with Site(HOST, SITE, USER, PASS) as site:
    # ---------------- Lists ----------------
    pets = site.list("Pets")

    # Add an item (metadata type is auto-inferred if omitted)
    new_id = pets.add_item({"Title": "Norwegian Blue"})

    # Update the item (uses MERGE)
    patch = {"Title": "Polly"} # Fields to be updated
    pets.update_item(new_id, patch)

    # Attach a file
    with open("notes.txt", "rb") as file_handle: # Read bytes
        pets.add_attachment(new_id, "notes.txt", file_handle)

    # Fetch one item
    item = pets.get_item(new_id)

    # Query contents (use any OData params you need)
    params = {
        "$select": "Id,Title,Created",
        "$top": 5,
        "$orderby": "Created desc",
    }
    r = pets.get_contents(params)

    # Delete the item
    pets.delete_item(new_id)

    # --------------- Libraries -------------
    shared_docs = site.library("Shared Documents")

    # Ensure a nested folder path exists
    shared_docs.add_folder("Napping", "2025")

    # Upload a document
    with open("report.pdf", "rb") as file_handle:
        unique_id = shared_docs.add_document("report.pdf", file_handle)

    # List library files
    params = {"$select": "Name,TimeCreated"}
    files = shared_docs.list_contents(params)

    # List files in subfolder
    folder_files = shared_docs.list_contents(params, "Napping", "2025")

    # Download a document (bytes)
    report = shared_docs.get_document("report.pdf")

    # Download a document in a subfolder (ex: Shared Documents/Napping/2025/report.pdf)
    report = shared_docs.get_document("report.pdf", "Napping", "2025")

    # Delete a document
    shared_docs.delete_document("report.pdf")

    # Delete a document in a subfolder
    shared_docs.delete_document("report.pdf", "Napping", "2025")

API Overview

Site

Model a SharePoint site with authentication and session management.

sppyte.Site(host, site, username, password)

Configure a SharePoint site connection.

Parameters

  • host: str - SharePoint site host (protocol://domain)
  • site: str - SharePoint site relative url
  • username: str - SharePoint site username
  • password: str - SharePoint site password

Returns: Site object

Usage:

from sppyte import Site

HOST = "https://sharepoint.example.com"
SITE = "/sites/parrots" # relative path
USER = "norwegian"
PASS = "••••••••"

site = Site(HOST, SITE, USER, PASS)
try:
  site.connect() # Start session
  # Do cool stuff
except HTTPError as e:
  # Deal with errors
finally:
  site.close() # Close session

# Using a context manager is preferred
with Site(HOST, SITE, USER, PASS) as site:
  # Do cool stuff

Notes

  • User should have permissions to the site, library, or list to be accessed. Updates require contribute or higher level access. Unauthorized user will raise a requests.HTTPError 401 - Unauthorized exception.
  • For user managed connections, call the connect method to start a session and close method to end the session. Using a with statement for context management will automatically connect and close sessions.

Site.connect()

Start a connected session.

Site.close()

Close connected session.

Site.list(name)

Get a List class instance.

Parameters

  • name: str - SharePoint list name

Returns: sppyte.List

Usage:

# Given a list named 'Pets'
pets = site.list('Pets')

Site.library(name)

Get a Library class instance.

Parameters

  • name (str): SharePoint document library name

Returns: sppyte.Library

Usage:

# Given a document library named 'Contracts'
contracts = site.library('Contracts')

List

Model a SharePoint list with authentication and methods to interact with the list items.

sppyte.List(name, site)

Create a list connection. Useful alternative when you only need to access a single list.

Parameters

  • name (str): SharePoint list name
  • site (Site): sppyte Site

Returns: List object

Usage:

from sppyte import Site, List

HOST = "https://sharepoint.example.com"
SITE = "/sites/parrots" # relative path
USER = "norwegian"
PASS = "••••••••"

# Given a list named 'Pets'
site = Site(HOST, SITE, USER, PASS)
pets = List('Pets', site)

try:
  pets.connect()
  # Do cool stuff
except HTTPError as e:
  # Deal with errors
finally:
  pets.close() # Close session

# Using a context manager is preferred
with List('Pets', site) as pets:
  # Do cool stuff

Notes

  • User should have permissions to the list to be accessed. Updates require contribute or higher level access. Unauthorized user will raise a requests.HTTPError 401 - Unauthorized exception.
  • For user managed connections, call the connect method to start a session and close method to end the session. Using a with statement for context management will automatically connect and close sessions.

List.connect()

Start a connected session.

List.close()

Close the session.

List.add_item(item)

Add an item to a SharePoint list. Returns the added item ID.

Parameters

  • item (Mapping[str, Any]): Item to be added. The mapping is not modified.

Returns: int

Usage:

# Given a item with Title and breed fields
new_item = {
  "Title": "Sonny",
  "breed": "Norwegian Blue"
}
pet_id = pets.add_item(new_item)

Notes

  • Required SharePoint metadata is added automatically.

List.add_attachment(sp_id, file_name, attachment)

Add an attachment to an existing list item.

Parameters

  • sp_id: int - Item to append attachment
  • file_name: str - Attachment file name (include file extension)
  • attachment: bytes | IO[bytes] - Stream file content

Returns: int - SharePoint item id

Usage:

# Given a item with ID of 23
pet_id = 23
with open("notes.txt", "rb") as fh:
    pets.add_attachment(pet_id, "notes.txt", fh)

List.delete_item(sp_id: int)

Parameters

  • sp_id: int - Item to delete

Returns: bool

Usage:

# Given a item with ID of 23
pet_id = 23
delete_success = pets.delete_item(pet_id)

List.get_contents(params)

Get contents of a SharePoint list.

Parameters

  • params: Mapping[str, str | int] | None - OData params (See the docs for supported OData params)

Returns: list[dict[str, Any]] - JSON decoded list items

Notes

  • SharePoint returns at most 100 items unless $top is given.

Usage:

pet_items = pets.get_contents({
    "$select": "Id,Title,Created",
    "$top": 500,
    "$orderby": "Created desc",
})

List.get_item(sp_id)

Get SharePoint list item by ID.

Parameters

  • sp_id: int - SharePoint ID to retrieve

Returns: dict[str, str | int] - JSON decoded item contents

Usage:

pet_id = 23
pet_item = pets.get_item(pet_id)

List.update_item(sp_id: int, patch: dict)

Update an existing list item merging properties from a patch.

Parameters

  • sp_id: int - SharePoint ID to update
  • patch: Mapping[str, Any] - Fields and values to update. The mapping is not modified.

Returns: int - Updated SharePoint ID

Usage:

pet_id = 23
patch = {
  "Title": "Polly",
}
pets.update_item(pet_id, patch)

Library

Model a SharePoint library with authentication and methods to interact with the documents.

sppyte.Library(name, site)

Connect to a document library. Useful alternative when you only need to access a single library.

Parameters

  • name (str): SharePoint library name
  • site (Site): sppyte Site

Returns: Library object

Usage:

from sppyte import Site, Library

HOST = "https://sharepoint.example.com"
SITE = "/sites/Parrots" # relative path
USER = "norwegian"
PASS = "••••••••"

# Given a document library named 'Contracts'
site = Site(HOST, SITE, USER, PASS)
contracts = Library('Contracts', site)

try:
  contracts.connect()
  # Do cool stuff
except HTTPError as e:
  # Deal with errors
finally:
  contracts.close() # Close session

# Using a context manager is preferred
with Library('Contracts', site) as contracts:
  # Do cool stuff

Notes

  • User should have permissions to the library to be accessed. Updates require contribute or higher level access. Unauthorized user will raise a requests.HTTPError 401 - Unauthorized exception.
  • For user managed connections, call the connect method to start a session and close method to end the session. Using a with statement for context management will automatically connect and close sessions.

Library.connect()

Start a connected session.

Library.close()

Close the session.

Library.add_folder(folder, *subfolders)

Add a folder to a SharePoint document library.

Parameters

  • folder: str - folder to add
  • *subfolders: str (Optional) - additional path folder names for nested folders

Returns: bool - Add succeeded

Usage:

contracts.add_folder('2025', 'January')

Library.add_document(file_name, document, *subfolders)

Load a document to a SharePoint document library.

Parameters

  • file_name: str - file name add
  • document: bytes | IO[bytes] - File content (bytes or a binary file-like object)
  • *subfolders: str (Optional) - additional path folder names for nested folders

Returns: str - Unique ID

Usage:

with open("notes.txt", "rb") as file_handler:
    contracts.add_document("notes.txt", file_handler, '2025', 'January')

Library.folder_exists(folder, *subfolders)

Check if a folder exists in a SharePoint document library.

Parameters

  • folder: str - Folder to check
  • *subfolders: str (Optional) - Additional path folder names for nested folders

Returns: bool - Folder exists

Usage:

contracts.folder_exists('2025', 'January')

Library.delete_document(file_name, *subfolders)

Delete a document from a SharePoint document library.

Parameters

  • file_name: str - File name to delete
  • *subfolders: str (Optional) - Additional path folder names for nested folders

Returns: bool - Delete succeeded

Usage:

contracts.delete_document("notes.txt", '2025', 'January')

Library.delete_folder(folder, *subfolders)

Delete a folder from a SharePoint document library.

Parameters

  • folder: str - Folder to delete
  • *subfolders: str (Optional) - Additional path folder names for nested folders

Returns: bool - Delete succeeded

Usage:

contracts.delete_folder('2025', 'January')

Library.list_contents(params, *subfolders)

List contents of a SharePoint document library.

Parameters

  • params: Mapping[str, str | int] | None - OData params (See the docs for supported OData params)
  • *subfolders: str (Optional) - Additional path folder names for nested folders

Returns: list[dict[str, Any]] - JSON decoded list metadata

Usage:

files = contracts.list_contents({
    "$select": "Name,TimeCreated"
  }, "January", "2025")

Library.get_document(file_name, *subfolders)

Read a document from a SharePoint document library.

Parameters

  • file_name: str - File name to read
  • *subfolders: str (Optional) - Additional path folder names for nested folders

Returns: bytes - Streamed contents

Usage:

document = contracts.get_document("notes.txt", "2025", "January")
contents = document.decode()

Errors

  • SessionError: raised when an HTTP session isn’t available.
  • ResponseFormatError: raised when an expected JSON field is missing (e.g., FormDigestValue, ListItemEntityTypeFullName, ID, UniqueId).

Handle them as you would any exception:

from sppyte import ResponseFormatError, SessionError

try:
    ...
except (ResponseFormatError, SessionError) as e:
    print("Sppyte error:", e)

Extension methods

SharePoint REST services endpoints not explicitly implemented can be accessed through the request method exposed on Site. This methods uses authentication from the current Site session and shadows requests.request from the requests package, using a site relative path instead of a complete url.

The get_form_digest method is provided to obtain the bearer token passed in the X-RequestDigest header for update requests.

List exposes the get_item_type method to obtain the required list item type metadata for list updates.

Notes

  • Special characters: list titles, folder names and file names are escaped for OData string literals automatically, so names containing spaces, ', #, %, ? or & work as-is.
  • OData Parameters: Methods like get_contents and list_contents accept any OData parameters via params (e.g., $select, $filter, $orderby, $top). See the docs for supported OData params.
  • HTTP request errors are passed through from the requests library unhandled for transparency. See the docs for more information.
  • SharePoint limits list response record counts by default. Use the $top OData param for larger response counts.

Contributing

This is a pet project to save me time at work and not open for contribution.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

License

MIT License

  1. What's the deal with this name? (S)hare(P)oint (Py)thon Si(te) ↩

Metadata

Release files for sppyte 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sppyte 0.2.0
File Size Uploaded Provenance
sppyte-0.2.0.tar.gz 16.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sppyte 0.2.0
File Interpreter ABI Platform
sppyte-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.4 kB

Release files / sppyte-0.2.0.tar.gz

Download URL sppyte-0.2.0.tar.gz
Size 16.0 kB
Tags Source
SHA-256 checksum
How to use checksums
90dd13b158d351356d467abfa6f7971ee14f2a881cd97b33fa711504fbe1e680
BLAKE2b-256 checksum
How to use checksums
7a5591b42a84bb4275a1e1400a86b3dce2eb3f0febb69d7e3cf73adab98bfd01
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Release files / sppyte-0.2.0-py3-none-any.whl

Download URL sppyte-0.2.0-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67eac33b2a9e9fd753ebd9230440e7700de814a05f941acee26fcf8c268d05a8
BLAKE2b-256 checksum
How to use checksums
3ef27a28c559f6bd99420205a654c2ec068b4d0f8d5446a258770b618384f08f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Security for sppyte 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sppyte-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page