ErlPort - Erlang port protocol for Python

Fork me on GitHub

Erlang terms

Encoding

Function encode() can encode Python types to Erlang external term format:

>>> from erlport.erlterms import encode, Atom, String, BitBinary

Binary strings:

>>> encode("")
'\x83m\x00\x00\x00\x00'
>>> encode("test")
'\x83m\x00\x00\x00\x04test'

Bit binaries:

>>> encode(BitBinary("", 0))
'\x83M\x00\x00\x00\x00\x00'
>>> encode(BitBinary("\x80", 4))
'\x83M\x00\x00\x00\x01\x04\x80'

Atoms:

>>> encode(Atom(""))
'\x83d\x00\x00'
>>> encode(Atom("test"))
'\x83d\x00\x04test'

Integer values:

>>> encode(0)
'\x83a\x00'
>>> encode(255)
'\x83a\xff'
>>> encode(256)
'\x83b\x00\x00\x01\x00'
>>> encode(2147483647)
'\x83b\x7f\xff\xff\xff'
>>> encode(-2147483648)
'\x83b\x80\x00\x00\x00'
>>> encode(-1)
'\x83b\xff\xff\xff\xff'

Big integers:

>>> encode(2147483648)
'\x83n\x04\x00\x00\x00\x00\x80'
>>> encode(-2147483649)
'\x83n\x04\x01\x01\x00\x00\x80'
>>> encode(256 ** 256) # doctest: +ELLIPSIS
'\x83o\x00\x00\x01\x01\x00\x00...\x00\x00\x01'
>>> encode(-256 ** 256) # doctest: +ELLIPSIS
'\x83o\x00\x00\x01\x01\x01\x00...\x00\x00\x01'

Float values:

>>> encode(0.0)
'\x83F\x00\x00\x00\x00\x00\x00\x00\x00'
>>> encode(1.1)
'\x83F?\xf1\x99\x99\x99\x99\x99\x9a'
>>> encode(10.12345)
'\x83F@$?4\xd6\xa1a\xe5'

Unicode strings:

>>> encode(u"")
'\x83j'
>>> encode(u"test")
'\x83k\x00\x04test'
>>> encode(u"\x00\xff")
'\x83k\x00\x02\x00\xff'
>>> encode(u"\u0100")
'\x83l\x00\x00\x00\x01b\x00\x00\x01\x00j'
>>> encode(unicode("тест", "utf-8"))
'\x83l\x00\x00\x00\x04b\x00\x00\x04Bb\x00\x00\x045b\x00\x00\x04Ab\x00\x00\x04Bj'
>>> encode(u"X" * 65536) # doctest: +ELLIPSIS
'\x83l\x00\x01\x00\x00aXaX...aXaXj'
>>> encode(unicode("А", "utf-8") * 65536) # doctest: +ELLIPSIS
'\x83l\x00\x01\x00\x00b\x00\x00\x04\x10...b\x00\x00\x04\x10j'
>>> encode(String(u""))
'\x83j'

Lists:

>>> encode([])
'\x83j'
>>> encode([1])
'\x83k\x00\x01\x01'
>>> encode([1.0])
'\x83l\x00\x00\x00\x01F?\xf0\x00\x00\x00\x00\x00\x00j'
>>> encode([[Atom("test")], "test"])
'\x83l\x00\x00\x00\x02l\x00\x00\x00\x01d\x00\x04testjm\x00\x00\x00\x04testj'

Tuples:

>>> encode(())
'\x83h\x00'
>>> encode((1,))
'\x83h\x01a\x01'
>>> encode((("test",), Atom("test")))
'\x83h\x02h\x01m\x00\x00\x00\x04testd\x00\x04test'
>>> encode((1,) * 256) # doctest: +ELLIPSIS
'\x83i\x00\x00\x01\x00a\x01...a\x01'

Compressed terms:

>>> encode([120] * 15, compressed=True)
'\x83P\x00\x00\x00\x12x\x9c\xcbf\xe0\xaf@\x05\x00@\xc8\x07\x83'

True and False encoded as atoms:

>>> encode(True) == encode(Atom('true'))
True
>>> encode(False) == encode(Atom('false'))
True

dict encoded as (Python) ordered proplists:

>>> encode(dict(a=1,b=2,c=3)) == encode([('a', 1), ('b', 2), ('c', 3)])
True

None encoded as atom none:

>>> encode(None) == encode(Atom('none'))
True

datetime objects encoded as a tuple of two tuples:

>>> from datetime import datetime
>>> encode(datetime(2010, 4, 1, 10, 20, 30)) == encode(
...     ((2010, 4, 1), (10, 20, 30)))
True

Decoding

Function decode() can decode Erlang external term format to Python types:

>>> from erlport.erlterms import decode

Binary strings:

>>> decode('\x83m\x00\x00\x00\x00')
('', '')
>>> decode('\x83m\x00\x00\x00\x04test')
('test', '')

Bit binaries:

>>> decode('\x83M\x00\x00\x00\x00\x00')
(bits(0, ''), '')
>>> decode('\x83M\x00\x00\x00\x01\x04\x80')
(bits(4, '\x80'), '')

Atoms:

>>> decode('\x83d\x00\x00')
(atom(), '')
>>> decode('\x83d\x00\x04test')
(atom(test), '')

Integer values:

>>> decode('\x83a\x00')
(0, '')
>>> decode('\x83a\xff')
(255, '')
>>> decode('\x83b\x00\x00\x01\x00')
(256, '')
>>> decode('\x83b\x7f\xff\xff\xff')
(2147483647, '')
>>> decode('\x83b\xff\xff\xff\xff')
(-1, '')

Big integers:

>>> decode('\x83n\x00\x00')
(0, '')
>>> decode('\x83n\x01\x00\xff')
(255, '')
>>> decode('\x83n\x04\x00\x00\xca\x9a\x3b')
(1000000000, '')
>>> decode('\x83n\x04\x00\xff\xff\xff\x7f')
(2147483647, '')
>>> decode('\x83n\x04\x01\xff\xff\xff\x7f')
(-2147483647, '')
>>> decode('\x83o\x00\x00\x00\x01\x00\xff')
(255, '')
>>> decode('\x83o\x00\x00\x00\x01\x01\xff')
(-255, '')
>>> decode('\x83h\x02n\x04\x00\xbe!\x0e\rn\x04\x00^/\x0e\r')
((219029950, 219033438), '')

Float values:

>>> decode('\x83F\x00\x00\x00\x00\x00\x00\x00\x00')
(0.0, '')
>>> decode('\x83F?\xf1\x99\x99\x99\x99\x99\x9a')
(1.1000000000000001, '')
>>> decode('\x83F@$?4\xd6\xa1a\xe5')
(10.12345, '')
>>> decode('\x83c0.00000000000000000000e+00\x00\x00\x00\x00\x00')
(0.0, '')
>>> decode('\x83c1.10000000000000008882e+00\x00\x00\x00\x00\x00')
(1.1000000000000001, '')
>>> decode('\x83c1.01234500000000000597e+01\x00\x00\x00\x00\x00')
(10.12345, '')

Unicode strings:

>>> u, t = decode('\x83j')
>>> String(u), t
(string(u''), '')
>>> u, t = decode('\x83k\x00\x04test')
>>> u
[116, 101, 115, 116]
>>> String(u), t
(string(u'test'), '')
>>> u, t = decode('\x83l\x00\x00\x00\x04b\x00\x00\x04Bb\x00\x00\x045b\x00\x00\x04Ab\x00\x00\x04Bj')
>>> u
[1090, 1077, 1089, 1090]
>>> String(u), t
(string(u'\u0442\u0435\u0441\u0442'), '')
>>> u, t = decode('\x83l\x00\x01\x00\x00' + 'aX' * 65536 + 'j')
>>> u # doctest: +ELLIPSIS
[88, 88, ... 88, 88]
>>> String(u), t # doctest: +ELLIPSIS
(string(u'XX...XX'), '')

Lists:

>>> decode('\x83j')
([], '')
>>> decode('\x83l\x00\x00\x00\x01a\x01j')
([1], '')
>>> decode('\x83l\x00\x00\x00\x02l\x00\x00\x00\x01d\x00\x04testjm\x00\x00\x00\x04testj')
([[atom(test)], 'test'], '')

Tuples:

>>> decode('\x83h\x00')
((), '')
>>> decode('\x83h\x01a\x01')
((1,), '')
>>> decode('\x83h\x02h\x01m\x00\x00\x00\x04testd\x00\x04test')
((('test',), atom(test)), '')
>>> decode('\x83i\x00\x00\x01\x00' + 'a\x01' * 256) # doctest: +ELLIPSIS
((1, 1, ... 1, 1), '')

Compressed terms:

>>> decode('\x83P\x00\x00\x00\x12x\x9c\xcbf\xe0\xaf@\x05\x00@\xc8\x07\x83')
([120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120], '')
>>> decode('\x83P\x00\x00\x00\x12x\x9c\xcbf\xe0\xaf@\x05\x00@\xc8\x07\x83tail')
([120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120], 'tail')

Atoms true and false decoded as True and False:

>>> decode('\x83d\x00\x04true')
(True, '')
>>> decode('\x83d\x00\x05false')
(False, '')

Atom none decoded as None:

>>> decode('\x83d\x00\x04none')
(None, '')