diff --git a/src/plumpy/ports.py b/src/plumpy/ports.py index 7e69bef8..399c598a 100644 --- a/src/plumpy/ports.py +++ b/src/plumpy/ports.py @@ -446,9 +446,20 @@ def get_port(self, name: str) -> Union[Port, 'PortNamespace']: namespace = name.split(self.NAMESPACE_SEPARATOR) port_name = namespace.pop(0) - if port_name not in self: + if port_name not in self and not self.dynamic: raise ValueError(f"port '{port_name}' does not exist in port namespace '{self.name}'") + if port_name not in self and self.dynamic: + self[port_name] = self.__class__( + name=port_name, + required=self.required, + validator=self.validator, + valid_type=self.valid_type, + default=self.default, + dynamic=self.dynamic, + populate_defaults=self.populate_defaults + ) + if namespace: portnamespace = cast(PortNamespace, self[port_name]) return portnamespace.get_port(self.NAMESPACE_SEPARATOR.join(namespace)) diff --git a/test/test_port.py b/test/test_port.py index 55ddbe66..eca1d09f 100644 --- a/test/test_port.py +++ b/test/test_port.py @@ -208,6 +208,27 @@ def test_port_namespace_get_port(self): port = self.port_namespace.get_port('sub.name.space.' + self.BASE_PORT_NAME) self.assertEqual(port, self.port) + def test_port_namespace_get_port_dynamic(self): + """Test that ``get_port`` does not raise if a port does not exist as long as the namespace is dynamic. + + In this case, the method should create the subnamespace on-the-fly with the same stats as the host namespace. + """ + port_namespace = PortNamespace(self.BASE_PORT_NAMESPACE_NAME, dynamic=True) + + name = 'undefined' + sub_namespace = port_namespace.get_port(name) + + assert isinstance(sub_namespace, PortNamespace) + assert sub_namespace.dynamic + assert sub_namespace.name == name + + name = 'nested.undefined' + sub_namespace = port_namespace.get_port(name) + + assert isinstance(sub_namespace, PortNamespace) + assert sub_namespace.dynamic + assert sub_namespace.name == 'undefined' + def test_port_namespace_create_port_namespace(self): """ Test the create_port_namespace function of the PortNamespace class