From 1894de29b41dc9685bfab74891552a1169ec92c8 Mon Sep 17 00:00:00 2001
From: Stefano Borini <sborini@enthought.com>
Date: Thu, 10 Aug 2017 13:30:47 +0100
Subject: [PATCH] Added trait for ZMQ socket url

---
 force_bdss/api.py                     |  5 +++++
 force_bdss/local_traits.py            | 22 +++++++++++++++++++++-
 force_bdss/tests/test_local_traits.py | 23 ++++++++++++++++++++++-
 3 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/force_bdss/api.py b/force_bdss/api.py
index fb6af34..60980c9 100644
--- a/force_bdss/api.py
+++ b/force_bdss/api.py
@@ -27,3 +27,8 @@ from .notification_listeners.i_notification_listener_factory import INotificatio
 from .notification_listeners.base_notification_listener import BaseNotificationListener  # noqa
 from .notification_listeners.base_notification_listener_factory import BaseNotificationListenerFactory  # noqa
 from .notification_listeners.base_notification_listener_model import BaseNotificationListenerModel  # noqa
+
+from .local_traits import (
+    ZMQSocketURL,
+    Identifier
+)
diff --git a/force_bdss/local_traits.py b/force_bdss/local_traits.py
index 1c5e3f1..7bd1e07 100644
--- a/force_bdss/local_traits.py
+++ b/force_bdss/local_traits.py
@@ -1,4 +1,5 @@
-from traits.api import Regex, String
+import re
+from traits.api import Regex, BaseStr, String
 
 #: Used for variable names, but allow also empty string as it's the default
 #: case and it will be present if the workflow is saved before actually
@@ -6,6 +7,25 @@ from traits.api import Regex, String
 Identifier = Regex(regex="(^[^\d\W]\w*\Z|^\Z)")
 
 
+class ZMQSocketURL(BaseStr):
+    def validate(self, object, name, value):
+        super(ZMQSocketURL, self).validate(object, name, value)
+        m = re.match(
+            "tcp://(\\d{1,3})\.(\\d{1,3})\.(\\d{1,3})\.(\\d{1,3}):(\\d+)",
+            value)
+        if m is None:
+            self.error(object, name, value)
+
+        a, b, c, d, port = m.groups()
+
+        if not all(map(lambda x: 0 <= int(x) <= 255, (a, b, c, d))):
+            self.error(object, name, value)
+
+        if not (1 <= int(port) <= 65535):
+            self.error(object, name, value)
+
+        return value
+
 #: Identifies a CUBA type with its key. At the moment a String with
 #: no validation, but will come later.
 CUBAType = String()
diff --git a/force_bdss/tests/test_local_traits.py b/force_bdss/tests/test_local_traits.py
index d61e6d2..e7d8281 100644
--- a/force_bdss/tests/test_local_traits.py
+++ b/force_bdss/tests/test_local_traits.py
@@ -1,12 +1,13 @@
 import unittest
 from traits.api import HasStrictTraits, TraitError
 
-from force_bdss.local_traits import Identifier, CUBAType
+from force_bdss.local_traits import Identifier, CUBAType, ZMQSocketURL
 
 
 class Traited(HasStrictTraits):
     val = Identifier()
     cuba = CUBAType()
+    socket_url = ZMQSocketURL()
 
 
 class TestLocalTraits(unittest.TestCase):
@@ -25,3 +26,23 @@ class TestLocalTraits(unittest.TestCase):
         c = Traited()
         c.cuba = "PRESSURE"
         self.assertEqual(c.cuba, "PRESSURE")
+
+    def test_zmq_socket_url(self):
+        c = Traited()
+
+        for working in ["tcp://127.0.0.1:12345",
+                        "tcp://255.255.255.255:65535",
+                        "tcp://1.1.1.1:65535"]:
+            c.socket_url = working
+            self.assertEqual(c.socket_url, working)
+
+        for broken in ["tcp://270.0.0.1:12345",
+                       "tcp://0.270.0.1:12345",
+                       "tcp://0.0.270.1:12345",
+                       "tcp://0.0.0.270:12345",
+                       "url://255.255.255.255:65535",
+                       "whatever",
+                       "tcp://1.1.1.1:100000"]:
+            with self.assertRaises(TraitError):
+                c.socket_url = broken
+
-- 
GitLab