Python
Highlights
The library has been fully rewritten to use only Rust. It should make no difference for users, except for a significant performance improvement.
The API has also been reworked to feel more pythonic, using notably context managers.
Context managers and background callbacks
You should close the zenoh session after use and the recommended way is through context manager:
import zenoh
+Python
Highlights
The library has been fully rewritten to use only Rust. It should make no difference for users, except for a significant performance improvement.
The API has also been reworked to feel more pythonic, using notably context managers.
Context managers and background callbacks
You should close the zenoh session after use and the recommended way is through context manager:
import zenoh
with zenoh.open(zenoh.Config()) as session:
# `session.close()` will be called at the end of the block
Session-managed objects like subscribers or queryables can also be managed using context managers:
with session.declare_subscriber("my/keyexpr") as subscriber:
# `subscriber.undeclare()` will be called at the end of the block`
-
In previous version, it was necessary to keep a variable in the scope for a subscriber/queryable declared with a callback. This constraint has been lifted, and it’s now possible to declare and forget an entity with a callback; in that case, the entity will keep living in background, until the session is closed.
import zenoh
+
In previous version, it was necessary to keep a variable in the scope for a subscriber/queryable declared with a callback. This constraint has been lifted, and it’s now possible to declare a “background” entity; this entity will keep living in background, having its callback executed until the session is closed.
import zenoh
with zenoh.open(zenoh.Config()) as session:
- session.declare_subscriber("my/keyepxr", lambda s: print(s))
+ # no need to declare a variable
+ session.declare_subscriber("my/keyepxr", lambda s: print(s), background=True)
sleep(10) # subscriber stays in background and its callback can be called
- # `session.close()` will be called at the end of the block, and it will undeclare the subscriber
+ # `session.close()` will be called at the end of the block,
+ # and it will undeclare the subscriber
Value is gone, long live ZBytes
Value
has been split into ZBytes
and Encoding
. put
and other operations now require a ZBytes
payload, and builders accept an optional Encoding
parameter.
ZBytes
is a raw bytes container. It can be created directly from raw bytes/strings using ZBytes
constructor. Then bytes can be retrieved using ZBytes.to_bytes
or ZBytes.to_string
. Sample payload is now a ZBytes
instead of bytes
.
- Zenoh 0.11.x
sample = subscriber.recv()
my_string = sample.payload.decode("utf-8")
- Zenoh 1.0.0
sample = subscriber.recv()
@@ -19,7 +21,7 @@
output = payload.to_bytes()
zenoh.ext
serialization doesn’t pretend to cover all use cases, as it is just one available choice among other serialization formats like JSON, Protobuf, CBOR, etc. In the end, Zenoh will just send and receive payload raw bytes independently of the serialization used.
NOTE: ⚠️ Serialization of bytes
is not the same as passing bytes
to ZBytes
constructor.
Encoding
Encoding
has been reworked.
Zenoh does not impose any encoding requirement on the user, nor does it operate on it.
-It can be thought of as optional metadata, carried over by Zenoh in such a way that the end user’s application may perform different operations based on encoding.
NOTE: ⚠️ The encoding is no longer automatically deduced from the payload type.
session.put(json.dumps({"key", "value"}), encoding=Encoding.APPLICATION_JSON)
+It can be thought of as optional metadata, carried over by Zenoh in such a way that the end user’s application may perform different operations based on encoding.NOTE: ⚠️ The encoding is no longer automatically inferred from the payload type.
session.put(json.dumps({"key", "value"}), encoding=Encoding.APPLICATION_JSON)
Users can also define their own encoding scheme that does not need to be based on the pre-defined variants.
encoding = Encoding("pointcloud/LAS")
Because encoding is now optional for put
, Publisher
can be declared with a default encoding, which will be used in every Publisher.put
.
publisher = session.declare_publisher("my/keyepxr", encoding=Encoding.APPLICATION_JSON)
// default encoding from publisher `application/json`
diff --git a/docs/migration_1.0/rust/index.html b/docs/migration_1.0/rust/index.html
index b67b73e4..a8335e5f 100644
--- a/docs/migration_1.0/rust/index.html
+++ b/docs/migration_1.0/rust/index.html
@@ -1,6 +1,6 @@
Rust · Zenoh - pub/sub, geo distributed storage, query
- Rust
Module reorganization
We reorganized the module tree, so import paths are not the same as before. The main difference is that everything should be imported via the root path zenoh::
. Here are some examples, but you can look into zenoh/src/lib.rs
for the complete list of changes.
// common use
+Rust
Module reorganization
We reorganized the module tree, so import paths are not the same as before. The main difference is that everything should be imported via the root path zenoh::
. Here are some examples, but you can look into zenoh/src/lib.rs
for the complete list of changes.
// common use
use zenoh::config::*;
use zenoh::{Config, Error, Result};
@@ -55,7 +55,7 @@
publisher.put(buf).wait().unwrap();
Session
is now clonable and can be closed easily
Session
implements Clone
now, so there is no more need to wrap it into an Arc<Session>
, and Session::into_arc
has been deprecated. All the session methods, except Session::close
, works like before, so only the session type need to be changed.
As a side effect, Subscriber
and Queryable
no longer have a generic lifetime parameter. Publisher
also looses one of its lifetime parameters, to keep only the one of its key expression.
The session is now closed automatically when the last Session
instance is dropped, even if publishers/subscribers/etc. are still alive. Session can also be manually closed using Session::close
, which now takes an immutable reference, so it can be called anytime, even if publishers/subscribers/etc. are still alive.
-Subscriber and queryable of a closed session will no longer receive data; trying to call Session::get
, Session::put
or Publisher::put
will result in an error. Closing session on the fly may save bandwidth on the wire, as it avoids propagating the undeclaration of remaining entities like subscribers/queryables/etc.
let session = zenoh::open(zenoh::config::peer()).await.unwrap();
+Subscriber and queryable of a closed session will no longer receive data; trying to call Session::get
, Session::put
or Publisher::put
will result in an error. Closing session on the fly may save bandwidth on the wire, as it avoids propagating the undeclaration of remaining entities like subscribers/queryables/etc.let session = zenoh::open(config).await.unwrap();
let subscriber = session
.declare_subscriber("key/expression")
.await
@@ -72,24 +72,16 @@
// **when all remaining data has been processed**.
// subscriber undeclaration has not been sent on the wire
subscriber_task.await.unwrap()
-
Callbacks run in background until session is closed
Session entities, e.g. subscribers, declared with callbacks are no longer undeclared when they are dropped; there is no longer need to keep a reference to an entity when the intent is to have it run until the session is closed.
let session = zenoh::open(zenoh::config::default()).await.unwrap();
+
Callbacks run in background until session is closed
It is now possible to declare “background” entities, e.g. subscribers, which have their callback called until the session is closed. So it is no longer needed to keep a dummy variable in scope when the intent is to have an entity living for the rest of the program.
let session = zenoh::open(config).await.unwrap();
session
.declare_subscriber("key/ expression")
.callback(|sample| { println!("Received: {} {:?}", sample. key_expr(), sample. payload()) })
- .await
+ .background() // declare the subscriber in background
+ .await
.unwrap();
-// subscriber run in background until the session is closed
+// subscriber runs in background until the session is closed
// no need to keep a variable around
-
If you still want the entity to be undeclared when dropped, you can simply use with
instead of callback
; it may just require you to annotate the callback, as type inference is not as good as with callback
method.
let session = zenoh::open(zenoh::config::default()).await.unwrap();
-let subscriber = session
- .declare_subscriber("key/ expression")
- // annotation needed
- .with(|sample: Sample| { println!("Received: {} {:?}", sample. key_expr(), sample. payload()) })
- .await
- .unwrap();
-// subscriber is undeclared when dropped
-
Going into details, a new method undeclare_on_drop(bool)
– default to true
, has been added to the builders, and callback(cb)
is now simply a shortcut to with(cb).undeclare_on_drop(false)
.
-However, the normal user would rarely need to call this method directly.
Value is gone, long live ZBytes
Value
has been split into ZBytes
and Encoding
. put
and other operations now require a ZBytes
payload, and builders accept an optional Encoding
parameter. The encoding is no longer automatically deduced from the payload type.
ZBytes
is a raw bytes container, which can also contain non-contiguous regions of memory. It can be created directly from raw bytes/strings using ZBytes::from
. The bytes can be retrieved using ZBytes::to_bytes
, which returns a Cow<[u8]>
, as a copy may have to be done if the underlying bytes are not contiguous.
- Zenoh 0.11.x
let sample = subscriber.recv_async().await.unwrap();
+
Value is gone, long live ZBytes
Value
has been split into ZBytes
and Encoding
. put
and other operations now require a ZBytes
payload, and builders accept an optional Encoding
parameter. The encoding is no longer automatically inferred from the payload type.
ZBytes
is a raw bytes container, which can also contain non-contiguous regions of memory. It can be created directly from raw bytes/strings using ZBytes::from
. The bytes can be retrieved using ZBytes::to_bytes
, which returns a Cow<[u8]>
, as a copy may have to be done if the underlying bytes are not contiguous.
- Zenoh 0.11.x
let sample = subscriber.recv_async().await.unwrap();
let value: Value = sample.value;
let raw_bytes: Vec<u8> = value.try_into().unwrap();
- Zenoh 1.0.0
let sample = subscriber.recv_async().await.unwrap();
@@ -217,8 +209,8 @@
.with(RingChannel::new(size))
.await
.unwrap();
-
⚠️ Note: We no longer support Pull mode in Zenoh
To get the same behavior of a Zenoh 0.11.0 PullSubscriber
, please make use of a RingChannel
an example of this is illustrated in z_pull.rs
.
Timestamps
We now tie generating a timestamp to a Zenoh session, with the timestamp inheriting the ZenohID
of the session.
Note that a Zenoh session will only be able to generate a timestamp if the timestamping
configuration option is enabled.
- Zenoh 0.11.x
let timestamp : Timestamp = zenoh::time::new_reception_timestamp();
-
- Zenoh 1.0.0
let session: Session = zenoh::open();
+
⚠️ Note: We no longer support Pull mode in Zenoh
To get the same behavior of a Zenoh 0.11.0 PullSubscriber
, please make use of a RingChannel
an example of this is illustrated in z_pull.rs
.
Timestamps
We now tie generating a timestamp to a Zenoh session, with the timestamp inheriting the ZenohID
of the session.
Note that a Zenoh session will only be able to generate a timestamp if the timestamping
configuration option is enabled.
- Zenoh 0.11.x
let timestamp : Timestamp = zenoh::time::new_reception_timestamp();
+
- Zenoh 1.0.0
let session: Session = zenoh::open(config);
// If the `timestamping` configuration is disabled, this call will return `None`.
let timestamp: Option<Timestamp> = session::new_timestamp();
This will affect user-created plugins and applications that need to generate timestamps.
Feature Flags
Removed:
complete_n
: due to a Legacy code cleanup
Storages
Zenoh 1.0.0 introduced the possibility for Zenoh nodes configured in a mode other than router
to load plugins.
A, somehow, implicit assumption that dictated the behaviour of storages is that the Zenoh node loading them has to add a timestamp to any received publication that did not have one. This functionality is controlled by the timestamping
configuration option.
Until Zenoh 1.0.0 this assumption held true as only a router could load storage and the default configuration for a router enables timestamping
. However, in Zenoh 1.0.0 nodes configured in client
& peer
mode can load storage and their default configuration disables timestamping
.
⚠️ The storage-manager
will fail to launch if the timestamping
configuration option is disabled.
Next up: C++