sharedbox 0.7.0__tar.gz → 0.9.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.
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/ci.yaml +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/CHANGELOG.md +159 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/CLAUDE.md +53 -20
- {sharedbox-0.7.0 → sharedbox-0.9.0}/PKG-INFO +3 -1
- sharedbox-0.9.0/docs/examples/attach_metadata.py +78 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/clean_up_segments.py +5 -1
- sharedbox-0.9.0/docs/examples/request_work_from_the_owner.py +95 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/send_items_through_a_stream.py +84 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/store_a_large_list.py +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/store_a_large_set_or_dict.py +2 -2
- sharedbox-0.9.0/docs/examples/store_a_value_with_its_time.py +49 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/store_arrays.py +23 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/field-types.md +1 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/glossary.md +36 -0
- sharedbox-0.9.0/docs/how-to/attach-metadata.md +193 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/clean-up-segments.md +14 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/index.md +10 -0
- sharedbox-0.9.0/docs/how-to/migrate-from-0.7.md +83 -0
- sharedbox-0.9.0/docs/how-to/request-work-from-the-owner.md +158 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/send-items-through-a-stream.md +109 -7
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/store-a-large-list.md +2 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/store-a-large-set-or-dict.md +4 -3
- sharedbox-0.9.0/docs/how-to/store-a-value-with-its-time.md +80 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/store-arrays.md +43 -9
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/arrays.md +5 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/box.md +40 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/errors.md +40 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/events.md +1 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/index.md +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/segment-layout.md +660 -60
- {sharedbox-0.7.0 → sharedbox-0.9.0}/include/sharedbox/box.hpp +665 -31
- {sharedbox-0.7.0 → sharedbox-0.9.0}/include/sharedbox/core.hpp +778 -29
- {sharedbox-0.7.0 → sharedbox-0.9.0}/include/sharedbox/sharedbox_c.cpp +37 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/include/sharedbox/sharedbox_c.h +19 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/include/sharedbox/stream.hpp +350 -77
- {sharedbox-0.7.0 → sharedbox-0.9.0}/includes/abbreviations.md +1 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/pyproject.toml +3 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/__init__.py +35 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_arrays.py +77 -23
- sharedbox-0.9.0/src/sharedbox/_attr.py +360 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_bounded.py +160 -28
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_box.py +302 -67
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_events.py +315 -46
- sharedbox-0.9.0/src/sharedbox/_exit.py +193 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_follow.py +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_layout.py +227 -15
- sharedbox-0.9.0/src/sharedbox/_metadata.py +134 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/module.cpp +148 -30
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/segment.cpp +220 -17
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/segment.hpp +50 -7
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/stream.cpp +273 -57
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/types.cpp +367 -18
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/types.hpp +67 -5
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native.pyi +316 -21
- sharedbox-0.9.0/src/sharedbox/_request.py +385 -0
- sharedbox-0.9.0/src/sharedbox/_status.py +49 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_stream.py +610 -94
- sharedbox-0.9.0/src/sharedbox/_timed.py +34 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_types.py +227 -27
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_version.py +3 -3
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/ops.py +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/stream.py +2 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/stubtest-allowlist.txt +1 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/CMakeLists.txt +1 -1
- sharedbox-0.9.0/tests/cpp/table_builder.hpp +175 -0
- sharedbox-0.9.0/tests/cpp/test_attr.cpp +621 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_c_smoke.c +17 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_c_smoke_box.cpp +2 -1
- sharedbox-0.9.0/tests/cpp/test_layout3.cpp +632 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_mapping.cpp +3 -3
- sharedbox-0.9.0/tests/cpp/test_metadata.cpp +1022 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_stream.cpp +399 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_stream_layout.cpp +77 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_types.cpp +167 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_write_in_place.cpp +15 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/crossproc.py +63 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/forged_types.py +4 -2
- sharedbox-0.9.0/tests/signatures.py +12 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/streamproc.py +89 -3
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_read_into.py +2 -2
- sharedbox-0.9.0/tests/test_attr.py +869 -0
- sharedbox-0.9.0/tests/test_attr_fields.py +402 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_bounded_dict.py +39 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_bounded_list.py +51 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_bounded_set.py +37 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_box.py +2 -2
- sharedbox-0.9.0/tests/test_box_max_shape.py +292 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_events_bytes.py +1 -1
- sharedbox-0.9.0/tests/test_exit.py +257 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_fields.py +9 -8
- sharedbox-0.9.0/tests/test_metadata.py +509 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_native_segment.py +55 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_native_stream.py +6 -14
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_numpy.py +38 -2
- sharedbox-0.9.0/tests/test_properties_stream.py +353 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_types.py +10 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_read_into.py +6 -6
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_refs.py +2 -1
- sharedbox-0.9.0/tests/test_segment_status.py +173 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_stream.py +381 -13
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_stream_async.py +71 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_stream_events.py +32 -1
- sharedbox-0.9.0/tests/test_stream_fetch.py +222 -0
- sharedbox-0.9.0/tests/test_stream_metadata.py +478 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_stream_processes.py +40 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_stream_writing.py +1 -1
- sharedbox-0.9.0/tests/test_timed.py +249 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_arrays.py +56 -35
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_arrays_bfloat16.py +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_arrays_torch.py +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_numpy.py +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_records.py +3 -3
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_value_reuse.py +1 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_writing.py +4 -4
- sharedbox-0.9.0/tests/type_checks/attr_types.py +49 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/type_checks/bounded_types.py +10 -2
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/type_checks/box_types.py +13 -1
- sharedbox-0.9.0/tests/type_checks/metadata_types.py +132 -0
- sharedbox-0.9.0/tests/type_checks/timed_types.py +15 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/uv.lock +68 -1
- {sharedbox-0.7.0 → sharedbox-0.9.0}/zensical.toml +4 -0
- sharedbox-0.7.0/tests/cpp/table_builder.hpp +0 -49
- sharedbox-0.7.0/tests/cpp/test_layout3.cpp +0 -188
- sharedbox-0.7.0/tests/test_exit.py +0 -53
- sharedbox-0.7.0/tests/test_properties_stream.py +0 -121
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.clang-format +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/dependabot.yml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/pull_request_template.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/check-changelog.yaml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/check-docs.yaml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/codspeed.yml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/contention.yaml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/ops.yaml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/prepare-release.yaml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/publish-docs.yaml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.github/workflows/streams.yaml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/.gitignore +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/CMakeLists.txt +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/LICENSE +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/README.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/benchmarks/test_bench_box.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/benchmarks/test_bench_stream.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/changelog.d/.gitkeep +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/cmake/sharedbox-config.cmake +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/cmake/sharedbox-require-cxx.cmake +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/assets/benchmarks/ops.json +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/assets/benchmarks/roundtrip.json +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/assets/benchmarks/stream-matrix.json +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/assets/benchmarks/stream-throughput.json +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/diagrams/style.d2 +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/change_several_fields_at_once.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/follow_a_whole_reference_graph.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/name_a_box.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/send_a_box_to_another_process.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/set_defaults_and_check_values.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/store_collections.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/store_numpy_numbers.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/store_records.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/examples/store_text_and_bytes.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/checking-a-process-is-alive.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/closing-and-lifetime.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/how-a-box-is-stored.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/how-the-module-is-built.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/index.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/limits.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/performance.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/reading-and-writing.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/references.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/waiting-for-changes.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/explanation/when-to-use-sharedbox.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/accept-a-box-in-c.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/accept-a-box-in-cpp.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/ai-contribution-policy.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/build-docs.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/change-several-fields-at-once.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/commits-and-prs.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/contribute.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/follow-a-whole-reference-graph.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/install-sharedbox.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/make-a-release.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/name-a-box.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/open-a-box-from-a-program.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/run-benchmarks.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/run-commit-checks.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/run-tests.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/send-a-box-to-another-process.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/set-defaults-and-check-values.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/set-up-development.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/store-collections.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/store-numpy-numbers.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/store-records.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/store-text-and-bytes.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/how-to/write-docs.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/index.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/javascripts/charts.js +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/library-authors.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/references.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/api/streams.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/changelog.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/cpp-and-c-api.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/reference/index.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/tutorials/index.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/tutorials/mailbox.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/tutorials/react-to-changes.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/tutorials/refer-to-another-box.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/docs/tutorials/share-a-record.md +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/include/sharedbox/sharedbox.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/prek.toml +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/scripts/check_xrefs.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/scripts/release_notes.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/scripts/stream_compare.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/scripts/vscode_setup.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/codec.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/codec.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/collection.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/collection.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/dict.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/dict.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/keys.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/keys.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/scalars.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/scalars.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/set.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/set.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_native/stream.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/_refs.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/__init__.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/__main__.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/_app.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/cli.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/contention.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/plot.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/roundtrip.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/size.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/benchmarks/size_diff.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/src/sharedbox/py.typed +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/conftest.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/bench_stream.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/compile_fail.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/consumer/CMakeLists.txt +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/consumer/consumer.c +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_atomics.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_core_alone.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_fork.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_lock.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_result.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_slots.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_small_shm.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_values.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_wait.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/test_windows_h.cpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/cpp/unique.hpp +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/forged_open.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/os_names.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/refs_future.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/stress_helpers.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_contention.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_crashes.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_follow.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_lock_timeout.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_memory.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_waiters.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/stress/test_stress_watchers.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_benchbox_all.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_benchbox_contention.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_benchbox_plot.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_benchbox_roundtrip.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_benchbox_stream.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_box_sync_async.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_capsule.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_doc_examples.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_doc_tutorials.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_events_async.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_events_future.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_events_signals.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_events_sync.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_follow.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_fork.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_layout.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_native_codec.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_native_liveness.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_native_types.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_native_wait.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_native_waiters.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_bounded.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_bounded_dict.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_bounded_set.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_codec.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_forged.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_layout.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_properties_stateful.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_refs_lazy.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_stream_fork.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_choices.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_collections.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_records_attrs.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_records_msgspec.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_scalars.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/test_types_unions.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/type_checks/array_types.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/type_checks/events_types.py +0 -0
- {sharedbox-0.7.0 → sharedbox-0.9.0}/tests/type_checks/stream_types.py +0 -0
|
@@ -114,7 +114,7 @@ jobs:
|
|
|
114
114
|
ref: ${{ github.event_name == 'release' && github.event.release.tag_name || '' }}
|
|
115
115
|
|
|
116
116
|
- name: Build wheels
|
|
117
|
-
uses: pypa/cibuildwheel@v4.3.
|
|
117
|
+
uses: pypa/cibuildwheel@v4.3.5
|
|
118
118
|
env:
|
|
119
119
|
CIBW_BUILD: ${{ matrix.python }}-${{ matrix.platform_id }}
|
|
120
120
|
CIBW_CONTAINER_ENGINE: "docker; create_args: --shm-size=1g"
|
|
@@ -9,6 +9,165 @@ Dates are marked as `DD-MM-YYYY`
|
|
|
9
9
|
|
|
10
10
|
<!-- towncrier release notes start -->
|
|
11
11
|
|
|
12
|
+
## [0.9.0](https://github.com/jacopoabramo/sharedbox/releases/tag/v0.9.0) - 04-11-2026
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `segment_status`: `segment_status("lab:counts")` returns a `SegmentStatus`,
|
|
17
|
+
`missing` when no box or stream is published under the name, `running` while the
|
|
18
|
+
process that created it runs and `creator_exited` once it has ended.
|
|
19
|
+
`core.hpp` adds `segment_status` and `segment_state` for C++. ([#94](https://github.com/jacopoabramo/sharedbox/pull/94))
|
|
20
|
+
- `SharedReceiveStream.fetch`, `fetch_into` and `fetch_future`: `reader.fetch(120)`
|
|
21
|
+
returns the item at position 120, waiting until the sender has sent it, and
|
|
22
|
+
leaves the reader's receive cursor and `missed` unchanged. `ItemGoneError`, a
|
|
23
|
+
`LookupError` whose `oldest` is the oldest position the ring held, is raised
|
|
24
|
+
once the ring no longer holds the item. `stream.hpp` adds
|
|
25
|
+
`stream_reader::fetch` and `fetch_with` for C++. ([#95](https://github.com/jacopoabramo/sharedbox/pull/95))
|
|
26
|
+
- `MaxShape` on box fields: a box field declared as
|
|
27
|
+
`Annotated[npt.NDArray[np.uint16], MaxShape((2048, 2048))]` holds an array of
|
|
28
|
+
any shape up to that maximum, as kind 75 of box layout 3.3, and every read
|
|
29
|
+
returns an array of the stored shape. A write stores the shape and only the
|
|
30
|
+
elements in use. `SharedBox.writing` takes `shape`, so
|
|
31
|
+
`box.writing("image", shape=(480, 640))` sets the shape and yields a view of
|
|
32
|
+
it under one lock. `read_into` raises `TypeError` for a `MaxShape` field. ([#97](https://github.com/jacopoabramo/sharedbox/pull/97))
|
|
33
|
+
- `BoundedList`, `BoundedSet` and `BoundedDict` take their element types as the
|
|
34
|
+
first arguments when the class fixes none: `BoundedList(int, [1, 2], capacity=4)`
|
|
35
|
+
equals `BoundedList[int]([1, 2], capacity=4)`, and
|
|
36
|
+
`BoundedDict(str, float, {"a": 1.0}, capacity=8)` takes the key and value types. ([#97](https://github.com/jacopoabramo/sharedbox/pull/97))
|
|
37
|
+
- `Timed` and `Timed.now`: a box field, record member, collection element or
|
|
38
|
+
stream item declared as `Timed[float]` stores the value with a timestamp in
|
|
39
|
+
nanoseconds since the Unix epoch, and `box.temperature = Timed.now(21.5)` stamps
|
|
40
|
+
it with the system clock when the write holds the box's lock, or just before a
|
|
41
|
+
stream send publishes the item. A `Timed` with a timestamp of its own is stored as
|
|
42
|
+
given. Timed values are kind 77, and streams use stream layout 1.5. ([#99](https://github.com/jacopoabramo/sharedbox/pull/99))
|
|
43
|
+
- `Attr`, `attr`, `AttrValue`, `RequestFuture` and `RequestServer`: a box
|
|
44
|
+
field declared as `exposure: Attr[float] = attr(timed=True, settable=True)`
|
|
45
|
+
holds a value its owner writes with
|
|
46
|
+
`box.exposure.publish(value=..., setpoint=...)` and any process reads with
|
|
47
|
+
`.value`, `.setpoint`, `.timestamp_ns` or `read()`, or watches with
|
|
48
|
+
`watch` and `events`. An attribute with arguments, such as
|
|
49
|
+
`move: Attr[float, [float]] = attr()`, or a settable one carries a typed
|
|
50
|
+
request to the one process that serves it: `box.move.serve(handler)`
|
|
51
|
+
answers with a sync or async handler, and `box.move(5.0)` or
|
|
52
|
+
`box.exposure.set(0.02)` returns a `RequestFuture` waited on with
|
|
53
|
+
`.result(timeout)` or `await`. Of the requests sent while the handler
|
|
54
|
+
runs, only the newest is handled next. `RequestError`,
|
|
55
|
+
`RequestSupersededError` and `ServerExitedError` report a failed, replaced
|
|
56
|
+
or abandoned request, and `AlreadyServedError` a second server. Attribute
|
|
57
|
+
fields are kind 76 of box layout 3.3, and `box.hpp` adds `attr_publish`,
|
|
58
|
+
`attr_read`, `attr_published`, `attr_value_at` and the request protocol
|
|
59
|
+
steps on `handle` for C++, and `type_view` gives an attribute's flags and
|
|
60
|
+
where its value, timestamp and setpoint start. ([#103](https://github.com/jacopoabramo/sharedbox/pull/103))
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- On Windows, an operating system failure to create or open a box or stream raises
|
|
65
|
+
`OSError` with the Windows error code in `winerror`, such as `PermissionError`
|
|
66
|
+
for a segment the process may not open, instead of `RuntimeError`. ([#96](https://github.com/jacopoabramo/sharedbox/pull/96))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## [0.8.0](https://github.com/jacopoabramo/sharedbox/releases/tag/v0.8.0) - 30-10-2026
|
|
70
|
+
|
|
71
|
+
### Breaking
|
|
72
|
+
|
|
73
|
+
- `sharedbox.Shape` takes its dimensions as one tuple, `Shape((480, 640))`, in
|
|
74
|
+
place of one argument per dimension. See
|
|
75
|
+
[How to migrate from 0.7](https://jacopoabramo.github.io/sharedbox/how-to/migrate-from-0.7/). ([#88](https://github.com/jacopoabramo/sharedbox/pull/88))
|
|
76
|
+
- `SharedBox` reserves the names `metadata`, `metadata_version` and
|
|
77
|
+
`metadata_version_of`: a field or `InitVar` with one of them raises
|
|
78
|
+
`TypeError` when the class is defined. Rename the field:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# 0.7
|
|
82
|
+
class Parcel(SharedBox):
|
|
83
|
+
metadata: Annotated[str, Capacity(64)] = ""
|
|
84
|
+
|
|
85
|
+
# 0.8
|
|
86
|
+
class Parcel(SharedBox):
|
|
87
|
+
label: Annotated[str, Capacity(64)] = ""
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`SharedBox.update` takes the keyword `metadata`, so a type checker refuses
|
|
91
|
+
`update(**values)` when the values of the dictionary have a type that the
|
|
92
|
+
box's metadata type does not accept, such as `str`:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
# 0.7
|
|
96
|
+
def restock(parcel: Parcel, values: dict[str, str]) -> None:
|
|
97
|
+
parcel.update(**values)
|
|
98
|
+
|
|
99
|
+
# 0.8
|
|
100
|
+
def restock(parcel: Parcel, values: dict[str, Any]) -> None:
|
|
101
|
+
parcel.update(**values)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
See
|
|
105
|
+
[How to migrate from 0.7](https://jacopoabramo.github.io/sharedbox/how-to/migrate-from-0.7/). ([#91](https://github.com/jacopoabramo/sharedbox/pull/91))
|
|
106
|
+
|
|
107
|
+
### Added
|
|
108
|
+
|
|
109
|
+
- `MaxShape`: an array of a stream item declared with a maximum shape, as in
|
|
110
|
+
`Annotated[npt.NDArray[np.uint16], MaxShape((2048, 2048))]`, stores its own
|
|
111
|
+
shape with each item, as kind 75 of stream layout 1.2. `writing()` views the
|
|
112
|
+
slot in the shape of the template's array, `slot.send` publishes the first
|
|
113
|
+
rows of that view without a copy, and `receive_into` returns a view of the
|
|
114
|
+
stored shape over `out`. ([#88](https://github.com/jacopoabramo/sharedbox/pull/88))
|
|
115
|
+
- `SharedStream.sender(on_full="release")`: a send that has waited its whole
|
|
116
|
+
`timeout` releases the lossless readers a full ring behind and sends, as in
|
|
117
|
+
`stream.sender(on_full="release").send(item, timeout=0.1)`. Each released
|
|
118
|
+
reader raises `ReaderReleased`, whose `missed` counts the items it lost, and
|
|
119
|
+
goes on at the newest item; `ReceiveEvents.released` reports the count to
|
|
120
|
+
callbacks. `SharedSendStream.asend` and `awriting` take a `timeout`. In
|
|
121
|
+
`stream.hpp`, `send`, `send_with` and `begin` take an `on_full` policy, and a
|
|
122
|
+
released reader's `receive` gives `status::released`, in stream layout 1.3. ([#89](https://github.com/jacopoabramo/sharedbox/pull/89))
|
|
123
|
+
- `MetadataFullError` and `MetadataGoneError`: raised when an add finds no
|
|
124
|
+
room for a version, and when the version a read asks for is no longer held. ([#91](https://github.com/jacopoabramo/sharedbox/pull/91))
|
|
125
|
+
- `SharedStream.metadata`: a stream keeps metadata the same way.
|
|
126
|
+
`SharedStream.create(Reading, capacity=8, metadata={"unit": "kg"})` stores
|
|
127
|
+
version 1. `SharedSendStream.send`, `asend`, `send_nowait` and
|
|
128
|
+
`SendSlot.send` take `metadata=` and add a version that applies from that
|
|
129
|
+
item. `SharedReceiveStream.metadata` and `metadata_version` give the version
|
|
130
|
+
of the item the reader received last. `SharedStream.create` takes
|
|
131
|
+
`metadata_capacity` and `metadata_versions`, and `create` and `attach` take
|
|
132
|
+
`metadata_type`. `sharedbox` 0.7.0 and earlier cannot open a stream created
|
|
133
|
+
with metadata or a `metadata_capacity`. ([#91](https://github.com/jacopoabramo/sharedbox/pull/91))
|
|
134
|
+
- `box.hpp`, `stream.hpp` and `sharedbox_c.h`: box layout 3.2 and stream
|
|
135
|
+
layout 1.4 hold metadata after the record or the description table.
|
|
136
|
+
`handle` and `stream` gain `metadata_head` and `read_metadata`, and
|
|
137
|
+
`stream_reader` gains `metadata_version_at`. `handle` and `stream_sender`
|
|
138
|
+
gain `add_metadata`. `handle::write(values, doc, lock_timeout)` and
|
|
139
|
+
`write_large` with the same arguments write fields and add a version in one
|
|
140
|
+
write, and
|
|
141
|
+
`stream_sender::can_add_metadata` checks an add without making it.
|
|
142
|
+
`sharedbox_c.h` adds `sbx_metadata_head`, `sbx_read_metadata`,
|
|
143
|
+
`sbx_add_metadata` and `SBX_E_METADATA_FULL`. ([#91](https://github.com/jacopoabramo/sharedbox/pull/91))
|
|
144
|
+
- `SharedBox.metadata`: a box keeps metadata, JSON-like values stored as CBOR
|
|
145
|
+
in its segment, in numbered versions. `Scale.create(name, metadata={"unit":
|
|
146
|
+
"kg"})` stores version 1, and `SharedBox.update(metadata=...)` adds the next
|
|
147
|
+
one from any process, with or without field values, in one write.
|
|
148
|
+
`metadata`, `metadata_version` and `metadata_version_of` read the versions,
|
|
149
|
+
a map as a read-only mapping and a list as a tuple. `BoxEvents.metadata` is
|
|
150
|
+
emitted with each new version. The class keywords `metadata_capacity` and
|
|
151
|
+
`metadata_versions` size the room for versions, and
|
|
152
|
+
`class Scale(SharedBox[Calibration])` gives the metadata's type to type
|
|
153
|
+
checkers. ([#91](https://github.com/jacopoabramo/sharedbox/pull/91))
|
|
154
|
+
|
|
155
|
+
### Changed
|
|
156
|
+
|
|
157
|
+
- `sharedbox.DType` is a `StrEnum` with one member per element type:
|
|
158
|
+
`DType(numpy.uint8)` returns `DType.uint8`, which equals `"uint8"`. ([#88](https://github.com/jacopoabramo/sharedbox/pull/88))
|
|
159
|
+
|
|
160
|
+
### Fixed
|
|
161
|
+
|
|
162
|
+
- `SharedBox` and `SharedStream` at exit: the `atexit` hook of `sharedbox`
|
|
163
|
+
closes every box and stream the process still has open and releases the
|
|
164
|
+
native objects of `SharedBox` subclasses, their watches and events groups,
|
|
165
|
+
so nanobind reports no leaked instances when a box class defined at module
|
|
166
|
+
level outlives shutdown. A box or stream used after the hook raises
|
|
167
|
+
`BoxClosedError` or `StreamClosedError`, and creating or attaching a box
|
|
168
|
+
raises `BoxClosedError`. ([#90](https://github.com/jacopoabramo/sharedbox/pull/90))
|
|
169
|
+
|
|
170
|
+
|
|
12
171
|
## [0.7.0](https://github.com/jacopoabramo/sharedbox/releases/tag/v0.7.0) - 28-10-2026
|
|
13
172
|
|
|
14
173
|
### Added
|
|
@@ -13,11 +13,11 @@ the layout and the native module converts values.
|
|
|
13
13
|
```text
|
|
14
14
|
sharedbox/
|
|
15
15
|
|-- include/sharedbox/
|
|
16
|
-
| |-- core.hpp what every segment kind uses: result and error, liveness, names, mappings, the open step, waiter slots, the type codec
|
|
17
|
-
| |-- box.hpp box layout 3.
|
|
18
|
-
| |-- stream.hpp stream layout 1.
|
|
16
|
+
| |-- core.hpp what every segment kind uses: result and error, liveness, names, mappings, the open step, waiter slots, the type codec, the metadata area and its CBOR check
|
|
17
|
+
| |-- box.hpp box layout 3.3 and its protocols: create, publish, open, lock, read, write, metadata, capsule handle
|
|
18
|
+
| |-- stream.hpp stream layout 1.5: create, open, the sender, readers, the gate, dead ends, metadata
|
|
19
19
|
| |-- sharedbox.hpp includes every kind; the header consumers include
|
|
20
|
-
| |-- sharedbox_c.h minimal C interface: sbx_open, sbx_import, sbx_read, sbx_write, sbx_schema_hash, sbx_release, sbx_field_desc, typed sbx_read_* and sbx_write_
|
|
20
|
+
| |-- sharedbox_c.h minimal C interface: sbx_open, sbx_import, sbx_read, sbx_write, sbx_schema_hash, sbx_release, sbx_field_desc, typed sbx_read_* and sbx_write_*, sbx_metadata_head, sbx_read_metadata, sbx_add_metadata
|
|
21
21
|
| `-- sharedbox_c.cpp its implementation, compiled by the consumer (CMake target sharedbox::c)
|
|
22
22
|
|-- cmake/
|
|
23
23
|
| |-- sharedbox-config.cmake find_package(sharedbox) from an installed wheel; the build writes
|
|
@@ -26,13 +26,20 @@ sharedbox/
|
|
|
26
26
|
|-- src/sharedbox/
|
|
27
27
|
| |-- __init__.py re-exports the public API, get_include()
|
|
28
28
|
| |-- _box.py SharedBox: class keywords, fields, fields(), create/attach, __post_init__, update, snapshot, unlink, __sharedbox_box__
|
|
29
|
-
| |-- _layout.py Capacity, field() and Field, field offsets and kind codes, schema hash
|
|
29
|
+
| |-- _layout.py Capacity, field(), attr() and Field, field offsets and kind codes, schema hash
|
|
30
30
|
| |-- _types.py annotation parsing into TypeSpec, the description table
|
|
31
|
-
| |-- _arrays.py Shape, DType, SupportsDLPack, register_array_type
|
|
32
|
-
| |--
|
|
31
|
+
| |-- _arrays.py Shape, MaxShape, DType, SupportsDLPack, register_array_type
|
|
32
|
+
| |-- _timed.py Timed: a value with its timestamp in ns, Timed.now and the mark a write replaces
|
|
33
|
+
| |-- _attr.py Attr and AttrValue: the handle of an attribute field, publish, read, requests and serve
|
|
34
|
+
| |-- _request.py request fields: RequestFuture, RequestServer, the request errors, serving threads and tasks
|
|
35
|
+
| |-- _events.py BoxEvents, FieldWatch, the watcher thread, which also completes request futures and kicks request servers
|
|
33
36
|
| |-- _follow.py BoxEvents.follow and unfollow: forwarding the events of boxes that references reach
|
|
34
37
|
| |-- _stream.py SharedStream, SharedSendStream, SharedReceiveStream, ReceiveEvents, the statistics classes, the worker threads
|
|
38
|
+
| |-- _metadata.py metadata documents: the type variable M, CBOR encoding, read-only decoding, the cache of decoded versions
|
|
35
39
|
| |-- _refs.py reference fields: BoxRef, the class registry, BrokenReferenceError, UnknownBoxClassError
|
|
40
|
+
| |-- _status.py segment_status and SegmentStatus: whether a name holds a segment and its creator runs
|
|
41
|
+
| |-- _exit.py the exit handler: stops the watcher, request server and stream threads, closes boxes, streams and ends,
|
|
42
|
+
| | replaces the native objects of watchers and box classes
|
|
36
43
|
| |-- _native.pyi hand-written stub for the extension
|
|
37
44
|
| |-- py.typed
|
|
38
45
|
| |-- benchmarks/ the benchbox command (extra: benchmarks)
|
|
@@ -67,11 +74,18 @@ sharedbox/
|
|
|
67
74
|
| |-- test_follow.py BoxEvents.follow, unfollow and nested
|
|
68
75
|
| |-- test_native_waiters.py waiter slots, dead owners, interrupt
|
|
69
76
|
| |-- test_box_sync_async.py a sync and an async watch on one box in two threads
|
|
77
|
+
| |-- test_metadata.py metadata of a box: documents, versions, events, typed access, reserved names
|
|
78
|
+
| |-- test_segment_status.py segment_status: missing, running and an exited creator
|
|
70
79
|
| |-- test_stream.py SharedStream, sender and reader, blocking and non-blocking calls
|
|
80
|
+
| |-- test_stream_metadata.py metadata of a stream: the version of each item, in one process and across processes
|
|
71
81
|
| |-- test_stream_async.py asyncio calls on a stream, cancellation
|
|
72
82
|
| |-- test_stream_events.py ReceiveEvents delivery
|
|
83
|
+
| |-- test_stream_fetch.py fetching an item by its position, in one process and across processes
|
|
73
84
|
| |-- test_stream_processes.py streams across processes, dead senders and readers
|
|
74
85
|
| |-- test_stream_fork.py stream ends inherited through fork
|
|
86
|
+
| |-- test_timed.py Timed fields and stream items: stamps, given times, where a Timed may go
|
|
87
|
+
| |-- test_attr.py attribute requests across processes: answers, superseding, a killed server, close, async handlers
|
|
88
|
+
| |-- test_attr_fields.py Attr in the layout: publish, read, watch, refused operations, where an Attr may go
|
|
75
89
|
| |-- streamproc.py helpers that run a stream end in another process
|
|
76
90
|
| |-- test_properties_*.py Hypothesis property tests, streams included
|
|
77
91
|
| |-- stress/ stress tests, marker stress, deselected by default
|
|
@@ -91,7 +105,7 @@ sharedbox/
|
|
|
91
105
|
| |-- examples/ one script per how-to guide, included by the guide
|
|
92
106
|
| |-- javascripts/charts.js draws each div of class sbx-chart from a plotly figure JSON file
|
|
93
107
|
| |-- assets/benchmarks/ the figure JSON files of the performance page, from benchbox plot
|
|
94
|
-
| `-- reference/segment-layout.md core 1.0, box layout 3.1, names and protocols
|
|
108
|
+
| `-- reference/segment-layout.md core 1.0, box layout 3.3, stream layout 1.5, names and protocols
|
|
95
109
|
|-- includes/abbreviations.md acronym tooltips appended to every page
|
|
96
110
|
|-- zensical.toml site configuration and navigation
|
|
97
111
|
|-- .github/workflows/ci.yaml lint, docs check, C++ tests, cibuildwheel wheels, tests, stress,
|
|
@@ -135,18 +149,19 @@ class's identity (the `identity` class keyword, by default
|
|
|
135
149
|
always asks for a new name and raises `SegmentExistsError` if it is taken.
|
|
136
150
|
|
|
137
151
|
Every segment starts with the same 64-byte line, whatever its kind. Core
|
|
138
|
-
version 1.0, box layout 3.
|
|
152
|
+
version 1.0, box layout 3.3, from offset 0:
|
|
139
153
|
|
|
140
154
|
- Common line 0, written once at creation: `magic` (`SBX_BOX_` for a box,
|
|
141
155
|
`SBX_STRM` for a stream), `core_major` 1, `core_minor` 0, `kind_major` 3,
|
|
142
|
-
`kind_minor`
|
|
156
|
+
`kind_minor` 3, `schema_hash`, `create_id`, `creator_start`,
|
|
143
157
|
`creator_pidns`, `creator_pid`, `waiter_slots`, `size`.
|
|
144
158
|
- Box line 1, at offset 64: `seq` (sequence lock; the generation is
|
|
145
159
|
`seq >> 1`, there is no generation field), `writer_pid`, `wake_word`,
|
|
146
160
|
`waiters` and `sleepers`, which writes and waits change; then written
|
|
147
161
|
once at creation `field_count`, `record_size`, `record`, `tail` (always
|
|
148
|
-
128)
|
|
149
|
-
|
|
162
|
+
128), `types_size`, `metadata_size` and `metadata` (the offset of the
|
|
163
|
+
metadata area, 0 for none); last `metadata_head`, the newest metadata
|
|
164
|
+
version, 0 for none, which each add changes. The header is 128 bytes.
|
|
150
165
|
- The tail: `field_count` field table entries of 8 bytes (`u32 offset`,
|
|
151
166
|
`u32 capacity_and_kind`: top 8 bits the kind code, the low 24 the
|
|
152
167
|
capacity or size, or for kinds 64 and up the offset of the field's
|
|
@@ -155,10 +170,20 @@ version 1.0, box layout 3.1, from offset 0:
|
|
|
155
170
|
`asleep_on`: the offset of the count the slot's current wait added 1 to,
|
|
156
171
|
which freeing a dead owner's slot takes back), then the description
|
|
157
172
|
table of `types_size` bytes. Kinds are 0 to 5, 6 to 12 (fixed-size
|
|
158
|
-
scalars), 13 to 23 (fixed-width numbers and `datetime64`) and 64 to
|
|
159
|
-
(described types
|
|
160
|
-
|
|
161
|
-
|
|
173
|
+
scalars), 13 to 23 (fixed-width numbers and `datetime64`), and 64 to 77
|
|
174
|
+
(described types; 75, an array up to a maximum shape, in a stream
|
|
175
|
+
item or a box field, written as its shape line and the elements in use;
|
|
176
|
+
76, an attribute, a box field only, holding the request part, the value
|
|
177
|
+
part with `published` and the setpoint; 77, a value with an
|
|
178
|
+
`i64` timestamp in ns, wherever a record may go, its timestamp `-2**63`
|
|
179
|
+
replaced by the time of the write).
|
|
180
|
+
- The record, at a multiple of 64. `record + record_size <= 2**32 - 4096`.
|
|
181
|
+
- The metadata area, when `metadata` is not 0, at the first multiple of 64
|
|
182
|
+
after the record, `metadata + metadata_size <= 2**32 - 4096`: a 64-byte
|
|
183
|
+
line (`entries`, `ring_size`), `entries` version entries of 32 bytes
|
|
184
|
+
(`seq`, `version`, `position`, `offset`, `length`), then a ring of
|
|
185
|
+
`ring_size` bytes holding one CBOR document per version. The mapping size
|
|
186
|
+
is rounded up to 4 KiB.
|
|
162
187
|
|
|
163
188
|
`magic` is stored last on create, with release ordering, after the initial
|
|
164
189
|
values are in the record; attach waits for it. Attach copies line 0 and the
|
|
@@ -174,8 +199,11 @@ layout 1.0 or 2.0, which 0.5 and earlier wrote.
|
|
|
174
199
|
A stream's segment starts with a 256-byte header: the common line, a line
|
|
175
200
|
of geometry written once, the sender's line and the readers' line. Then
|
|
176
201
|
come a 64-byte entry per reader, the waiter slots, `capacity` slots each
|
|
177
|
-
holding a `seq` and one item,
|
|
178
|
-
|
|
202
|
+
holding a `seq` and one item, the description table, and the metadata
|
|
203
|
+
area laid out as a box's. Stream layout 1.5 keeps `metadata_size` and
|
|
204
|
+
`metadata` in the geometry line and `metadata_head` in the sender's line.
|
|
205
|
+
Every offset is 64-bit. The full specification is in
|
|
206
|
+
`docs/reference/segment-layout.md`.
|
|
179
207
|
|
|
180
208
|
### Record encoding
|
|
181
209
|
|
|
@@ -190,8 +218,10 @@ capacity counts elements, 1 to 1048576.
|
|
|
190
218
|
|
|
191
219
|
### Lifecycle
|
|
192
220
|
|
|
193
|
-
- `close()` interrupts and stops the watcher thread, stops
|
|
194
|
-
|
|
221
|
+
- `close()` interrupts and stops the watcher thread, stops the box's
|
|
222
|
+
request servers, releasing each field, and cancels its pending request
|
|
223
|
+
futures, stops forwarding started with `events.follow`, and detaches
|
|
224
|
+
this box. Later reads and
|
|
195
225
|
writes raise `BoxClosedError`. Garbage collection closes a box too, but
|
|
196
226
|
forwarding it started keeps running until the cycle collector frees its
|
|
197
227
|
events groups.
|
|
@@ -340,6 +370,9 @@ A read decodes the stored bytes; a value that cannot be changed (a
|
|
|
340
370
|
`datetime`, or a frozen record, tuple or frozenset holding only such values)
|
|
341
371
|
is reused until its field is written. `update(**values)` writes several
|
|
342
372
|
fields at once; `watch(field)` and `events` report changes from any process.
|
|
373
|
+
A field declared `Attr[T]` with `attr()` is published by its owner with
|
|
374
|
+
`publish` and read by any process, and may take requests the owner serves;
|
|
375
|
+
see `docs/how-to/request-work-from-the-owner.md`.
|
|
343
376
|
C++ and C code take a box through `__sharedbox_box__` or open it by name; see
|
|
344
377
|
`docs/how-to/accept-a-box-in-cpp.md`, `docs/how-to/accept-a-box-in-c.md` and
|
|
345
378
|
`docs/how-to/open-a-box-from-a-program.md`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sharedbox
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Python containers using shared memory.
|
|
5
5
|
Author-Email: Jacopo Abramo <jacopo.abramo@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -14,7 +14,9 @@ Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
|
14
14
|
Classifier: Programming Language :: C++
|
|
15
15
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
16
|
Requires-Python: >=3.11
|
|
17
|
+
Requires-Dist: cbor2>=6.1.5
|
|
17
18
|
Requires-Dist: psygnal>=0.16.1
|
|
19
|
+
Requires-Dist: typing-extensions>=4.16.0; python_full_version < "3.13"
|
|
18
20
|
Provides-Extra: benchmarks
|
|
19
21
|
Requires-Dist: numpy>=2.4.6; extra == "benchmarks"
|
|
20
22
|
Requires-Dist: plotly>=7.1.0; extra == "benchmarks"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""The script of the guide "How to attach metadata to a box or stream"."""
|
|
2
|
+
|
|
3
|
+
# --8<-- [start:box]
|
|
4
|
+
from typing import TypedDict
|
|
5
|
+
|
|
6
|
+
from sharedbox import SharedBox, SharedStream
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# --8<-- [start:calibration]
|
|
10
|
+
class Calibration(TypedDict):
|
|
11
|
+
unit: str
|
|
12
|
+
offset: float
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# --8<-- [end:calibration]
|
|
16
|
+
class Scale(SharedBox[Calibration]):
|
|
17
|
+
weight: float = 0.0
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
scale = Scale.create("example-scale", metadata={"unit": "kg", "offset": 0.0})
|
|
21
|
+
print(scale.metadata_version) # 1
|
|
22
|
+
print(scale.metadata) # {'unit': 'kg', 'offset': 0.0}
|
|
23
|
+
# --8<-- [end:box]
|
|
24
|
+
|
|
25
|
+
# --8<-- [start:add]
|
|
26
|
+
scale.update(weight=1.2, metadata={"unit": "kg", "offset": 0.25})
|
|
27
|
+
print(scale.weight, scale.metadata_version) # 1.2 2
|
|
28
|
+
print(scale.metadata_version_of(1)["offset"]) # 0.0
|
|
29
|
+
print(scale.metadata_version_of(2)["offset"]) # 0.25
|
|
30
|
+
scale.update(metadata={"unit": "kg", "offset": 0.3})
|
|
31
|
+
print(scale.weight, scale.metadata_version) # 1.2 3
|
|
32
|
+
# --8<-- [end:add]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# --8<-- [start:capacity]
|
|
36
|
+
class Display(SharedBox[Calibration], metadata_capacity=4096, metadata_versions=8):
|
|
37
|
+
weight: float = 0.0
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
display = Display.create("example-display")
|
|
41
|
+
print(display.metadata) # None
|
|
42
|
+
display.update(metadata={"unit": "g", "offset": 0.0})
|
|
43
|
+
# --8<-- [end:capacity]
|
|
44
|
+
|
|
45
|
+
# --8<-- [start:read-only]
|
|
46
|
+
stored = scale.metadata_version_of(2)
|
|
47
|
+
try:
|
|
48
|
+
stored["offset"] = 0.5
|
|
49
|
+
except TypeError as error:
|
|
50
|
+
print(error) # 'mappingproxy' object does not support item assignment
|
|
51
|
+
scale.update(metadata={**stored, "offset": 0.5})
|
|
52
|
+
# --8<-- [end:read-only]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# --8<-- [start:stream]
|
|
56
|
+
with SharedStream.create(
|
|
57
|
+
float,
|
|
58
|
+
"example-scale:readings",
|
|
59
|
+
capacity=8,
|
|
60
|
+
metadata={"unit": "kg", "offset": 0.0},
|
|
61
|
+
metadata_type=Calibration,
|
|
62
|
+
) as stream:
|
|
63
|
+
reader = stream.reader()
|
|
64
|
+
with stream.sender() as sender:
|
|
65
|
+
sender.send(1.5)
|
|
66
|
+
sender.send(1.75, metadata={"unit": "kg", "offset": 0.25})
|
|
67
|
+
for weight in reader:
|
|
68
|
+
calibration = reader.metadata
|
|
69
|
+
if calibration is not None:
|
|
70
|
+
print(reader.metadata_version, weight - calibration["offset"])
|
|
71
|
+
# prints 1 1.5, then 2 1.5
|
|
72
|
+
SharedStream.unlink("example-scale:readings")
|
|
73
|
+
# --8<-- [end:stream]
|
|
74
|
+
|
|
75
|
+
scale.close()
|
|
76
|
+
display.close()
|
|
77
|
+
Scale.unlink("example-scale")
|
|
78
|
+
Display.unlink("example-display")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""The script of the guide "How to clean up segments"."""
|
|
2
2
|
|
|
3
3
|
# --8<-- [start:close]
|
|
4
|
-
from sharedbox import LockTimeoutError, SharedBox
|
|
4
|
+
from sharedbox import LockTimeoutError, SharedBox, segment_status
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class Delivery(SharedBox, name="example-delivery"):
|
|
@@ -18,6 +18,10 @@ delivery.close()
|
|
|
18
18
|
Delivery.unlink()
|
|
19
19
|
# --8<-- [end:unlink]
|
|
20
20
|
|
|
21
|
+
# --8<-- [start:status]
|
|
22
|
+
print(segment_status("example-delivery")) # missing
|
|
23
|
+
# --8<-- [end:status]
|
|
24
|
+
|
|
21
25
|
creator = Delivery(True)
|
|
22
26
|
|
|
23
27
|
# --8<-- [start:force-unlock]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""The script of the guide "How to request work from the process that owns a box"."""
|
|
2
|
+
|
|
3
|
+
# --8<-- [start:declare]
|
|
4
|
+
import asyncio
|
|
5
|
+
import threading
|
|
6
|
+
|
|
7
|
+
from sharedbox import Attr, RequestError, RequestSupersededError, SharedBox, attr
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Camera(SharedBox, name="example-camera"):
|
|
11
|
+
temperature: Attr[float] = attr(timed=True)
|
|
12
|
+
exposure: Attr[float] = attr(timed=True, settable=True, default=0.01)
|
|
13
|
+
move: Attr[float, [float]] = attr()
|
|
14
|
+
home: Attr[None] = attr()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# --8<-- [end:declare]
|
|
18
|
+
|
|
19
|
+
# --8<-- [start:publish]
|
|
20
|
+
camera = Camera()
|
|
21
|
+
camera.temperature.publish(value=21.5)
|
|
22
|
+
print(camera.temperature.value) # 21.5
|
|
23
|
+
reading = camera.temperature.read()
|
|
24
|
+
print(reading["value"], reading["timestamp_ns"] > 0) # 21.5 True
|
|
25
|
+
# --8<-- [end:publish]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# --8<-- [start:serve]
|
|
29
|
+
def set_exposure(value: float) -> float:
|
|
30
|
+
accepted = min(max(value, 0.001), 1.0)
|
|
31
|
+
camera.exposure.publish(setpoint=accepted)
|
|
32
|
+
camera.exposure.publish(value=accepted)
|
|
33
|
+
return accepted
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def move(target: float) -> float:
|
|
37
|
+
if target > 100.0:
|
|
38
|
+
raise ValueError(f"{target} is out of range")
|
|
39
|
+
return target
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
exposure_server = camera.exposure.serve(set_exposure)
|
|
43
|
+
move_server = camera.move.serve(move)
|
|
44
|
+
# --8<-- [end:serve]
|
|
45
|
+
|
|
46
|
+
# --8<-- [start:request]
|
|
47
|
+
print(camera.exposure.set(5.0).result(timeout=5)) # 1.0
|
|
48
|
+
print(camera.exposure.setpoint) # 1.0
|
|
49
|
+
print(camera.move(5.0).result(timeout=5)) # 5.0
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def main() -> None:
|
|
53
|
+
print(await camera.exposure.set(0.02)) # 0.02
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
asyncio.run(main())
|
|
57
|
+
# --8<-- [end:request]
|
|
58
|
+
|
|
59
|
+
# --8<-- [start:error]
|
|
60
|
+
try:
|
|
61
|
+
camera.move(250.0).result(timeout=5)
|
|
62
|
+
except RequestError as error:
|
|
63
|
+
print(error) # Camera.move: ValueError: 250.0 is out of range
|
|
64
|
+
# --8<-- [end:error]
|
|
65
|
+
|
|
66
|
+
move_server.stop()
|
|
67
|
+
|
|
68
|
+
# --8<-- [start:supersede]
|
|
69
|
+
started = threading.Event()
|
|
70
|
+
release = threading.Event()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def slow_move(target: float) -> float:
|
|
74
|
+
started.set()
|
|
75
|
+
release.wait()
|
|
76
|
+
return target
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
move_server = camera.move.serve(slow_move)
|
|
80
|
+
first = camera.move(1.0)
|
|
81
|
+
started.wait()
|
|
82
|
+
second = camera.move(2.0)
|
|
83
|
+
third = camera.move(3.0)
|
|
84
|
+
release.set()
|
|
85
|
+
print(first.result(timeout=5), third.result(timeout=5)) # 1.0 3.0
|
|
86
|
+
try:
|
|
87
|
+
second.result(timeout=5)
|
|
88
|
+
except RequestSupersededError:
|
|
89
|
+
print("the second request was superseded")
|
|
90
|
+
# --8<-- [end:supersede]
|
|
91
|
+
|
|
92
|
+
move_server.stop()
|
|
93
|
+
exposure_server.stop()
|
|
94
|
+
camera.close()
|
|
95
|
+
Camera.unlink()
|
|
@@ -12,6 +12,9 @@ from sharedbox import (
|
|
|
12
12
|
Capacity,
|
|
13
13
|
DType,
|
|
14
14
|
EndOfStream,
|
|
15
|
+
ItemGoneError,
|
|
16
|
+
MaxShape,
|
|
17
|
+
ReaderReleased,
|
|
15
18
|
Shape,
|
|
16
19
|
SharedReceiveStream,
|
|
17
20
|
SharedSendStream,
|
|
@@ -23,7 +26,7 @@ from sharedbox import (
|
|
|
23
26
|
class Letter:
|
|
24
27
|
index: int
|
|
25
28
|
recipient: Annotated[str, Capacity(32)]
|
|
26
|
-
scan: Annotated[np.ndarray, Shape(32, 32), DType("uint8")]
|
|
29
|
+
scan: Annotated[np.ndarray, Shape((32, 32)), DType("uint8")]
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
# --8<-- [end:types]
|
|
@@ -41,6 +44,23 @@ def register(stream: SharedStream[Letter], ready: "mp.synchronize.Event") -> Non
|
|
|
41
44
|
# --8<-- [end:reader]
|
|
42
45
|
|
|
43
46
|
|
|
47
|
+
# --8<-- [start:fetch]
|
|
48
|
+
def fetch_letters(reader: SharedReceiveStream[Letter], first: int, last: int) -> None:
|
|
49
|
+
position = first
|
|
50
|
+
while position <= last:
|
|
51
|
+
try:
|
|
52
|
+
letter = reader.fetch(position, timeout=5)
|
|
53
|
+
except ItemGoneError as gone:
|
|
54
|
+
print("skipped", position, "to", gone.oldest - 1)
|
|
55
|
+
position = gone.oldest
|
|
56
|
+
continue
|
|
57
|
+
print("fetched", letter.index)
|
|
58
|
+
position += 1
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# --8<-- [end:fetch]
|
|
62
|
+
|
|
63
|
+
|
|
44
64
|
# --8<-- [start:tasks]
|
|
45
65
|
async def produce(sender: SharedSendStream[Letter]) -> None:
|
|
46
66
|
async with sender:
|
|
@@ -93,6 +113,50 @@ def send_filled(sender: SharedSendStream[Letter], count: int) -> None:
|
|
|
93
113
|
# --8<-- [end:writing]
|
|
94
114
|
|
|
95
115
|
|
|
116
|
+
# --8<-- [start:shapes]
|
|
117
|
+
@dataclass(frozen=True)
|
|
118
|
+
class Sack:
|
|
119
|
+
index: int
|
|
120
|
+
weights: Annotated[np.ndarray, MaxShape((64,)), DType("float32")]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def send_sacks(sender: SharedSendStream[Sack]) -> None:
|
|
124
|
+
sender.send(Sack(0, np.array([1.5, 0.25, 4.0], np.float32)))
|
|
125
|
+
template = Sack(1, np.empty(64, np.float32))
|
|
126
|
+
with sender.writing(template) as slot:
|
|
127
|
+
weights = slot.item.weights
|
|
128
|
+
weights[:5] = 2.5
|
|
129
|
+
slot.send(replace(slot.item, weights=weights[:5]))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def read_sacks(reader: SharedReceiveStream[Sack]) -> None:
|
|
133
|
+
weights = np.empty(64, np.float32)
|
|
134
|
+
for sack in reader.iter_into({"weights": weights}):
|
|
135
|
+
print(sack.index, sack.weights.shape)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# --8<-- [end:shapes]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# --8<-- [start:release]
|
|
142
|
+
def sort_without_stalling(sender: SharedSendStream[Letter], count: int) -> None:
|
|
143
|
+
for i in range(count):
|
|
144
|
+
sender.send(Letter(i, "Ada", np.full((32, 32), i, np.uint8)), timeout=0.1)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def file_letters(reader: SharedReceiveStream[Letter]) -> None:
|
|
148
|
+
while True:
|
|
149
|
+
try:
|
|
150
|
+
for letter in reader:
|
|
151
|
+
print("filed", letter.index)
|
|
152
|
+
return
|
|
153
|
+
except ReaderReleased as released:
|
|
154
|
+
print("missed", released.missed)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# --8<-- [end:release]
|
|
158
|
+
|
|
159
|
+
|
|
96
160
|
# --8<-- [start:main]
|
|
97
161
|
if __name__ == "__main__":
|
|
98
162
|
context = mp.get_context("spawn")
|
|
@@ -127,3 +191,22 @@ if __name__ == "__main__":
|
|
|
127
191
|
for letter in reader:
|
|
128
192
|
print(letter.index, int(letter.scan[0, 0]))
|
|
129
193
|
SharedStream.unlink("example-sorting:filled")
|
|
194
|
+
with SharedStream.create(Sack, "example-sorting:sacks", capacity=4) as sacks:
|
|
195
|
+
sack_reader = sacks.reader()
|
|
196
|
+
with sacks.sender() as sack_sender:
|
|
197
|
+
send_sacks(sack_sender)
|
|
198
|
+
read_sacks(sack_reader)
|
|
199
|
+
SharedStream.unlink("example-sorting:sacks")
|
|
200
|
+
with SharedStream.create(Letter, "example-sorting:release", capacity=4) as stream:
|
|
201
|
+
reader = stream.reader()
|
|
202
|
+
with stream.sender(on_full="release") as sender:
|
|
203
|
+
sort_without_stalling(sender, 6)
|
|
204
|
+
file_letters(reader)
|
|
205
|
+
SharedStream.unlink("example-sorting:release")
|
|
206
|
+
with SharedStream.create(Letter, "example-sorting:fetch", capacity=8) as stream:
|
|
207
|
+
reader = stream.reader(mode="lossy")
|
|
208
|
+
with stream.sender() as sender:
|
|
209
|
+
for i in range(6):
|
|
210
|
+
sender.send(Letter(i, "Ada", np.full((32, 32), i, np.uint8)))
|
|
211
|
+
fetch_letters(reader, 2, 4)
|
|
212
|
+
SharedStream.unlink("example-sorting:fetch")
|
|
@@ -15,7 +15,7 @@ class Recording(SharedBox, name="example-recording"):
|
|
|
15
15
|
# --8<-- [end:declare]
|
|
16
16
|
|
|
17
17
|
# --8<-- [start:create]
|
|
18
|
-
recording = Recording(BoundedList
|
|
18
|
+
recording = Recording(BoundedList(float, [0.0] * 50000, capacity=65536))
|
|
19
19
|
# --8<-- [end:create]
|
|
20
20
|
|
|
21
21
|
# --8<-- [start:change]
|