nimbusimage 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nimbusimage-0.1.0/PKG-INFO +207 -0
- nimbusimage-0.1.0/README.md +177 -0
- nimbusimage-0.1.0/nimbusimage/__init__.py +107 -0
- nimbusimage-0.1.0/nimbusimage/_access.py +20 -0
- nimbusimage-0.1.0/nimbusimage/_girder.py +77 -0
- nimbusimage-0.1.0/nimbusimage/annotations.py +247 -0
- nimbusimage-0.1.0/nimbusimage/client.py +263 -0
- nimbusimage-0.1.0/nimbusimage/collections.py +195 -0
- nimbusimage-0.1.0/nimbusimage/connections.py +111 -0
- nimbusimage-0.1.0/nimbusimage/coordinates.py +221 -0
- nimbusimage-0.1.0/nimbusimage/dataset.py +264 -0
- nimbusimage-0.1.0/nimbusimage/export.py +76 -0
- nimbusimage-0.1.0/nimbusimage/filters.py +80 -0
- nimbusimage-0.1.0/nimbusimage/history.py +31 -0
- nimbusimage-0.1.0/nimbusimage/images.py +338 -0
- nimbusimage-0.1.0/nimbusimage/jobs.py +140 -0
- nimbusimage-0.1.0/nimbusimage/models.py +201 -0
- nimbusimage-0.1.0/nimbusimage/projects.py +142 -0
- nimbusimage-0.1.0/nimbusimage/properties.py +215 -0
- nimbusimage-0.1.0/nimbusimage/sharing.py +47 -0
- nimbusimage-0.1.0/nimbusimage/urls.py +94 -0
- nimbusimage-0.1.0/nimbusimage/worker.py +256 -0
- nimbusimage-0.1.0/nimbusimage.egg-info/PKG-INFO +207 -0
- nimbusimage-0.1.0/nimbusimage.egg-info/SOURCES.txt +44 -0
- nimbusimage-0.1.0/nimbusimage.egg-info/dependency_links.txt +1 -0
- nimbusimage-0.1.0/nimbusimage.egg-info/requires.txt +17 -0
- nimbusimage-0.1.0/nimbusimage.egg-info/top_level.txt +1 -0
- nimbusimage-0.1.0/pyproject.toml +46 -0
- nimbusimage-0.1.0/setup.cfg +4 -0
- nimbusimage-0.1.0/tests/test_annotations.py +135 -0
- nimbusimage-0.1.0/tests/test_client.py +135 -0
- nimbusimage-0.1.0/tests/test_collections.py +209 -0
- nimbusimage-0.1.0/tests/test_connections.py +94 -0
- nimbusimage-0.1.0/tests/test_coordinates.py +266 -0
- nimbusimage-0.1.0/tests/test_dataset.py +89 -0
- nimbusimage-0.1.0/tests/test_export.py +35 -0
- nimbusimage-0.1.0/tests/test_filters.py +87 -0
- nimbusimage-0.1.0/tests/test_history.py +26 -0
- nimbusimage-0.1.0/tests/test_images.py +288 -0
- nimbusimage-0.1.0/tests/test_jobs.py +324 -0
- nimbusimage-0.1.0/tests/test_models.py +203 -0
- nimbusimage-0.1.0/tests/test_projects.py +88 -0
- nimbusimage-0.1.0/tests/test_properties.py +117 -0
- nimbusimage-0.1.0/tests/test_sharing.py +36 -0
- nimbusimage-0.1.0/tests/test_urls.py +176 -0
- nimbusimage-0.1.0/tests/test_worker.py +187 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nimbusimage
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python API for NimbusImage
|
|
5
|
+
Author-email: Arjun Raj <arjunrajlab@gmail.com>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://nimbusimage.com
|
|
8
|
+
Project-URL: Repository, https://github.com/arjunrajlaboratory/NimbusImage
|
|
9
|
+
Project-URL: Documentation, https://docs.nimbusimage.com
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: girder-client
|
|
17
|
+
Requires-Dist: numpy
|
|
18
|
+
Requires-Dist: pydantic>=2.0
|
|
19
|
+
Requires-Dist: shapely
|
|
20
|
+
Requires-Dist: scikit-image
|
|
21
|
+
Provides-Extra: worker
|
|
22
|
+
Requires-Dist: large-image; extra == "worker"
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
26
|
+
Provides-Extra: docs
|
|
27
|
+
Requires-Dist: mkdocs; extra == "docs"
|
|
28
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
29
|
+
Requires-Dist: mkdocstrings[python]; extra == "docs"
|
|
30
|
+
|
|
31
|
+
# nimbusimage
|
|
32
|
+
|
|
33
|
+
Python API for [NimbusImage](https://nimbusimage.com) — programmatic access to scientific imaging datasets, annotations, workers, and analysis.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install nimbusimage
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For Docker worker development (includes `large_image` for writing TIFF files):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install nimbusimage[worker]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Authentication
|
|
48
|
+
|
|
49
|
+
The recommended setup uses a **Girder API key**, which is persistent and doesn't expire.
|
|
50
|
+
|
|
51
|
+
**How to get an API key:**
|
|
52
|
+
|
|
53
|
+
- **nimbusimage.com (hosted):** Email **[support@cytopixel.com](mailto:support@cytopixel.com)** with your account email address to request an API key.
|
|
54
|
+
- **Local/self-hosted server:** In the Girder admin UI, go to **Users** > select the user > **Edit User** > **API Keys** > create a new key and copy the key string.
|
|
55
|
+
|
|
56
|
+
Set environment variables for persistent access:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Add to ~/.zshrc or ~/.bashrc
|
|
60
|
+
|
|
61
|
+
# For nimbusimage.com:
|
|
62
|
+
export NI_API_URL="https://nimbusimage.com/girder"
|
|
63
|
+
export NI_API_KEY="your-api-key-here"
|
|
64
|
+
|
|
65
|
+
# For a local server:
|
|
66
|
+
export NI_API_URL="http://localhost:8080/api/v1"
|
|
67
|
+
export NI_API_KEY="your-api-key-here"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Then connect with no arguments:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import nimbusimage as ni
|
|
74
|
+
|
|
75
|
+
client = ni.connect()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or pass credentials explicitly:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
client = ni.connect("http://localhost:8080/api/v1", api_key="your-api-key")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Quick start
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
import nimbusimage as ni
|
|
88
|
+
|
|
89
|
+
client = ni.connect()
|
|
90
|
+
|
|
91
|
+
# List datasets
|
|
92
|
+
for d in client.list_datasets():
|
|
93
|
+
print(f"{d['name']} (ID: {d['_id']})")
|
|
94
|
+
|
|
95
|
+
# Open a dataset
|
|
96
|
+
ds = client.dataset(name="My Experiment")
|
|
97
|
+
print(f"{ds.name}: {ds.channels}, {ds.num_z} z-slices, {ds.shape}")
|
|
98
|
+
|
|
99
|
+
# Fetch an image
|
|
100
|
+
img = ds.images.get(channel=0, z=0) # numpy array
|
|
101
|
+
|
|
102
|
+
# Get a composite RGB image
|
|
103
|
+
rgb = ds.images.get_composite(dtype="uint8")
|
|
104
|
+
|
|
105
|
+
# List annotations
|
|
106
|
+
polygons = ds.annotations.list(shape="polygon")
|
|
107
|
+
|
|
108
|
+
# Run a worker
|
|
109
|
+
job = ds.annotations.compute(
|
|
110
|
+
image="annotations/random_squares:latest",
|
|
111
|
+
channel=0, tags=["detected"],
|
|
112
|
+
worker_interface={"Number of squares": 10, "Square size": 15},
|
|
113
|
+
)
|
|
114
|
+
job.wait()
|
|
115
|
+
|
|
116
|
+
# Export data
|
|
117
|
+
ds.export.to_csv(property_paths=[["prop_id", "Area"]], path="results.csv")
|
|
118
|
+
|
|
119
|
+
# Open in browser
|
|
120
|
+
ds.open(z=3)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## API overview
|
|
124
|
+
|
|
125
|
+
The package follows an accessor pattern:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
ni.connect() -> NimbusClient
|
|
129
|
+
client.dataset(id) -> Dataset
|
|
130
|
+
ds.images # fetch frames, composites, z-stacks
|
|
131
|
+
ds.annotations # create, list, filter, delete annotations
|
|
132
|
+
ds.connections # parent-child annotation links
|
|
133
|
+
ds.properties # computed measurements
|
|
134
|
+
ds.collections # display configuration (layers, tools)
|
|
135
|
+
ds.export # JSON and CSV export
|
|
136
|
+
ds.history # undo/redo
|
|
137
|
+
ds.sharing # access control
|
|
138
|
+
client.list_datasets()
|
|
139
|
+
client.list_workers()
|
|
140
|
+
client.list_projects()
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
See the [full documentation](docs/) for detailed API reference and examples.
|
|
144
|
+
|
|
145
|
+
## Claude Code integration
|
|
146
|
+
|
|
147
|
+
NimbusImage includes skills for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) that teach Claude how to use this API. After installing, you can ask Claude things like "connect to my NimbusImage server and list datasets" and it will write correct code.
|
|
148
|
+
|
|
149
|
+
### Install the skills
|
|
150
|
+
|
|
151
|
+
**Option A — Marketplace install (recommended):**
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Add the NimbusImage marketplace (one-time)
|
|
155
|
+
claude plugin marketplace add arjunrajlaboratory/NimbusImage
|
|
156
|
+
|
|
157
|
+
# Install the nimbusimage plugin
|
|
158
|
+
claude plugin install nimbusimage@arjunrajlaboratory/NimbusImage
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Option B — For this session only:**
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
claude --plugin-dir /path/to/NimbusImage/plugins/nimbusimage
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Option C — Permanent (project-scoped):**
|
|
168
|
+
|
|
169
|
+
Add to your project's `.claude/settings.local.json`:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"plugins": ["/path/to/NimbusImage/plugins/nimbusimage"]
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Available skills
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
| Command | What it covers |
|
|
181
|
+
| -------------------------- | -------------------------------------------------- |
|
|
182
|
+
| `/nimbusimage` | Connection, dataset discovery, metadata, projects |
|
|
183
|
+
| `/nimbusimage:annotations` | Annotation CRUD, geometry helpers, bulk operations |
|
|
184
|
+
| `/nimbusimage:images` | Frame retrieval, composites, z-stacks, crops |
|
|
185
|
+
| `/nimbusimage:workers` | Docker worker discovery, execution, job tracking |
|
|
186
|
+
| `/nimbusimage:analyze` | Properties, export, connections, sharing |
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
The skills use progressive disclosure — Claude loads only what it needs for the current task.
|
|
190
|
+
|
|
191
|
+
## Development
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
cd nimbusimage
|
|
195
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
196
|
+
pip install -e ".[dev]"
|
|
197
|
+
|
|
198
|
+
# Run unit tests (no backend required)
|
|
199
|
+
pytest tests/ --ignore=tests/integration -v
|
|
200
|
+
|
|
201
|
+
# Run integration tests (requires docker compose up)
|
|
202
|
+
pytest tests/integration/ -v -m integration
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
See the project root for license information.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# nimbusimage
|
|
2
|
+
|
|
3
|
+
Python API for [NimbusImage](https://nimbusimage.com) — programmatic access to scientific imaging datasets, annotations, workers, and analysis.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install nimbusimage
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For Docker worker development (includes `large_image` for writing TIFF files):
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install nimbusimage[worker]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Authentication
|
|
18
|
+
|
|
19
|
+
The recommended setup uses a **Girder API key**, which is persistent and doesn't expire.
|
|
20
|
+
|
|
21
|
+
**How to get an API key:**
|
|
22
|
+
|
|
23
|
+
- **nimbusimage.com (hosted):** Email **[support@cytopixel.com](mailto:support@cytopixel.com)** with your account email address to request an API key.
|
|
24
|
+
- **Local/self-hosted server:** In the Girder admin UI, go to **Users** > select the user > **Edit User** > **API Keys** > create a new key and copy the key string.
|
|
25
|
+
|
|
26
|
+
Set environment variables for persistent access:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Add to ~/.zshrc or ~/.bashrc
|
|
30
|
+
|
|
31
|
+
# For nimbusimage.com:
|
|
32
|
+
export NI_API_URL="https://nimbusimage.com/girder"
|
|
33
|
+
export NI_API_KEY="your-api-key-here"
|
|
34
|
+
|
|
35
|
+
# For a local server:
|
|
36
|
+
export NI_API_URL="http://localhost:8080/api/v1"
|
|
37
|
+
export NI_API_KEY="your-api-key-here"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then connect with no arguments:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import nimbusimage as ni
|
|
44
|
+
|
|
45
|
+
client = ni.connect()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or pass credentials explicitly:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
client = ni.connect("http://localhost:8080/api/v1", api_key="your-api-key")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Quick start
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import nimbusimage as ni
|
|
58
|
+
|
|
59
|
+
client = ni.connect()
|
|
60
|
+
|
|
61
|
+
# List datasets
|
|
62
|
+
for d in client.list_datasets():
|
|
63
|
+
print(f"{d['name']} (ID: {d['_id']})")
|
|
64
|
+
|
|
65
|
+
# Open a dataset
|
|
66
|
+
ds = client.dataset(name="My Experiment")
|
|
67
|
+
print(f"{ds.name}: {ds.channels}, {ds.num_z} z-slices, {ds.shape}")
|
|
68
|
+
|
|
69
|
+
# Fetch an image
|
|
70
|
+
img = ds.images.get(channel=0, z=0) # numpy array
|
|
71
|
+
|
|
72
|
+
# Get a composite RGB image
|
|
73
|
+
rgb = ds.images.get_composite(dtype="uint8")
|
|
74
|
+
|
|
75
|
+
# List annotations
|
|
76
|
+
polygons = ds.annotations.list(shape="polygon")
|
|
77
|
+
|
|
78
|
+
# Run a worker
|
|
79
|
+
job = ds.annotations.compute(
|
|
80
|
+
image="annotations/random_squares:latest",
|
|
81
|
+
channel=0, tags=["detected"],
|
|
82
|
+
worker_interface={"Number of squares": 10, "Square size": 15},
|
|
83
|
+
)
|
|
84
|
+
job.wait()
|
|
85
|
+
|
|
86
|
+
# Export data
|
|
87
|
+
ds.export.to_csv(property_paths=[["prop_id", "Area"]], path="results.csv")
|
|
88
|
+
|
|
89
|
+
# Open in browser
|
|
90
|
+
ds.open(z=3)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## API overview
|
|
94
|
+
|
|
95
|
+
The package follows an accessor pattern:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
ni.connect() -> NimbusClient
|
|
99
|
+
client.dataset(id) -> Dataset
|
|
100
|
+
ds.images # fetch frames, composites, z-stacks
|
|
101
|
+
ds.annotations # create, list, filter, delete annotations
|
|
102
|
+
ds.connections # parent-child annotation links
|
|
103
|
+
ds.properties # computed measurements
|
|
104
|
+
ds.collections # display configuration (layers, tools)
|
|
105
|
+
ds.export # JSON and CSV export
|
|
106
|
+
ds.history # undo/redo
|
|
107
|
+
ds.sharing # access control
|
|
108
|
+
client.list_datasets()
|
|
109
|
+
client.list_workers()
|
|
110
|
+
client.list_projects()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
See the [full documentation](docs/) for detailed API reference and examples.
|
|
114
|
+
|
|
115
|
+
## Claude Code integration
|
|
116
|
+
|
|
117
|
+
NimbusImage includes skills for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) that teach Claude how to use this API. After installing, you can ask Claude things like "connect to my NimbusImage server and list datasets" and it will write correct code.
|
|
118
|
+
|
|
119
|
+
### Install the skills
|
|
120
|
+
|
|
121
|
+
**Option A — Marketplace install (recommended):**
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Add the NimbusImage marketplace (one-time)
|
|
125
|
+
claude plugin marketplace add arjunrajlaboratory/NimbusImage
|
|
126
|
+
|
|
127
|
+
# Install the nimbusimage plugin
|
|
128
|
+
claude plugin install nimbusimage@arjunrajlaboratory/NimbusImage
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Option B — For this session only:**
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
claude --plugin-dir /path/to/NimbusImage/plugins/nimbusimage
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Option C — Permanent (project-scoped):**
|
|
138
|
+
|
|
139
|
+
Add to your project's `.claude/settings.local.json`:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"plugins": ["/path/to/NimbusImage/plugins/nimbusimage"]
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Available skills
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
| Command | What it covers |
|
|
151
|
+
| -------------------------- | -------------------------------------------------- |
|
|
152
|
+
| `/nimbusimage` | Connection, dataset discovery, metadata, projects |
|
|
153
|
+
| `/nimbusimage:annotations` | Annotation CRUD, geometry helpers, bulk operations |
|
|
154
|
+
| `/nimbusimage:images` | Frame retrieval, composites, z-stacks, crops |
|
|
155
|
+
| `/nimbusimage:workers` | Docker worker discovery, execution, job tracking |
|
|
156
|
+
| `/nimbusimage:analyze` | Properties, export, connections, sharing |
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
The skills use progressive disclosure — Claude loads only what it needs for the current task.
|
|
160
|
+
|
|
161
|
+
## Development
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
cd nimbusimage
|
|
165
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
166
|
+
pip install -e ".[dev]"
|
|
167
|
+
|
|
168
|
+
# Run unit tests (no backend required)
|
|
169
|
+
pytest tests/ --ignore=tests/integration -v
|
|
170
|
+
|
|
171
|
+
# Run integration tests (requires docker compose up)
|
|
172
|
+
pytest tests/integration/ -v -m integration
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
See the project root for license information.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""NimbusImage Python API.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
import nimbusimage as ni
|
|
5
|
+
|
|
6
|
+
client = ni.connect(api_url, token=...)
|
|
7
|
+
ds = client.dataset(dataset_id)
|
|
8
|
+
img = ds.images.get(channel=0)
|
|
9
|
+
anns = ds.annotations.list(shape='polygon')
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from nimbusimage.client import NimbusClient
|
|
13
|
+
from nimbusimage.collections import Collection
|
|
14
|
+
from nimbusimage.coordinates import attach_geometry_methods
|
|
15
|
+
from nimbusimage.dataset import Dataset
|
|
16
|
+
from nimbusimage.jobs import Job
|
|
17
|
+
from nimbusimage.filters import (
|
|
18
|
+
filter_by_tags,
|
|
19
|
+
filter_by_location,
|
|
20
|
+
group_by_location,
|
|
21
|
+
)
|
|
22
|
+
from nimbusimage.models import (
|
|
23
|
+
Annotation,
|
|
24
|
+
Connection,
|
|
25
|
+
FrameInfo,
|
|
26
|
+
Location,
|
|
27
|
+
PixelSize,
|
|
28
|
+
Property,
|
|
29
|
+
)
|
|
30
|
+
from nimbusimage.worker import WorkerContext
|
|
31
|
+
|
|
32
|
+
# Attach geometry methods (polygon, point, get_mask, etc.) to Annotation
|
|
33
|
+
attach_geometry_methods()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def connect(
|
|
37
|
+
api_url: str | None = None,
|
|
38
|
+
token: str | None = None,
|
|
39
|
+
api_key: str | None = None,
|
|
40
|
+
username: str | None = None,
|
|
41
|
+
password: str | None = None,
|
|
42
|
+
) -> NimbusClient:
|
|
43
|
+
"""Connect to a NimbusImage server.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
api_url: Girder API URL. Or set NI_API_URL env var.
|
|
47
|
+
token: Auth token. Or set NI_TOKEN env var.
|
|
48
|
+
api_key: Girder API key. Or set NI_API_KEY env var.
|
|
49
|
+
API keys are persistent and don't expire (unlike
|
|
50
|
+
session tokens). Recommended for automation.
|
|
51
|
+
username: Username for interactive auth.
|
|
52
|
+
password: Password for interactive auth.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Authenticated NimbusClient.
|
|
56
|
+
"""
|
|
57
|
+
return NimbusClient(
|
|
58
|
+
api_url=api_url, token=token, api_key=api_key,
|
|
59
|
+
username=username, password=password,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def worker_context(
|
|
64
|
+
dataset_id: str | None = None,
|
|
65
|
+
api_url: str | None = None,
|
|
66
|
+
token: str | None = None,
|
|
67
|
+
params: dict | None = None,
|
|
68
|
+
) -> WorkerContext:
|
|
69
|
+
"""Create a worker context for Docker worker scripts.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
dataset_id: The dataset folder ID.
|
|
73
|
+
api_url: Girder API URL.
|
|
74
|
+
token: Auth token.
|
|
75
|
+
params: Worker parameters dict (from the job).
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
WorkerContext with parsed parameters and dataset access.
|
|
79
|
+
"""
|
|
80
|
+
return WorkerContext(
|
|
81
|
+
dataset_id=dataset_id, api_url=api_url,
|
|
82
|
+
token=token, params=params,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
__all__ = [
|
|
87
|
+
# Connection
|
|
88
|
+
"connect",
|
|
89
|
+
"worker_context",
|
|
90
|
+
# Classes
|
|
91
|
+
"NimbusClient",
|
|
92
|
+
"Collection",
|
|
93
|
+
"Dataset",
|
|
94
|
+
"Job",
|
|
95
|
+
"WorkerContext",
|
|
96
|
+
# Data models
|
|
97
|
+
"Annotation",
|
|
98
|
+
"Connection",
|
|
99
|
+
"Property",
|
|
100
|
+
"Location",
|
|
101
|
+
"PixelSize",
|
|
102
|
+
"FrameInfo",
|
|
103
|
+
# Filters
|
|
104
|
+
"filter_by_tags",
|
|
105
|
+
"filter_by_location",
|
|
106
|
+
"group_by_location",
|
|
107
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Shared access level constants and helpers."""
|
|
2
|
+
|
|
3
|
+
ACCESS_MAP = {"read": 0, "write": 1, "admin": 2, "remove": -1}
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def resolve_access(access: str) -> int:
|
|
7
|
+
"""Convert a human-readable access level to its integer code.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
access: One of 'read', 'write', 'admin', 'remove'.
|
|
11
|
+
|
|
12
|
+
Raises:
|
|
13
|
+
ValueError: If the access level is not recognized.
|
|
14
|
+
"""
|
|
15
|
+
if access not in ACCESS_MAP:
|
|
16
|
+
raise ValueError(
|
|
17
|
+
f"Invalid access level '{access}'. "
|
|
18
|
+
f"Must be one of: {', '.join(ACCESS_MAP.keys())}"
|
|
19
|
+
)
|
|
20
|
+
return ACCESS_MAP[access]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Internal wrapper around girder_client.GirderClient.
|
|
2
|
+
|
|
3
|
+
This module is an implementation detail. Users should never import from it.
|
|
4
|
+
All HTTP communication goes through this wrapper so that endpoint paths
|
|
5
|
+
and error handling are centralized.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
import girder_client
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_client(
|
|
16
|
+
api_url: str | None = None,
|
|
17
|
+
token: str | None = None,
|
|
18
|
+
api_key: str | None = None,
|
|
19
|
+
username: str | None = None,
|
|
20
|
+
password: str | None = None,
|
|
21
|
+
) -> girder_client.GirderClient:
|
|
22
|
+
"""Create and authenticate a GirderClient.
|
|
23
|
+
|
|
24
|
+
Connection modes (tried in order):
|
|
25
|
+
1. Explicit token
|
|
26
|
+
2. Explicit API key
|
|
27
|
+
3. Username + password
|
|
28
|
+
4. NI_API_KEY environment variable
|
|
29
|
+
5. NI_TOKEN environment variable
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
api_url: Girder API URL (e.g., 'http://localhost:8080/api/v1').
|
|
33
|
+
token: Pre-existing authentication token.
|
|
34
|
+
api_key: Girder API key (persistent, doesn't expire).
|
|
35
|
+
username: Username for interactive auth.
|
|
36
|
+
password: Password for interactive auth.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Authenticated GirderClient instance.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
ValueError: If no valid authentication method is provided.
|
|
43
|
+
"""
|
|
44
|
+
if api_url is None:
|
|
45
|
+
api_url = os.environ.get("NI_API_URL")
|
|
46
|
+
if api_url is None:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
"api_url must be provided or set NI_API_URL "
|
|
49
|
+
"environment variable"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
gc = girder_client.GirderClient(apiUrl=api_url)
|
|
53
|
+
|
|
54
|
+
if token is not None:
|
|
55
|
+
gc.setToken(token)
|
|
56
|
+
elif api_key is not None:
|
|
57
|
+
gc.authenticate(apiKey=api_key)
|
|
58
|
+
elif username is not None or password is not None:
|
|
59
|
+
if username is None or password is None:
|
|
60
|
+
raise ValueError(
|
|
61
|
+
"Both username and password must be provided"
|
|
62
|
+
)
|
|
63
|
+
gc.authenticate(username=username, password=password)
|
|
64
|
+
else:
|
|
65
|
+
env_api_key = os.environ.get("NI_API_KEY")
|
|
66
|
+
env_token = os.environ.get("NI_TOKEN")
|
|
67
|
+
if env_api_key is not None:
|
|
68
|
+
gc.authenticate(apiKey=env_api_key)
|
|
69
|
+
elif env_token is not None:
|
|
70
|
+
gc.setToken(env_token)
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError(
|
|
73
|
+
"Provide token=, api_key=, username=/password=, "
|
|
74
|
+
"or set NI_API_KEY/NI_TOKEN environment variable"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
return gc
|