pax_global_header00006660000000000000000000000064137524477530014533gustar00rootroot0000000000000052 comment=2532253350fba41b71c5cf2083d1cdaa22d27080 pybeam-0.7/000077500000000000000000000000001375244775300126565ustar00rootroot00000000000000pybeam-0.7/.travis.yml000066400000000000000000000016161375244775300147730ustar00rootroot00000000000000language: python env: - CONSTRUCT_VERSION='>=2.9,<2.10' - CONSTRUCT_VERSION='>=2.10,<2.11' python: - '2.7' - '3.4' - '3.5' - '3.6' - '3.7' - '3.8' install: - pip install construct$CONSTRUCT_VERSION - pip install -r requirements.txt script: - python setup.py test jobs: exclude: - python: '2.7' env: CONSTRUCT_VERSION='>=2.10,<2.11' - python: '3.4' env: CONSTRUCT_VERSION='>=2.10,<2.11' - python: '3.5' env: CONSTRUCT_VERSION='>=2.10,<2.11' include: - stage: deploy script: skip python: '3.6' deploy: &pypi provider: pypi user: matwey password: secure: AWqdz752Wms7YXy3m86FigQgn9XDSUI9ArCTMh0O6hu4Irbqkoa06G+XFa+zjj8CSwEYPOpv5gG1xTB/dIC+E6IaZGIDDds7Hm8G+I4vkJs8QAjuIoXANCpxMgsnFc7dpcTzYrNJ9qlYf4fQsPtHBbtPmEHatufMOrEYbg/a14k= skip_existing: true distributions: sdist bdist_wheel on: tags: true pybeam-0.7/LICENSE000066400000000000000000000021321375244775300136610ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2013 Matwey V. Kornilov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pybeam-0.7/MANIFEST.in000066400000000000000000000001451375244775300144140ustar00rootroot00000000000000include LICENSE include README.md include doc/* include requirements.txt recursive-include test *.py pybeam-0.7/README.md000066400000000000000000000017661375244775300141470ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/matwey/pybeam.svg?branch=master)](https://travis-ci.org/matwey/pybeam) [![PyPI version](https://badge.fury.io/py/pybeam.svg)](https://badge.fury.io/py/pybeam) [![Documentation Status](https://readthedocs.org/projects/pybeam/badge/?version=latest)](http://pybeam.readthedocs.io/en/latest/?badge=latest) pybeam ====== Python module to parse Erlang BEAM files. Both python 2.7 and python 3.3 are supported. Python 3.2 are known not to work. Pull-requests are always welcome. ## Quick start: ```python import pybeam p = pybeam.BeamFile("/usr/lib64/erlang/lib/appmon-2.1.14.1/ebin/appmon.beam") print(p.imports) print(p.exports) print(p.atoms) ``` ## References * [Erlang BEAM file format](http://www.erlang.se/~bjorn/beam_file_format.html) * [Erlang external term format](http://erlang.org/doc/apps/erts/erl_ext_dist.html) * [BEAM file format](http://synrc.com/publications/cat/Functional%20Languages/Erlang/BEAM.pdf) * [BEAM Wisdoms](http://beam-wisdoms.clau.se/en/latest/) pybeam-0.7/doc/000077500000000000000000000000001375244775300134235ustar00rootroot00000000000000pybeam-0.7/doc/_static/000077500000000000000000000000001375244775300150515ustar00rootroot00000000000000pybeam-0.7/doc/_static/.gitignore000066400000000000000000000000001375244775300170270ustar00rootroot00000000000000pybeam-0.7/doc/conf.py000066400000000000000000000113311375244775300147210ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os import sys sys.path.insert(0, os.path.abspath('./..')) # -- Project information ----------------------------------------------------- project = 'pybeam' copyright = '2018, Matwey V. Kornilov' author = 'Matwey V. Kornilov' # The short X.Y version version = '' # The full version, including alpha/beta/rc tags release = '' # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'pybeamdoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'pybeam.tex', 'pybeam Documentation', 'Matwey V. Kornilov', 'manual'), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'pybeam', 'pybeam Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'pybeam', 'pybeam Documentation', author, 'pybeam', 'One line description of project.', 'Miscellaneous'), ] # -- Extension configuration ------------------------------------------------- pybeam-0.7/doc/index.rst000066400000000000000000000006511375244775300152660ustar00rootroot00000000000000.. pybeam documentation master file, created by sphinx-quickstart on Thu May 3 18:01:53 2018. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to pybeam's documentation! ================================== .. toctree:: :maxdepth: 2 modules.rst Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` pybeam-0.7/doc/modules.rst000066400000000000000000000000671375244775300156300ustar00rootroot00000000000000pybeam ====== .. toctree:: :maxdepth: 4 pybeam pybeam-0.7/doc/pybeam.rst000066400000000000000000000007141375244775300154340ustar00rootroot00000000000000pybeam package ============== Submodules ---------- pybeam.beam\_file module ------------------------ .. automodule:: pybeam.beam_file :members: :undoc-members: :show-inheritance: pybeam.erlang\_types module --------------------------- .. automodule:: pybeam.erlang_types :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: pybeam :members: :undoc-members: :show-inheritance: pybeam-0.7/pybeam/000077500000000000000000000000001375244775300141335ustar00rootroot00000000000000pybeam-0.7/pybeam/__init__.py000066400000000000000000000022551375244775300162500ustar00rootroot00000000000000# # Copyright (c) 2013-2018 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from pybeam.beam_file import BeamFile __all__ = ["BeamFile"] pybeam-0.7/pybeam/beam_file.py000066400000000000000000000047601375244775300164170ustar00rootroot00000000000000# # Copyright (c) 2013-2018 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from pybeam.schema import beam class BeamFile(object): def __init__(self, f): if not hasattr(f, 'read'): f = open(f, "rb") self._chunks = beam.parse(f.read()) def selectChunkByName(self, name): return self._chunks.get(name) @property def atoms(self): atom = self.selectChunkByName(b"AtU8") atom = atom if atom is not None else self.selectChunkByName(b"Atom") return atom @property def attributes(self): attr = self.selectChunkByName(b"Attr") # convert from proplist to dict return dict(attr) if attr is not None else None @property def code(self): code = self.selectChunkByName(b"Code") return (code.set, code.opcode_max, code.labels, code.functions, code.code) @property def compileinfo(self): cinf = self.selectChunkByName(b"CInf") return dict(cinf) if cinf is not None else None @property def exports(self): expt = self.selectChunkByName(b"ExpT") atoms = self.atoms return [(atoms[e.function-1], e.arity, e.label) for e in expt.entry] if expt is not None else None @property def literals(self): litt = self.selectChunkByName(b"LitT") return litt.entry if litt is not None else None @property def imports(self): impt = self.selectChunkByName(b"ImpT") atoms = self.atoms return [(atoms[e.module-1], atoms[e.function-1], e.arity) for e in impt.entry] if impt is not None else None @property def modulename(self): return self.atoms[0] pybeam-0.7/pybeam/erlang_types.py000066400000000000000000000041251375244775300172030ustar00rootroot00000000000000# # Copyright (c) 2013-2018 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from collections import namedtuple from six import PY2 import warnings class AtomCacheReference(int): @property def index(self): warnings.warn("x.index is deprecated; use x instead", DeprecationWarning) return self Reference = namedtuple("Reference", ["node", "id", "creation"]) Port = namedtuple("Port", ["node", "id", "creation"]) Pid = namedtuple("Pid", ["node", "id", "serial", "creation"]) class String(bytes): @property def value(self): warnings.warn("x.value is deprecated; use x instead", DeprecationWarning) return self if PY2: def __getitem__(self, index): return ord(super(String, self).__getitem__(index)) class Binary(bytes): @property def value(self): warnings.warn("x.value is deprecated; use x instead", DeprecationWarning) return self Fun = namedtuple("Fun", ["arity", "uniq", "index", "module", "oldindex", "olduniq", "pid", "free"]) MFA = namedtuple("MFA", ["module", "function", "arity"]) BitBinary = namedtuple("BitBinary", ["value", "bits"]) pybeam-0.7/pybeam/schema/000077500000000000000000000000001375244775300153735ustar00rootroot00000000000000pybeam-0.7/pybeam/schema/__init__.py000066400000000000000000000023451375244775300175100ustar00rootroot00000000000000# # Copyright (c) 2013-2018 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from pybeam.schema.beam import beam from pybeam.schema.eetf import external_term __all__ = ["beam", "external_term"] pybeam-0.7/pybeam/schema/beam/000077500000000000000000000000001375244775300162775ustar00rootroot00000000000000pybeam-0.7/pybeam/schema/beam/__init__.py000066400000000000000000000031251375244775300204110ustar00rootroot00000000000000# # Copyright (c) 2013-2018 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from construct import Adapter, Const, FocusedSeq, GreedyRange, Int32ub, Prefixed, Terminated from pybeam.schema.beam.chunks import chunk class DictAdapter(Adapter): def _decode(self, obj, context, path): return dict(obj) def _encode(self, obj, context, path): return obj.items() beam = FocusedSeq("chunks", Const(b'FOR1'), "chunks" / Prefixed(Int32ub, FocusedSeq("chunks", Const(b'BEAM'), "chunks" / DictAdapter(GreedyRange(chunk)), Terminated))) __all__ = ["beam"] pybeam-0.7/pybeam/schema/beam/chunks.py000066400000000000000000000052621375244775300201510ustar00rootroot00000000000000# # Copyright (c) 2013-2018 Matwey V. Kornilov # Copyright (c) 2013 Fredrik Ahlberg # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from construct import this from construct import ( Aligned, Bytes, Compressed, GreedyBytes, Int32ub, Int8ub, PascalString, Prefixed, PrefixedArray, Sequence, Struct, Switch,) from pybeam.schema.eetf import external_term Atom = PrefixedArray(Int32ub, PascalString(lengthfield=Int8ub, encoding="latin1")) AtU8 = PrefixedArray(Int32ub, PascalString(lengthfield=Int8ub, encoding="utf8")) Attr = external_term CInf = external_term Code = Struct("headerlen" / Int32ub, "set" / Int32ub, "opcode_max" / Int32ub, "labels" / Int32ub, "functions" / Int32ub, Bytes(lambda ctx: ctx.headerlen-16), GreedyBytes) ExpT = Struct("entry" / PrefixedArray(Int32ub, Struct("function" / Int32ub, "arity" / Int32ub, "label" / Int32ub))) ImpT = Struct("entry" / PrefixedArray(Int32ub, Struct("module" / Int32ub, "function" / Int32ub, "arity" / Int32ub))) uncomp_chunk_litt = PrefixedArray(Int32ub, Prefixed(Int32ub, external_term)) LitT = Struct(Int32ub, "entry" / Compressed(uncomp_chunk_litt, "zlib")) LocT = PrefixedArray(Int32ub, Struct("function" / Int32ub, "arity" / Int32ub, "label" / Int32ub)) chunk = Sequence( "chunk_name" / Bytes(4), Aligned(4, Prefixed(Int32ub, Switch(this.chunk_name, { # "Abst" : chunk_abst, b"Atom" : Atom, b"AtU8" : AtU8, b"Attr" : Attr, b"CInf" : CInf, b"Code" : Code, b"ExpT" : ExpT, # "FunT" : chunk_funt, b"ImpT" : ImpT, # "Line" : chink_line, b"LitT" : LitT, b"LocT" : LocT, # "StrT" : chunk_strt, # "Trac" : chunk_trac, }, default=GreedyBytes)))) __all__ = ["chunk"] pybeam-0.7/pybeam/schema/eetf.py000066400000000000000000000157351375244775300167030ustar00rootroot00000000000000# # Copyright (c) 2013-2018 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # import sys from six import text_type from construct import this from construct import ( Adapter, Array, Bytes, Const, ExprAdapter, Float64b, GreedyBytes, Int16ub, Int32sb, Int32ub, Int8ub, LazyBound, PaddedString, PascalString, Prefixed, PrefixedArray, Sequence, Switch, ) from pybeam.erlang_types import ( AtomCacheReference, Binary, BitBinary, Fun, MFA, Pid, Port, Reference, String as etString,) if sys.version > '3': long = int class TupleAdapter(Adapter): def _decode(self, obj, context, path): # we got a list from construct and want to see a tuple return tuple(obj) def _encode(self, obj, context, path): return list(obj) class ListAdapter(Adapter): def _decode(self, obj, context, path): if isinstance(obj[2], list) and obj[2] == []: return obj[1] obj[1].append(obj[2]) return obj[1] def _encode(self, obj, context, path): return (len(obj), obj, []) class MapAdapter(Adapter): def _decode(self, obj, context, path): return dict(obj) def _encode(self, obj, context, path): return list(obj.items()) def BigInteger(length_field): def decode_big(obj, _ctx): (_length, isNegative, value) = obj ret = sum([d << i*8 for (d, i) in zip(value, range(0, len(value)))]) if isNegative: return -ret return ret def encode_big(obj, _ctx): isNegative = 0 if obj < 0: isNegative = 1 obj = -obj value = [] while obj > 0: value.append(obj & 0xFF) obj = obj >> 8 return (len(value), isNegative, value) return ExprAdapter(Sequence("len" / length_field, "isNegative" / Int8ub, "value" / Array(lambda ctx: ctx.len, Int8ub)), encoder=encode_big, decoder=decode_big) def tag(obj): mapping = { AtomCacheReference : 82, int : 98, float : 70, text_type : 118, # unicode in Python 2 and str in Python 3 Reference : 114, Port : 102, Pid : 103, tuple : 105, etString : 107, list : 108, Binary : 109, long : 111, Fun : 112, MFA : 113, map : 116, BitBinary : 77, } if obj == []: return 106 return mapping[obj.__class__] # Recurrent term term_ = LazyBound(lambda: term) atom_cache_ref = ExprAdapter(Int8ub, encoder=lambda obj, ctx: obj, decoder=lambda obj, ctx: AtomCacheReference(obj)) small_integer = Int8ub integer = Int32sb float_ = ExprAdapter(PaddedString(31, encoding="ascii"), encoder=lambda obj, ctx: u"{:.20e} ".format(obj), decoder=lambda obj, ctx: float(obj)) atom = PascalString(lengthfield=Int16ub, encoding="latin1") reference = ExprAdapter(Sequence("node" / term_, "id" / Int32ub, "creation" / Int8ub), encoder=lambda obj, ctx: (obj.node, obj.id, obj.creation), decoder=lambda obj, ctx: Reference(*obj)) port = ExprAdapter(Sequence("node" / term_, "id" / Int32ub, "creation" / Int8ub), encoder=lambda obj, ctx: (obj.node, obj.id, obj.creation), decoder=lambda obj, ctx: Port(*obj)) pid = ExprAdapter(Sequence("node" / term_, "id" / Int32ub, "serial" / Int32ub, "creation" / Int8ub), encoder=lambda obj, ctx: (obj.node, obj.id, obj.serial, obj.creation), decoder=lambda obj, ctx: Pid(*obj)) small_tuple = TupleAdapter(PrefixedArray(Int8ub, term_)) large_tuple = TupleAdapter(PrefixedArray(Int32ub, term_)) nil = ExprAdapter(Sequence(), encoder=lambda obj, ctx: (), decoder=lambda obj, ctx: []) string = ExprAdapter(Prefixed(Int16ub, GreedyBytes), encoder=lambda obj, ctx: obj, decoder=lambda obj, ctx: etString(obj)) list_ = ListAdapter(Sequence("len" / Int32ub, Array(this.len, term_), term_)) binary = ExprAdapter(Prefixed(Int32ub, GreedyBytes), encoder=lambda obj, ctx: obj, decoder=lambda obj, ctx: Binary(obj)) small_big = BigInteger(Int8ub) large_big = BigInteger(Int32ub) new_reference = ExprAdapter(Sequence("len" / Int16ub, "node" / term_, "creation" / Int8ub, "id" / Array(this.len, Int32ub)), encoder=lambda obj, ctx: (len(obj.id), obj.node, obj.creation, obj.id), decoder=lambda obj, ctx: Reference(obj[1], obj[3], obj[2])) small_atom = PascalString(lengthfield=Int8ub, encoding="latin1") fun = ExprAdapter(Sequence("num_free" / Int32ub, "pid" / term_, "module" / term_, "oldindex" / term_, "olduniq" / term_, "free" / Array(this.num_free, term_)), encoder=lambda obj, ctx: (len(obj.free), obj.pid, obj.module, obj.oldindex, obj.olduniq, obj.free), decoder=lambda obj, ctx: Fun(None, None, None, obj[2], obj[3], obj[4], obj[1], obj[5])) # new fun to be implemented later new_fun = fun export = ExprAdapter(Sequence("module" / LazyBound(lambda: term), "function" / LazyBound(lambda: term), "arity" / LazyBound(lambda: term)), encoder=lambda obj, ctx: (obj.module, obj.function, obj.arity), decoder=lambda obj, ctx: MFA(*obj)) bit_binary = ExprAdapter(Sequence("len" / Int32ub, "bits" / Int8ub, "data" / Bytes(this.len)), encoder=lambda obj, ctx: (len(obj.value), obj.bits, obj.value), decoder=lambda obj, ctx: BitBinary(obj[2], obj[1])) new_float = Float64b atom_utf8 = PascalString(lengthfield=Int16ub, encoding="utf8") small_atom_utf8 = PascalString(lengthfield=Int8ub, encoding="utf8") key_value = ExprAdapter(Sequence(term_, term_), encoder=lambda obj, ctx: obj, decoder=lambda obj, ctx: tuple(obj)) map_ = MapAdapter(PrefixedArray(Int32ub, key_value)) term = ExprAdapter(Sequence("tag" / Int8ub, Switch(this.tag, { 82: atom_cache_ref, 97: small_integer, 98: integer, 99: float_, 100: atom, 101: reference, 102: port, 103: pid, 104: small_tuple, 105: large_tuple, 106: nil, 107: string, 108: list_, 109: binary, 110: small_big, 111: large_big, 114: new_reference, 115: small_atom, 116: map_, 117: fun, 112: new_fun, 113: export, 77: bit_binary, 70: new_float, 118: atom_utf8, 119: small_atom_utf8, })), encoder=lambda obj, ctx: (tag(obj), obj), decoder=lambda obj, ctx: obj[1], ) erl_version_magic = Const(b'\x83') external_term = ExprAdapter(Sequence(erl_version_magic, term), encoder=lambda obj, ctx: (None, obj), decoder=lambda obj, ctx: obj[1]) __all__ = ["term", "external_term"] pybeam-0.7/requirements.txt000066400000000000000000000000401375244775300161340ustar00rootroot00000000000000construct>=2.9,<2.11 six sphinx pybeam-0.7/setup.py000066400000000000000000000013661375244775300143760ustar00rootroot00000000000000from setuptools import find_packages, setup try: from sphinx.setup_command import BuildDoc cmdclass = {'build_sphinx': BuildDoc} except ImportError: pass name="pybeam" version="0.7" test_suite="test" setup(name=name, version=version, description='Python module to parse Erlang BEAM files', url='http://github.com/matwey/pybeam', author='Matwey V. Kornilov', author_email='matwey.kornilov@gmail.com', license='MIT', packages=find_packages(exclude=(test_suite,)), test_suite=test_suite, install_requires=['construct>=2.9,<2.11', 'six'], command_options={ 'build_sphinx': { 'project': ('setup.py', name), 'version': ('setup.py', version), 'release': ('setup.py', version), 'source_dir': ('setup.py', 'doc') } }, zip_safe=False) pybeam-0.7/test/000077500000000000000000000000001375244775300136355ustar00rootroot00000000000000pybeam-0.7/test/__init__.py000066400000000000000000000002261375244775300157460ustar00rootroot00000000000000from test.schema_beam import BEAMConstructTest from test.schema_eetf import EETFConstructTest from test.beam_file import BEAMFileTest import unittest pybeam-0.7/test/beam_file.py000066400000000000000000000101571375244775300161160ustar00rootroot00000000000000# # Copyright (c) 2016 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from pybeam import beam_file from pybeam.erlang_types import String import unittest import io class BEAMFileTest(unittest.TestCase): def setUp(self): self.raw = b'FOR1\x00\x00\x02\xd4BEAMAtom\x00\x00\x00U\x00\x00\x00\x08\x08ssh_math\x04ipow\x06crypto\x07mod_pow\x10bytes_to_integer\x0bmodule_info\x06erlang\x0fget_module_info\x00\x00\x00Code\x00\x00\x00\\\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x99\x00\x00\x00\x07\x00\x00\x00\x03\x01\x10\x99\x10\x02\x12"0\x01 \'\x15\x01#(\x15\x13\x01\x0c\x000\x99 \x070\x00\x99 \x08\x10\x10\x00\x010\x99\x00\x02\x12b\x00\x01@@\x12\x03\x99\x00N\x10 \x01P\x99\x00\x02\x12b\x10\x01`@\x03\x13@\x12\x03\x99\x00N 0\x03StrT\x00\x00\x00\x00ImpT\x00\x00\x004\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\x02ExpT\x00\x00\x00(\x00\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02Attr\x00\x00\x00(\x83l\x00\x00\x00\x01h\x02d\x00\x03vsnl\x00\x00\x00\x01n\x10\x00\x8f\xde\xf9V}\xf3wr\x8a\x93\xc1p\xedDK\x9ajjCInf\x00\x00\x01@\x83l\x00\x00\x00\x04h\x02d\x00\x07optionsl\x00\x00\x00\x04h\x02d\x00\x06outdirk\x00 # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # from pybeam.schema import beam from pybeam.schema.beam.chunks import Atom, AtU8, Attr, CInf, LitT from construct import Container, StreamError from construct.core import TerminatedError import unittest class BEAMConstructTest(unittest.TestCase): def setUp(self): pass def test_beam1(self): c = beam self.assertEqual(c.parse(b'FOR1\x00\x00\x00\x04BEAM'), {}) def test_beam2(self): c = beam raw = b'FOR1\x00\x00\x02TBEAMAtU8\x00\x00\x002\x00\x00\x00\x07\x01m\x04fact\x06erlang\x01-\x01*\x0bmodule_info\x0fget_module_info\x00\x00Code\x00\x00\x00w\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x99\x00\x00\x00\x08\x00\x00\x00\x03\x01\x10\x99\x10\x02\x12"\x10\x01 \'5\x01\x03\x0e\x10\x10\x99\x10}\x05\x10\x00\x03\x11\x13@\x03\x04@\x13\x03\x99\x10\x04\x10%\x99\x10}\x05\x10\x10\x04\x03\x03\x12\x10\x13\x010+\x15\x03\x01@\x11\x03\x13\x01@\x99\x00\x02\x12b\x00\x01P@\x12\x03\x99\x00N\x10 \x01`\x99\x00\x02\x12b\x10\x01p@\x03\x13@\x12\x03\x99\x00N 0\x03\x00StrT\x00\x00\x00\x00ImpT\x00\x00\x004\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x05\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x07\x00\x00\x00\x02ExpT\x00\x00\x00(\x00\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02LocT\x00\x00\x00\x04\x00\x00\x00\x00Attr\x00\x00\x00(\x83l\x00\x00\x00\x01h\x02d\x00\x03vsnl\x00\x00\x00\x01n\x10\x007\xfc\x18\xc42\x03\xc0\xfa\xe0\x91w.a\xb8\xebqjjCInf\x00\x00\x00l\x83l\x00\x00\x00\x03h\x02d\x00\x07optionsl\x00\x00\x00\x01d\x00\rno_debug_infojh\x02d\x00\x07versionk\x00\x057.1.5h\x02d\x00\x06sourcek\x00!/home/matwey/rpmbuild/BUILD/m.erljDbgi\x00\x00\x00F\x83h\x03d\x00\rdebug_info_v1d\x00\x11erl_abstract_codeh\x02d\x00\x04nonel\x00\x00\x00\x01d\x00\rno_debug_infoj\x00\x00Line\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00A\x00\x00\x00' chunks = c.parse(raw) self.assertSetEqual(set(chunks.keys()), set([b'AtU8', b'Code', b'StrT', b'ImpT', b'ExpT', b'LocT', b'Attr', b'CInf', b'Dbgi', b'Line'])) def test_beam3(self): c = beam self.assertRaises(TerminatedError, lambda: c.parse(b'FOR1\x00\x00\x00\x0cBEAMAtU8\x00\x00\x002')) def test_chunk_atom(self): c = Atom self.assertEqual(c.parse(b'\x00\x00\x00\x00'), []) self.assertEqual(c.parse(b'\x00\x00\x00\x01\x08burtovoy'),[u"burtovoy"]) self.assertEqual(c.parse(b'\x00\x00\x00\x02\x08burtovoy\x08yegorsaf'), [u"burtovoy",u"yegorsaf"]) self.assertEqual(c.parse(c.build([])), []) self.assertEqual(c.parse(c.build([u"burtovoy"])), [u"burtovoy"]) self.assertEqual(c.parse(c.build([u"burtovoy",u"yegorsaf"])), [u"burtovoy",u"yegorsaf"]) self.assertRaises(StreamError, c.parse, b'\x00\x00\xff\x00') def test_chunk_atu8(self): c = AtU8 self.assertEqual(c.parse(b'\x00\x00\x00\x00'), []) self.assertEqual(c.parse(b'\x00\x00\x00\x01\x08burtovoy'),[u"burtovoy"]) self.assertEqual(c.parse(b'\x00\x00\x00\x01\x10\xd0\x91\xd1\x83\xd1\x80\xd1\x82\xd0\xbe\xd0\xb2\xd0\xbe\xd0\xb9'),[u"\u0411\u0443\u0440\u0442\u043e\u0432\u043e\u0439"]) def test_chunk_attr(self): c = Attr self.assertEqual(c.parse(b'\x83\x64\x00\x08burtovoy'), u"burtovoy") self.assertEqual(c.parse(c.build(u"burtovoy")), u"burtovoy") self.assertEqual(c.parse(b'\x83\x6a'), []) def test_chunk_cinf(self): c = CInf self.assertEqual(c.parse(b'\x83\x64\x00\x08burtovoy'), u"burtovoy") self.assertEqual(c.parse(c.build(u"burtovoy")), u"burtovoy") self.assertEqual(c.parse(b'\x83\x6a'), []) def test_chunk_litt1(self): c = LitT littc = b'x\x9cc```d```j\xce\x02\x00\x01\x87\x00\xf1' litt = b'\x00\x00\x00\x0a' + littc + b'\x00\x00' self.assertEqual(c.parse(litt).entry[0], []) def test_chunk_litt2(self): c = LitT litt = b'\x00\x00\x03?x\x9cuR\xc1n\xd40\x10M\xb2mi\xab]T@THP4\xea\r\x84\x96\x13|\x01\x0b\x8a\xb4\x80T8\xf4f9\xce,\xf1\xaecG\xb6S\xef\nqZ\x89/\xe0\x02\'>\x80\x8f\xe1\x17\xf8\x0e.\xd8\xde\x84\x94\x03\x97\xf1\xf8yf\xde\x9b\x19\'Ir?I\x92\xcb\xad\xf0\xf6\xa0\xca\\Z\xd0\xd4\x1fG%2U7\xca \xcd\x02ZEtO5(\xa3\x97\xdax\x9cYM\xa5\x11\xd4"aT\x88\x82\xb2\x15\x91\xb4FB5\xb7\x1b\x9a.}\xd5\xd3m\xed\xed\xc9\xdd\xdf\xe3[_\xcf\x9e\x7f~\x9c\x8d\'\xbf\xbe\xff\xfc\xe1\xb1;\xf1ebqm\x9f\xd6T\xafJ\xe5d\x90\x11\xe1$z\xb6\xf3nD,\x05o\x1em\xab\x91\xcb>~Z\x06\xc9#7\x99\t\xbe\xe6z\xfaZ\x95\xad@wH\x08\x97\x0bE\xc8\x8e\xfca\x08\xfe\x7f\xc8 \xa2T\xac\xadQZj\xb9\n"\x1e\xc4\x89d\xee\xa4\xcf\xa5L\xab\xe9L^\xf9\xd6Ca\xe8\xde\x0f\xfb\xbe\xdd\xa4\x0e!\xfd5\xc4\xdc\x0e\xe4#\xc9\xc5`<\xba\xbf]%\xe9\xb1w\xee\xf5%\x16\xadd\x81\xd6\xed\xc7\x12!\xf5[T\xf5%_\x00\x97\xc6"-A-\x802\x86\xc6p\xf9\x01\xfeQ\x0b\x1b\xd5\x82S\xad(A\xf0\x15B\xad4B\xe8P\xd7\xbbwZ\xa8\xd6\x02\x85+*Z\x04\xa5;\xc0V\x08\x1aM+l,.\x01\xd7\x8d\x0e\x04J>\x81\xd6`\x0c8\xe7\xe7P\xa1hP\xf7J\xbc\xaeWq/i\x90\x98\xa1\x0c\xc7\xb3\xddl\xc1Q\x03\xe1\xe3p\x81%8n\xab@\xe4\xd5\x9a)\xbc\xab\x94\x0b\xda\x95\x14\x1b0\rz,\x0c>\x0e!u{v\xd3\xe0r\xd8\xf4\xf1\xb0\x9a\xd9<\xbf\xcc/\xc8\xecE\xfe\xfe\xed\x85\x07\xc6\x11>\xf8{\xbf\x19\xef~\xab/\xf3\xf9\x8c\x90\xeb\xc8<\x7f\xb3CN;\x9a\t-\x8c\xff\xb3\xcc\x12\xa6\xca\xc8w\x14cG\x82\x17!e\xdb\xf54\xfc\xdb\xa0\xeb\xfa4\x87\x14\xa3\xd9\x1f2\xc5\xe6\n\x00\x00\x00' self.assertEqual(len(c.parse(litt).entry), 27) pybeam-0.7/test/schema_eetf.py000066400000000000000000000202241375244775300164520ustar00rootroot00000000000000# Copyright (c) 2013 Matwey V. Kornilov # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # import pybeam.schema.eetf as eetf from pybeam import erlang_types from six import int2byte import unittest class EETFConstructTest(unittest.TestCase): def setUp(self): pass def test_atom_cache_ref(self): c = eetf.atom_cache_ref self.assertEqual(c.parse(b'\x23'), erlang_types.AtomCacheReference(0x23)) self.assertEqual(c.parse(c.build(erlang_types.AtomCacheReference(0x23))),erlang_types.AtomCacheReference(0x23)) def test_small_integer(self): c = eetf.small_integer self.assertEqual(c.parse(b'\x23'), 0x23) self.assertEqual(c.parse(c.build(123)),123) def test_integer(self): c = eetf.integer self.assertEqual(c.parse(b'\00\xff\00\x11'), 0xff0011) self.assertEqual(c.parse(b'\xff\xff\xff\xff'), -1) self.assertEqual(c.parse(c.build(0xff0011)),0xff0011) def test_float(self): c = eetf.float_ self.assertEqual(c.parse(b' 1.12344300000000002910e+04'), 11234.43) self.assertEqual(c.parse(b'1.00000000000000000000e+00\00\00\00\00\00'), 1.0) self.assertEqual(c.parse(c.build(-3.1415926)),-3.1415926) def test_new_float(self): c = eetf.new_float self.assertEqual(c.parse(b'\x40\x00\x00\x00\x00\x00\x00\x00'), 2.0 ) self.assertEqual(c.parse(b'\xc0\x00\x00\x00\x00\x00\x00\x00'), -2.0 ) self.assertEqual(c.parse(c.build(-3.1415926)),-3.1415926) def test_atom_utf8(self): c = eetf.atom_utf8 self.assertEqual(c.parse(b'\x00\x08\xd0\xb0\xd1\x82\xd0\xbe\xd0\xbc'), u"\u0430\u0442\u043e\u043c") self.assertEqual(c.parse(c.build(u"\u0430\u0442\u043e\u043c")),u"\u0430\u0442\u043e\u043c") def test_small_atom_utf8(self): c = eetf.small_atom_utf8 self.assertEqual(c.parse(b'\x08\xd0\xb0\xd1\x82\xd0\xbe\xd0\xbc'), u"\u0430\u0442\u043e\u043c") self.assertEqual(c.parse(c.build(u"\u0430\u0442\u043e\u043c")),u"\u0430\u0442\u043e\u043c") def test_atom1(self): c = eetf.atom self.assertEqual(c.parse(b'\x00\x06myatom'), u"myatom") self.assertEqual(c.parse(c.build(u"robots")),u"robots") def test_atom2(self): raw = b'\x00\x06r\xf2b\xf3ts' c = eetf.atom self.assertEqual(c.parse(raw), u"r\u00f2b\u00f3ts") def test_small_atom1(self): c = eetf.small_atom self.assertEqual(c.parse(b'\x06myatom'), u"myatom") self.assertEqual(c.parse(c.build(u"robots")),u"robots") def test_small_atom2(self): raw = b'\x06r\xf2b\xf3ts' c = eetf.small_atom self.assertEqual(c.parse(raw), u"r\u00f2b\u00f3ts") def test_reference(self): c = eetf.reference r = erlang_types.Reference(u"myatom",0x12,0x48) self.assertEqual(c.parse(b'\x64\x00\x06myatom\x00\x00\x00\x12\x48'), r) self.assertEqual(c.parse(c.build(r)),r) self.assertEqual(c.build(r),b'\x76\x00\x06myatom\x00\x00\x00\x12\x48') def test_new_reference(self): c = eetf.new_reference r = erlang_types.Reference(u"myatom",[0x12,0x13],0x48) self.assertEqual(c.parse(b'\x00\x02\x76\x00\x06myatom\x48\x00\x00\x00\x12\x00\x00\x00\x13'), r) self.assertEqual(c.parse(c.build(r)),r) def test_port(self): c = eetf.port self.assertEqual(c.parse(b'\x64\x00\x06myatom\x00\x00\x00\x12\x48'), erlang_types.Port("myatom",0x12,0x48)) def test_pid(self): c = eetf.pid self.assertEqual(c.parse(b'\x64\x00\x06myatom\x00\x00\x00\x12\x00\x00\x00\x32\x48'), erlang_types.Pid("myatom",0x12,0x32,0x48)) def test_small_tuple(self): c = eetf.small_tuple self.assertEqual(c.parse(b"\x02\x64\x00\x06myatom\x64\x00\x06robert"), ("myatom","robert")) self.assertEqual(c.parse(c.build((1,2,u"myatom"))),(1,2,u"myatom")) def test_large_tuple(self): c = eetf.large_tuple self.assertEqual(c.parse(b"\x00\x00\x00\x02\x64\x00\x06myatom\x64\x00\x06robert"), ("myatom","robert")) self.assertEqual(c.parse(c.build((1,2,u"myatom"))),(1,2,u"myatom")) def test_list(self): c = eetf.list_ self.assertEqual(c.parse(b'\x00\x00\x00\x02\x64\x00\x08YegorSaf\x64\x00\x0aRoBurToVoY\x6a'), ["YegorSaf","RoBurToVoY"]) self.assertEqual(c.parse(c.build([1,2,3,u"OO"])),[1,2,3,u"OO"]) self.assertEqual(c.parse(c.build([u"Nu",u"poskoku"])),[u"Nu",u"poskoku"]) attrs0 = b'\x00\x00\x00\x02h\x02d\x00\x03vsnl\x00\x00\x00\x01n\x10\x00\xb3\xf2\xab&|\xd3\xdeHL\xa0\x0fV\xdf\xc1\x05\x96jh\x02d\x00\tbehaviourl\x00\x00\x00\x01d\x00\ngen_serverjj' self.assertEqual(c.parse(attrs0), [("vsn", [199414093051598402244823387542347575987]), ("behaviour", ["gen_server"])]) t1 = b'\x00\x00\x00\x01d\x00\x05alignm\x00\x00\x00\x02\x01\x00' self.assertEqual(c.parse(t1), ["align", erlang_types.Binary(b'\x01\x00')]) def test_nil(self): c = eetf.nil self.assertEqual(c.parse(b'\x6a'), []) self.assertEqual(c.parse(c.build([])),[]) def test_bitbinary(self): c = eetf.bit_binary self.assertEqual(c.parse(b'\00\00\00\x0a\x03RoBurToVoY'), erlang_types.BitBinary(b'RoBurToVoY',3)) s = erlang_types.BitBinary(b'RoBurToVoY',1) self.assertEqual(c.parse(c.build(s)),s) def test_string(self): c = eetf.string self.assertEqual(c.parse(b'\x00\x0aRoBurToVoY'), erlang_types.String(b'RoBurToVoY')) s = erlang_types.String(b'RoBurToVoY') self.assertEqual(c.parse(c.build(s)),s) n = b"\x01\x00" + b"".join(map(int2byte, range(0,256))) self.assertListEqual(list(c.parse(n)), list(range(0,256))) self.assertEqual(c.build(erlang_types.String(b"".join(map(int2byte, range(0,256))))), n) def test_binary(self): c = eetf.binary self.assertEqual(c.parse(b'\x00\x00\x00\x0aRoBurToVoY'), erlang_types.Binary(b'RoBurToVoY')) s = erlang_types.Binary(b'RoBurToVoY') self.assertEqual(c.parse(c.build(s)),s) def test_small_big(self): c = eetf.small_big self.assertEqual(c.parse(b'\x02\x00\x02\x01'), 258) self.assertEqual(c.parse(b'\x02\x01\x02\x01'), -258) self.assertEqual(c.parse(c.build(123456789123456789)),123456789123456789) def test_large_big(self): c = eetf.large_big self.assertEqual(c.parse(b'\x00\x00\x00\x02\x00\x02\x01'), 258) self.assertEqual(c.parse(c.build(123456789123456789)),123456789123456789) def test_fun(self): c = eetf.fun self.assertEqual(c.parse(b'\00\00\00\x02\x64\x00\x06myatom\x64\x00\x06myatom\x61\x13\x64\x00\x06myatom\x64\x00\x06myatom\x64\x00\x06myatom'), erlang_types.Fun(None,None,None,"myatom",0x13,"myatom","myatom",["myatom","myatom"])) def test_export(self): c = eetf.export mfa = erlang_types.MFA(u"myatom",u"myat0m",0x13) self.assertEqual(c.parse(b'\x64\x00\x06myatom\x64\x00\x06myat0m\x61\x13'),mfa) self.assertEqual(c.parse(c.build(mfa)),mfa) def test_term(self): c = eetf.term self.assertEqual(c.parse(b'\x6f\x00\x00\x00\x02\x00\x02\x01'), 258) self.assertEqual(c.parse(c.build(258)), 258) self.assertEqual(c.parse(c.build([3,2,1])), [3,2,1]) self.assertEqual(c.build(u"BurToVoY"), b'\x76\x00\x08BurToVoY') def test_external(self): c = eetf.external_term self.assertEqual(c.parse(b'\x83\x6f\x00\x00\x00\x02\x00\x02\x01'), 258) self.assertEqual(c.parse(c.build(258)), 258) self.assertEqual(c.parse(c.build([3,2,1])), [3,2,1]) self.assertEqual(c.build(u"BurToVoY"), b'\x83\x76\x00\x08BurToVoY') def test_key_value(self): c = eetf.key_value self.assertEqual(c.parse(b'a\x01a\x02'), (1,2)) self.assertEqual(c.parse(c.build((1,2))), (1,2)) def test_map(self): c = eetf.map_ self.assertEqual(c.parse(b'\x00\x00\x00\x02a\x01a\x02a\x03a\x04'), {1:2,3:4}) self.assertEqual(c.parse(c.build({1:2,3:4})), {1:2,3:4})