Source code for scitex_app._files_api

#!/usr/bin/env python3
# Timestamp: 2026-05-12
# File: scitex_app/_files_api.py

"""Flat module-level wrappers around `FilesBackend` operations.

These mirror the package's MCP tool surface (`app_read_file`,
`app_write_file`, …) so users have a single-call Python API that
matches what MCP exposes — closing the API↔MCP parity check
(§6) and giving users a more discoverable surface for one-off
file operations than `get_files(root).read(path)`.

Each wrapper resolves the backend via :func:`scitex_app.sdk.get_files`
on every call, so it honours the same auto-detection rules
(``SCITEX_API_TOKEN`` for cloud, filesystem otherwise) and stays
in lock-step with whatever backend the caller has registered.

Heavy file shims (binary handling, traversal safety) live on the
backend; this module is intentionally thin.
"""

from __future__ import annotations

from pathlib import Path
from typing import List, Optional, Union

from .sdk import get_files


[docs] def read_file( path: str, *, root: Union[str, Path] = ".", binary: bool = False, ) -> Union[str, bytes]: """Read a single file via the resolved :class:`FilesBackend`. Equivalent to ``get_files(root).read(path, binary=binary)``; mirrors the ``app_read_file`` MCP tool. """ return get_files(root).read(path, binary=binary)
[docs] def write_file( path: str, content: Union[str, bytes], *, root: Union[str, Path] = ".", ) -> None: """Write a file via the resolved :class:`FilesBackend`. Mirrors the ``app_write_file`` MCP tool. """ get_files(root).write(path, content)
[docs] def list_files( directory: str = "", *, root: Union[str, Path] = ".", extensions: Optional[List[str]] = None, ) -> List[str]: """List file paths under *directory*. Mirrors the ``app_list_files`` MCP tool. """ return get_files(root).list(directory, extensions=extensions)
[docs] def file_exists(path: str, *, root: Union[str, Path] = ".") -> bool: """Return whether *path* exists in the resolved backend. Mirrors the ``app_file_exists`` MCP tool. """ return get_files(root).exists(path)
[docs] def delete_file(path: str, *, root: Union[str, Path] = ".") -> None: """Delete *path* in the resolved backend. Mirrors the ``app_delete_file`` MCP tool. """ get_files(root).delete(path)
[docs] def copy_file( src_path: str, dest_path: str, *, root: Union[str, Path] = ".", ) -> None: """Copy *src_path* to *dest_path* within the resolved backend. Mirrors the ``app_copy_file`` MCP tool. """ get_files(root).copy(src_path, dest_path)
[docs] def rename_file( old_path: str, new_path: str, *, root: Union[str, Path] = ".", ) -> None: """Rename *old_path* to *new_path* within the resolved backend. Mirrors the ``app_rename_file`` MCP tool. """ get_files(root).rename(old_path, new_path)
[docs] def scaffold( target_dir: Union[str, Path] = ".", *, name: Optional[str] = None, label: Optional[str] = None, icon: str = "fas fa-puzzle-piece", description: str = "", frontend: str = "html", overwrite: bool = False, ) -> List[Path]: """Generate a new SciTeX workspace app skeleton. Mirrors the ``app_scaffold`` MCP tool. Auto-appends ``_app`` / ``-app`` to *name* (matching the MCP tool's behaviour) so Python and MCP callers see the same result for the same inputs. """ from .appmaker import init_app target = Path(target_dir).resolve() app_name = name or target.name if not (app_name.endswith("_app") or app_name.endswith("-app")): sep = "-" if "-" in app_name else "_" app_name = f"{app_name}{sep}app" return init_app( target_dir=target, name=app_name, label=label or "", icon=icon, description=description, overwrite=overwrite, frontend_type=frontend, )
[docs] def validate(app_dir: Union[str, Path] = ".") -> List[str]: """Audit a SciTeX app for cloud-submission readiness. Mirrors the ``app_validate`` MCP tool. Returns the list of errors (empty when the app is ready). """ from .appmaker import validate as _validate return _validate(app_dir)
__all__ = [ "read_file", "write_file", "list_files", "file_exists", "delete_file", "copy_file", "rename_file", "scaffold", "validate", ] # EOF