Skip to content
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

docs: add z_bytes example #325

Merged
merged 5 commits into from
Sep 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions examples/z_bytes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#
# Copyright (c) 2024 ZettaScale Technology
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# ZettaScale Zenoh Team, <[email protected]>
#
import zenoh
from zenoh import UInt32, ZBytes


def main():
# Numeric: UInt8, UInt16, Uint32, UInt64, UInt128, Int8, Int16, Int32, Int64,
# Int128, Float32, Float64, int (handled as Int64), float (handled as Float64)
input = UInt32(1234)
payload = ZBytes.serialize(input)
output = payload.deserialize(UInt32)
assert input == output
# Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc.
# encoding = Encoding.ZENOH_UINT32;

# str
input = "test"
payload = ZBytes.serialize(input)
output = payload.deserialize(str)
assert input == output
# Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc.
# encoding = Encoding.ZENOH_STRING;

# bytes, bytearray
input = b"test"
payload = ZBytes.serialize(input)
output = payload.deserialize(bytes)
assert input == output
# Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc.
# encoding = Encoding.ZENOH_STRING;

# tuple
input = 1234, "test"
payload = ZBytes.serialize(input)
output = payload.deserialize(tuple[int, str])
assert input == output

# list
input = [1, 2, 3, 4]
payload = ZBytes.serialize(input)
output = payload.deserialize(list[int])
assert input == output

# dict
input = {0: "abc", 1: "def"}
payload = ZBytes.serialize(input)
output = payload.deserialize(dict[int, str])
assert input == output

# JSON
import json

input = {"name": "John Doe", "age": 43, "phones": ["+44 1234567", "+44 2345678"]}
payload = ZBytes.serialize(json.dumps(input))
output = json.loads(payload.deserialize(str))
assert input == output
# Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc.
# encoding = Encoding.APPLICATION_JSON;

# Other formats like protobuf can be used the same way as JSON, i.e. dumps to
# bytes/str before serializing to ZBytes, and loads from ZBytes after deserializing
# to str/bytes.

# arbitrary type
import struct
from dataclasses import dataclass

@dataclass
class Coordinates:
x: float
y: float
z: float

@zenoh.serializer # input type is retrieved from serializer signature
def serialize_coordinates(c: Coordinates) -> ZBytes:
return ZBytes(struct.pack("<fff", c.x, c.y, c.z))

@zenoh.deserializer # output type is retrieved from deserializer signature
def deserialize_coordinates(zbytes: ZBytes) -> Coordinates:
return Coordinates(*struct.unpack("<fff", bytes(zbytes)))

input = Coordinates(42, 1.5, 0)
payload = ZBytes.serialize(input)
output = payload.deserialize(Coordinates)
assert input == output


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion examples/z_delete.py
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ def main(conf: zenoh.Config, key: str):

print("Opening session...")
with zenoh.open(conf) as session:
print("Deleting resources matching '{}'...".format(key))
print(f"Deleting resources matching '{key}'...")
session.delete(key)


12 changes: 3 additions & 9 deletions examples/z_get.py
Original file line number Diff line number Diff line change
@@ -20,21 +20,15 @@ def main(conf: zenoh.Config, selector: str, target: zenoh.QueryTarget, payload:

print("Opening session...")
with zenoh.open(conf) as session:
print("Sending Query '{}'...".format(selector))
print(f"Sending Query '{selector}'...")
replies = session.get(selector, target=target, payload=payload)
for reply in replies:
try:
print(
">> Received ('{}': '{}')".format(
reply.ok.key_expr, reply.ok.payload.deserialize(str)
)
f">> Received ('{reply.ok.key_expr}': '{reply.ok.payload.deserialize(str)}')"
)
except:
print(
">> Received (ERROR: '{}')".format(
reply.err.payload.deserialize(str)
)
)
print(f">> Received (ERROR: '{reply.err.payload.deserialize(str)}')")


if __name__ == "__main__":
2 changes: 1 addition & 1 deletion examples/z_pull.py
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ def main(conf: zenoh.Config, key: str, size: int, interval: int):
print("Opening session...")
with zenoh.open(conf) as session:

print("Declaring Subscriber on '{}'...".format(key))
print(f"Declaring Subscriber on '{key}'...")
# Subscriber doesn't receive messages over the RingBuffer size.
# The oldest message is overwritten by the latest one.
sub = session.declare_subscriber(key, zenoh.handlers.RingChannel(size))
3 changes: 2 additions & 1 deletion examples/z_put.py
Original file line number Diff line number Diff line change
@@ -21,7 +21,8 @@ def main(conf: zenoh.Config, key: str, payload: str):
print("Opening session...")
with zenoh.open(conf) as session:

print("Putting Data ('{}': '{}')...".format(key, payload))
print(f"Putting Data ('{key}': '{payload}')...")
# Refer to z_bytes.py to see how to serialize different types of message
session.put(key, payload)

# --- Examples of put with other types:
2 changes: 1 addition & 1 deletion examples/z_queryable.py
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ def queryable_callback(query):

print("Opening session...")
with zenoh.open(conf) as session:
print("Declaring Queryable on '{}'...".format(key))
print(f"Declaring Queryable on '{key}'...")
session.declare_queryable(key, queryable_callback, complete=complete)

print("Press CTRL-C to quit...")
11 changes: 4 additions & 7 deletions examples/z_storage.py
Original file line number Diff line number Diff line change
@@ -20,9 +20,7 @@

def listener(sample: zenoh.Sample):
print(
">> [Subscriber] Received {} ('{}': '{}')".format(
sample.kind, sample.key_expr, sample.payload.deserialize(str)
)
f">> [Subscriber] Received {sample.kind} ('{sample.key_expr}': '{sample.payload.deserialize(str)}')"
)
if sample.kind == zenoh.SampleKind.DELETE:
store.pop(sample.key_expr, None)
@@ -31,8 +29,7 @@ def listener(sample: zenoh.Sample):


def query_handler(query: zenoh.Query):
print(">> [Queryable ] Received Query '{}'".format(query.selector))
replies = []
print(f">> [Queryable ] Received Query '{query.selector}'")
for stored_name, sample in store.items():
if query.key_expr.intersects(stored_name):
query.reply(
@@ -51,10 +48,10 @@ def main(conf: zenoh.Config, key: str, complete: bool):

print("Opening session...")
with zenoh.open(conf) as session:
print("Declaring Subscriber on '{}'...".format(key))
print(f"Declaring Subscriber on '{key}'...")
session.declare_subscriber(key, listener)

print("Declaring Queryable on '{}'...".format(key))
print(f"Declaring Queryable on '{key}'...")
session.declare_queryable(key, query_handler, complete=complete)

print("Press CTRL-C to quit...")
2 changes: 1 addition & 1 deletion examples/z_sub.py
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ def main(conf: zenoh.Config, key: str):
print("Opening session...")
with zenoh.open(conf) as session:

print("Declaring Subscriber on '{}'...".format(key))
print(f"Declaring Subscriber on '{key}'...")

def listener(sample: zenoh.Sample):
print(
2 changes: 1 addition & 1 deletion examples/z_sub_queued.py
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ def main(conf: zenoh.Config, key: str):

print("Opening session...")
with zenoh.open(conf) as session:
print("Declaring Subscriber on '{}'...".format(key))
print(f"Declaring Subscriber on '{key}'...")
with session.declare_subscriber(key) as sub:
print("Press CTRL-C to quit...")
for sample in sub:
93 changes: 90 additions & 3 deletions src/bytes.rs
Original file line number Diff line number Diff line change
@@ -37,7 +37,19 @@ enum SupportedType {
ByteArray,
Str,
Int,
Int8,
Int16,
Int32,
Int64,
Int128,
UInt8,
UInt16,
UInt32,
UInt64,
UInt128,
Float,
Float32,
Float64,
Bool,
List,
Tuple,
@@ -48,16 +60,33 @@ enum SupportedType {

impl SupportedType {
fn init_dict(py: Python) -> Py<PyDict> {
let dict = PyDict::new_bound(py);
fn add_type<T: PyTypeInfo>(py: Python, dict: &Bound<PyDict>, tp: SupportedType) {
dict.set_item(T::type_object_bound(py), tp as u8).unwrap()
}
let dict = PyDict::new_bound(py);
let zenoh = py.import_bound("zenoh").unwrap();
let add_wrapper_type = |name, tp| {
let wrapper = zenoh.getattr(name).unwrap();
dict.set_item(wrapper, tp as u8).unwrap();
};
add_type::<ZBytes>(py, &dict, SupportedType::ZBytes);
add_type::<PyBytes>(py, &dict, SupportedType::Bytes);
add_type::<PyByteArray>(py, &dict, SupportedType::ByteArray);
add_type::<PyString>(py, &dict, SupportedType::Str);
add_type::<PyInt>(py, &dict, SupportedType::Int);
add_wrapper_type("Int8", SupportedType::Int8);
add_wrapper_type("Int16", SupportedType::Int16);
add_wrapper_type("Int32", SupportedType::Int32);
add_wrapper_type("Int64", SupportedType::Int64);
add_wrapper_type("Int128", SupportedType::Int128);
add_wrapper_type("UInt8", SupportedType::UInt8);
add_wrapper_type("UInt16", SupportedType::UInt16);
add_wrapper_type("UInt32", SupportedType::UInt32);
add_wrapper_type("UInt64", SupportedType::UInt64);
add_wrapper_type("UInt128", SupportedType::UInt128);
add_type::<PyFloat>(py, &dict, SupportedType::Float);
add_wrapper_type("Float32", SupportedType::Float32);
add_wrapper_type("Float64", SupportedType::Float64);
add_type::<PyBool>(py, &dict, SupportedType::Bool);
add_type::<PyList>(py, &dict, SupportedType::List);
add_type::<PyTuple>(py, &dict, SupportedType::Tuple);
@@ -74,7 +103,19 @@ impl SupportedType {
n if n == Self::ByteArray as u8 => Some(Self::ByteArray),
n if n == Self::Str as u8 => Some(Self::Str),
n if n == Self::Int as u8 => Some(Self::Int),
n if n == Self::Int8 as u8 => Some(Self::Int8),
n if n == Self::Int16 as u8 => Some(Self::Int16),
n if n == Self::Int32 as u8 => Some(Self::Int32),
n if n == Self::Int64 as u8 => Some(Self::Int64),
n if n == Self::Int128 as u8 => Some(Self::Int128),
n if n == Self::UInt8 as u8 => Some(Self::UInt8),
n if n == Self::UInt16 as u8 => Some(Self::UInt16),
n if n == Self::UInt32 as u8 => Some(Self::UInt32),
n if n == Self::UInt64 as u8 => Some(Self::UInt64),
n if n == Self::UInt128 as u8 => Some(Self::UInt128),
n if n == Self::Float as u8 => Some(Self::Float),
n if n == Self::Float32 as u8 => Some(Self::Float32),
n if n == Self::Float64 as u8 => Some(Self::Float64),
n if n == Self::Bool as u8 => Some(Self::Bool),
n if n == Self::List as u8 => Some(Self::List),
n if n == Self::Tuple as u8 => Some(Self::Tuple),
@@ -214,8 +255,18 @@ impl ZBytes {
<Vec<u8>>::extract_bound(obj)?.into()
}
SupportedType::Str => String::extract_bound(obj)?.into(),
SupportedType::Int => i64::extract_bound(obj)?.into(),
SupportedType::Float => f64::extract_bound(obj)?.into(),
SupportedType::Int | SupportedType::Int64 => i64::extract_bound(obj)?.into(),
SupportedType::Int8 => i8::extract_bound(obj)?.into(),
SupportedType::Int16 => i16::extract_bound(obj)?.into(),
SupportedType::Int32 => i32::extract_bound(obj)?.into(),
SupportedType::Int128 => i128::extract_bound(obj)?.into(),
SupportedType::UInt8 => u8::extract_bound(obj)?.into(),
SupportedType::UInt16 => u16::extract_bound(obj)?.into(),
SupportedType::UInt32 => u32::extract_bound(obj)?.into(),
SupportedType::UInt64 => u64::extract_bound(obj)?.into(),
SupportedType::UInt128 => u128::extract_bound(obj)?.into(),
SupportedType::Float | SupportedType::Float64 => f64::extract_bound(obj)?.into(),
SupportedType::Float32 => (f64::extract_bound(obj)? as f32).into(),
SupportedType::Bool => bool::extract_bound(obj)?.into(),
SupportedType::List => obj
.downcast::<PyList>()?
@@ -271,7 +322,43 @@ impl ZBytes {
.into_py(py),
SupportedType::Str => this.0.deserialize::<Cow<str>>().into_pyres()?.into_py(py),
SupportedType::Int => this.0.deserialize::<i64>().into_pyres()?.into_py(py),
SupportedType::Int8 => import!(py, zenoh.Int8)
.call1((this.0.deserialize::<i8>().into_pyres()?,))?
.into_py(py),
SupportedType::Int16 => import!(py, zenoh.Int16)
.call1((this.0.deserialize::<i16>().into_pyres()?,))?
.into_py(py),
SupportedType::Int32 => import!(py, zenoh.Int32)
.call1((this.0.deserialize::<i32>().into_pyres()?,))?
.into_py(py),
SupportedType::Int64 => import!(py, zenoh.Int64)
.call1((this.0.deserialize::<i64>().into_pyres()?,))?
.into_py(py),
SupportedType::Int128 => import!(py, zenoh.Int128)
.call1((this.0.deserialize::<i128>().into_pyres()?,))?
.into_py(py),
SupportedType::UInt8 => import!(py, zenoh.UInt8)
.call1((this.0.deserialize::<u8>().into_pyres()?,))?
.into_py(py),
SupportedType::UInt16 => import!(py, zenoh.UInt16)
.call1((this.0.deserialize::<u16>().into_pyres()?,))?
.into_py(py),
SupportedType::UInt32 => import!(py, zenoh.UInt32)
.call1((this.0.deserialize::<u32>().into_pyres()?,))?
.into_py(py),
SupportedType::UInt64 => import!(py, zenoh.UInt64)
.call1((this.0.deserialize::<u64>().into_pyres()?,))?
.into_py(py),
SupportedType::UInt128 => import!(py, zenoh.UInt128)
.call1((this.0.deserialize::<u128>().into_pyres()?,))?
.into_py(py),
SupportedType::Float => this.0.deserialize::<f64>().into_pyres()?.into_py(py),
SupportedType::Float32 => import!(py, zenoh.Float32)
.call1((this.0.deserialize::<f32>().into_pyres()?,))?
.into_py(py),
SupportedType::Float64 => import!(py, zenoh.Float64)
.call1((this.0.deserialize::<f64>().into_pyres()?,))?
.into_py(py),
SupportedType::Bool => this.0.deserialize::<bool>().into_pyres()?.into_py(py),
SupportedType::List => PyList::new_bound(py, to_vec()).into_py(py),
SupportedType::Tuple => PyTuple::new_bound(py, to_vec()).into_py(py),
17 changes: 13 additions & 4 deletions tests/examples_check.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Copyright (c) 2017, 2022 ZettaScale Technology Inc.
import sys
import time
from os import getpgid, killpg, path
from signal import SIGINT
from subprocess import PIPE, Popen

# Contributors:
# ZettaScale Zenoh team, <[email protected]>
@@ -10,10 +15,6 @@

# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0

import time
from os import getpgid, killpg, path
from signal import SIGINT
from subprocess import PIPE, Popen

examples = path.realpath(__file__).split("/tests")[0] + "/examples/"
tab = "\t"
@@ -90,6 +91,14 @@ def time(self):

errors = []

if sys.version_info >= (3, 9):
# Test z_bytes
print("=> Test z_bytes")
z_bytes = Pyrun("z_bytes.py")
if error := z_bytes.status():
z_bytes.dbg()
errors.append(error)

# Test z_info & z_scout
print("=> Test z_info & z_scout")
info = Pyrun("z_info.py")
Loading
Loading