Workspaces API (DEPRECATED)

Last Updated: May 2024

Warning

The Workspaces API has been replaced by the Paths API and is now deprecated. It will be removed in Tethys v5.0. Please see Paths API to start using the Paths API.

Guide to transitioning to the Paths API

Use the following guide to transition apps that have been using the Workspaces API to use the new Paths API.

In Tethys v4.3 a temporary setting (USE_OLD_WORKSPACES_API) was introduces to ensure that apps will not break with the introduction of the Paths API. To begin using the Paths API set the value of USE_OLD_WORKSPACES_API to False.

tethys settings -s USE_OLD_WORKSPACES_API False

The primary difference with transitioning to the Paths API is that rather than returning TethysWorkspace objects Paths API calls will return a TethysPath object. The TethysPath object has the same interface as the TethysWorkspace with the exception that it will return Python pathlib.Path objects to represent files and directories rather than strings. For example when using the Workspaces API you might do something along these lines:

import os
...

@controller(
    app_workspace=True
)
def my_controller(request, app_workspace):
    my_path = os.path.join(app_workspace.path, 'my_dir')
    ...

When using the Paths API it would look something like this:

...

@controller(
    app_workspace=True
)
def my_controller(request, app_workspace):
    my_path = app_workspace.path / 'my_dir'
    ...

Note

if you are unfamiliar with Python's pathlib module then see the pathlib documentation

If you are using workspaces with the Handler Decorator then note that the with_workspaces argument should be replaced with with_paths:

from tethys_sdk.routing import handler

@handler(
    with_paths=True
)
def my_handler(doc):
    my_dir = doc.app_workspace.path / 'my_dir'

Functions and decorators that were imported from tethys_sdk.workspaces should now be imported from tethys_sdk.paths.

from tethys_sdk.paths import (
    get_app_workspace,
    get_user_workspace,
    app_workspace,
    user_workspace,
)

Note that the Paths API has additional functions and decorators. For more information the Paths API documentation.

Workspaces Overview

The Workspaces API makes it easy for you to create directories for storing files that your app operates on. This can be a tricky task for a web application, because of the multi-user, simultaneous-connection environment of the web. The Workspaces API provides a simple mechanism for creating and managing a global workspace for your app and individual workspaces for each user of your app to prevent unwanted overwrites and file lock conflicts.

Getting Workspaces

There are four methods for obtaining the workspaces that are supported in Tethys Platform. In order of recommended use, the workspace methods are:

  • Controller Decorator

  • Workspaces Decorators

  • App Class Methods

  • Workspace Functions

Controller Decorator

The recommended method for obtaining workspaces in controllers is to use the app_workspace and user_workspace arguments of the controller decorator:

from tethys_sdk.routing import controller

@controller(app_workspace=True)
def my_controller(request, app_workspace):
   ...

@controller(user_workspace=True)
def my_controller(request, user_workspace):
   ...

@controller(app_workspace=True, user_workspace=True)
def my_controller(request, app_workspace, user_workspace):
   ...

To learn more about the controller decorator, see: Controller Decorator

Workspace Decorators

The Workspaces API includes two decorators, that can be used to retrieve the app workspace and the user workspaces, respectively. To use these decorators, import them from tethys_sdk.workspaces. Explanations of the decorators and example usage follows.

@app_workspace

workspace.app_workspace()

Decorator: Get the file workspace (directory) for the app. Add an argument named "app_workspace" to your controller. The TethysWorkspace will be passed to via this argument.

Returns:

An object representing the workspace.

Return type:

TethysWorkspace

Example:

import os
from .app import App
from tethys_sdk.workspaces import app_workspace

@app_workspace
def a_controller(request, app_workspace):
    """
    Example controller that uses @app_workspace() decorator.
    """
    new_file_path = os.path.join(app_workspace.path, 'new_file.txt')

    with open(new_file_path, 'w') as a_file:
        a_file.write('...')

    context = {}

    return App.render(request, 'template.html', context)

@user_workspace

workspace.user_workspace()

Decorator: Get the file workspace (directory) for the given User. Add an argument named "user_workspace" to your controller. The TethysWorkspace will be passed to via this argument.

Returns:

An object representing the workspace.

Return type:

TethysWorkspace

Example:

import os
from .app import App
from tethys_sdk.workspaces import user_workspace

@user_workspace
def a_controller(request, user_workspace):
    """
    Example controller that uses @user_workspace() decorator.
    """
    new_file_path = os.path.join(user_workspace.path, 'new_file.txt')

    with open(new_file_path, 'w') as a_file:
        a_file.write('...')

    context = {}

    return App.render(request, 'template.html', context)

App Class Methods

In cases where it is not possible to use one of the decorators, the app class provides methods for getting the workspaces:

from .app import App
from django.contrib.auth.models import User

user = User.objects.get(id=1)
app_workspace = App.get_app_workspace()
user_workspace = App.get_user_workspace(user)
...

For more details see App Base Class API

Workspace Functions

In the rare cases where you need to use a workspace where it is not convenient or not possible to use one of the decorators OR the app class methods, the Workspaces API provides function versions of the getters. Import them from tethys_sdk.workspaces:

paths.get_app_workspace()
Parameters:

app_or_request (TethysAppBase, TethysApp, or HttpRequest) -- The Tethys app class that is defined in app.py or HttpRequest to app endpoint.

Raises:
  • ValueError -- if app_or_request is not correct type.

  • AssertionError -- if quota for the app workspace/media directory has been exceeded.

Return type:

TethysPath

Returns: TethysPath representing the app workspace.

paths.get_user_workspace(user_or_request)

Get the dedicated user workspace for the given app. If an HttpRequest is given, the workspace of the logged-in user will be returned (i.e. request.user).

Parameters:
  • app_or_request (TethysAppBase, TethysApp, or HttpRequest) -- The Tethys app class that is defined in app.py or HttpRequest to app endpoint.

  • user_or_request (User or HttpRequest) -- Either an HttpRequest with active user session or Django User object.

Raises:
  • ValueError -- if app_or_request or user_or_request are not correct types.

  • AssertionError -- if quota for the user workspace/media directory has been exceeded.

Return type:

TethysPath

Returns:

TethysPath representing the user's workspace directory.

from tethys_sdk.workspaces import get_user_workspace
from .app import App

def some_function(user):
    user_workspace = get_user_workspace(App, user)
    ...

Working with Workspaces

All of the methods described above return a TethysWorkspace object that contains the path to the workspace and several convenience methods for working with the workspace directory. An explanation of the TethysWorkspace object and examples of it's usage are provided below.

TethysWorkspace Objects

class tethys_apps.base.TethysWorkspace(path)

Defines objects that represent file workspaces (directories) for apps and users.

path

The absolute path to the workspace directory. Cannot be overwritten.

Type:

str

clear(exclude=None, exclude_files=False, exclude_directories=False)

Remove all files and directories in the workspace.

Parameters:
  • exclude (iterable) -- A list or tuple of file and directory names to exclude from clearing operation.

  • exclude_files (bool) -- Excludes all files from clearing operation when True. Defaults to False.

  • exclude_directories (bool) -- Excludes all directories from clearing operation when True. Defaults to False.

Examples:

# Clear everything
workspace.clear()

# Clear directories only
workspace.clear(exclude_files=True)

# Clear files only
workspace.clear(exclude_directories=True)

# Clear all but specified files and directories
workspace.clear(exclude=['file1.txt', '/full/path/to/directory1', 'directory2', '/full/path/to/file2.txt'])
directories(full_path=False)

Return a list of directories that are in the workspace.

Parameters:

full_path (bool) -- Returns list of directories with full path names when True. Defaults to False.

Returns:

A list of directories in the workspace.

Return type:

list

Examples:

# List directory names
workspace.directories()

# List full path directory names
workspace.directories(full_path=True)
files(full_path=False)

Return a list of files that are in the workspace.

Parameters:

full_path (bool) -- Returns list of files with full path names when True. Defaults to False.

Returns:

A list of files in the workspace.

Return type:

list

Examples:

# List file names
workspace.files()

# List full path file names
workspace.files(full_path=True)
remove(item)

Remove a file or directory from the workspace.

Parameters:

item (str) -- Name of the item to remove from the workspace.

Examples:

workspace.remove('file.txt')
workspace.remove('/full/path/to/file.txt')
workspace.remove('relative/path/to/file.txt')
workspace.remove('directory')
workspace.remove('/full/path/to/directory')
workspace.remove('relative/path/to/directory')

Note: Though you can specify relative paths, the remove() method will not allow you to back into other directories using "../" or similar notation. Futhermore, absolute paths given must contain the path of the workspace to be valid.

Centralize Workspaces

The Workspaces API provides a Command Line Interface command, collectworkspaces, for moving all workspaces to a central location and symbolically linking them back to the app project directories. This command is intended for use in production installations where the administrator may want to locate workspace content on a mounted drive to optimize storage and make it easier to backup app data. A brief explanation of how to use this command will follow. Refer to the Command Line Interface documentation for details about the collectworkspaces command.

Setting

To enable centralized workspaces create a directory for the workspaces and specify its path in the portal_config.yml file using the TETHYS_WORKSPACES_ROOT setting.

TETHYS_WORKSPACES_ROOT: /var/www/tethys/workspaces

Command

Run the collectworkspaces command to automatically move all of the workspace directories to the TETHYS_WORKSPACES_ROOT directory and symbolically link them back. You will need to run this command each time you install new apps.

tethys manage collectworkspaces

Tip

A convenience command is provided called collectall that can be used to run both the collectstatic and the collectworkspaces commands:

tethys manage collectall

Handling Workspace Clearing

Users and portal administrators are able to clear their user and app workspaces through pages in the Tethys Portal. The app class provides methods to allow the app developer to customize how the app handles clearing user/app workspaces. Override these methods in your app class to handle workspaces clearing appropriately in your app. When a workspace is cleared through the portal admin pages or user profile pages, the appropriate 'pre-delete' method is called, the workspace is cleared, and then the appropriate 'post-delete' method is called.

classmethod TethysAppBase.pre_delete_app_workspace()

Override this method to pre-process the app workspace before it is emptied

classmethod TethysAppBase.post_delete_app_workspace()

Override this method to post-process the app workspace after it is emptied

classmethod TethysAppBase.pre_delete_user_workspace(user)

Override this method to pre-process a user's workspace before it is emptied

Parameters:

user (User, required) -- User that requested to clear their workspace

classmethod TethysAppBase.post_delete_user_workspace(user)

Override this method to post-process a user's workspace after it is emptied

Parameters:

user (User, required) -- User that requested to clear their workspace