Giter Site home page Giter Site logo

Comments (6)

artas728 avatar artas728 commented on June 21, 2024 2

Hello Rob
Thank you for your feedback!
We will fix the data type problem with the next release

from panini.

roblight avatar roblight commented on June 21, 2024

Hello Rob Thank you for your feedback! We will fix the data type problem with the next release

Do we have a next release date in mind? Thank you!

from panini.

artas728 avatar artas728 commented on June 21, 2024

Oh, sorry @roblight I missed your last message.
I'm going to make an alpha release in a few hours. There will be significant changes with data_types/serialization logic. I will write here when it is ready

from panini.

artas728 avatar artas728 commented on June 21, 2024

@roblight, Panini v0.8.0a1 available via pip. This will still take a few weeks before the release of v0.8.0. In the meantime, I suggest you try to solve your problem with v0.8.0a1.

I think the solution is a bit more global than you would expect. So, update with the "data_type" parameter that is associated with this issue:

  1. Parameter data_type "json" has been removed. Actually, "json" here meant jsonble python object. Perhaps it was not the most explicit data type name. I believe it was confusing many developers, we decided to remove it from v0.8.0.
  2. For "publish" and "request" methods no need to declare "data_type" anymore, Panini detects a type of your message by itself.
  3. New parameter for “request” method - “response_data_type”. For example:
subject = "a.b.c"
message = {"param1": "value1"}


response: bytes = app.request(subject=subject, message=message, response_data_type=bytes)


Let's update your code according to the above:


import json
import traceback

from panini import app as panini_app

app = panini_app.App(
    service_name="quickstart-app",
    host="127.0.0.1",
    port=4222,
)

message = {
    "key4": "value1",
    "key7": 2,
    "key3": 3.024444412342342342,
    "key1": [1, 2, 3, 4],
    "key6": {"1": 1, "2": 2, "3": 3, "4": 4, "5": 5},
    "key5": {"subkey1": "1", "subkey2": 2, "3": 3, "4": 4, "5": 5},
    "key2": None,
}

@app.task()
async def publish_string():
    some_string = json.dumps(message, sort_keys=True)

    try:
        print(f"*** sending request for json")
        # default data_type is "json"
        response = await app.request(
            subject="some.publish.subject.json",
            message=message,
            timeout=5
        )
        print(f"response expecting json: type: {type(response)} (it should be dict)")
    except BaseException as exc:
        print(f"****** got exception: {exc}")

    try:
        print(f"*** sending request for str")
        response = await app.request(
            subject="some.publish.subject.str",
            message=some_string,
            response_data_type=str,
            timeout=5
        )
        print(f"response expecting str: type: {type(response)}")
    except BaseException as exc:
        print(f"****** got exception: {exc}")

    try:
        print(f"*** sending request for bytes")
        response = await app.request(
            subject="some.publish.subject.bytes",
            message=some_string.encode(),
            response_data_type=bytes,
            timeout=5
        )
        print(f"response expecting bytes: type: {type(response)}")
    except BaseException as exc:
        print(f"****** got exception: {exc}")

# default data_type is "json"
@app.listen("some.publish.subject.json")
async def receive_dict(msg):
    print(f"request expecting json: type: {type(msg.data)} (it should be dict)")
    return {"some": "response"}

@app.listen("some.publish.subject.str", data_type=str)
async def receive_string(msg):
    print(f"request expecting str: type: {type(msg.data)}")
    return '{"some": "response"}'

@app.listen("some.publish.subject.bytes", data_type=bytes)
async def receive_bytes(msg):
    print(f"request expecting bytes: type: {type(msg.data)}")
    return b'{"some": "response"}'

if __name__ == "__main__":
    app.start()
*** sending request for json
request expecting json: type: <class 'dict'> (it should be dict)
response expecting json: type: <class 'dict'> (it should be dict)
*** sending request for str
request expecting str: type: <class 'str'>
response expecting str: type: <class 'str'>
*** sending request for bytes
request expecting bytes: type: <class 'bytes'>
response expecting bytes: type: <class 'bytes'>

Let me know if you have any questions about it.

from panini.

artas728 avatar artas728 commented on June 21, 2024

Also, other updates that are not directly related to the issue, but may be useful for solving the problem with "data_type":

  1. Panini supports dataclass as data_type now. You may use it to serialize or validate your messages. I’ve tested it mostly with pydantic dataclasses and also with mashumaro. Example of usage is here: https://github.com/lwinterface/panini/blob/develop/examples/simple_examples/dataclass_msg.py

  2. Panini supports any Callable object as data_type for custom processing. An example of usage is here:

from panini.exceptions import MessageSchemaError
from panini import app as panini_app

app = panini_app.App(
    service_name="test_serializer_callable",
    host="127.0.0.1",
    port=4222,
)


def callable_validator(**message):
    if type(message) is not dict:
        raise MessageSchemaError("type(data) is not dict")
    if "data" not in message:
        raise MessageSchemaError("'data' not in message")
    if type(message["data"]) is not int:
        raise MessageSchemaError("type(message['data']) is not int")
    if message["data"] < 0:
        raise MessageSchemaError(f"Value of field 'data' is {message['data']} that negative")
    message["data"] += 1
    return message


@app.listen("test_validator.foo", data_type=callable_validator)
async def publish(msg):
    return {"success": True}


@app.listen("test_validator.foo-with-error-cb", data_type=callable_validator)
async def publish(msg):
    return {"success": True}


@app.listen("test_validator.check")
async def check(msg):
    try:
        message = callable_validator(**msg.data)
    except MessageSchemaError:
        return {"success": False}

    return {"success": True}


if __name__ == "__main__":
    app.start()
  1. Panini validator has been removed. If you need incoming message validation, we recommend to use dataclasses. Example of usage for Pydantic: https://pydantic-docs.helpmanual.io/usage/validators/

from panini.

roblight avatar roblight commented on June 21, 2024

Hi @artas728 thank you so much! I plan to review the changes and give feedback ASAP.

from panini.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.