CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-osfclient

A Python library and command-line interface for interacting with the Open Science Framework

Pending
Overview
Eval results
Files

project-management.mddocs/

Project Management

Project, storage, file, and folder management classes for navigating and manipulating OSF project structures. These classes provide the core functionality for working with OSF data and files.

Capabilities

Project Class

Represents an OSF project containing multiple storage providers and associated metadata.

class Project:
    def storage(self, provider='osfstorage'):
        """
        Return specific storage provider.

        Args:
            provider (str): Storage provider name (default: 'osfstorage')
                          Options: 'osfstorage', 'github', 'figshare', 'googledrive', 'owncloud'

        Returns:
            Storage: Storage instance for the specified provider

        Raises:
            RuntimeError: If project has no storage provider with the given name
        """

    @property
    def storages(self):
        """
        Iterate over all storage providers for this project.

        Yields:
            Storage: Storage instances for each available provider
        """

    @property
    def id(self):
        """Project ID (GUID)."""

    @property
    def title(self):
        """Project title."""

    @property
    def description(self):
        """Project description."""

    @property
    def date_created(self):
        """Project creation date."""

    @property
    def date_modified(self):
        """Project last modified date."""

Storage Class

Represents a storage provider within a project, such as OSF Storage, GitHub, Figshare, etc.

class Storage:
    def create_file(self, path, fp, force=False, update=False):
        """
        Store a new file at path in this storage.

        Args:
            path (str): Full path where to store the file
            fp (file): File descriptor opened in 'rb' mode
            force (bool): Force overwrite of existing file
            update (bool): Overwrite existing file only if files differ

        Raises:
            ValueError: If file not opened in binary mode
            FileExistsError: If file exists and neither force nor update is True
            RuntimeError: If upload fails or file cannot be created/updated
        """

    def create_folder(self, name, exist_ok=False):
        """
        Create a new folder.

        Args:
            name (str): Folder name
            exist_ok (bool): Don't raise exception if folder already exists

        Returns:
            Folder: Created folder instance

        Raises:
            FolderExistsException: If folder exists and exist_ok is False
            RuntimeError: If folder creation fails
        """

    @property
    def files(self):
        """
        Iterate over all files in this storage.

        Recursively lists all files in all subfolders.

        Yields:
            File: File instances for each file in storage
        """

    @property
    def folders(self):
        """
        Iterate over top-level folders in this storage.

        Yields:
            Folder: Folder instances for each top-level folder
        """

    @property
    def id(self):
        """Storage ID."""

    @property
    def name(self):
        """Storage name."""

    @property
    def provider(self):
        """Storage provider name ('osfstorage', 'github', etc.)."""

    @property
    def path(self):
        """Storage path."""

    @property
    def node(self):
        """Associated project node."""

File Class

Represents an individual file in OSF storage with download, update, and deletion capabilities.

class File:
    def write_to(self, fp):
        """
        Write contents of this file to a local file.

        Args:
            fp (file): File pointer opened for writing in binary mode

        Raises:
            ValueError: If file not opened in binary mode
            RuntimeError: If download fails
        """

    def remove(self):
        """
        Remove this file from remote storage.

        Raises:
            RuntimeError: If deletion fails
        """

    def update(self, fp):
        """
        Update the remote file from a local file.

        Args:
            fp (file): File pointer opened for reading in binary mode

        Raises:
            ValueError: If file not opened in binary mode
            RuntimeError: If update fails
        """

    @property
    def id(self):
        """File ID."""

    @property
    def name(self):
        """File name."""

    @property
    def path(self):
        """Materialized file path."""

    @property
    def osf_path(self):
        """OSF internal path."""

    @property
    def size(self):
        """File size in bytes."""

    @property
    def date_created(self):
        """File creation date."""

    @property
    def date_modified(self):
        """File last modified date."""

    @property
    def hashes(self):
        """
        Dictionary of file hashes.

        Returns:
            dict: Hash values keyed by algorithm ('md5', 'sha256', etc.)
        """

Folder Class

Represents a folder in OSF storage with file and subfolder access capabilities.

class Folder:
    def create_folder(self, name, exist_ok=False):
        """
        Create a subfolder within this folder.

        Args:
            name (str): Subfolder name
            exist_ok (bool): Don't raise exception if folder already exists

        Returns:
            Folder: Created subfolder instance

        Raises:
            FolderExistsException: If folder exists and exist_ok is False
            RuntimeError: If folder creation fails
        """

    @property
    def files(self):
        """
        Iterate over files in this folder.

        Unlike Storage.files, this does not recursively find all files.
        Only lists files directly in this folder.

        Yields:
            File: File instances for each file in folder
        """

    @property
    def folders(self):
        """
        Iterate over subfolders in this folder.

        Yields:
            Folder: Folder instances for each subfolder
        """

    @property
    def id(self):
        """Folder ID."""

    @property
    def name(self):
        """Folder name."""

    @property
    def path(self):
        """Materialized folder path."""

    @property
    def osf_path(self):
        """OSF internal path."""

    @property
    def date_created(self):
        """Folder creation date."""

    @property
    def date_modified(self):
        """Folder last modified date."""

Usage Examples

Working with Projects

from osfclient import OSF

osf = OSF(token='your_token')
project = osf.project('project_id')

print(f"Project: {project.title}")
print(f"Created: {project.date_created}")
print(f"Description: {project.description}")

# List all storage providers
for storage in project.storages:
    print(f"Storage: {storage.name} ({storage.provider})")

# Get default OSF Storage
osf_storage = project.storage()  # defaults to 'osfstorage'

# Get specific storage provider
try:
    github_storage = project.storage('github')
    print(f"GitHub storage available: {github_storage.name}")
except RuntimeError:
    print("No GitHub storage configured for this project")

File Operations

# List all files recursively
storage = project.storage()
for file in storage.files:
    print(f"File: {file.path}")
    print(f"  Size: {file.size} bytes")
    print(f"  Modified: {file.date_modified}")
    print(f"  MD5: {file.hashes.get('md5', 'N/A')}")

# Download a specific file
target_file = next((f for f in storage.files if f.name == 'data.csv'), None)
if target_file:
    with open('local_data.csv', 'wb') as local_file:
        target_file.write_to(local_file)
    print("File downloaded successfully")

# Upload a new file
with open('local_upload.txt', 'rb') as upload_file:
    storage.create_file('remote_folder/uploaded_file.txt', upload_file)
    print("File uploaded successfully")

# Update existing file
existing_file = next((f for f in storage.files if f.name == 'update_me.txt'), None)
if existing_file:
    with open('new_content.txt', 'rb') as content:
        existing_file.update(content)
    print("File updated successfully")

# Delete a file
file_to_delete = next((f for f in storage.files if f.name == 'delete_me.txt'), None)
if file_to_delete:
    file_to_delete.remove()
    print("File deleted successfully")

Folder Operations

# Create folder structure
storage = project.storage()
main_folder = storage.create_folder('data_analysis', exist_ok=True)
sub_folder = main_folder.create_folder('raw_data', exist_ok=True)

# Navigate folder structure
for folder in storage.folders:
    print(f"Top-level folder: {folder.name}")
    for subfolder in folder.folders:
        print(f"  Subfolder: {subfolder.name}")
    for file in folder.files:
        print(f"  File: {file.name}")

# Upload file to specific folder structure
with open('experiment_data.csv', 'rb') as data_file:
    storage.create_file('data_analysis/raw_data/experiment_data.csv', data_file)

Handling Upload Conflicts

with open('existing_file.txt', 'rb') as upload_file:
    try:
        # This will fail if file already exists
        storage.create_file('path/existing_file.txt', upload_file)
    except FileExistsError:
        print("File already exists")
        
        # Force overwrite
        upload_file.seek(0)  # Reset file pointer
        storage.create_file('path/existing_file.txt', upload_file, force=True)
        print("File overwritten")

# Or use update mode (only overwrites if files differ)
with open('maybe_changed.txt', 'rb') as upload_file:
    storage.create_file('path/maybe_changed.txt', upload_file, update=True)
    print("File uploaded or updated if changed")

Install with Tessl CLI

npx tessl i tessl/pypi-osfclient

docs

cli-interface.md

index.md

project-management.md

python-api.md

utilities.md

tile.json