-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bioformats2raw export: unify Zarr layout and add OMERO metadata #76
Changes from 4 commits
c4b1c43
27620bd
91bf1a1
0835e4f
7ae24db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,9 +8,16 @@ | |
from omero.cli import CLI, BaseControl, Parser, ProxyStringType | ||
from omero.gateway import BlitzGateway, BlitzObjectWrapper | ||
from omero.model import ImageI, PlateI | ||
from zarr.hierarchy import open_group | ||
from zarr.storage import FSStore | ||
|
||
from .masks import MASK_DTYPE_SIZE, image_shapes_to_zarr, plate_shapes_to_zarr | ||
from .raw_pixels import image_to_zarr, plate_to_zarr | ||
from .raw_pixels import ( | ||
add_omero_metadata, | ||
add_toplevel_metadata, | ||
image_to_zarr, | ||
plate_to_zarr, | ||
) | ||
|
||
HELP = """Export data in zarr format. | ||
|
||
|
@@ -237,19 +244,8 @@ def polygons(self, args: argparse.Namespace) -> None: | |
def export(self, args: argparse.Namespace) -> None: | ||
if isinstance(args.object, ImageI): | ||
image = self._lookup(self.gateway, "Image", args.object.id) | ||
inplace = image.getInplaceImport() | ||
|
||
if args.bf: | ||
if self.client is None: | ||
raise Exception("This cannot happen") # mypy is confused | ||
prx, desc = self.client.getManagedRepository(description=True) | ||
repo_path = Path(desc._path._val) / Path(desc._name._val) | ||
if inplace: | ||
for p in image.getImportedImageFilePaths()["client_paths"]: | ||
self._bf_export(Path("/") / Path(p), args) | ||
else: | ||
for p in image.getImportedImageFilePaths()["server_paths"]: | ||
self._bf_export(repo_path / p, args) | ||
self._bf_export(image, args) | ||
else: | ||
image_to_zarr(image, args) | ||
elif isinstance(args.object, PlateI): | ||
|
@@ -266,8 +262,23 @@ def _lookup( | |
self.ctx.die(110, f"No such {otype}: {oid}") | ||
return obj | ||
|
||
def _bf_export(self, abs_path: Path, args: argparse.Namespace) -> None: | ||
def _bf_export(self, image: BlitzObjectWrapper, args: argparse.Namespace) -> None: | ||
if image.getInplaceImport(): | ||
p = image.getImportedImageFilePaths()["client_paths"][0] | ||
abs_path = Path("/") / Path(p) | ||
else: | ||
if self.client is None: | ||
raise Exception("This cannot happen") # mypy is confused | ||
prx, desc = self.client.getManagedRepository(description=True) | ||
p = image.getImportedImageFilePaths()["server_paths"][0] | ||
abs_path = Path(desc._path._val) / Path(desc._name._val) / Path(p) | ||
target = (Path(args.output) or Path.cwd()) / Path(abs_path).name | ||
image_target = (Path(args.output) or Path.cwd()) / f"{image.id}.zarr" | ||
|
||
if target.exists(): | ||
self.ctx.die(111, f"{target.resolve()} already exists") | ||
if image_target.exists(): | ||
self.ctx.die(111, f"{image_target.resolve()} already exists") | ||
|
||
cmd: List[str] = [ | ||
"bioformats2raw", | ||
|
@@ -283,6 +294,9 @@ def _bf_export(self, abs_path: Path, args: argparse.Namespace) -> None: | |
cmd.append(f"--resolutions={args.resolutions}") | ||
if args.max_workers: | ||
cmd.append(f"--max_workers={args.max_workers}") | ||
cmd.append(f"--series={image.series}") | ||
cmd.append("--no-root-group") | ||
cmd.append("--no-ome-meta-export") | ||
|
||
self.ctx.dbg(" ".join(cmd)) | ||
process = subprocess.Popen( | ||
|
@@ -294,7 +308,21 @@ def _bf_export(self, abs_path: Path, args: argparse.Namespace) -> None: | |
if stderr: | ||
self.ctx.err(stderr.decode("utf-8")) | ||
if process.returncode == 0: | ||
self.ctx.out(f"Image exported to {target.resolve()}") | ||
image_source = target / "0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's always There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunate, it means that you can't then make use of OME-XML if enabled. |
||
image_source.rename(image_target) | ||
target.rmdir() | ||
self.ctx.out(f"Image exported to {image_target.resolve()}") | ||
|
||
# Add OMERO metadata | ||
store = FSStore( | ||
str(image_target.resolve()), | ||
auto_mkdir=False, | ||
normalize_keys=False, | ||
mode="w", | ||
) | ||
root = open_group(store) | ||
add_omero_metadata(root, image) | ||
add_toplevel_metadata(root) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this just sets There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely a mix. There is some Bio-Formats metadata under There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to, ... 😉 |
||
|
||
|
||
try: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This happens if the field is ever assigned with a
None
like inomero-cli-zarr/src/omero_zarr/cli.py
Line 70 in 0835e4f
I don't know if changing that to
del self.client
keeps mypy and everyone else happy.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error is still confusing to me. I don't understand why
mypy
does not throw the same error withself.gateway
which has the same behavior asself.client
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's certainly an element of magic involved, at least partially related to
finally
s and otherif
checks.