How to Use CommuniCats - MrMan567/CommuniCats GitHub Wiki
Introduction
CommuniCats is an IPC (Inter Process Communication) framework. This lets two processes running in parallel to share data with each other. Here, you can find a short guide on the basics of using CommuniCats and a usage manual explaining in detail how to use each of the functions.
Using CommuniCats
This is a short guide on setting up and using CommuniCats. Here you will find basics on how to set it up and use the communication features.
Creating the CSV file
CommuniCats uses a CSV file to transmit data. There are a few steps to set this file up.
- Create a CSV file. You can name it anything, but for the purpose of this tutorial, I will name it
master.csv
- In the CSV, write the header
address,data
. Use COMMAS to separate the values. It is NOT a Semicolon-Separated-Values file, it is a Comma-Separated-Values file! - Add a single blank line below the header. Without this, the file will be written to incorrectly.
This is what the CSV file should look like:
address,data
How to use the Receiver
Now that you have your CSV file, next make a Python file. The name does not matter, so I will name it learnCommuniCats.py
. CommuniCats comes with two classes, Sender and Receiver. The Sender handles writing to the CSV file, and the Receiver handles reading the CSV. We`ll start with a Receiver. They have 3 parameters:
address
, which is a string that this Receiver checks for in the CSV file.masterFile
, which is a string that contains the path to the file that this Receiver scans.- and
interval
, which is the interval at which this Receiver checks the master file.
We will create a Receiver named myReceiver
with this code:
myReceiver = Receiver(address, masterFile, interval)
.
Interval is optional and has a default of 5
Once we create our Receiver, it will begin scanning master.csv
in the address
column for their address. To access this data, we will use the wait()
function. This waits for the Receiver to find new data in the CSV, and return the data. Note that it only returns when the file CHANGES, not just the current data.
Try this program out:
myReceiver = Receiver("myAddress", "master.csv")
print(myReceiver.wait())
Next, put this data in the master.csv
file:
myAddress,'Hello World!'
In your python file, you should have the output Hello World!
. If you don't, just wait a little. It might not have updated yet! This works because myReceiver has the "myAddress"
address locked in it, and we put into the address
column "myAddress"
. Next. the Receiver checks the data
column for the data tied to the address, and takes that into the program. The wait()
function detects a change in the stored data and outputs the new data to the print statement.
How to use the Sender
We didn't talk about the other half of CommuniCats yet, the Sender. We will now, though. The Sender's job is to write data to the master CSV file. It has 2 parameters:
masterFile
, which is the default file this Sender should write to.- and
address
, which is the address that this Sender should always send to.
The address
parameter is optional. if you don't include it, then you can send to any other process (This is called a "Wildcard Sender"). Let's create a Sender object called mySender
:
mySender = Sender("master.csv")
and create code to send some data to myReceiver
:
mySender.send("Hello!", "myAddress")
The send()
function writes data to the master file. It has 3 parameters:
data
, which is the information to send. To send multiple pieces of data, use a tuple instead of a string.address
, which is only required when your Sender is a Wildcard.- and
masterFile
, which defaults to theself.masterFile
but when a parameter is provided it sends to that file instead.
When we run our code (Make sure the Sender comes BEFORE the wait()
function call) it should output "Hello!" This because mySender
writes "Hello"
tied to the address myAddress
to the master file, which our Receiver (who has the address myAddress
) picks up and prints out.
What to do if an error occurs
If something does not go correctly, the first step is to check your CSV file. Chances are, the file was written into wrong because of incorrect formatting. If the CSV looks messed up, recheck the formatting in "Creating the CSV file". If another error occurs even after you correct your CSV, create a GitHub issue about it (Create a "Help wanted" issue. DO NOT mark it as a bug.).
Offers and Requests
In CommuniCats, whenever we send something with a Sender, the address, data pair is called an Offer. An offer is anything that a Receiver can pick up. A Request is a way for a process to "ask" for data from another process. This is very easy to do, just create a Sender that sends an offer to the process we are asking for data from. Then on the other process, when that data is received, send the requested data back to the original process.
Communicating Between Files
Communicating between files is just as easy as communicating within the same file. All thats needed is to create a Sender in one file and a Receiver in the other. No extra setup required.
Requests example
Here we have two processes: A and B. A has the variable x, and B needs it. A does not know when to send B x, so B should send a request for x. Example code is shown here:
A:
import CommuniCats as cc
x = 10
# creates the sender and receiver
myReceiver = cc.Receiver("A", "master.csv")
mySender = cc.Sender("master.csv", "B")
# waiting for the request
if bool(myReceiver.wait()):
# sending the data
mySender.send(x)
B:
import CommuniCats as cc
# creates the sender and receiver
myReceiver = cc.Receiver("B", "master.csv")
mySender = cc.Sender("master.csv", "A")
# sending the request
mySender.send(True)
# waiting for x and printing it out
print(f"x = {myReceiver.wait()}")
This works because when B requires x, it sends True to A. A picks that up, and since the wait()
is the parameter to an if
statement, that activates the part that sends x to B.
Asyncio and CommuniCats
If you are familiar with the wait()
function, you may be aware of its main drawback: halting the program until wait()
has finished waiting. There are two solutions to this:
-
Use the
Receiver.data
attribute -
Run
wait()
asynchronously.
Solution #1 works because wait()
just returns a change in Receiver.data
. So if you were to draw directly from Receiver.data
, you would get the current data the Receiver stores. However, if you draw from Receiver.data
too early or too late, you will get inaccurate data. Solution #2 uses the asyncio
module. If you are not familiar, Asyncio is a module for Python that adds methods to run asynchronous functions. Using Asyncio, we can run the wait()
function as a coroutine. This does not stop the main program, but you still are able to run wait()
.
Usage Manual
This Usage Manual contains a list of all the functions and classes in CommuniCats and how to use them.
Master File
The Master File is a file that stores all of the offers. Receivers can read from only one master file, and Senders can send to any but have a default. You can have multiple master files for organization or security. Master files follow this format:
address,data
Make sure it is a COMMA as the delimiter. Leave one line of whitespace below the address,data
header, or else it will not work.
Offers
Offers are anything that has an address tied to data inside of the master file. Receivers can read these, and Senders can create these.
Sender
The Sender is a class that handles sending (writing) data into the master file. Senders can send to any master file, but have a default which is considered their 'parent'.
Syntax for creation: senderName = Sender(masterFile: string, address: string
)
-
masterFile: Contains the path to this Sender's master csv.
-
address: Optional. Contains a string of which address to send to. This will be the address this Sender will have to send to EVER. If you want a Sender to send to any address, then do not put a parameter here.
Wildcard Sender
If no address parameter is given, then this Sender is considered a 'Wildcard Sender'. Wildcard Senders can send to any address.
Sender.send()
the send()
method sends data to this Sender's master file. Use this to send data to another process.
Syntax for usage: `senderName.send(data: tuple, masterFile: string, address: string)
-
data: A tuple (or string) that stores all of the data that you want to send
-
masterFile: An override for this Sender's default master file. Use only when you want to send to a master file other than this Sender's parent.
-
address: The address to send to. Only needed when the Sender is a Wildcard Sender.
Sender.send_multiple()
the send_multiple()
method is exactly the same as the send()
method except that the address is a list of addresses that it iterates over. It sends to each address in the list.
Receiver
The Receiver is a class that handles receiving data from the master file. Receivers can only read from one master file, which is also considered their 'parent'.
Syntax for creation: receiverName = Receiver(address: string, masterFile: string, checkInterval: int)
-
address: A string of the address that this Receiver should look for.
-
masterFile: A string that contains the path to the master file this Receiver should read from.
-
checkInterval: An integer containing the interval at which this Receiver should check the master file at.
Receiver.data
The Receiver.data
attribute contains the most current data that this Receiver picked up. Use it to extract data from the Receiver for usage. In most cases, it is better to use the wait()
function.
Receiver.wait()
The wait()
function waits for a change in Receiver.data
. Once it finds a change, it returns the data after the change. This function can be used to
get new data from the master file. However, this function will halt your program until it is finished so if your program needs to continue running during this time, run this function asynchronously.