import re
-from fints.formals import Container, SegmentHeader, DataElementGroupField, DataElementField, ReferenceMessage, SegmentSequenceField, SecurityProfile, SecurityIdentificationDetails, SecurityDateTime, EncryptionAlgorithm, KeyName, Certificate, HashAlgorithm, SignatureAlgorithm, UserDefinedSignature, Response
+from fints.formals import Container, ContainerMeta, SegmentHeader, DataElementGroupField, DataElementField, ReferenceMessage, SegmentSequenceField, SecurityProfile, SecurityIdentificationDetails, SecurityDateTime, EncryptionAlgorithm, KeyName, Certificate, HashAlgorithm, SignatureAlgorithm, UserDefinedSignature, Response
from fints.utils import classproperty, SubclassesMixin
TYPE_VERSION_RE = re.compile(r'^([A-Z]+)(\d+)$')
-class FinTS3Segment(Container, SubclassesMixin):
+class FinTS3SegmentMeta(ContainerMeta):
+ @staticmethod
+ def _check_fields_recursive(instance):
+ for name, field in instance._fields.items():
+ if not isinstance(field, (DataElementField, DataElementGroupField)):
+ raise TypeError("{}={!r} is not DataElementField or DataElementGroupField".format(name, field))
+ if isinstance(field, DataElementGroupField):
+ FinTS3SegmentMeta._check_fields_recursive(field.type)
+
+ def __new__(cls, name, bases, classdict):
+ retval = super().__new__(cls, name, bases, classdict)
+ FinTS3SegmentMeta._check_fields_recursive(retval)
+ return retval
+
+class FinTS3Segment(Container, SubclassesMixin, metaclass=FinTS3SegmentMeta):
header = DataElementGroupField(type=SegmentHeader)
@classproperty
assert list(a._fields) == ['header', 'message_size', 'hbci_version', 'dialogue_id', 'message_number', 'reference_message']
assert a._fields['header']
+def test_fints3_only_de_and_deg():
+ from fints.formals import Field, Container, DataElementGroupField, ContainerField
+
+ with pytest.raises(TypeError, match="b=.* is not DataElementField or DataElementGroupField"):
+ class Foo(FinTS3Segment):
+ a = NumericField()
+ b = Field()
+
+ class A(Container):
+ a = Field()
+
+ class B(Container):
+ b = DataElementGroupField(type=A)
+
+ with pytest.raises(TypeError, match="a=.* is not DataElementField or DataElementGroupField"):
+ class Foo(FinTS3Segment):
+ c = DataElementGroupField(type=B)
+
def test_descriptor_subclassing():
a = DataElementField(type='an')
assert isinstance(a, AlphanumericField)