Repository: opensistemas-hub/osbrain (python)

Issue:
Allow running agents without alias
If an alias is missing, maybe a random alias should be generated.

Pull request:
Auto generate names for agents
Fixes #223 

I  was unsure how to test it, though. This is the best solution I could come up with.

Patch:
diff --git a/osbrain/agent.py b/osbrain/agent.py
index 4ae5504..9876896 100644
--- a/osbrain/agent.py
+++ b/osbrain/agent.py
@@ -205,10 +205,13 @@ class Agent():
     running : bool
         Set to `True` if the agent is running (executing the main loop).
     """
-    def __init__(self, name=None, host=None, serializer=None, transport=None,
+    def __init__(self, name='', host=None, serializer=None, transport=None,
                  attributes=None):
         self.uuid = unique_identifier()
         self.name = name
+        if not self.name:
+            self.name = self.uuid.decode()
+
         self.host = host
         if not self.host:
             self.host = '127.0.0.1'
@@ -241,14 +244,18 @@ class Agent():
                   handler=self._handle_loopback_safe, transport='inproc',
                   serializer='pickle')
 
-        if attributes:
-            for key, value in attributes.items():
-                if hasattr(self, key):
-                    raise KeyError('Agent already has "%s" attribute!' % key)
-                setattr(self, key, value)
-
+        self._set_attributes(attributes)
         self.on_init()
 
+    def _set_attributes(self, attributes):
+        if not attributes:
+            return
+
+        for key, value in attributes.items():
+            if hasattr(self, key):
+                raise KeyError('Agent already has "%s" attribute!' % key)
+            setattr(self, key, value)
+
     def on_init(self):
         """
         This user-defined method is to be executed after initialization.
@@ -1724,7 +1731,7 @@ class AgentProcess(multiprocessing.Process):
     Agent class. Instances of an Agent are system processes which
     can be run independently.
     """
-    def __init__(self, name, nsaddr=None, addr=None, serializer=None,
+    def __init__(self, name='', nsaddr=None, addr=None, serializer=None,
                  transport=None, base=Agent, attributes=None):
         super().__init__()
         self.name = name
@@ -1759,6 +1766,7 @@ class AgentProcess(multiprocessing.Process):
             self.queue.put(format_exception())
             return
 
+        self.name = self.agent.name
         uri = self._daemon.register(self.agent)
         try:
             ns.register(self.name, uri, safe=True)
@@ -1768,7 +1776,7 @@ class AgentProcess(multiprocessing.Process):
         finally:
             ns.release()
 
-        self.queue.put('STARTED')
+        self.queue.put('STARTED:'+self.name)
 
         self._daemon.requestLoop(lambda: not self.shutdown_event.is_set())
         self._daemon.unregister(self.agent)
@@ -1811,10 +1819,11 @@ class AgentProcess(multiprocessing.Process):
         """
         super().start()
         status = self.queue.get()
-        if status == 'STARTED':
-            return
-        raise RuntimeError('An error occured while creating the daemon!' +
-                           '\n===============\n'.join(['', status, '']))
+        if not status.startswith('STARTED'):
+            raise RuntimeError('An error occured while creating the daemon!' +
+                               '\n===============\n'.join(['', status, '']))
+
+        return status.partition(':')[-1]
 
     def kill(self):
         """
@@ -1832,7 +1841,7 @@ class AgentProcess(multiprocessing.Process):
         self.kill()
 
 
-def run_agent(name, nsaddr=None, addr=None, base=Agent, serializer=None,
+def run_agent(name='', nsaddr=None, addr=None, base=Agent, serializer=None,
               transport=None, safe=None, attributes=None):
     """
     Ease the agent creation process.
@@ -1842,7 +1851,7 @@ def run_agent(name, nsaddr=None, addr=None, base=Agent, serializer=None,
 
     Parameters
     ----------
-    name : str
+    name : str, default is ''
         Agent name or alias.
     nsaddr : SocketAddress, default is None
         Name server address.
@@ -1862,10 +1871,12 @@ def run_agent(name, nsaddr=None, addr=None, base=Agent, serializer=None,
     """
     if not nsaddr:
         nsaddr = os.environ.get('OSBRAIN_NAMESERVER_ADDRESS')
-    AgentProcess(name, nsaddr=nsaddr, addr=addr, base=base,
-                 serializer=serializer, transport=transport,
-                 attributes=attributes).start()
-    proxy = Proxy(name, nsaddr, safe=safe)
+    agent = AgentProcess(name=name, nsaddr=nsaddr, addr=addr, base=base,
+                         serializer=serializer, transport=transport,
+                         attributes=attributes)
+    agent_name = agent.start()
+
+    proxy = Proxy(agent_name, nsaddr, safe=safe)
     proxy.run()
     proxy.wait_for_running()
 


Test patch:
diff --git a/osbrain/tests/test_agent.py b/osbrain/tests/test_agent.py
index 980dc68..22b58d2 100644
--- a/osbrain/tests/test_agent.py
+++ b/osbrain/tests/test_agent.py
@@ -39,6 +39,18 @@ def test_agent_uuid():
     assert all(isinstance(identifier, bytes) for identifier in bunch)
 
 
+def test_agent_auto_generated_name(nsproxy):
+    """
+    If an agent is initialized without a name, a globally unique one must be
+    auto generated for it.
+    """
+    count = 10
+    names = set([run_agent().get_attr('name') for x in range(count)])
+    assert all(isinstance(name, str) for name in names)
+    assert len(names) == count
+    assert names == set(nsproxy.agents())
+
+
 def test_early_agent_proxy(nsproxy):
     """
     It must be possible to create a Proxy when the registration of the new