{"action":"created","comment":{"url":"https://api.github.com/repos/nengo/nengo/pulls/comments/65007040","id":65007040,"diff_hunk":"@@ -0,0 +1,151 @@\n+import math\n+import threading\n+import numpy as np\n+\n+import nengo\n+from nengo.utils import sockets\n+\n+\n+class SimThread(threading.Thread):\n+    def __init__(self, simulator, sim_time, lock=None, wait=False):\n+        threading.Thread.__init__(self)\n+        self.sim = simulator\n+        self.sim_time = sim_time\n+        self.lock = lock\n+        self.wait = wait\n+\n+    def run(self):\n+        if self.lock is not None and self.wait:\n+            self.lock.wait()\n+        if self.lock is not None and not self.wait:\n+            self.lock.set()\n+        self.sim.run(self.sim_time)\n+\n+\n+def test_send_recv_chain(Simulator, plt, seed, rng):\n+    # Model that sends data\n+    udp_send = sockets.UDPSocket(dest_port=54321, send_dim=1)\n+    m_send = nengo.Network(label='Send', seed=seed)\n+    with m_send:\n+        input = nengo.Node(output=lambda t: math.sin(10 * t))\n+        socket_node = nengo.Node(size_in=1, output=udp_send.run)\n+\n+        nengo.Connection(input, socket_node, synapse=None)\n+        p_s = nengo.Probe(input, synapse=None)\n+    sim_send = Simulator(m_send)\n+\n+    # Model that receives data from previous model, feeds data back to itself,\n+    # and sends that data out again\n+    udp_both = sockets.UDPSocket(dest_port=54322, local_port=54321,\n+                                 send_dim=1, recv_dim=1, timeout=1)\n+    m_both = nengo.Network(label='Both', seed=seed)\n+    with m_both:\n+        socket_node = nengo.Node(size_in=1, output=udp_both.run)\n+\n+        nengo.Connection(socket_node, socket_node, synapse=0)\n+        p_b = nengo.Probe(socket_node, synapse=None)\n+    sim_both = Simulator(m_both)\n+\n+    # Model that receives data from previous model\n+    udp_recv = sockets.UDPSocket(local_port=54322, recv_dim=1, timeout=1)\n+    m_recv = nengo.Network(label='Recv', seed=seed)\n+    with m_recv:\n+        socket_node = nengo.Node(output=udp_recv.run)\n+        p_r = nengo.Probe(socket_node, synapse=None)\n+    sim_recv = Simulator(m_recv)\n+\n+    # Create thread lock to lock sending thread until receiving thread is ready\n+    thread_lock = threading.Event()\n+\n+    # Create threads to run simulations\n+    sim_thread_send = SimThread(sim_send, 0.5, thread_lock, True)\n+    sim_thread_both = SimThread(sim_both, 0.5, thread_lock, True)\n+    sim_thread_recv = SimThread(sim_recv, 0.5, thread_lock, False)\n+    sim_thread_recv.start()\n+    sim_thread_both.start()\n+    sim_thread_send.start()\n+    sim_thread_send.join()\n+    sim_thread_both.join()\n+    sim_thread_recv.join()\n+\n+    # Cleanup sockets\n+    udp_send.close()\n+    udp_both.close()\n+    udp_recv.close()\n+\n+    # Do plots\n+    plt.subplot(3, 1, 1)\n+    plt.plot(sim_send.trange(), sim_send.data[p_s])\n+    plt.title('1: Send node. Sends to 2.')\n+    plt.subplot(3, 1, 2)\n+    plt.plot(sim_both.trange(), sim_both.data[p_b])\n+    plt.title('2: Send and recv node. Recvs from 1, sends to 3.')\n+    plt.subplot(3, 1, 3)\n+    plt.plot(sim_recv.trange(), sim_recv.data[p_r])\n+    plt.title('3: Recv node. Recvs from 2.')\n+\n+    # Note: The socket communication delays information by 1 timestep in m_both\n+    assert np.allclose(sim_send.data[p_s], sim_both.data[p_b],\n+                       atol=0.0001, rtol=0.0001)\n+    assert np.allclose(sim_both.data[p_b][:-1], sim_recv.data[p_r][1:],\n+                       atol=0.0001, rtol=0.0001)\n+\n+\n+def test_time_sync(Simulator, plt, seed, rng):\n+    udp1 = sockets.UDPSocket(dest_port=54322, local_port=54321,\n+                             send_dim=1, recv_dim=2, timeout=1)\n+    m1 = nengo.Network(label='One', seed=seed)\n+    with m1:\n+        input = nengo.Node(output=lambda t: math.sin(10 * t))\n+        socket_node = nengo.Node(size_in=1, output=udp1.run)","path":"nengo/utils/tests/test_socket.py","position":null,"original_position":100,"commit_id":"b53f21f8134dd71e5b9b21074c57ef4fcdda6379","original_commit_id":"d67bd7a6110add4cce686be282e11009e0852074","user":{"login":"Seanny123","id":1918825,"avatar_url":"https://avatars.githubusercontent.com/u/1918825?v=3","gravatar_id":"","url":"https://api.github.com/users/Seanny123","html_url":"https://github.com/Seanny123","followers_url":"https://api.github.com/users/Seanny123/followers","following_url":"https://api.github.com/users/Seanny123/following{/other_user}","gists_url":"https://api.github.com/users/Seanny123/gists{/gist_id}","starred_url":"https://api.github.com/users/Seanny123/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Seanny123/subscriptions","organizations_url":"https://api.github.com/users/Seanny123/orgs","repos_url":"https://api.github.com/users/Seanny123/repos","events_url":"https://api.github.com/users/Seanny123/events{/privacy}","received_events_url":"https://api.github.com/users/Seanny123/received_events","type":"User","site_admin":false},"body":"My opinion is that this is a special enough case that a process shouldn't be used. Another option that Terry was throwing around was making the UDP socket thing a subclass of a Node. What do you think about that option?","created_at":"2016-05-29T15:46:07Z","updated_at":"2016-05-29T15:46:07Z","html_url":"https://github.com/nengo/nengo/pull/441#discussion_r65007040","pull_request_url":"https://api.github.com/repos/nengo/nengo/pulls/441","_links":{"self":{"href":"https://api.github.com/repos/nengo/nengo/pulls/comments/65007040"},"html":{"href":"https://github.com/nengo/nengo/pull/441#discussion_r65007040"},"pull_request":{"href":"https://api.github.com/repos/nengo/nengo/pulls/441"}}},"pull_request":{"url":"https://api.github.com/repos/nengo/nengo/pulls/441","id":18258023,"html_url":"https://github.com/nengo/nengo/pull/441","diff_url":"https://github.com/nengo/nengo/pull/441.diff","patch_url":"https://github.com/nengo/nengo/pull/441.patch","issue_url":"https://api.github.com/repos/nengo/nengo/issues/441","number":441,"state":"open","locked":false,"title":"Implemented UDP socket utility function for Nodes","user":{"login":"xchoo","id":1971583,"avatar_url":"https://avatars.githubusercontent.com/u/1971583?v=3","gravatar_id":"","url":"https://api.github.com/users/xchoo","html_url":"https://github.com/xchoo","followers_url":"https://api.github.com/users/xchoo/followers","following_url":"https://api.github.com/users/xchoo/following{/other_user}","gists_url":"https://api.github.com/users/xchoo/gists{/gist_id}","starred_url":"https://api.github.com/users/xchoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xchoo/subscriptions","organizations_url":"https://api.github.com/users/xchoo/orgs","repos_url":"https://api.github.com/users/xchoo/repos","events_url":"https://api.github.com/users/xchoo/events{/privacy}","received_events_url":"https://api.github.com/users/xchoo/received_events","type":"User","site_admin":false},"body":"Initial working prototype of udp socket functions for nengo Nodes. \r\n- Sockets can be easily inserted into nengo models by creating the socket class with appropriate parameters, and then creating a nengo.Node and passing the socket class' run function as the output parameter.\r\n- Socket class is designed to be not require any special tweaking on the simulator side, and also designed to close itself after a predefined period of inactivity (or by the user if desired).\r\n","created_at":"2014-07-11T02:29:19Z","updated_at":"2016-05-29T15:46:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a1dbd1164e3968a9dadf16ad40d7177001c17a85","assignee":{"login":"Seanny123","id":1918825,"avatar_url":"https://avatars.githubusercontent.com/u/1918825?v=3","gravatar_id":"","url":"https://api.github.com/users/Seanny123","html_url":"https://github.com/Seanny123","followers_url":"https://api.github.com/users/Seanny123/followers","following_url":"https://api.github.com/users/Seanny123/following{/other_user}","gists_url":"https://api.github.com/users/Seanny123/gists{/gist_id}","starred_url":"https://api.github.com/users/Seanny123/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Seanny123/subscriptions","organizations_url":"https://api.github.com/users/Seanny123/orgs","repos_url":"https://api.github.com/users/Seanny123/repos","events_url":"https://api.github.com/users/Seanny123/events{/privacy}","received_events_url":"https://api.github.com/users/Seanny123/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/nengo/nengo/milestones/8","html_url":"https://github.com/nengo/nengo/milestones/2.1.1%20release","labels_url":"https://api.github.com/repos/nengo/nengo/milestones/8/labels","id":1145351,"number":8,"title":"2.1.1 release","description":"","creator":{"login":"tbekolay","id":203709,"avatar_url":"https://avatars.githubusercontent.com/u/203709?v=3","gravatar_id":"","url":"https://api.github.com/users/tbekolay","html_url":"https://github.com/tbekolay","followers_url":"https://api.github.com/users/tbekolay/followers","following_url":"https://api.github.com/users/tbekolay/following{/other_user}","gists_url":"https://api.github.com/users/tbekolay/gists{/gist_id}","starred_url":"https://api.github.com/users/tbekolay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tbekolay/subscriptions","organizations_url":"https://api.github.com/users/tbekolay/orgs","repos_url":"https://api.github.com/users/tbekolay/repos","events_url":"https://api.github.com/users/tbekolay/events{/privacy}","received_events_url":"https://api.github.com/users/tbekolay/received_events","type":"User","site_admin":false},"open_issues":31,"closed_issues":13,"state":"open","created_at":"2015-06-02T15:54:38Z","updated_at":"2016-05-28T21:06:29Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/nengo/nengo/pulls/441/commits","review_comments_url":"https://api.github.com/repos/nengo/nengo/pulls/441/comments","review_comment_url":"https://api.github.com/repos/nengo/nengo/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nengo/nengo/issues/441/comments","statuses_url":"https://api.github.com/repos/nengo/nengo/statuses/b53f21f8134dd71e5b9b21074c57ef4fcdda6379","head":{"label":"nengo:socket","ref":"socket","sha":"b53f21f8134dd71e5b9b21074c57ef4fcdda6379","user":{"login":"nengo","id":9197486,"avatar_url":"https://avatars.githubusercontent.com/u/9197486?v=3","gravatar_id":"","url":"https://api.github.com/users/nengo","html_url":"https://github.com/nengo","followers_url":"https://api.github.com/users/nengo/followers","following_url":"https://api.github.com/users/nengo/following{/other_user}","gists_url":"https://api.github.com/users/nengo/gists{/gist_id}","starred_url":"https://api.github.com/users/nengo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nengo/subscriptions","organizations_url":"https://api.github.com/users/nengo/orgs","repos_url":"https://api.github.com/users/nengo/repos","events_url":"https://api.github.com/users/nengo/events{/privacy}","received_events_url":"https://api.github.com/users/nengo/received_events","type":"Organization","site_admin":false},"repo":{"id":9568894,"name":"nengo","full_name":"nengo/nengo","owner":{"login":"nengo","id":9197486,"avatar_url":"https://avatars.githubusercontent.com/u/9197486?v=3","gravatar_id":"","url":"https://api.github.com/users/nengo","html_url":"https://github.com/nengo","followers_url":"https://api.github.com/users/nengo/followers","following_url":"https://api.github.com/users/nengo/following{/other_user}","gists_url":"https://api.github.com/users/nengo/gists{/gist_id}","starred_url":"https://api.github.com/users/nengo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nengo/subscriptions","organizations_url":"https://api.github.com/users/nengo/orgs","repos_url":"https://api.github.com/users/nengo/repos","events_url":"https://api.github.com/users/nengo/events{/privacy}","received_events_url":"https://api.github.com/users/nengo/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nengo/nengo","description":"A Python library for creating and simulating large-scale brain models","fork":false,"url":"https://api.github.com/repos/nengo/nengo","forks_url":"https://api.github.com/repos/nengo/nengo/forks","keys_url":"https://api.github.com/repos/nengo/nengo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nengo/nengo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nengo/nengo/teams","hooks_url":"https://api.github.com/repos/nengo/nengo/hooks","issue_events_url":"https://api.github.com/repos/nengo/nengo/issues/events{/number}","events_url":"https://api.github.com/repos/nengo/nengo/events","assignees_url":"https://api.github.com/repos/nengo/nengo/assignees{/user}","branches_url":"https://api.github.com/repos/nengo/nengo/branches{/branch}","tags_url":"https://api.github.com/repos/nengo/nengo/tags","blobs_url":"https://api.github.com/repos/nengo/nengo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nengo/nengo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nengo/nengo/git/refs{/sha}","trees_url":"https://api.github.com/repos/nengo/nengo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nengo/nengo/statuses/{sha}","languages_url":"https://api.github.com/repos/nengo/nengo/languages","stargazers_url":"https://api.github.com/repos/nengo/nengo/stargazers","contributors_url":"https://api.github.com/repos/nengo/nengo/contributors","subscribers_url":"https://api.github.com/repos/nengo/nengo/subscribers","subscription_url":"https://api.github.com/repos/nengo/nengo/subscription","commits_url":"https://api.github.com/repos/nengo/nengo/commits{/sha}","git_commits_url":"https://api.github.com/repos/nengo/nengo/git/commits{/sha}","comments_url":"https://api.github.com/repos/nengo/nengo/comments{/number}","issue_comment_url":"https://api.github.com/repos/nengo/nengo/issues/comments{/number}","contents_url":"https://api.github.com/repos/nengo/nengo/contents/{+path}","compare_url":"https://api.github.com/repos/nengo/nengo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nengo/nengo/merges","archive_url":"https://api.github.com/repos/nengo/nengo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nengo/nengo/downloads","issues_url":"https://api.github.com/repos/nengo/nengo/issues{/number}","pulls_url":"https://api.github.com/repos/nengo/nengo/pulls{/number}","milestones_url":"https://api.github.com/repos/nengo/nengo/milestones{/number}","notifications_url":"https://api.github.com/repos/nengo/nengo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nengo/nengo/labels{/name}","releases_url":"https://api.github.com/repos/nengo/nengo/releases{/id}","deployments_url":"https://api.github.com/repos/nengo/nengo/deployments","created_at":"2013-04-20T18:46:06Z","updated_at":"2016-05-24T11:56:11Z","pushed_at":"2016-05-28T21:44:40Z","git_url":"git://github.com/nengo/nengo.git","ssh_url":"git@github.com:nengo/nengo.git","clone_url":"https://github.com/nengo/nengo.git","svn_url":"https://github.com/nengo/nengo","homepage":"","size":25387,"stargazers_count":119,"watchers_count":119,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":44,"mirror_url":null,"open_issues_count":267,"forks":44,"open_issues":267,"watchers":119,"default_branch":"master"}},"base":{"label":"nengo:master","ref":"master","sha":"6d191de1650f24d18b3b593e1602ee7c7d812ba7","user":{"login":"nengo","id":9197486,"avatar_url":"https://avatars.githubusercontent.com/u/9197486?v=3","gravatar_id":"","url":"https://api.github.com/users/nengo","html_url":"https://github.com/nengo","followers_url":"https://api.github.com/users/nengo/followers","following_url":"https://api.github.com/users/nengo/following{/other_user}","gists_url":"https://api.github.com/users/nengo/gists{/gist_id}","starred_url":"https://api.github.com/users/nengo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nengo/subscriptions","organizations_url":"https://api.github.com/users/nengo/orgs","repos_url":"https://api.github.com/users/nengo/repos","events_url":"https://api.github.com/users/nengo/events{/privacy}","received_events_url":"https://api.github.com/users/nengo/received_events","type":"Organization","site_admin":false},"repo":{"id":9568894,"name":"nengo","full_name":"nengo/nengo","owner":{"login":"nengo","id":9197486,"avatar_url":"https://avatars.githubusercontent.com/u/9197486?v=3","gravatar_id":"","url":"https://api.github.com/users/nengo","html_url":"https://github.com/nengo","followers_url":"https://api.github.com/users/nengo/followers","following_url":"https://api.github.com/users/nengo/following{/other_user}","gists_url":"https://api.github.com/users/nengo/gists{/gist_id}","starred_url":"https://api.github.com/users/nengo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nengo/subscriptions","organizations_url":"https://api.github.com/users/nengo/orgs","repos_url":"https://api.github.com/users/nengo/repos","events_url":"https://api.github.com/users/nengo/events{/privacy}","received_events_url":"https://api.github.com/users/nengo/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nengo/nengo","description":"A Python library for creating and simulating large-scale brain models","fork":false,"url":"https://api.github.com/repos/nengo/nengo","forks_url":"https://api.github.com/repos/nengo/nengo/forks","keys_url":"https://api.github.com/repos/nengo/nengo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nengo/nengo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nengo/nengo/teams","hooks_url":"https://api.github.com/repos/nengo/nengo/hooks","issue_events_url":"https://api.github.com/repos/nengo/nengo/issues/events{/number}","events_url":"https://api.github.com/repos/nengo/nengo/events","assignees_url":"https://api.github.com/repos/nengo/nengo/assignees{/user}","branches_url":"https://api.github.com/repos/nengo/nengo/branches{/branch}","tags_url":"https://api.github.com/repos/nengo/nengo/tags","blobs_url":"https://api.github.com/repos/nengo/nengo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nengo/nengo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nengo/nengo/git/refs{/sha}","trees_url":"https://api.github.com/repos/nengo/nengo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nengo/nengo/statuses/{sha}","languages_url":"https://api.github.com/repos/nengo/nengo/languages","stargazers_url":"https://api.github.com/repos/nengo/nengo/stargazers","contributors_url":"https://api.github.com/repos/nengo/nengo/contributors","subscribers_url":"https://api.github.com/repos/nengo/nengo/subscribers","subscription_url":"https://api.github.com/repos/nengo/nengo/subscription","commits_url":"https://api.github.com/repos/nengo/nengo/commits{/sha}","git_commits_url":"https://api.github.com/repos/nengo/nengo/git/commits{/sha}","comments_url":"https://api.github.com/repos/nengo/nengo/comments{/number}","issue_comment_url":"https://api.github.com/repos/nengo/nengo/issues/comments{/number}","contents_url":"https://api.github.com/repos/nengo/nengo/contents/{+path}","compare_url":"https://api.github.com/repos/nengo/nengo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nengo/nengo/merges","archive_url":"https://api.github.com/repos/nengo/nengo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nengo/nengo/downloads","issues_url":"https://api.github.com/repos/nengo/nengo/issues{/number}","pulls_url":"https://api.github.com/repos/nengo/nengo/pulls{/number}","milestones_url":"https://api.github.com/repos/nengo/nengo/milestones{/number}","notifications_url":"https://api.github.com/repos/nengo/nengo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nengo/nengo/labels{/name}","releases_url":"https://api.github.com/repos/nengo/nengo/releases{/id}","deployments_url":"https://api.github.com/repos/nengo/nengo/deployments","created_at":"2013-04-20T18:46:06Z","updated_at":"2016-05-24T11:56:11Z","pushed_at":"2016-05-28T21:44:40Z","git_url":"git://github.com/nengo/nengo.git","ssh_url":"git@github.com:nengo/nengo.git","clone_url":"https://github.com/nengo/nengo.git","svn_url":"https://github.com/nengo/nengo","homepage":"","size":25387,"stargazers_count":119,"watchers_count":119,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":44,"mirror_url":null,"open_issues_count":267,"forks":44,"open_issues":267,"watchers":119,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/nengo/nengo/pulls/441"},"html":{"href":"https://github.com/nengo/nengo/pull/441"},"issue":{"href":"https://api.github.com/repos/nengo/nengo/issues/441"},"comments":{"href":"https://api.github.com/repos/nengo/nengo/issues/441/comments"},"review_comments":{"href":"https://api.github.com/repos/nengo/nengo/pulls/441/comments"},"review_comment":{"href":"https://api.github.com/repos/nengo/nengo/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nengo/nengo/pulls/441/commits"},"statuses":{"href":"https://api.github.com/repos/nengo/nengo/statuses/b53f21f8134dd71e5b9b21074c57ef4fcdda6379"}}}}
{"actor":{"display_login":"Seanny123"}}