Metadata-Version: 2.4
Name: mycloud-sdk
Version: 0.1.1
Summary: Official Python SDK for myCloud - your personal cloud storage
Author-email: myCloud <support@mysphere.co.in>
License: MIT
Project-URL: Homepage, https://mysphere.co.in
Project-URL: Documentation, https://github.com/mysphere/mycloud
Project-URL: Repository, https://github.com/mysphere/mycloud
Project-URL: Bug Tracker, https://github.com/mysphere/mycloud/issues
Keywords: mycloud,cloud,storage,api,sdk,async
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"

# myCloud Python SDK

![PyPI version](https://img.shields.io/pypi/v/mycloud-sdk.svg)
![Python Versions](https://img.shields.io/pypi/pyversions/mycloud-sdk.svg)
![License](https://img.shields.io/github/license/mysphere/mycloud-sdk)

The official Python SDK for **myCloud** by mySphere. This SDK provides a robust, fully-featured, and type-safe interface to interact with your myCloud storage, including both synchronous and highly concurrent asynchronous APIs.

## Features

- **Dual API:** Both blocking (`MyCloud`) and non-blocking (`AsyncMyCloud`) clients available out of the box.
- **Zero-Configuration:** Automatically detects and reads credentials generated by the myCloud CLI (`~/.mycloud/credentials.json`).
- **Comprehensive:** Full support for file lifecycles, folder management, sharing, batch operations, stash, search, and private storage nodes.
- **Type-Safe:** Written with complete type hints for seamless IDE integration and autocomplete.
- **Graceful Error Handling:** Automatically catches and parses server validation errors, mapping them to typed Python exceptions.

---

## Installation

Install via pip:

```bash
pip install mycloud-sdk
```

---

## Configuration

By default, the SDK uses the production myCloud API at `https://cloud.mysphere.co.in`.
You can configure the server and authentication token in three ways:

1. **Auto-Discovery (Recommended):** If you use the [myCloud CLI](https://github.com/mysphere/mycloud) and have run `mycloud login`, the SDK will automatically read your `~/.mycloud/credentials.json` file.
2. **Environment Variables:** Set `MYCLOUD_URL` to point to a custom server.
3. **Explicit Initialization:** Pass them directly to the client:
   ```python
   cloud = MyCloud(server="https://custom-cloud.domain.com", token="your_api_token")
   ```

---

## Quick Start

### Synchronous Usage

```python
from pathlib import Path
from mycloud import MyCloud

# Initialize the client (automatically uses ~/.mycloud/credentials.json if available)
cloud = MyCloud()

# 1. Login manually (if not using the CLI's auto-config)
cloud.auth.login("your_username", "your_password")

# 2. List your root files and folders
files = cloud.files.list()
for f in files:
    print(f"Found file: {f.name} ({f.size} bytes)")

# 3. Upload a new file
my_file = Path("important_document.pdf")
uploaded_file = cloud.files.upload(my_file)
print(f"Uploaded successfully! ID: {uploaded_file.id}")

# 4. Download a file
cloud.files.download(uploaded_file.id, dest="downloads/important_document.pdf")
```

### Asynchronous Usage (For high concurrency)

For applications requiring high throughput, use `AsyncMyCloud`. It supports asynchronous context managers (`async with`) for proper resource cleanup.

```python
import asyncio
from pathlib import Path
from mycloud import AsyncMyCloud

async def main():
    async with AsyncMyCloud() as cloud:
        # Concurrently upload multiple files
        paths = [Path(f"data_{i}.csv") for i in range(10)]
        
        # asyncio.gather fires all uploads in parallel
        upload_tasks = [cloud.files.upload(p) for p in paths]
        uploaded_files = await asyncio.gather(*upload_tasks)
        
        for f in uploaded_files:
            print(f"Uploaded: {f.name}")

asyncio.run(main())
```

---

## Core Modules Overview

The SDK exposes 13 distinct modules.

### `cloud.files`
- `upload(path: Union[str, Path], folder_id: Optional[int], node: str, stash: bool)`: Upload a file.
- `download(file_id: int, dest: Union[str, Path])`: Download a file.
- `list(folder_id: Optional[int], node: str, favorites: bool)`: List files in a directory.
- `read(file_id: int)`: Read the raw text contents of a file.
- `info(file_id: int)`: Get detailed metadata.
- `rename(file_id: int, new_name: str)`: Rename a file.
- `move(file_id: int, folder_id: int)`: Move a file to a new folder.
- `delete(file_id: int)`: Delete a file permanently.
- `favorite(file_id: int)`: Toggle a file's favorite status.

### `cloud.folders`
- `create(name: str, parent_id: Optional[int])`: Create a new directory.
- `list(folder_id: Optional[int])`: List sub-directories.
- `rename(folder_id: int, new_name: str)`: Rename a directory.
- `move(folder_id: int, new_parent_id: int)`: Move a folder.
- `delete(folder_id: int)`: Delete a folder.
- `favorite(folder_id: int)`: Toggle a folder's favorite status.

### `cloud.stash`
- `add(file_id: int, days: int)`: Secure an existing file in your stash (recycle bin style).
- `restore(stash_id: int)`: Restore a file from the stash.
- `list()`: List all stashed items.
- `empty()`: Permanently delete all stashed files.

### `cloud.batch` (Bulk Operations)
- `delete(file_ids: List[int])`: Delete multiple files.
- `move(file_ids: List[int], folder_id: int)`: Move multiple files.
- `stash(file_ids: List[int], days: int)`: Stash multiple files.
- `share(file_ids: List[int], user: str)`: Share multiple files at once.
- `link(file_ids: List[int])`: Generate a public link for a bundle of files.

### `cloud.share`
- `create(item_id: int, user: str, permission: str, item_type: str)`: Share a file/folder with a user.
- `link(item_id: int, item_type: str)`: Create a public shareable URL.
- `info(item_id: int, item_type: str)`: Get sharing metadata.
- `disable_link(item_id: int)`: Revoke access to a public link.

### `cloud.search`
- `query(q: str, filter_type: str, filter_date: str)`: Search files and folders globally.

### `cloud.favorites`
- `list_files()`: List all favorited files.
- `list_folders()`: List all favorited folders.
- `toggle_file(file_id: int)`: Toggle a file's favorite status.
- `toggle_folder(folder_id: int)`: Toggle a folder's favorite status.

### `cloud.servers`
- `list()`: List all registered private node servers.
- `add()`: Generate a new API key for a private node.
- `delete(node_id: int)`: Remove a private node from your account.

### `cloud.profile` & `cloud.auth`
- Manage your account, upload avatars, enable 2FA, register, reset passwords, and login.

### `cloud.storage`, `cloud.notifications`, `cloud.prefs`, `cloud.batch_share`
- Monitor storage stats, manage email preferences, handle share invites, and manage named batch shares.

---

## Exception Handling

The SDK provides specific exceptions directly from the `mycloud` package.

```python
from mycloud import MyCloud
from mycloud import AuthError, NotFoundError, ValidationError

cloud = MyCloud()

try:
    cloud.files.download(9999999, dest=".")
except NotFoundError:
    print("The requested file does not exist!")
except AuthError:
    print("Your session has expired. Please login again.")
except ValidationError as e:
    print(f"Invalid input: {e}")
```

## Known Server API Limitations

The SDK is designed to be highly resilient. However, please note that certain backend functionalities currently have documented limitations:
- **Share Disabling**: The server API expects a `share_id` for revoking public links, but the endpoints provide `item_id`.
- **Private Node Key Generation**: The node generation endpoint currently returns an HTML redirect instead of a JSON payload on success. The SDK gracefully catches this limitation as a standard Python Exception.
- **Upload Filename Synchronization**: When deleting and recreating identical filenames quickly, the auto-increment tracker on the server may desync from `MAX(id)`.

*All known limitations are safely caught by the SDK to prevent hard application crashes.*

---

## License

This project is licensed under the MIT License.
