CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-webdavclient

WebDAV client library providing easy access to cloud storage services like Yandex.Drive, Dropbox, Google Drive, Box, and 4shared.

Overview
Eval results
Files

synchronization.mddocs/

Synchronization

Advanced directory synchronization capabilities for keeping local and remote directories in sync. These operations provide intelligent synchronization with support for push, pull, and bidirectional synchronization, handling file comparisons and conflict resolution.

Capabilities

Push Synchronization

Uploads missing or changed files from local directory to remote directory, ensuring remote has all local changes.

def push(self, remote_directory: str, local_directory: str) -> None:
    """
    Upload missing or changed files from local to remote directory.
    
    Compares local and remote directories, then uploads files that are:
    - Present locally but missing remotely
    - Modified locally (newer modification time)
    - Different in size between local and remote
    
    Parameters:
    - remote_directory: str, path to remote directory
    - local_directory: str, path to local directory
    
    Raises:
    - LocalResourceNotFound: if local directory doesn't exist
    - RemoteParentNotFound: if remote parent directory doesn't exist
    - NotConnection: if connection to server fails
    - NotEnoughSpace: if insufficient space on server
    """

Pull Synchronization

Downloads missing or changed files from remote directory to local directory, ensuring local has all remote changes.

def pull(self, remote_directory: str, local_directory: str) -> None:
    """
    Download missing or changed files from remote to local directory.
    
    Compares remote and local directories, then downloads files that are:
    - Present remotely but missing locally
    - Modified remotely (newer modification time)
    - Different in size between remote and local
    
    Parameters:
    - remote_directory: str, path to remote directory
    - local_directory: str, path to local directory
    
    Raises:
    - RemoteResourceNotFound: if remote directory doesn't exist
    - LocalResourceNotFound: if local parent directory doesn't exist  
    - NotConnection: if connection to server fails
    """

Bidirectional Synchronization

Synchronizes both directories bidirectionally, ensuring both local and remote directories have the latest version of all files.

def sync(self, remote_directory: str, local_directory: str) -> None:
    """
    Bidirectionally synchronize local and remote directories.
    
    Performs both push and pull operations to ensure both directories
    contain the most recent version of all files. Handles conflicts by
    preferring the file with the most recent modification time.
    
    Parameters:
    - remote_directory: str, path to remote directory
    - local_directory: str, path to local directory
    
    Raises:
    - LocalResourceNotFound: if local directory doesn't exist
    - RemoteResourceNotFound: if remote directory doesn't exist
    - NotConnection: if connection to server fails
    - NotEnoughSpace: if insufficient space on server
    """

Usage Examples

Basic Push Operation

import webdav.client as wc

client = wc.Client({
    'webdav_hostname': "https://webdav.server.com",
    'webdav_login': "username",
    'webdav_password': "password"
})

# Push local changes to remote
client.push("projects/website/", "~/Development/website/")
print("Local changes pushed to remote directory")

Basic Pull Operation

# Pull remote changes to local
client.pull("documents/shared/", "~/Documents/shared/")
print("Remote changes pulled to local directory")

Full Bidirectional Sync

# Synchronize both directions
client.sync("backup/important/", "~/Documents/important/")
print("Directories synchronized bidirectionally")

Sync with Error Handling

from webdav.client import WebDavException, NotConnection, LocalResourceNotFound, RemoteResourceNotFound

def safe_sync(client, remote_dir, local_dir, operation="sync"):
    try:
        if operation == "push":
            client.push(remote_dir, local_dir)
            print(f"Successfully pushed {local_dir} to {remote_dir}")
        elif operation == "pull":
            client.pull(remote_dir, local_dir)
            print(f"Successfully pulled {remote_dir} to {local_dir}")
        elif operation == "sync":
            client.sync(remote_dir, local_dir)
            print(f"Successfully synchronized {remote_dir} and {local_dir}")
    
    except LocalResourceNotFound as e:
        print(f"Local directory not found: {e}")
    except RemoteResourceNotFound as e:
        print(f"Remote directory not found: {e}")
    except NotConnection as e:
        print(f"Connection failed: {e}")
    except WebDavException as e:
        print(f"WebDAV error: {e}")

# Use safe sync operations
safe_sync(client, "projects/webapp/", "~/Development/webapp/", "push")
safe_sync(client, "documents/reports/", "~/Documents/reports/", "pull")
safe_sync(client, "shared/collaboration/", "~/Shared/collaboration/", "sync")

Periodic Synchronization

import time
import schedule

def sync_directories():
    """Periodic sync function"""
    try:
        client.sync("backup/documents/", "~/Documents/")
        print(f"Sync completed at {time.strftime('%Y-%m-%d %H:%M:%S')}")
    except Exception as e:
        print(f"Sync failed: {e}")

# Schedule sync every hour
schedule.every().hour.do(sync_directories)

# Or run once daily at 2 AM
schedule.every().day.at("02:00").do(sync_directories)

# Keep scheduler running
while True:
    schedule.run_pending()
    time.sleep(60)

Project Backup Sync

import os
from datetime import datetime

def backup_project(project_name, local_path):
    """Backup project to WebDAV with timestamp"""
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    remote_backup_path = f"backups/{project_name}_{timestamp}/"
    
    try:
        # Create timestamped backup
        client.push(remote_backup_path, local_path)
        print(f"Project {project_name} backed up to {remote_backup_path}")
        
        # Also maintain current backup
        current_backup_path = f"backups/{project_name}_current/"
        client.sync(current_backup_path, local_path)
        print(f"Current backup updated at {current_backup_path}")
        
    except Exception as e:
        print(f"Backup failed for {project_name}: {e}")

# Backup multiple projects
projects = {
    "webapp": "~/Development/webapp/",
    "mobile_app": "~/Development/mobile/",
    "documentation": "~/Documents/project_docs/"
}

for project, path in projects.items():
    if os.path.exists(os.path.expanduser(path)):
        backup_project(project, path)
    else:
        print(f"Local path not found: {path}")

Collaborative Workflow

def collaborate_workflow(shared_remote_dir, local_work_dir):
    """Workflow for collaborative projects"""
    
    print("Starting collaborative workflow...")
    
    # 1. Pull latest changes from team
    print("Pulling latest changes...")
    client.pull(shared_remote_dir, local_work_dir)
    
    # 2. Do local work here
    print("Work on your changes locally...")
    input("Press Enter when you've completed your local changes...")
    
    # 3. Pull again to get any new changes before pushing
    print("Pulling latest changes before push...")
    client.pull(shared_remote_dir, local_work_dir)
    
    # 4. Push your changes
    print("Pushing your changes...")
    client.push(shared_remote_dir, local_work_dir)
    
    print("Collaborative workflow completed!")

# Use collaborative workflow
collaborate_workflow("team/project_alpha/", "~/Work/project_alpha/")

Selective Synchronization

import os
import fnmatch

def selective_sync(remote_dir, local_dir, include_patterns=None, exclude_patterns=None):
    """
    Sync with file filtering based on patterns
    Note: This is a conceptual example - actual implementation would need
    to be built on top of the basic sync operations
    """
    
    include_patterns = include_patterns or ['*']
    exclude_patterns = exclude_patterns or []
    
    print(f"Syncing {local_dir} with {remote_dir}")
    print(f"Including: {include_patterns}")
    print(f"Excluding: {exclude_patterns}")
    
    # Basic sync (in real implementation, you'd filter before sync)
    client.sync(remote_dir, local_dir)
    
    # Post-sync cleanup of excluded files (conceptual)
    if exclude_patterns:
        print("Note: Full filtering would require custom implementation")

# Example: Sync only Python files, exclude cache
selective_sync(
    "projects/python_app/",
    "~/Development/python_app/",
    include_patterns=['*.py', '*.txt', '*.md'],
    exclude_patterns=['__pycache__/*', '*.pyc', '.git/*']
)

Sync Status Monitoring

import os
from datetime import datetime

class SyncMonitor:
    def __init__(self, client):
        self.client = client
        self.sync_log = []
    
    def log_sync(self, operation, remote_dir, local_dir, success, error=None):
        """Log sync operation result"""
        log_entry = {
            'timestamp': datetime.now().isoformat(),
            'operation': operation,
            'remote_dir': remote_dir,
            'local_dir': local_dir,
            'success': success,
            'error': str(error) if error else None
        }
        self.sync_log.append(log_entry)
    
    def monitored_sync(self, remote_dir, local_dir, operation="sync"):
        """Perform sync with monitoring"""
        try:
            print(f"Starting {operation} operation...")
            
            if operation == "push":
                self.client.push(remote_dir, local_dir)
            elif operation == "pull":
                self.client.pull(remote_dir, local_dir)
            else:
                self.client.sync(remote_dir, local_dir)
            
            self.log_sync(operation, remote_dir, local_dir, True)
            print(f"{operation.capitalize()} completed successfully")
            
        except Exception as e:
            self.log_sync(operation, remote_dir, local_dir, False, e)
            print(f"{operation.capitalize()} failed: {e}")
    
    def get_sync_report(self):
        """Generate sync status report"""
        total_ops = len(self.sync_log)
        successful_ops = sum(1 for log in self.sync_log if log['success'])
        
        print(f"\nSync Report:")
        print(f"Total operations: {total_ops}")
        print(f"Successful: {successful_ops}")
        print(f"Failed: {total_ops - successful_ops}")
        
        # Show recent failures
        recent_failures = [log for log in self.sync_log[-10:] if not log['success']]
        if recent_failures:
            print("\nRecent failures:")
            for failure in recent_failures:
                print(f"  {failure['timestamp']}: {failure['operation']} - {failure['error']}")

# Use sync monitor
monitor = SyncMonitor(client)
monitor.monitored_sync("projects/website/", "~/Development/website/", "sync")
monitor.monitored_sync("documents/", "~/Documents/", "pull")
monitor.get_sync_report()

Install with Tessl CLI

npx tessl i tessl/pypi-webdavclient

docs

client-operations.md

configuration.md

file-transfer.md

index.md

resource-management.md

synchronization.md

tile.json