예제 #1
0
    def test_lambda_default(self):
        """Test that an input port can specify a lambda as a default."""
        port_namespace = PortNamespace('base')

        # Defining lambda for default that returns incorrect type should not except at construction
        port_namespace['port'] = InputPort('port',
                                           valid_type=Int,
                                           default=lambda: 'string')

        # However, pre processing the namespace, which shall evaluate the default followed by validation will fail
        inputs = port_namespace.pre_process({})
        self.assertIsNotNone(port_namespace.validate(inputs))

        # Passing an explicit value for the port will forego the default and validation on returned inputs should pass
        inputs = port_namespace.pre_process({'port': Int(5)})
        self.assertIsNone(port_namespace.validate(inputs))

        # Redefining the port, this time with a correct default
        port_namespace['port'] = InputPort('port',
                                           valid_type=Int,
                                           default=lambda: Int(5))

        # Pre processing the namespace shall evaluate the default and return the int node
        inputs = port_namespace.pre_process({})
        self.assertIsInstance(inputs['port'], Int)
        self.assertEqual(inputs['port'].value, 5)

        # Passing an explicit value for the port will forego the default
        inputs = port_namespace.pre_process({'port': Int(3)})
        self.assertIsInstance(inputs['port'], Int)
        self.assertEqual(inputs['port'].value, 3)
예제 #2
0
    def test_with_non_db(self):
        """Ports inserted to a `PortNamespace` should inherit the `non_db` attribute if not explicitly set."""
        namespace_non_db = True
        port_namespace = PortNamespace('namespace', non_db=namespace_non_db)

        # When explicitly set upon port construction, value should not be inherited even when different
        port = InputPort('storable', non_db=False)
        port_namespace['storable'] = port
        self.assertEqual(port.non_db, False)

        port = InputPort('not_storable', non_db=True)
        port_namespace['not_storable'] = port
        self.assertEqual(port.non_db, True)

        # If not explicitly defined, it should inherit from parent namespace
        port = InputPort('not_storable')
        port_namespace['not_storable'] = port
        self.assertEqual(port.non_db, namespace_non_db)
예제 #3
0
    def __init__(self, port_namespace: PortNamespace) -> None:
        """Dynamically construct the get and set properties for the ports of the given port namespace.

        For each port in the given port namespace a get and set property will be constructed dynamically
        and added to the ProcessBuilderNamespace. The docstring for these properties will be defined
        by calling str() on the Port, which should return the description of the Port.

        :param port_namespace: the inputs PortNamespace for which to construct the builder

        """
        # pylint: disable=super-init-not-called
        self._port_namespace = port_namespace
        self._valid_fields = []
        self._data = {}

        # The name and port objects have to be passed to the defined functions as defaults for
        # their arguments, because this way the content at the time of defining the method is
        # saved. If they are used directly in the body, it will try to capture the value from
        # its enclosing scope at the time of being called.
        for name, port in port_namespace.items():

            self._valid_fields.append(name)

            if isinstance(port, PortNamespace):
                self._data[name] = ProcessBuilderNamespace(port)

                def fgetter(self, name=name):
                    return self._data.get(name)
            elif port.has_default():

                def fgetter(self, name=name, default=port.default):  # type: ignore # pylint: disable=cell-var-from-loop
                    return self._data.get(name, default)
            else:

                def fgetter(self, name=name):
                    return self._data.get(name, None)

            def fsetter(self, value, name=name):
                self._data[name] = value

            fgetter.__doc__ = str(port)
            getter = property(fgetter)
            getter.setter(fsetter)  # pylint: disable=too-many-function-args
            setattr(self.__class__, name, getter)
예제 #4
0
    def test_validate_port_name(self):
        """This test will ensure that illegal port names will raise a `ValueError` when trying to add it."""
        port = InputPort('port')
        port_namespace = PortNamespace('namespace')

        illegal_port_names = [
            'two__underscores',
            'three___underscores',
            '_leading_underscore',
            'trailing_underscore_',
            'non_numeric_%',
            'including.period',
            'disallowed👻unicodecharacters',
            'white space',
            'das-hes',
        ]

        for port_name in illegal_port_names:
            with self.assertRaises(ValueError):
                port_namespace[port_name] = port
예제 #5
0
    def test_serialize_type_check(self):
        """Test that `serialize` will include full port namespace in exception message."""
        base_namespace = 'base'
        nested_namespace = 'some.nested.namespace'
        port_namespace = PortNamespace(base_namespace)
        port_namespace.create_port_namespace(nested_namespace)

        with self.assertRaisesRegex(
                TypeError, f'.*{base_namespace}.*{nested_namespace}.*'):
            port_namespace.serialize(
                {'some': {
                    'nested': {
                        'namespace': Dict()
                    }
                }})
예제 #6
0
    def test_serialize_type_check(self):
        """Test that `serialize` will include full port namespace in exception message."""
        base_namespace = 'base'
        nested_namespace = 'some.nested.namespace'
        port_namespace = PortNamespace(base_namespace)
        port_namespace.create_port_namespace(nested_namespace)

        # pylint: disable=deprecated-method
        # The `assertRaisesRegexp` method is deprecated in python 3 but assertRaisesRegex` does not exist in python 2
        with self.assertRaisesRegexp(
                TypeError, '.*{}.*{}.*'.format(base_namespace,
                                               nested_namespace)):
            port_namespace.serialize(
                {'some': {
                    'nested': {
                        'namespace': {Dict()}
                    }
                }})