Skip to content

move_to_using_path is not thread-safe #937

Open
@infohash

Description

@infohash

Sometimes you have to move a bunch of files together to another folder. If you use move_to_using_path concurrently using ThreadPoolExecutor, ClientRequestException is raised.

How to reproduce

import concurrent.futures

from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.files.move_operations import MoveOperations

ctx: ClientContext = ClientContext(base_url='https://example.sharepoint.com/sites/tenant').with_user_credentials(
    username='test_user', password='test_password')


def main(source_filename):
    """Moves a file from source folder to destination folder.

    Args:
        source_filename: Name of the file.
    """
    ctx.web.get_file_by_server_relative_path(path=f'Shared Documents/{source_filename}').move_to_using_path(
        destination='Shared Documents/destination_folder', flag=MoveOperations.overwrite).execute_query()


>>> with concurrent.futures.ThreadPoolExecutor() as executor:
...     executor.map(main, ['one.csv', 'two.csv', 'three.csv'])

office365.runtime.client_request_exception.ClientRequestException: ('-2147024809, System.ArgumentException', 'Server relative urls must start with SPWeb.ServerRelativeUrl', "400 Client Error: Bad Request for url: https://example.sharepoint.com/sites/tenant/_api/Web/getFileByServerRelativePath(DecodedUrl='%2Fsites%2Ftenant%2FShared%20Documents%2Fone.csv')/MoveToUsingPath(DecodedUrl='%2Fone.csv',moveOperations=1)")

It will work fine if there is only one thread.

>>> with concurrent.futures.ThreadPoolExecutor() as executor:
...     executor.map(main, ['one.csv'])

Workaround

Use copy.deepcopy to prevent the statefulness of the object from being overwritten by other threads.

def main(source_filename):
    """Moves a file from source folder to destination folder.

    Args:
        source_filename: Name of the file.
    """
    import copy

    copy.deepcopy(ctx).web.get_file_by_server_relative_path(path=f'Shared Documents/{source_filename}').move_to_using_path(
        destination='Shared Documents/destination_folder', flag=MoveOperations.overwrite).execute_query()

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions