mirror of
https://github.com/Brandon-Rozek/website.git
synced 2024-11-09 10:40:34 -05:00
Compare commits
2 commits
9d246f9a45
...
0d0eef1c28
Author | SHA1 | Date | |
---|---|---|---|
0d0eef1c28 | |||
b1d7c0e09f |
3 changed files with 126 additions and 0 deletions
98
content/blog/marshalling-python-dataclasses.md
Normal file
98
content/blog/marshalling-python-dataclasses.md
Normal file
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
title: "Marshalling Python Dataclasses"
|
||||
date: 2024-01-20T22:52:50-05:00
|
||||
draft: false
|
||||
tags:
|
||||
- Python
|
||||
math: false
|
||||
medium_enabled: false
|
||||
---
|
||||
|
||||
Recently I wanted a way to transfer structured messages between two python applications over a unix domain socket. The cleanest and simplest way I found so far is to make use of the dataclasses and json standard libraries.
|
||||
|
||||
We'll consider the following message for the rest of the post:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class QueryUserMessage:
|
||||
auth_key: str
|
||||
username: str
|
||||
```
|
||||
|
||||
## Marshalling
|
||||
|
||||
Let's say we have a message we want to send:
|
||||
|
||||
```python
|
||||
message = QueryUserMessage("lkajdfsas", "brozek")
|
||||
```
|
||||
|
||||
We first need to get its dictionary representation. Luckily the standard library has us there:
|
||||
|
||||
```python
|
||||
from dataclasses import asdict
|
||||
|
||||
message_dict = asdict(message)
|
||||
```
|
||||
|
||||
Then we can use the `json` module to give us a string representation
|
||||
|
||||
```python
|
||||
import json
|
||||
|
||||
message_str = json.dumps(message_dict)
|
||||
```
|
||||
|
||||
Finally, we can encode it into bytes and send it away:
|
||||
|
||||
```python
|
||||
# Default encoding is "utf-8"
|
||||
message_bytes = message_str.encode()
|
||||
# Assuming connetion is defined...
|
||||
connection.sendall(message_bytes)
|
||||
```
|
||||
|
||||
To make this easier for myself, I create a custom `json` encoder and a function that uses the connection to send off the message
|
||||
|
||||
```python
|
||||
class DataclassEncoder(json.JSONEncoder):
|
||||
def default(self, o):
|
||||
return asdict(o)
|
||||
def send_message(connection, message_dataclass):
|
||||
contents = json.dumps(message_dataclass, cls=DataclassEncoder).encode()
|
||||
connection.sendall(contents)
|
||||
```
|
||||
|
||||
## Un-marshalling
|
||||
|
||||
On the other end, let us receive the bytes and decode it into a string:
|
||||
|
||||
```python
|
||||
MESSAGE_BUFFER_LEN = 1024
|
||||
message_bytes = connection.recv(MESSAGE_BUFFER_LEN)
|
||||
message_str = message_bytes.decode()
|
||||
```
|
||||
|
||||
We can use the `json` module to turn it into a Python dictionary
|
||||
|
||||
```python
|
||||
message_dict = json.loads(message_str)
|
||||
```
|
||||
|
||||
In this post, we can make use of the fact that we only have one message class. In other cases, you would either want to rely on some protocol or pass in the message type ahead of time. Therefore, we can pass the fields of the dictionary straight to the constructor.
|
||||
|
||||
```python
|
||||
message = QueryUserMessage(**message_dict)
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
In production use cases, we'll need to introduce a gambit of error-handling to capture failures in json de-serialization and class instantiation. I hope, however, that this serves as a good starting point.
|
||||
|
||||
Some things to consider:
|
||||
|
||||
1) If you have multiple types of messages, maybe including a field in the dictionary that is a string which represents the message type. Both applications can then maintain a map between these strings and the class constructors.
|
||||
2) If it's possible to have messages larger than the buffer length, then consider either setting it higher or sending the size of the message beforehand.
|
||||
3) Using a standard HTTP library ;)
|
|
@ -35,6 +35,7 @@ The following menu contains meals that are in rotation at my home. These are mad
|
|||
- {{< vegetarian >}}Broccoli Cheddar
|
||||
- {{< vegetarian >}}Loaded Baked Potato
|
||||
- {{< vegetarian >}}Egg Drop Soup
|
||||
- {{< vegetarian >}}[Black Bean Soup](black-bean-soup/)
|
||||
|
||||
## Entrees
|
||||
|
||||
|
|
27
content/menu/black-bean-soup.md
Normal file
27
content/menu/black-bean-soup.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: "Black Bean Soup"
|
||||
date: 2024-01-20
|
||||
hideDate: true
|
||||
draft: false
|
||||
---
|
||||
|
||||
## Ingredients
|
||||
- 2 tablespoons vegetable oil
|
||||
- 1 small yellow onion
|
||||
- 1 large carrot
|
||||
- 1 red bell pepper
|
||||
- 2 tablespoons garlic powder
|
||||
- 60 ounces of black beans
|
||||
- 32 ounces of broth
|
||||
- 1 tablespoon cumin
|
||||
- sprinkle of dried oregano
|
||||
- 1 bay leaf
|
||||
- 1 tablespoon lime juice
|
||||
|
||||
## Recipe
|
||||
1. Cook black beans
|
||||
2. In a large pot, heat the olive oil on medium high heat. Dice and add the onion, carrots, and red pepper. Cooking for about 5 minutes
|
||||
3. Add in broth, cumin, garlic powder, oregano, and the bayleaf. Cook for another 15 minutes
|
||||
4. Add the black beans (can be added in step 3 if available) and cook for another 10 minutes
|
||||
5. Remove the bay leaf. Either use an immersion blender or transfer 1 cup to a regular blender to thicken the soup.
|
||||
6. Add lime juice and serve
|
Loading…
Reference in a new issue