Endpoints
Accessed as sepal.files, sepal.tasks, and sepal.recipes. Each sync class
below has an identical async twin (AsyncUserFilesEndpoint, AsyncTasksEndpoint,
AsyncRecipesEndpoint) whose methods mirror these with await.
Files — sepal.files
pysepal_api.endpoints.user_files.UserFilesEndpoint
UserFilesEndpoint(http: Client)
Source code in src/pysepal_api/endpoints/_base.py
| def __init__(self, http: httpx.Client) -> None:
self._http = http
|
list
list(
folder: str = ".",
*,
extensions: Sequence[str] | None = None,
include_hidden: bool = False
) -> DirectoryListing
Source code in src/pysepal_api/endpoints/user_files.py
90
91
92
93
94
95
96
97
98 | def list(
self,
folder: str = ".",
*,
extensions: Sequence[str] | None = None,
include_hidden: bool = False,
) -> DirectoryListing:
resp = self._send(_list_spec(folder, extensions, include_hidden))
return parse_one(resp, DirectoryListing)
|
read_bytes
read_bytes(file_path: str) -> bytes
Download a file and return its raw bytes.
Source code in src/pysepal_api/endpoints/user_files.py
| def read_bytes(self, file_path: str) -> bytes:
"""Download a file and return its raw bytes."""
return self._send(_download_spec(file_path)).content
|
read_text
read_text(file_path: str) -> str
Download a file and decode it as text (charset from the response).
Source code in src/pysepal_api/endpoints/user_files.py
| def read_text(self, file_path: str) -> str:
"""Download a file and decode it as text (charset from the response)."""
return self._send(_download_spec(file_path)).text
|
read_json
read_json(file_path: str) -> Any
Download a file and parse it as JSON.
Source code in src/pysepal_api/endpoints/user_files.py
| def read_json(self, file_path: str) -> Any:
"""Download a file and parse it as JSON."""
return _parse_json(self._send(_download_spec(file_path)))
|
write
write(
file_path: str,
content: str | bytes,
*,
overwrite: bool = False
) -> FileWriteResult
Upload a file via multipart/form-data (form field file).
Raises Conflict if the file already exists and overwrite is false.
Source code in src/pysepal_api/endpoints/user_files.py
112
113
114
115
116
117
118
119
120
121
122
123
124 | def write(
self,
file_path: str,
content: str | bytes,
*,
overwrite: bool = False,
) -> FileWriteResult:
"""Upload a file via multipart/form-data (form field `file`).
Raises `Conflict` if the file already exists and `overwrite` is false.
"""
resp = self._send(_write_spec(file_path, content, overwrite))
return parse_one(resp, FileWriteResult, default={})
|
mkdir
mkdir(path: str, *, parents: bool = True) -> PurePosixPath
Create a folder under the user workspace; idempotent on 409/403.
SEPAL returns 403 (not 409) for an already-existing folder in some
deployments, so both are swallowed to keep mkdir idempotent. Caveat:
that also hides a genuine permission failure — it will surface on the
first write into the folder instead.
Source code in src/pysepal_api/endpoints/user_files.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139 | def mkdir(self, path: str, *, parents: bool = True) -> PurePosixPath:
"""Create a folder under the user workspace; idempotent on 409/403.
SEPAL returns 403 (not 409) for an already-existing folder in some
deployments, so both are swallowed to keep `mkdir` idempotent. Caveat:
that also hides a genuine permission failure — it will surface on the
first write into the folder instead.
"""
relative = sanitize_write_path(path)
try:
self._send(_mkdir_spec(path, parents))
except (Conflict, Forbidden):
pass
return relative
|
module_dir
module_dir(module_name: str) -> PurePosixPath
Create and return /home/sepal-user/module_results/{module_name}.
Source code in src/pysepal_api/endpoints/user_files.py
| def module_dir(self, module_name: str) -> PurePosixPath:
"""Create and return `/home/sepal-user/module_results/{module_name}`."""
self.mkdir(str(module_results_relative(module_name)), parents=True)
return module_results_path(module_name)
|
Tasks — sepal.tasks
pysepal_api.endpoints.tasks.TasksEndpoint
TasksEndpoint(http: Client)
Source code in src/pysepal_api/endpoints/_base.py
| def __init__(self, http: httpx.Client) -> None:
self._http = http
|
submit
submit(
operation: str,
params: dict[str, Any],
*,
recipe_id: str | None = None,
instance_type: str | None = None
) -> Task
Source code in src/pysepal_api/endpoints/tasks.py
80
81
82
83
84
85
86
87
88
89 | def submit(
self,
operation: str,
params: dict[str, Any],
*,
recipe_id: str | None = None,
instance_type: str | None = None,
) -> Task:
resp = self._send(_submit_spec(operation, params, recipe_id, instance_type))
return parse_one(resp, Task)
|
list
list(
status: TaskState | str | None = None,
*,
output_path: str | None = None,
destination: str | None = None
) -> list[Task]
Source code in src/pysepal_api/endpoints/tasks.py
91
92
93
94
95
96
97
98
99 | def list(
self,
status: TaskState | str | None = None,
*,
output_path: str | None = None,
destination: str | None = None,
) -> list[Task]:
resp = self._send(_list_spec(status, output_path, destination))
return parse_many(resp, Task)
|
get
get(task_id: str, *, details: bool = False) -> Task
Source code in src/pysepal_api/endpoints/tasks.py
| def get(self, task_id: str, *, details: bool = False) -> Task:
resp = self._send(_get_spec(task_id, details))
return parse_one(resp, Task)
|
cancel
cancel(task_id: str) -> None
Source code in src/pysepal_api/endpoints/tasks.py
| def cancel(self, task_id: str) -> None:
self._send(_action_spec(task_id, "cancel"))
|
remove
remove(task_id: str) -> None
Source code in src/pysepal_api/endpoints/tasks.py
| def remove(self, task_id: str) -> None:
self._send(_action_spec(task_id, "remove"))
|
restart
restart(task_id: str) -> None
Maps to SEPAL's execute route.
Source code in src/pysepal_api/endpoints/tasks.py
| def restart(self, task_id: str) -> None:
"""Maps to SEPAL's `execute` route."""
self._send(_action_spec(task_id, "execute"))
|
wait
wait(
task_id: str,
*,
poll_interval: float = 5.0,
timeout: float | None = None
) -> Task
Poll get(task_id) until terminal. Raises on FAILED/CANCELED/timeout.
Source code in src/pysepal_api/endpoints/tasks.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 | def wait(
self, task_id: str, *, poll_interval: float = 5.0, timeout: float | None = None
) -> Task:
"""Poll `get(task_id)` until terminal. Raises on FAILED/CANCELED/timeout."""
start = time.monotonic()
while True:
task = self.get(task_id)
done = _wait_step(task, task_id)
if done is not None:
return done
if timeout is not None and time.monotonic() - start >= timeout:
raise TaskTimeout(
f"Task {task_id} did not reach terminal state in {timeout}s", task=task
)
time.sleep(poll_interval)
|
Recipes — sepal.recipes
pysepal_api.endpoints.recipes.RecipesEndpoint
RecipesEndpoint(http: Client)
Source code in src/pysepal_api/endpoints/_base.py
| def __init__(self, http: httpx.Client) -> None:
self._http = http
|
list
list() -> RecipeSummaries
Source code in src/pysepal_api/endpoints/recipes.py
| def list(self) -> RecipeSummaries:
return _summaries(self._send(RequestSpec("GET", "/api/processing-recipes")))
|
get
get(recipe_id: str) -> Any
Load a recipe as parsed JSON. Use get_raw for the exact bytes.
Source code in src/pysepal_api/endpoints/recipes.py
| def get(self, recipe_id: str) -> Any:
"""Load a recipe as parsed JSON. Use `get_raw` for the exact bytes."""
return _parse_json(self._send(RequestSpec("GET", f"/api/processing-recipes/{recipe_id}")))
|
get_raw
get_raw(recipe_id: str) -> bytes
Load a recipe body exactly as stored, without JSON parsing.
Source code in src/pysepal_api/endpoints/recipes.py
| def get_raw(self, recipe_id: str) -> bytes:
"""Load a recipe body exactly as stored, without JSON parsing."""
return self._send(RequestSpec("GET", f"/api/processing-recipes/{recipe_id}")).content
|
save
save(
recipe_id: str,
*,
project_id: str,
type: str,
name: str,
contents: RecipeContents
) -> RecipeSummaries
POST a recipe. SEPAL stores the gzipped body as-is; pass either
already-encoded bytes/str or a JSON-serializable structure that the
client will encode for you.
Source code in src/pysepal_api/endpoints/recipes.py
66
67
68
69
70
71
72
73
74
75
76
77
78 | def save(
self,
recipe_id: str,
*,
project_id: str,
type: str,
name: str,
contents: RecipeContents,
) -> RecipeSummaries:
"""POST a recipe. SEPAL stores the gzipped body as-is; pass either
already-encoded bytes/str or a JSON-serializable structure that the
client will encode for you."""
return _summaries(self._send(_save_spec(recipe_id, project_id, type, name, contents)))
|
delete
delete(recipe_id: str) -> RecipeSummaries
Source code in src/pysepal_api/endpoints/recipes.py
| def delete(self, recipe_id: str) -> RecipeSummaries:
return _summaries(self._send(RequestSpec("DELETE", f"/api/processing-recipes/{recipe_id}")))
|