Skip to content

Commit 6b3f73e

Browse files
authored
Merge pull request #13 from compas-dev/simpler-api
Simplify API and add more examples
2 parents 8ceb89c + 1a51ac8 commit 6b3f73e

File tree

11 files changed

+199
-91
lines changed

11 files changed

+199
-91
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
* Fix/add json serialization support to `Message` class.
1515
* Fix get/set attr/item recursion bug.
16+
* Simplify API:
17+
* Default to `Message` class if no message type is specified.
18+
* Allow to use a string with the topic name in place of an instance of `Topic`.
19+
* Added an `EchoSubscriber` to showcase basic usage.
1620

1721
### Removed
1822

README.md

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,90 @@
1-
# compas_eve
1+
# COMPAS EVE
22

3-
COMPAS Event Extensions: adds event-based communication infrastructure to the COMPAS framework.
3+
Event-based communication for the COMPAS framework.
44

5+
```python
6+
>>> import compas_eve as eve
7+
>>> pub = eve.Publisher("/hello_world")
8+
>>> sub = eve.EchoSubscriber("/hello_world")
9+
>>> sub.subscribe()
10+
>>> for i in range(10):
11+
... pub.publish(dict(text=f"Hello World {i}"))
12+
```
513

6-
## Getting started with this project
14+
It is extremely easy to send messages around. COMPAS EVE supports
15+
different transport mechanisms to send messages between different threads, processes, computers, etc.
716

8-
### Setup code editor
17+
## Installation
918

10-
1. Open project folder in VS Code
11-
2. Select python environment for the project
12-
3. First time using VS Code and on Windows? Make sure select the correct terminal profile: `Ctrl+Shift+P`, `Terminal: Select Default Profile` and select `Command Prompt`.
19+
Install using `pip`:
1320

14-
> All terminal commands in the following sections can be run from the VS Code integrated terminal.
21+
```bash
1522

23+
pip install compas_eve
24+
```
1625

17-
### First steps with git
26+
Or using `conda`:
1827

19-
1. Go to the `Source control` tab
20-
2. Make an initial commit with all newly created files
28+
```bash
2129

30+
conda install compas_eve
31+
```
2232

23-
### First steps with code
33+
## Supported features
2434

25-
1. Install the newly created project
35+
* Publisher/subscriber communication model (N-to-N communication)
36+
* In-process events
37+
* MQTT support
38+
* CPython & IronPython support
2639

27-
pip install -e .
40+
## Examples
2841

29-
2. Install it on Rhino
42+
### In-process events
3043

31-
python -m compas_rhino.install
44+
The simplest option is to use in-process events. This works for
45+
simple applications and allows to communicate between threads.
3246

47+
```python
48+
import compas_eve as eve
3349

34-
### Code conventions
50+
pub = eve.Publisher("/hello_world")
51+
sub = eve.EchoSubscriber("/hello_world")
52+
sub.subscribe()
3553

36-
Code convention follows [PEP8](https://pep8.org/) style guidelines and line length of 120 characters.
54+
for i in range(10):
55+
pub.publish(dict(text=f"Hello World {i}"))
56+
```
3757

38-
1. Check adherence to style guidelines
58+
### MQTT
3959

40-
invoke lint
60+
MQTT is a protocol that allows to send messages between different
61+
systems/computers. Using MQTT is very simple as well:
4162

42-
2. Format code automatically
63+
```python
64+
import compas_eve as eve
65+
from compas_eve.mqtt import MqttTransport
4366

44-
invoke format
67+
tx = MqttTransport("broker.hivemq.com")
68+
eve.set_default_transport(tx)
4569

70+
pub = eve.Publisher("/hello_world")
71+
sub = eve.EchoSubscriber("/hello_world")
72+
sub.subscribe()
4673

47-
### Documentation
74+
for i in range(10):
75+
pub.publish(dict(text=f"Hello World {i}"))
76+
```
4877

49-
Documentation is generated automatically out of docstrings and [RST](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) files in this repository
78+
This example shows how to send and receive from a single script, but
79+
running publishers and subscribers on different scripts, different processes, or even different computers will work the exact same way.
5080

51-
1. Generate the docs
5281

53-
invoke docs
82+
### Usage from Rhinoceros 3D
5483

55-
2. Check links in docs are valid
84+
It is possible to use the same code from within Rhino/Grasshopper.
5685

57-
invoke linkcheck
86+
Make sure you have installed it to Rhino using the COMPAS installation mechanism:
5887

59-
3. Open docs in your browser (file explorer -> `dist/docs/index.html`)
60-
61-
62-
### Testing
63-
64-
Tests are written using the [pytest](https://docs.pytest.org/) framework
65-
66-
1. Run all tests from terminal
67-
68-
invoke test
69-
70-
2. Or run them from VS Code from the `Testing` tab
71-
72-
73-
### Developing Grasshopper components
74-
75-
We use [Grasshopper Componentizer](https://github.com/compas-dev/compas-actions.ghpython_components) to develop Python components that can be stored and edited on git.
76-
77-
1. Build components
78-
79-
invoke build-ghuser-components
80-
81-
2. Install components on Rhino
82-
83-
python -m compas_rhino.install
84-
85-
86-
### Publish release
87-
88-
Releases follow the [semver](https://semver.org/spec/v2.0.0.html) versioning convention.
89-
90-
1. Create a new release
91-
92-
invoke release major
88+
```bash
89+
python -m compas_rhino.install -v 7.0
90+
```

docs/examples.rst

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Hello Distributed World
5959
-----------------------
6060

6161
Fortunately, it is very easy to extend our example and enable communication across processes, machines,
62-
networks, continents, anything that is connected to the Internet!
62+
networks, continents, and anything that is connected to the Internet!
6363

6464
The only difference is that we are going to configure a different :class:`Transport` implementation for
6565
our messages. In this case, we will use the MQTT transport method. `MQTT <https://en.wikipedia.org/wiki/MQTT>`_
@@ -85,3 +85,16 @@ or even completely different computers and they will be able to communicate!
8585
And since pub/sub allows any number of publishers and any number of
8686
subscriber per topic, you can start the same scripts more than once and the
8787
messages will be received and send multiple times!
88+
89+
Add typing information to messages
90+
----------------------------------
91+
92+
So far, we have defined our messages as simple dictionaries.
93+
It is also possible to define a class that messages need to comform to,
94+
in order to get typing information on the messages.
95+
96+
.. literalinclude :: examples/04_message_type.py
97+
:language: python
98+
99+
This example also shows how to set a default transport so that it does
100+
not need to be specified on every publisher and subscriber instance.

docs/examples/01_hello_world.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import time
22

3-
from compas_eve import Message
43
from compas_eve import Publisher
54
from compas_eve import Subscriber
65
from compas_eve import Topic
76

87

9-
topic = Topic("/compas_eve/hello_world/", Message)
8+
topic = Topic("/compas_eve/hello_world/")
109

1110
publisher = Publisher(topic)
12-
subcriber = Subscriber(topic, callback=lambda msg: print(f"Received message: {msg.text}"))
11+
subcriber = Subscriber(topic, callback=lambda msg: print(f"Received message: {msg}"))
1312
subcriber.subscribe()
1413

1514
for i in range(20):
16-
msg = Message(text=f"Hello world #{i}")
17-
print(f"Publishing message: {msg.text}")
15+
msg = dict(text=f"Hello world #{i}")
16+
print(f"Publishing message: {msg}")
1817
publisher.publish(msg)
1918
time.sleep(1)

docs/examples/02_hello_threaded_world.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
import time
22
from threading import Thread
33

4-
from compas_eve import Message
54
from compas_eve import Publisher
65
from compas_eve import Subscriber
76
from compas_eve import Topic
87

9-
topic = Topic("/compas_eve/hello_world/", Message)
8+
topic = Topic("/compas_eve/hello_world/")
109

1110

1211
def start_publisher():
1312
publisher = Publisher(topic)
1413

1514
for i in range(20):
16-
msg = Message(text=f"Hello world #{i}")
17-
print(f"Publishing message: {msg.text}")
15+
msg = dict(text=f"Hello world #{i}")
16+
print(f"Publishing message: {msg}")
1817
publisher.publish(msg)
1918
time.sleep(1)
2019

2120

2221
def start_subscriber():
23-
subcriber = Subscriber(topic, callback=lambda msg: print(f"Received message: {msg.text}"))
22+
subcriber = Subscriber(topic, callback=lambda msg: print(f"Received message: {msg}"))
2423
subcriber.subscribe()
2524

2625

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import time
22

3-
from compas_eve import Message
43
from compas_eve import Publisher
54
from compas_eve import Topic
65
from compas_eve.mqtt import MqttTransport
76

8-
topic = Topic("/compas_eve/hello_world/", Message)
7+
topic = Topic("/compas_eve/hello_world/")
98
tx = MqttTransport("broker.hivemq.com")
109

1110
publisher = Publisher(topic, transport=tx)
1211

1312
for i in range(20):
14-
msg = Message(text=f"Hello world #{i}")
15-
print(f"Publishing message: {msg.text}")
13+
msg = dict(text=f"Hello world #{i}")
14+
print(f"Publishing message: {msg}")
1615
publisher.publish(msg)
1716
time.sleep(1)

docs/examples/03_hello_distributed_world_sub.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import time
22

3-
from compas_eve import Message
43
from compas_eve import Subscriber
54
from compas_eve import Topic
65
from compas_eve.mqtt import MqttTransport
76

8-
topic = Topic("/compas_eve/hello_world/", Message)
7+
topic = Topic("/compas_eve/hello_world/")
98
tx = MqttTransport("broker.hivemq.com")
109

11-
subcriber = Subscriber(topic, callback=lambda msg: print(f"Received message: {msg.text}"), transport=tx)
10+
subcriber = Subscriber(topic, callback=lambda msg: print(f"Received message: {msg}"), transport=tx)
1211
subcriber.subscribe()
1312

1413
print("Waiting for messages, press CTRL+C to cancel")

docs/examples/04_message_type.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import compas_eve as eve
2+
3+
4+
# Create a custom message type
5+
class CustomMessage(eve.Message):
6+
def __init__(self, value=None):
7+
super(CustomMessage, self).__init__()
8+
self["value"] = value
9+
10+
11+
# Define a default transport using MQTT
12+
from compas_eve.mqtt import MqttTransport
13+
14+
tx = MqttTransport("broker.hivemq.com")
15+
eve.set_default_transport(tx)
16+
17+
# Create publisher and subscriber (using the EchoSubscriber for simplicity)
18+
topic = eve.Topic("/hello_world/", message_type=CustomMessage)
19+
pub = eve.Publisher(topic)
20+
sub = eve.EchoSubscriber(topic)
21+
sub.subscribe()
22+
23+
# Starting publishing messages
24+
import time
25+
26+
for i in range(10):
27+
pub.publish(CustomMessage(i))
28+
time.sleep(1)

docs/index.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,22 @@ Event Extensions for COMPAS
66

77
``compas_eve`` adds event-based communication infrastructure to the COMPAS framework.
88

9+
Using events is a way to decouple the components of a system, making it easier to develop, test, and maintain.
10+
911
.. figure:: /_images/pubsub.png
1012
:figclass: figure
1113
:class: figure-img img-fluid
1214

1315

16+
.. code-block:: python
17+
18+
>>> import compas_eve as eve
19+
>>> pub = eve.Publisher("/hello_world")
20+
>>> sub = eve.EchoSubscriber("/hello_world")
21+
>>> sub.subscribe()
22+
>>> for i in range(10):
23+
... pub.publish(dict(text=f"Hello World {i}"))
24+
1425
Table of Contents
1526
=================
1627

src/compas_eve/__init__.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
Topic
1818
Publisher
1919
Subscriber
20+
EchoSubscriber
2021
Transport
2122
InMemoryTransport
2223
get_default_transport
@@ -36,7 +37,16 @@
3637
__version__ = "0.4.0"
3738

3839
from .event_emitter import EventEmitterMixin # noqa: F401 needed here to avoid circular import on py2.7
39-
from .core import Message, Publisher, Subscriber, Transport, Topic, get_default_transport, set_default_transport
40+
from .core import (
41+
Message,
42+
Publisher,
43+
Subscriber,
44+
EchoSubscriber,
45+
Transport,
46+
Topic,
47+
get_default_transport,
48+
set_default_transport,
49+
)
4050
from .memory import InMemoryTransport
4151

4252
HERE = os.path.dirname(__file__)
@@ -49,6 +59,7 @@
4959
"Message",
5060
"Publisher",
5161
"Subscriber",
62+
"EchoSubscriber",
5263
"Topic",
5364
"Transport",
5465
"get_default_transport",

0 commit comments

Comments
 (0)