Skip to content

Repository files navigation

Erlastic

Installation

pip3 install git+https://github.com/skosch/python-erlastic

Usage

Erlastic allows you to serialize/deserialize python objects into erlang binary term.

Basic usage is :

importerlasticpy_struct=erlastic.decode(binary_term)
binary=erlastic.encode(py_struct)

Sending and receiving from Python

The library contains also a function to use python with erlastic in an erlang port to communicate erlang binary term : port_communication() which return (mailbox,port). They are both python coroutines (executed generator) so you can communicate with erlang coroutine using python abstractions :

So for instance, if you want to create a Python script which receives a 2-tuple of numbers {A, B} and returns {ok, A/B} or {error, divisionbyzero}, then you can use:

fromerlasticimportport_connection, AtomasAmailbox, port=port_connection()
for (a, b) inmailbox:
ifb!=0:
port.send((A("ok"), a/b))
else:
port.send((A("error"), A("divisionbyzero")))

Converting between bytes and strings

Strings are sent as raw bytes with unknown character encoding. To recursively convert data from raw bytes to Python strings, you can pass received data through a function like

defconvert_to_string(data):
ifisinstance(data, bytes): returndata.decode('ascii') # or 'utf-8' ...ifisinstance(data, dict): returndict(map(convert_to_string, data.items()))
ifisinstance(data, tuple): returntuple(map(convert_to_string, data))
ifisinstance(data, list): returnlist(map(convert_to_string, data))
returndata

Printing to the terminal from iex

If the output of Python's print statements aren't showing up in your terminal, try printing to stderr instead, using a function like eprint below:

importsysimportpprintpprinter=pprint.PrettyPrinter(indent=2, stream=sys.stderr, width=80)
defeprint(*args):
pprinter.pprint(args)

Sending and receiving from Erlang or Elixir

and at the erlang side, use -u python parameter to prevent python output buffering, use 4 bytes packet length because it is the configuration used by the python generators.

Port=open_port({spawn,"python3 -u division.py"},[binary,{packet,4}]),
Div=fun(A,B)->
Port! {self(),{command,term_to_binary({A,B})}},
receive {Port,{data,Bin}}->binary_to_term(Bin) after1000->{error,timeout} endend,
io:format("send {A,B}=~p, python result : ~p~n",[{32,10},Div(32,10)]),
io:format("send {A,B}=~p, python result : ~p~n",[{2,0},Div(2,0)]),
io:format("send {A,B}=~p, python result : ~p~n",[{1,1},Div(1,1)])

or in Elixir:

port=Port.open({:spawn,"python3 -u division.py"},[:binary,:exit_status,packet: 4])div=fn(a,b)->sendport,{self(),{:command,:erlang.term_to_binary({a,b})}}receivedo{^port,{_,b}}->binary_to_term(b)after100->{:error,:timeout}endendIO.puts"send {a, b}={32, 10}, python result: #{inspectdiv.(32,10)}"IO.puts"send {a, b}={2, 0}, python result: #{inspectdiv.(2,0)}"IO.puts"send {a, b}={1, 1}, python result: #{inspectdiv.(1,1)}"

About

UTF8-ready fork: Erlang binary term codec and port interface. Modeled after Erlectricity.

Resources

Stars

10 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages