Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export default defineConfig({
label: "Modern Imaging Format Support",
slug: "features/image-support",
},
{ label: "Python API", slug: "features/python-api" },
],
},
{
Expand Down
179 changes: 179 additions & 0 deletions src/content/docs/features/python-api.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
---
title: Python API
description: Use Fileglancer from Python with an API token
---

Fileglancer's HTTP API can be driven from Python using an API token. The client ships inside the same `fileglancer` package as the command-line tool, so `pip install fileglancer` is all you need on the machine running your script or notebook.

## Creating a Token

The API Tokens page is available from the profile menu in the upper-right corner of any Fileglancer page.

Click your **username or profile icon** in the top-right corner, then select **API Tokens** from the dropdown menu.

Click **New Token**, then fill in the dialog:

- **Name** — a label you will recognize later, such as `laptop notebook`.
- **Scopes** — check the boxes for what the token should be allowed to do. See [Scopes](#scopes) below.
- **Expires in** — 30, 90, or 365 days. There is no option to create a token that never expires.

Click **Create**.

:::caution[Copy this now — it will not be shown again]
The token secret is never stored by Fileglancer. A **Token created** dialog shows two lines:

```bash
export FILEGLANCER_URL=https://your-fileglancer-server
export FILEGLANCER_TOKEN=fgt_...
```

Click **Copy** and save both lines somewhere safe, such as your shell profile or a `.env` file, before closing the dialog. If you lose the secret, revoke the token and create another.
:::

## Scopes

| Scope | Grants |
| --- | --- |
| `files:read` | List directories and read file contents |
| `files:write` | Create, rename, delete, and write files |
| `links:read` | List data links and Neuroglancer links |
| `links:write` | Create and delete data links and Neuroglancer links |
| `jobs:read` | List jobs and read each job's full details, parameters, environment, and log files |
| `jobs:write` | Submit and cancel jobs |

`files:write` and `jobs:write` are **not enabled by default**. Both amount to full access to your files, so each server opts into them deliberately — if they are missing from the scope list when you create a token, contact your Fileglancer administrator to ask whether they can be enabled.

A server can withhold any scope, not just those two. The token creation dialog shows only the scopes your server supports, and a token that carries a scope the server has since stopped supporting loses it: requests needing it fail with a 403 saying the scope is not enabled on this server.

A `:write` scope also grants the matching `:read`.

`jobs:write` runs code (`pre_run`, `post_run`, and the job command itself) on your behalf, so it has the same access to your files as you do — it is not confined by `files:read` or `files:write`.

Tokens cannot reach every endpoint. SSH keys, apps and the app catalog, preferences, file-conversion tickets, and token management itself are available only in the web interface, so a leaked token cannot be used to mint another one or change your account.

## Connecting from Python

The client reads two environment variables:

```bash
export FILEGLANCER_URL=https://your-fileglancer-server
export FILEGLANCER_TOKEN=fgt_...
```

```python
from fileglancer import Fileglancer

fg = Fileglancer()
```

You can also pass them directly, which takes precedence over the environment:

```python
fg = Fileglancer(url="https://your-fileglancer-server", token="fgt_...")
```

`Fileglancer` also works as a context manager, which closes its connection pool automatically:

```python
with Fileglancer() as fg:
fg.ls("/data/alice")
```

Otherwise, call `fg.close()` when you are done with it.

## Working with Paths

Every method takes an absolute filesystem path, the same path you would use on the command line.

```python
fg.ls("/data/alice")
fg.stat("/data/alice/notes.txt")
fg.mkdir("/data/alice/analysis")
fg.write("/data/alice/notes.txt", b"hello")
fg.read("/data/alice/notes.txt")
fg.rename("/data/alice/a.zarr", "/data/alice/b.zarr")
fg.delete("/data/alice/tmp")
```

`ls` raises `FileglancerError` if the path is not a directory, rather than returning an empty list. `stat` returns metadata for a single file or directory without listing its contents.

`mkdir` and `write` both require the parent directory to already exist.

Paths in Mac (`smb://...`) and Windows (`\\server\share\...`) form are accepted too. Paths returned by the client are always in Linux form.

`fg.file_share_paths()` lists the shares available to you. A path that matches no share raises `FileglancerError` naming the path; call `file_share_paths()` to see what is available.

## Data Links

A data link serves a folder over HTTP so that a viewer can read it.

```python
link = fg.create_data_link("/data/alice/sample.zarr")
print(link.url)

fg.data_links()
fg.delete_data_link(link.sharing_key)
```

## Neuroglancer Links

`create_ng_link` takes a Neuroglancer state as a plain dictionary, which is what `neuroglancer.ViewerState.to_json()` produces.

```python
import neuroglancer
from fileglancer import Fileglancer

fg = Fileglancer()
link = fg.create_data_link("/data/alice/sample.zarr")

state = neuroglancer.ViewerState()
state.layers["sample"] = neuroglancer.ImageLayer(source=f"zarr://{link.url}")

print(fg.create_ng_link(state.to_json(), title="sample"))
```

This needs `links:write` on the token, and `neuroglancer` installed separately — the Fileglancer client does not depend on it.

Pass `url_base` to open the link in a different Neuroglancer instance.

## Jobs

```python
fg.jobs()
fg.jobs(status="RUNNING")
fg.job(job_id)
fg.cancel_job(job_id)
```

`submit_job` requires the app's URL and an entry point id. The server requires a `parameters` field even when the entry point takes no arguments, so the client defaults it to an empty dict:

```python
job = fg.submit_job(
"https://github.com/owner/repo",
"entry-point-id",
parameters={"threshold": 0.5},
)
```

Any other field the `/api/jobs` endpoint accepts — `resources`, `name`, `env`, `container`, and so on — can be passed as an extra keyword argument.

## Handling Errors

Anything the server rejects raises `FileglancerError`, carrying the server's message and its HTTP status code.

```python
from fileglancer import FileglancerError

try:
fg.mkdir("/data/alice/new")
except FileglancerError as error:
print(error, error.status_code)
```

A 403 usually means the token is missing a scope; the message names the one it needs.

A 401 with a message like `API token expired on 2026-08-24` means the token's expiry has passed. Expired tokens are not deleted — the API Tokens page still lists them, marked with an **Expired** badge, so you can tell which one lapsed. Tokens cannot be renewed or extended; create a new one and revoke the expired one.

## Revoking a Token

Open the API Tokens page from the profile menu and click **Revoke** on the token you want to remove. A confirmation dialog asks you to confirm, since any script or notebook using that token will stop working immediately. Click **Revoke Token** to confirm, or **Keep token** to back out. This cannot be undone — create a new token if you need one again.