You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4b608a1
Browse filesBrowse the repository at this point in the historyBrowse files
Open the em.image module with the types read and write need (#148)
First half of #143. Opens `em` and binds the types `read` and `write`
take,
without binding either function — that is the second half. Everything
here is
independently reachable and tested, so the API decisions land before the
functions that depend on them.
Follows the three answers on the issue: the format managers are services
like
any other, `image_metadata` stays out, and nothing parses a location out
of a
string on the Python side.
## What is bound
| Name | Is |
|---|---|
| `rexlib.em.image.ImageLocation` | Path plus a zero based index,
`no_position` for the whole file |
| `rexlib.em.image.parse_image_location` | `str` to `ImageLocation |
None` |
| `rexlib.em.image.ImageReadFormatManager` | Opaque handle, like
`ProgramManager` |
| `rexlib.em.image.ImageWriteFormatManager` | Same, for writing |
| `rexlib.em.image.get_image_{read,write}_format_manager` |
`ServiceCatalog` to the manager |
The managers are bound with no methods at all. `open` would drag in
`image_reader`, and `get_most_suitable_format` `image_probe` and
`image_read_format`; none of that is needed to pass a manager to `read`,
which
is all the issue asks for. `ProgramManager` is bound exactly this way
today.
## The module path
`em/image/`, not `em/`, which is the decision argued on the issue and
not yet
confirmed there — flag it if you disagree, it is cheap now and expensive
once
released. Short version: the submodules follow rexlib's directories, and
the
area has to be the module path rather than part of the function name, or
`read` becomes `read_image` the day metadata reading lands.
This is the first public subpackage in `python/rexlib/`, where the
convention
so far is a flat set of private modules re-exported by `__init__.py`.
Here the
path is the API, so `em/` and `em/image/` are named without an
underscore and
carry `__all__` of their own. `AGENTS.md` records the exception.
## No parsing, deliberately
`DeviceIndex` sets the opposite precedent: it takes a second `py::init`
that
parses `"cuda:0"` and throws on nonsense. `ImageLocation` does not,
because
`ImageLocation("3@stack.mrc")` would be Python inventing a conversion
that C++
does not have, and because the primary constructor already gives a
single
string the meaning "this path, whole file" — the two would be ambiguous
rather
than complementary. `parse_image_location` is asked for by name and
returns
`None` rather than throwing, since failing to parse is a routine outcome
here
where `DeviceIndex`'s is an error. A test pins it:
```python
def test_a_path_is_never_parsed_on_its_way_into_a_location():
assert ImageLocation('3@stack.mrc').path == '3@stack.mrc'
```
## The stub collection had to change
This is the first submodule holding a submodule, and pybind11-stubgen
renders
that as a directory rather than a file. Verified against 2.5.5, the
pinned
version:
```
_binding/__init__.pyi
_binding/numerical.pyi
_binding/em/__init__.pyi <- new shape
_binding/em/image.pyi
```
`deploy.yml` collected stubs with `cp .../_binding/*.pyi stubs/`, a flat
glob
that would have taken the top level and silently dropped `em`. Nothing
would
have failed: `install_python_stubs` only checks that *some* `.pyi`
exists, and
`install(DIRECTORY ... FILES_MATCHING)` is recursive, so every published
wheel
would have shipped typed except for the area this PR adds. It now copies
the
tree.
## Checked
- `ruff check .` passes.
- Every new and modified translation unit compiles clean under
`g++ -std=c++20 -fsyntax-only -Wall -Wextra -Wpedantic` against rexlib's
headers and the pinned pybind11.
- The parse test cases are taken from `parse_image_location`'s actual
rejections — empty index, index zero, non-digits — not guessed.
- 28 tests collect under `tests/em/image/`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
0 commit comments