def nb_retrieve(self, value_id):
        """ Remote call from ``py.erl``: Retrieves a historical value by index.
        """
        if value_id in self.history_:
            return Atom('ok'), self.history_[value_id]

        return Atom('error'), Atom('not_found')
Exemple #2
0
    def link(self, pid1, pid2, local_only=False):
        """ Check each of processes pid1 and pid2 if they are local, mutually
            link them. Assume remote process handles its own linking.

            :param pid1: First pid
            :type pid1: term.pid.Pid
            :param pid2: Second pid
            :type pid2: term.pid.Pid
            :param local_only: If set to True, linking to remote pids will send
                LINK message over distribution protocol
        """
        if pid1.is_local_to(self):
            if pid1 in self.processes_:
                self.processes_[pid1].add_link(pid2)
            else:
                # not exists
                self.send_exit_signal(pid2, pid1, Atom("noproc"))

        elif not local_only:
            link_m = ('link', pid2, pid1)
            self._dist_command(receiver_node=pid1.node_name_, message=link_m)

        if pid2.is_local_to(self):
            if pid2 in self.processes_:
                self.processes_[pid2].add_link(pid1)
            else:
                # not exists
                self.send_exit_signal(pid1, pid2, Atom("noproc"))

        elif not local_only:
            link_m = ('link', pid1, pid2)
            self._dist_command(receiver_node=pid2.node_name_, message=link_m)
    def _control_term_send(from_pid, dst):
        """ Creates a control term for dist protocol.

            :type from_pid: term.pid.Pid
            :type dst: term.atom.Atom or term.pid.Pid
        """
        if isinstance(dst, Atom):
            return CONTROL_TERM_REG_SEND, from_pid, Atom(''), dst
        else:
            return CONTROL_TERM_SEND, Atom(''), dst
Exemple #4
0
 def _trigger_monitors(self, reason):
     """ On process exit inform all monitor owners that monitor us about the
         exit reason.
     """
     node = self.get_node()
     for (monitor_ref, monitor_owner) in self._monitored_by.items():
         down_msg = (Atom("DOWN"), monitor_ref, Atom("process"), self.pid_,
                     reason)
         node.send_nowait(sender=self.pid_,
                          receiver=monitor_owner,
                          message=down_msg)
Exemple #5
0
 def _encode_map(self, codec):
     """ Try a map #{1 => 2, ok => error} """
     sample = bytes([
         py_impl.ETF_VERSION_TAG, py_impl.TAG_MAP_EXT, 0, 0, 0, 2,
         py_impl.TAG_SMALL_INT, 1, py_impl.TAG_SMALL_INT, 2,
         py_impl.TAG_SMALL_ATOM_UTF8_EXT, 2, 111, 107,
         py_impl.TAG_SMALL_ATOM_UTF8_EXT, 5, 101, 114, 114, 111, 114
     ])
     val = {1: 2, Atom("ok"): Atom("error")}
     bin1 = codec.term_to_binary(val, None)
     self.assertEqual(bin1, sample)
Exemple #6
0
 def _decode_map(self, codec):
     """ Try a map #{1 => 2, ok => error} """
     data = self._etf_bytes([
         131, py_impl.TAG_MAP_EXT, 0, 0, 0, 2, py_impl.TAG_SMALL_INT, 1,
         py_impl.TAG_SMALL_INT, 2, py_impl.TAG_ATOM_EXT, 0, 2, 111, 107,
         py_impl.TAG_ATOM_EXT, 0, 5, 101, 114, 114, 111, 114
     ])
     (val, tail) = codec.binary_to_term(data, None)
     self.assertTrue(isinstance(val, dict))
     self.assertEqual(val, {1: 2, Atom("ok"): Atom("error")})
     self.assertExpectedTail(tail)
        def resolve_arg(key_val):
            key, pyrlangval_tuple = key_val
            if isinstance(pyrlangval_tuple, tuple) \
                    and pyrlangval_tuple[0] == Atom("$pyrlangval"):
                return key, self._retrieve_value(pyrlangval_tuple)

            return key, pyrlangval_tuple
Exemple #8
0
    def _encode_atom_utf8(self, codec):
        # Create and encode 'hallå...hallå' 50 times (300 bytes)
        repeat1 = 50
        example1 = bytes([py_impl.ETF_VERSION_TAG,
                          py_impl.TAG_ATOM_UTF8_EXT, 1, (300-256)]) \
                   + (bytes("hallå", "utf8") * repeat1)
        b1 = codec.term_to_binary(Atom("hallå" * repeat1), None)
        self.assertEqual(b1, example1)

        # Create and encode 'hallå...hallå' 5 times (30 bytes)
        repeat2 = 5
        example2 = bytes([py_impl.ETF_VERSION_TAG,
                          py_impl.TAG_SMALL_ATOM_UTF8_EXT, 30]) \
                   + (bytes("hallå", "utf8") * repeat2)
        b2 = codec.term_to_binary(Atom("hallå" * repeat2), None)
        self.assertEqual(b2, example2)
 def __init__(self, node) -> None:
     """ :param node: pyrlang.node.Node
     """
     GenServer.__init__(self,
                        node_name=node.node_name_,
                        accepted_calls=['is_auth'])
     node.register_name(self, Atom('net_kernel'))
Exemple #10
0
    def _encode_list(self, codec):
        """ Encode list of something, an improper list and an empty list. """
        example1 = bytes([py_impl.ETF_VERSION_TAG,
                          py_impl.TAG_LIST_EXT,
                          0, 0, 0, 2,  # length
                          py_impl.TAG_SMALL_INT, 1,
                          py_impl.TAG_SMALL_ATOM_UTF8_EXT, 2, 111, 107,
                          py_impl.TAG_NIL_EXT])
        b1 = codec.term_to_binary([1, Atom("ok")], None)
        self.assertEqual(b1, example1)

        example2 = bytes([py_impl.ETF_VERSION_TAG, py_impl.TAG_LIST_EXT,
                          0, 0, 0, 1,  # length
                          py_impl.TAG_SMALL_INT, 1,
                          py_impl.TAG_SMALL_ATOM_UTF8_EXT, 2, 111, 107])
        b2 = codec.term_to_binary(ImproperList([1], Atom("ok")), None)
        self.assertEqual(b2, example2)
Exemple #11
0
 def _tuple(self, codec):
     """ Encode a tuple """
     example1 = bytes([py_impl.ETF_VERSION_TAG,
                       py_impl.TAG_SMALL_TUPLE_EXT,
                       2,  # length
                       py_impl.TAG_SMALL_INT, 1,
                       py_impl.TAG_SMALL_ATOM_UTF8_EXT, 2, 111, 107])
     b1 = codec.term_to_binary((1, Atom("ok")), None)
     self.assertEqual(b1, example1)
Exemple #12
0
    def __init__(self) -> None:
        """ :param node: pyrlang.node.Node
        """
        Process.__init__(self)
        node = self.node_db.get()
        node.register_name(self, Atom('rex'))

        self.traceback_depth_ = 5
        """ This being non-zero enables formatting exception tracebacks with the
Exemple #13
0
    def _on_exit_signal(self, reason):
        """ Internal function triggered between message handling. """
        if reason is None:
            reason = Atom('normal')

        self.is_exiting_ = True
        self._trigger_monitors(reason)
        self._trigger_links(reason)

        n = self.node_db.get(self.node_name_)
        n.on_exit_process(self.pid_, reason)
Exemple #14
0
    def _encode_atom(self, codec):
        """ Try an atom 'hello' encoded as Latin1 atom (16-bit length)
            or small atom (8bit length)
        """
        # Create and encode 'hello...hello' 52 times (260 bytes)
        # Expect UTF8 back because encoder only does UTF8 atoms
        repeat1 = 52
        example1 = bytes([py_impl.ETF_VERSION_TAG,
                          py_impl.TAG_ATOM_UTF8_EXT, 1, 4]) \
                   + (b'hello' * repeat1)
        b1 = codec.term_to_binary(Atom("hello" * repeat1), None)
        self.assertEqual(b1, example1)

        # Create and encode 'hello...hello' 5 times (25 bytes)
        repeat2 = 5
        example2 = bytes([py_impl.ETF_VERSION_TAG,
                          py_impl.TAG_SMALL_ATOM_UTF8_EXT, 25]) \
                   + (b'hello' * repeat2)
        b2 = codec.term_to_binary(Atom("hello" * repeat2), None)
        self.assertEqual(b2, example2)
Exemple #15
0
    def _on_exit_signal(self, reason):
        """ Internal function triggered between message handling. """
        if reason is None:
            reason = Atom('normal')

        self.is_exiting_ = True
        self._trigger_monitors(reason)
        self._trigger_links(reason)

        from pyrlang import Node
        n = Node.all_nodes[self.node_name_]
        n.on_exit_process(self.pid_, reason)
Exemple #16
0
 def _decode_improper_list(self, codec):
     # Test data is [1 | ok]
     data3 = self._etf_bytes([
         131, py_impl.TAG_LIST_EXT, 0, 0, 0, 1, py_impl.TAG_SMALL_INT, 1,
         py_impl.TAG_ATOM_EXT, 0, 2, 111, 107
     ])
     (val3, tail3) = codec.binary_to_term(data3, None)
     self.assertTrue(
         isinstance(val3, ImproperList),
         "Expected list, got: %s (%s)" % (val3.__class__.__name__, val3))
     self.assertEqual(val3, ImproperList([1], Atom("ok")))
     self.assertExpectedTail(tail3)
Exemple #17
0
    def nb_call(self, msg):
        """ Remote call from ``py.erl``: Calls function defined in ``args``,
            stores the result in history.

            :param msg: contains param in msg[1] ``path``: list of strings
                where first one is to be imported and remaining are used to
                find the function; ``args``: list of arguments for the callable;
                ``kwargs``; ``immediate``: will return the value instead of the
                value ref if this is ``True``, also will not update the history.
            :returns: Index for stored history value.
        """
        param = msg[1]
        call_path = param[Atom("path")]
        call_args = self._resolve_valuerefs_in_args(param[Atom("args")])
        call_kwargs = self._resolve_valuerefs_in_kwargs(param[Atom("kwargs")])
        call_imm = param[Atom("immediate")]

        fn = self._resolve_path(call_path)
        result = fn(*call_args, **call_kwargs)

        if call_imm:
            return Atom('value'), result

        index = self._store_result(result)
        return Atom('ok'), result.__class__.__name__, index
Exemple #18
0
    def _decode_tuple(self, codec):
        """ Try decode some tuple values """
        data1 = self._etf_bytes([
            131, py_impl.TAG_SMALL_TUPLE_EXT, 2, py_impl.TAG_SMALL_INT, 1,
            py_impl.TAG_ATOM_EXT, 0, 2, 111, 107
        ])
        (val1, tail1) = codec.binary_to_term(data1, None)
        self.assertEqual((1, Atom("ok")), val1)
        self.assertExpectedTail(tail1)

        data2 = self._etf_bytes([
            131, py_impl.TAG_LARGE_TUPLE_EXT, 0, 0, 0, 2,
            py_impl.TAG_SMALL_INT, 1, py_impl.TAG_ATOM_EXT, 0, 2, 111, 107
        ])
        (val2, tail2) = codec.binary_to_term(data2, None)
        self.assertEqual((1, Atom("ok")), val2)
        self.assertExpectedTail(tail2)

        # Empty tuple
        data3 = self._etf_bytes([131, py_impl.TAG_SMALL_TUPLE_EXT, 0])
        (val3, tail3) = codec.binary_to_term(data3, None)
        self.assertEqual((), val3)
        self.assertExpectedTail(tail3)
Exemple #19
0
class NetKernel(GenServer):
    """ A special process which registers itself as ``net_kernel`` and handles
        one specific ``is_auth`` message, which is used by ``net_adm:ping``.
    """
    def __init__(self) -> None:
        """ :param node: pyrlang.node.Node
        """
        super().__init__()
        self.node_db.get().register_name(self, Atom('net_kernel'))

    @call(lambda msg: type(msg) == tuple and len(msg) == 2 and msg[0] == Atom(
        'is_auth'))
    def is_auth(self, msg):
        return Atom('yes')
    def nb_batch(self, batch: List[tuple], param: Dict[Atom, any]):
        """ Take a remote call from Erlang to execute batch of Python calls. """
        if not batch:
            return Atom("error"), Atom("batch_empty")

        call_imm = param[Atom("immediate")]
        for bitem in batch:
            call_path = bitem[Atom("path")]
            call_args = self._resolve_valuerefs_in_args(bitem[Atom("args")])
            call_kwargs = self._resolve_valuerefs_in_kwargs(
                bitem[Atom("kwargs")])
            call_ret = bitem[Atom("ret")]

            fn = self._resolve_path(call_path)
            result = fn(*call_args, **call_kwargs)

            last_result_name = self._store_result_as(result, call_ret)

        if call_imm:
            return Atom("value"), result

        return Atom("ok"), result.__class__.__name__, last_result_name
Exemple #21
0
    def _trigger_links(self, reason):
        """ Pass any exit reason other than 'normal' to linked processes.
            If Reason is 'kill' it will be converted to 'killed'.
        """
        if isinstance(reason, Atom):
            if reason == 'normal':
                return

            elif reason == 'kill':
                reason = Atom('killed')

        node = self.get_node()
        for link in self._links:
            # For local pids, just forward them the exit signal
            node.send_link_exit_notification(sender=self.pid_,
                                             receiver=link,
                                             reason=reason)
Exemple #22
0
    def _decode_list(self, codec):
        """ Try decode some list values """
        data1 = self._etf_bytes([131, py_impl.TAG_NIL_EXT])
        (val1, tail1) = codec.binary_to_term(data1, None)
        self.assertEqual([], val1)
        self.assertExpectedTail(tail1)

        # Test data is [1, ok]
        data2 = self._etf_bytes([
            131, py_impl.TAG_LIST_EXT, 0, 0, 0, 2, py_impl.TAG_SMALL_INT, 1,
            py_impl.TAG_ATOM_EXT, 0, 2, 111, 107, py_impl.TAG_NIL_EXT
        ])
        (val2, tail2) = codec.binary_to_term(data2, None)
        self.assertTrue(
            isinstance(val2, list),
            "Expected list, got: %s (%s)" % (val2.__class__.__name__, val2))
        self.assertEqual(val2, [1, Atom("ok")])
        self.assertExpectedTail(tail2)
Exemple #23
0
def call(name, msg_len=2):
    """ specific decorator function

        Handle the decorator where we expect a tuple of a specific size and
        the first item being an atom with specific name
    """
    atom = Atom(name)

    def pattern_match(msg):
        if type(msg) != tuple:
            return False
        if len(msg) != msg_len:
            return False
        if msg[0] != atom:
            return False
        return True

    return main_call(pattern_match)
    def _resolve_path(self, p: List[str]) -> Callable:
        """ Imports p[0] and then follows the list p, by applying getattr()
            repeatedly. """
        if isinstance(p, str):
            p = [p]

        # First element would be the import, or a stored value reference
        first_path_element = p[0]
        if isinstance(first_path_element, tuple) \
                and first_path_element[0] == Atom("$pyrlangval"):
            # First element is {'$pyrlangval', X} - query the value
            val = self._retrieve_value(first_path_element)
        else:
            # First element is a string, import it
            val = __import__(as_str(first_path_element))

        # Follow the elements in path, and getattr deeper
        for item in p[1:]:
            val = getattr(val, as_str(item))

        return val
Exemple #25
0
    def destroy(self):
        """ Closes incoming and outgoing connections and destroys the local
            node. This is Python, so some refs from running async handlers
            may remain.
        """
        self.is_exiting_ = True

        import copy
        all_processes = copy.copy(self.processes_)
        for p in all_processes.values():
            p.exit(Atom('killed'))
        self.processes_.clear()
        self.reg_names_.clear()

        for dproto in self.dist_nodes_.values():
            dproto.destroy()
        self.dist_nodes_.clear()

        self.dist_.destroy()
        del Node.all_nodes[self.node_name_]

        self.engine_.destroy()
 def is_auth():
     return Atom('yes')
Exemple #27
0
 def __etf__(self):
     """ This function will fire if no "encode_hook" was passed in
         options, and the library doesn't know what to do with this
         'CustomClass'
     """
     return Atom('custom-member!')
Exemple #28
0
 def encode_hook_fn(obj):
     """ This function will fire if "encode_hook" is passed in encode
         options dict.
     """
     if isinstance(obj, Class1):
         return Atom('custom-hook!')
Exemple #29
0
 def catch_all_fn(obj):
     """ This function will fire if "encode_hook" is passed in encode
         options dict with the key "catch_all" present.
     """
     if isinstance(obj, Class1):
         return Atom('custom-hook!')
        def resolve_arg(pyrlangval_tuple):
            if isinstance(pyrlangval_tuple, tuple) \
                    and pyrlangval_tuple[0] == Atom("$pyrlangval"):
                return self._retrieve_value(pyrlangval_tuple)

            return pyrlangval_tuple