Skip to content

Commit 3bb9a9b

Browse files
authored
Fix mag paths under Windows (#1329)
* fix windows paths, maybe * ci * tests * ci * windowspath * windowspath * uv version * changelog * windows minio * ci * ci * ci * ci * ci * utc * utc * ci * ci * ci * lint * absolute path * more as_posix * ci * ci * ci * ci * use as_posix
1 parent 95273c4 commit 3bb9a9b

18 files changed

+489
-305
lines changed

.github/workflows/ci.yml

Lines changed: 98 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ jobs:
4444
- uses: actions/checkout@v4
4545
- uses: astral-sh/setup-uv@v6
4646
with:
47-
version: "0.6.3"
4847
enable-cache: true
4948
cache-dependency-glob: "cluster_tools/uv.lock"
5049
- run: uv python install ${{ matrix.python-version }}
@@ -104,7 +103,6 @@ jobs:
104103
- name: Install uv
105104
uses: astral-sh/setup-uv@v6
106105
with:
107-
version: "0.6.3"
108106
enable-cache: true
109107
cache-dependency-glob: "cluster_tools/uv.lock"
110108
- name: Set up Python ${{ matrix.python-version }}
@@ -142,7 +140,6 @@ jobs:
142140
- name: Install uv
143141
uses: astral-sh/setup-uv@v6
144142
with:
145-
version: "0.6.3"
146143
enable-cache: true
147144
cache-dependency-glob: "cluster_tools/uv.lock"
148145
- name: Set up Python ${{ matrix.python-version }}
@@ -184,7 +181,6 @@ jobs:
184181
- name: Install uv
185182
uses: astral-sh/setup-uv@v6
186183
with:
187-
version: "0.6.3"
188184
enable-cache: true
189185
cache-dependency-glob: "cluster_tools/uv.lock"
190186
- name: Set up Python ${{ matrix.python-version }}
@@ -217,8 +213,6 @@ jobs:
217213
- name: Install uv
218214
uses: astral-sh/setup-uv@v3
219215
with:
220-
# Install a specific version of uv.
221-
version: "0.5.26"
222216
enable-cache: true
223217
cache-dependency-glob: "webknossos/uv.lock"
224218

@@ -273,6 +267,88 @@ jobs:
273267
git diff --no-ext-diff --exit-code
274268
[[ -z $(git status -s) ]]
275269
270+
webknossos_windows:
271+
needs: changes
272+
if: |
273+
${{ needs.changes.outputs.cluster_tools == 'true' }} ||
274+
${{ needs.changes.outputs.webknossos == 'true' }}
275+
runs-on: windows-latest
276+
strategy:
277+
matrix:
278+
python-version: ["3.12"]
279+
group: [1, 2, 3]
280+
fail-fast: false
281+
defaults:
282+
run:
283+
working-directory: webknossos
284+
285+
steps:
286+
- uses: actions/checkout@v3
287+
288+
- name: Install uv
289+
uses: astral-sh/setup-uv@v3
290+
with:
291+
enable-cache: true
292+
cache-dependency-glob: "webknossos/uv.lock"
293+
294+
- name: Install proxay
295+
run: npm install -g proxay
296+
297+
- name: Install minio
298+
run: Invoke-WebRequest -Uri "https://dl.min.io/server/minio/release/windows-amd64/minio.exe" -OutFile "minio.exe"
299+
300+
- name: Set up Python ${{ matrix.python-version }}
301+
run: uv python install ${{ matrix.python-version }}
302+
303+
- name: Python tests
304+
timeout-minutes: 30
305+
shell: bash
306+
env:
307+
PYTHON_VERSION: ${{ matrix.python-version }}
308+
MULTIPROCESSING_DEFAULT_START_METHOD: spawn
309+
run: ./test.sh --splits 3 --group ${{ matrix.group }} --splitting-algorithm least_duration
310+
311+
webknossos_macos:
312+
needs: changes
313+
if: |
314+
${{ needs.changes.outputs.cluster_tools == 'true' }} ||
315+
${{ needs.changes.outputs.webknossos == 'true' }}
316+
runs-on: macos-latest
317+
strategy:
318+
matrix:
319+
python-version: ["3.12"]
320+
group: [1, 2, 3]
321+
fail-fast: false
322+
defaults:
323+
run:
324+
working-directory: webknossos
325+
326+
steps:
327+
- uses: actions/checkout@v3
328+
329+
- name: Install uv
330+
uses: astral-sh/setup-uv@v3
331+
with:
332+
enable-cache: true
333+
cache-dependency-glob: "webknossos/uv.lock"
334+
335+
- name: Install proxay
336+
run: npm install -g proxay
337+
338+
- name: Install minio
339+
run: brew install minio/stable/minio
340+
341+
- name: Set up Python ${{ matrix.python-version }}
342+
run: uv python install ${{ matrix.python-version }}
343+
344+
- name: Python tests
345+
timeout-minutes: 30
346+
shell: bash
347+
env:
348+
PYTHON_VERSION: ${{ matrix.python-version }}
349+
run: ./test.sh --splits 3 --group ${{ matrix.group }} --splitting-algorithm least_duration
350+
351+
276352
coverage_report:
277353
needs: [webknossos_linux]
278354
if: success()
@@ -316,6 +392,8 @@ jobs:
316392
- cluster_tools_kubernetes
317393
- cluster_tools_dask
318394
- webknossos_linux
395+
- webknossos_windows
396+
- webknossos_macos
319397
if: |
320398
always() &&
321399
!contains(needs.*.result, 'failure') &&
@@ -326,9 +404,6 @@ jobs:
326404
- uses: actions/checkout@v3
327405
- name: Install uv
328406
uses: astral-sh/setup-uv@v3
329-
with:
330-
# Install a specific version of uv.
331-
version: "0.6.3"
332407
- name: Write version file
333408
run: |
334409
pushd webknossos
@@ -393,6 +468,8 @@ jobs:
393468
- cluster_tools_kubernetes
394469
- cluster_tools_dask
395470
- webknossos_linux
471+
- webknossos_windows
472+
- webknossos_macos
396473
runs-on: ubuntu-latest
397474
if: |
398475
always() &&
@@ -408,9 +485,6 @@ jobs:
408485
path: docs/wk-repo
409486
- name: Install uv
410487
uses: astral-sh/setup-uv@v3
411-
with:
412-
# Install a specific version of uv.
413-
version: "0.6.3"
414488
- name: Build Docs
415489
run: |
416490
cd docs
@@ -454,6 +528,8 @@ jobs:
454528
- cluster_tools_kubernetes
455529
- cluster_tools_dask
456530
- webknossos_linux
531+
- webknossos_windows
532+
- webknossos_macos
457533
if: |
458534
always() &&
459535
!contains(needs.*.result, 'failure') &&
@@ -465,9 +541,6 @@ jobs:
465541
- uses: actions/checkout@v3
466542
- name: Install uv
467543
uses: astral-sh/setup-uv@v3
468-
with:
469-
# Install a specific version of uv.
470-
version: "0.6.3"
471544
- name: Publish python packages
472545
env:
473546
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_PASSWORD }}
@@ -490,16 +563,16 @@ jobs:
490563

491564
complete:
492565
needs:
493-
[
494-
cluster_tools_dask,
495-
cluster_tools_kubernetes,
496-
cluster_tools_multiprocessing,
497-
cluster_tools_slurm,
498-
webknossos_linux,
499-
webknossos_cli_docker,
500-
docs,
501-
pypi_and_gh_release,
502-
]
566+
- cluster_tools_dask
567+
- cluster_tools_kubernetes
568+
- cluster_tools_multiprocessing
569+
- cluster_tools_slurm
570+
- webknossos_linux
571+
- webknossos_windows
572+
- webknossos_macos
573+
- webknossos_cli_docker
574+
- docs
575+
- pypi_and_gh_release
503576
if: always()
504577
runs-on: ubuntu-latest
505578
steps:

.github/workflows/nightly.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ jobs:
2323

2424
- name: Install uv
2525
uses: astral-sh/setup-uv@v3
26-
with:
27-
version: "0.5.26"
2826

2927
- name: Install proxay
3028
run: npm install -g proxay

.github/workflows/publish_docs.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ jobs:
1717
path: docs/wk-repo
1818
- name: Install uv
1919
uses: astral-sh/setup-uv@v3
20-
with:
21-
# Install a specific version of uv.
22-
version: "0.6.3"
2320

2421
- name: Build Docs
2522
run: |

webknossos/Changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ For upgrade instructions, please check the respective _Breaking Changes_ section
2020
- Warnings regarding missing pims image readers are only printed once during conversion. Error messages regarding wk-libs version are not displayed in slurm environments. [#1266](https://github.com/scalableminds/webknossos-libs/pull/1266)
2121

2222
### Fixed
23-
23+
- Fixed mag and attachment paths under Windows. [#1329](https://github.com/scalableminds/webknossos-libs/pull/1329)
2424

2525
## [2.4.2](https://github.com/scalableminds/webknossos-libs/releases/tag/v2.4.2) - 2025-07-07
2626
[Commits](https://github.com/scalableminds/webknossos-libs/compare/v2.4.1...v2.4.2)

webknossos/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM python:3.12
22

3-
COPY --from=ghcr.io/astral-sh/uv:0.5.26 /uv /bin/uv
3+
COPY --from=ghcr.io/astral-sh/uv:0.7.17 /uv /bin/uv
44

55
RUN mkdir /webknossos
66
COPY webknossos/webknossos /webknossos/webknossos

webknossos/test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ set -eEuo pipefail
44
source local_wk_setup.sh
55

66
# Using forkserver instead of spawn is faster. Fork should never be used due to potential deadlock problems.
7-
export MULTIPROCESSING_DEFAULT_START_METHOD=forkserver
7+
export MULTIPROCESSING_DEFAULT_START_METHOD=${MULTIPROCESSING_DEFAULT_START_METHOD:-forkserver}
88

99
# Note that pytest should be executed via `python -m`, since
1010
# this will ensure that the current directory is added to sys.path

webknossos/tests/constants.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ def use_minio() -> Iterator[None]:
4949
minio_process.terminate()
5050
sleep(1)
5151
rmtree(minio_path)
52+
elif sys.platform == "win32":
53+
minio_path = UPath("testoutput_minio")
54+
rmtree(minio_path)
55+
minio_process = subprocess.Popen(
56+
shlex.split(f"minio.exe server --address :8000 {minio_path.absolute()}"),
57+
env={
58+
**os.environ,
59+
"MINIO_ROOT_USER": MINIO_ROOT_USER,
60+
"MINIO_ROOT_PASSWORD": MINIO_ROOT_PASSWORD,
61+
},
62+
)
63+
sleep(3)
64+
assert minio_process.poll() is None
65+
REMOTE_TESTOUTPUT_DIR.fs.mkdirs("testoutput", exist_ok=True)
66+
try:
67+
yield
68+
finally:
69+
minio_process.terminate()
70+
sleep(1)
71+
rmtree(minio_path)
5272
else:
5373
container_name = "minio"
5474
cmd = (

webknossos/tests/dataset/test_add_layer_from_images.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
import warnings
23
from collections.abc import Iterator
34
from pathlib import Path
@@ -341,6 +342,7 @@ def _test_bioformats(
341342
return ds
342343

343344

345+
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
344346
@pytest.mark.parametrize(
345347
"url, filename, kwargs, dtype, num_channels, size, num_layers", BIOFORMATS_ARGS
346348
)
@@ -509,6 +511,7 @@ def _test_test_images(
509511
@pytest.mark.parametrize(
510512
"url, filename, kwargs, dtype, num_channels, size", TEST_IMAGES_ARGS
511513
)
514+
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
512515
def test_test_images(
513516
tmp_path: Path,
514517
url: str | list[str],

webknossos/tests/dataset/test_attachments.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ def test_attachments(tmp_upath: UPath) -> None:
8282

8383
# segment index
8484
seg_layer.attachments.set_segment_index(
85-
"/usr/segment_index.hdf5",
85+
Path.home() / "segment_index.hdf5",
8686
name="main",
8787
data_format=AttachmentDataFormat.HDF5,
8888
)
8989
assert seg_layer._properties.attachments.segment_index is not None
9090
assert (
9191
seg_layer._properties.attachments.segment_index.path
92-
== "/usr/segment_index.hdf5"
92+
== (Path.home() / "segment_index.hdf5").as_posix()
9393
)
9494
assert (
9595
seg_layer._properties.attachments.segment_index.data_format
@@ -225,8 +225,9 @@ def test_fs_copy_layer(tmp_upath: UPath) -> None:
225225

226226
# has not been copied
227227
assert copy_layer.attachments.agglomerates[0].path == agglomerate_path
228-
assert copy_layer.attachments.agglomerates[0]._properties.path == str(
229-
agglomerate_path
228+
assert (
229+
copy_layer.attachments.agglomerates[0]._properties.path
230+
== agglomerate_path.as_posix()
230231
)
231232

232233

@@ -427,7 +428,7 @@ def test_add_symlink_attachments(tmp_upath: UPath) -> None:
427428
with pytest.warns(DeprecationWarning):
428429
seg_layer.attachments.add_symlink_attachments(mesh)
429430
assert seg_layer._properties.attachments.meshes is not None
430-
assert seg_layer._properties.attachments.meshes[0].path == str(mesh_path)
431+
assert seg_layer._properties.attachments.meshes[0].path == mesh_path.as_posix()
431432
assert seg_layer.attachments.meshes[0].name == "meshfile_4-4-1"
432433
assert (dataset.path / "seg" / "meshes" / "meshfile_4-4-1").exists()
433434
assert (dataset.path / "seg" / "meshes" / "meshfile_4-4-1").is_symlink()
@@ -446,8 +447,9 @@ def test_add_symlink_attachments(tmp_upath: UPath) -> None:
446447
with pytest.warns(DeprecationWarning):
447448
seg_layer.attachments.add_symlink_attachments(segment_index)
448449
assert seg_layer._properties.attachments.segment_index is not None
449-
assert seg_layer._properties.attachments.segment_index.path == str(
450-
segment_index_path
450+
assert (
451+
seg_layer._properties.attachments.segment_index.path
452+
== segment_index_path.as_posix()
451453
)
452454
assert (dataset.path / "seg" / "segmentIndex" / "main").exists()
453455
assert (dataset.path / "seg" / "segmentIndex" / "main").is_symlink()

webknossos/tests/dataset/test_dataset.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,22 @@ def recursive_chmod(ds_path: Path, mode: int) -> None:
359359
recursive_chmod(ds_path, 0o777)
360360

361361

362+
@pytest.mark.parametrize("data_format", DATA_FORMATS)
363+
def test_mag_paths(data_format: DataFormat) -> None:
364+
ds_path = prepare_dataset_path(data_format, TESTOUTPUT_DIR)
365+
layer = Dataset(ds_path, voxel_size=(1, 1, 4)).add_layer(
366+
"color",
367+
COLOR_CATEGORY,
368+
bounding_box=BoundingBox((0, 0, 0), (32, 32, 32)),
369+
data_format=data_format,
370+
)
371+
mag1 = layer.add_mag("1")
372+
mag2 = layer.add_mag("2-2-1")
373+
374+
assert mag1._properties.path == "./color/1"
375+
assert mag2._properties.path == "./color/2-2-1"
376+
377+
362378
def test_create_default_layer() -> None:
363379
ds_path = prepare_dataset_path(DEFAULT_DATA_FORMAT, TESTOUTPUT_DIR)
364380
ds = Dataset(ds_path, voxel_size=(1, 1, 1))
@@ -2890,7 +2906,7 @@ def test_rename_layer(data_format: DataFormat, output_path: UPath) -> None:
28902906
len([layer for layer in ds._properties.data_layers if layer.name == "color2"])
28912907
== 1
28922908
)
2893-
assert ds._properties.data_layers[0].mags[0].path == "color2/1"
2909+
assert ds._properties.data_layers[0].mags[0].path == "./color2/1"
28942910
assert "color2" in ds.layers.keys()
28952911
assert "color" not in ds.layers.keys()
28962912
assert ds.get_layer("color2").data_format == data_format

0 commit comments

Comments
 (0)