New Admins: Register for our new Pure Lecture Series!
Pure's logos
Pure Help Center for Pure Administrators

If you are a researcher, or other non-admin at your institution, click here.

  • Home
  • Announcements
  • Release Notes
  • Technical user guides
  • Training
  • Events
  • Support
  • Contact Us
  • Home
  • Training
  • Technical user guides
  • Pure API
  • API Examples

How Can We Help?

Search Results

Filter By Category

Contact Us

If you still have questions or prefer to get help directly from an agent, please submit a request.
We’ll get back to you as soon as possible.

Contact us

Bulk Upload of Profile photos using Python with Pure APIBulk Upload of Profile photos using Python with Pure API

Introduction

Pure currently only supports uploading one file at a time with a specific mime type. However, tools can be utilized to overcome this limitation and automate the process of uploading multiple files in bulk. The objective of this script is to enable users to bulk upload photos for specific persons in Pure Admin by leveraging Python to interact with the 'Person' and 'File-uploads' endpoints. The primary goal is to automate the process of updating person profiles with new photos based on UUIDs provided in a CSV file.

 

Pure API examples disclaimer

Disclaimer
•    Proceed at your own risk. Running this script/function means you will not blame the author if this breaks your data.
•    This script/function is provided AS IS without warranty of any kind. It is recommended to run them in a test-staging environment to assess the outcome and understand their functionality.
•    Elsevier will not support or review any code that uses or is based on these examples. Nor will Elsevier support it in any other way.
•    This script has been tested with Pure 5.31 but might not work for future versions of Pure.
•    This script is developed for Python version 3.11 and have not been tested with any other version of Python.
•    Please make sure any Pure server you run this script against, has been backed up prior to running this script, to insure you can return to a working Pure if things fail

 

 

Expertise level

Knowledge of Python is required. See also Python API Requests: Fundamental Coding Examples

 

Requirements

  • Pure Admin Account
  • Valid API Key
  • API Documentation
  • Python.

 

Setup Before Running the Script 


Ensure the following prerequisites are met:

  1. Python 3.x installed.
  2. The necessary libraries must be installed:
    • requests
    • json
    • csv
  3. The CSV file (csv_files.csv) containing person UUIDs and photo file names must be located in the same directory as the script.
  4. The Images folder (images) must contain the corresponding image files that match the names listed in the CSV file. 

Sample CSV File Structure

The csv_files.csv file should contain two columns:

  1. uuid: The UUID of the person whose profile will be updated.
  2. photo_file: The name of the image file to be uploaded.
    1. Verify that the images folder contains the exact file names (case-sensitive).

Example CSV:

uuid,photo_file
933da504-1d3a-455f-8e74-da853dbeea61,male33.jpg
4d0dd5c2-3bd1-4f65-a839-6bf8c9703bde,male2.jpg
dfcad164-49e9-459a-9396-eb93adf2b131,female1.jpg
90fe4e71-8c93-417e-8eb0-8f886b3335f2,female2.jpg
1da376b8-21ac-4992-9638-6160324c450e,male3.jpg

Folder Structure

  • The folder containing the Python script should have the following structure:
    • bulk_upload_person_profile_photos.py (your Python script)
    • csv_files.csv (the CSV file containing UUIDs and photo file names)
    • images/ (folder containing the image files like male33.jpg, male34.jpg, etc.)

Python Script

Below is the complete Python script. You can copy it and modify the parameters as needed.

# -*- coding: utf-8 -*-
"""
Created on Wed Jan 22 20:21:47 2025
@author: mlr
# DISCLAIMER:
# running this script/function means you will not blame the author if this breaks your data.
# This script/function is provided AS IS without warranty of any kind.
# There is no support for the script.
# This script has been tested with Pure 5.31  but might not work for future versions of Pure.
# This script is developed for Python version 3.11, and have not been tested with any other version of Python.
# Please make sure any Pure server you run this script against, has been backed up prior to running this script,
# to insure you can return to a working Pure if things fails.
"""
import os
import requests
import json
import csv

# API endpoint URLs
person_url = "https://YourPureURL/ws/api/persons/"  # Replace with your actual person update URL
photo_url = "https://YourPureURL/ws/api/persons/file-uploads"  # Replace with your actual photo upload URL

# Headers for the requests
headers = {
    'api-key': 'YourAPIKeyHere',  # Replace with your actual API key 
    'Accept': 'application/json'
}

# Get the current script directory
script_dir = os.path.dirname(os.path.abspath(__file__))

# Relative paths to the CSV file and the images folder
csv_file_path = os.path.join(script_dir, 'csv_files.csv')
photo_dir = os.path.join(script_dir, 'images')

# Ensure the images folder exists
if not os.path.exists(photo_dir):
    print(f"❌ Error: Images folder not found at {photo_dir}")
    exit(1)

# Ensure the CSV file exists
if not os.path.exists(csv_file_path):
    print(f"❌ Error: CSV file not found at {csv_file_path}")
    exit(1)

# Function to upload a photo and get its digest and metadata
def upload_photo(file_path):
    with open(file_path, 'rb') as photo_file:
        headers['Content-Type'] = 'image/jpeg'
        response = requests.put(photo_url, headers=headers, data=photo_file)

    if response.status_code == 200:
        print(f"✅ Photo upload successful: {file_path}")
        response_data = response.json()
        return {
            "digest": response_data.get("digest"),
            "digestType": response_data.get("digestType"),
            "size": response_data.get("size"),
            "timestamp": response_data.get("timeStamp"),
            "expire": response_data.get("expires"),
            "key": response_data.get("key")
        }
    else:
        print(f"❌ Photo upload failed: {file_path} with status code: {response.status_code}")
        print(f"Response Body: {response.text}")
        raise Exception(f"Photo upload failed with status code: {response.status_code}")

# Read the CSV file and process each row
with open(csv_file_path, newline='', encoding='utf-8') as csvfile:
    csvreader = csv.DictReader(csvfile)

    # Validate CSV headers
    required_headers = {'uuid', 'photo_file'}
    if not required_headers.issubset(csvreader.fieldnames):
        print(f"❌ Error: CSV file must contain the following columns: {', '.join(required_headers)}")
        exit(1)

    for row in csvreader:
        uuid = row.get('uuid', '').strip()
        photo_file_name = row.get('photo_file', '').strip()

        # Skip rows with missing UUID or photo filename
        if not uuid or not photo_file_name:
            print(f"⚠️ Skipping row due to missing data: {row}")
            continue

        photo_path = os.path.join(photo_dir, photo_file_name)

        # Debugging: Print out the file path to verify
        print(f"🔍 Checking file: {photo_path}")

        if not os.path.exists(photo_path):
            print(f"⚠️ Skipping {photo_file_name}, file not found at {photo_path}.")
            continue

        # Upload photo to get the digest and metadata
        photo_metadata = upload_photo(photo_path)

        # Prepare JSON payload for updating the person
        json_payload = {
            "profilePhotos": [
                {
                    "fileName": photo_file_name,
                    "mimeType": "image/jpeg",
                    "uploadedFile": {
                        "digest": photo_metadata["digest"],
                        "digestType": photo_metadata["digestType"],
                        "size": photo_metadata["size"],
                        "timestamp": photo_metadata["timestamp"],
                        "expire": photo_metadata["expire"],
                        "key": photo_metadata["key"]
                    },
                    "type": {
                        "uri": "/dk/atira/pure/person/personfiles/portrait",
                        "term": {
                            "en_GB": "Some text"
                        }
                    },
                    "copyrightConfirmation": True,
                    "caption": {
                        "en_GB": f"Uploaded photo for {uuid}"
                    },
                    "altText": {
                        "en_GB": f"Profile photo for {uuid}"
                    },
                    "copyrightStatement": {
                        "en_GB": "Enter you own copyright statement for the photos here"
                    }
                }
            ]
        }
        # Log JSON payload to check before sending
        print(f"📤 Payload for updating person {uuid}: {json.dumps(json_payload, indent=2)}")

        # Make the PUT request to update the person with the photo
        person_update_url = f"{person_url}/{uuid}"

        # Ensure the correct content type for the JSON payload
        update_headers = headers.copy()
        update_headers['Content-Type'] = 'application/json'

        response = requests.put(person_update_url, headers=update_headers, data=json.dumps(json_payload))

        # Log the response status, body, and headers
        print(f"📬 Response Status Code: {response.status_code}")
        print(f"📬 Response Headers: {response.headers}")
        print(f"📬 Response Body: {response.text}")

        if response.status_code == 200:
            print(f"✅ Successfully updated person {uuid} with photo {photo_file_name}.")
        else:
            print(f"❌ Failed to update person {uuid} with photo {photo_file_name}. Status code: {response.status_code}")

 

Checkpoint validation process

✅ Handles missing uuid or photo_file in individual rows by skipping them.
✅ Prints warnings (⚠️) instead of crashing when files or data are missing.
✅ Uses structured logging (✅, ❌, 📤, 📬) to make debugging easier. 

✅ Customization: Replace placeholders such as API URLs and keys with actual values.

Example Command for Running the Script

Once all files are in place, simply run the script: 

python bulk_upload_person_profile_photos.py	

Published at February 13, 2025

Download
Table of Contents
  1. Introduction
  2. Pure API examples disclaimer
  3. Expertise level
  4. Requirements
  5. Setup Before Running the Script 
  6. Ensure the following prerequisites are met:
  7. Sample CSV File Structure
  8. Folder Structure
  9. Python Script
  10. Checkpoint validation process
  11. Example Command for Running the Script
Related Articles
  • Pure API: Uploading files
  • Pure API: Bulk Delete of Profile Photos using Python
  • Getting started: Pure API user guide
  • Python API Requests: Fundamental Coding Examples
Keywords
  • api
  • batch
  • pure api
  • pure api bulk
  • bulk upload
  • python
  • script
  • api example

Was this article helpful?

Yes
No
Give feedback about this article

    About Pure

  • Announcements

    Additional Support

  • Events
  • Client Community
  • Training

    Need Help?

  • Contact Us
  • Submit a Support Case
  • My Cases
  • Linkedin
  • Twitter
  • Facebook
  • Youtube
Elsevier logo Relx logo

Copyright © 2025 Elsevier, except certain content provided by third parties.

  • Terms & Conditions Terms & Conditions
  • Privacy policyPrivacy policy
  • AccesibilityAccesibility
  • Cookie SettingsCookie Settings
  • Log in to Pure Help CenterLog in to Helpjuice Center

Knowledge Base Software powered by Helpjuice

Expand