@@ -118,6 +118,17 @@ def _check_value(self, value):
118118 with suppress (NotImplementedError ):
119119 self ._render_value (value )
120120
121+ def _check_value_length (self , value ):
122+ if self .max_length is not None and len (value ) > self .max_length :
123+ raise ValueError ("Value {!r} cannot be rendered: max_length={} exceeded" .format (value , self .max_length ))
124+
125+ if self .min_length is not None and len (value ) < self .min_length :
126+ raise ValueError ("Value {!r} cannot be rendered: min_length={} not reached" .format (value , self .min_length ))
127+
128+ if self .length is not None and len (value ) != self .length :
129+ raise ValueError ("Value {!r} cannot be rendered: length={} not satisfied" .format (value , self .length ))
130+
131+
121132class TypedField (Field , SubclassesMixin ):
122133 flat_length = 1
123134
@@ -145,6 +156,15 @@ def __init__(self, type=None, *args, **kwargs):
145156class DataElementField (TypedField ):
146157 pass
147158
159+ class FieldRenderFormatStringMixin :
160+ FORMAT_STRING = None
161+
162+ def _render_value (self , value ):
163+ retval = self .FORMAT_STRING .format (value )
164+ self ._check_value_length (retval )
165+
166+ return retval
167+
148168class ContainerField (TypedField ):
149169 def _check_value (self , value ):
150170 if self .type :
@@ -168,8 +188,10 @@ def flat_length(self):
168188class DataElementGroupField (ContainerField ):
169189 pass
170190
171- class GenericField (DataElementField ):
191+ class GenericField (FieldRenderFormatStringMixin , DataElementField ):
172192 type = None
193+ FORMAT_STRING = "{}"
194+
173195 def _parse_value (self , value ):
174196 warnings .warn ("Generic field used for type {!r} value {!r}" .format (self .type , value ))
175197 return value
@@ -188,8 +210,9 @@ def _parse_value(self, value):
188210 warnings .warn ("Generic field used for type {!r} value {!r}" .format (self .type , value ))
189211 return value
190212
191- class TextField (DataElementField ):
213+ class TextField (FieldRenderFormatStringMixin , DataElementField ):
192214 type = 'txt'
215+ FORMAT_STRING = "{}" ## FIXME Restrict CRLF
193216
194217 def _parse_value (self , value ): return str (value )
195218
@@ -199,30 +222,38 @@ class AlphanumericField(TextField):
199222class DTAUSField (DataElementField ):
200223 type = 'dta'
201224
202- class NumericField (DataElementField ):
225+ class NumericField (FieldRenderFormatStringMixin , DataElementField ):
203226 type = 'num'
227+ FORMAT_STRING = "{:d}"
204228
205229 def _parse_value (self , value ):
206230 _value = str (value )
207231 if len (_value ) > 1 and _value [0 ] == '0' :
208232 raise TypeError ("Leading zeroes not allowed for value of type 'num': {!r}" .format (value ))
209233 return int (_value , 10 )
210234
211- class DigitsField (DataElementField ):
235+ class DigitsField (FieldRenderFormatStringMixin , DataElementField ):
212236 type = 'dig'
237+ FORMAT_STRING = "{}"
213238
214239 def _parse_value (self , value ):
215240 _value = str (value )
216241 if not re .match (r'^\d*$' , _value ):
217242 raise TypeError ("Only digits allowed for value of type 'dig': {!r}" .format (value ))
218243 return _value
219244
220- class FloatField (DataElementField ):
245+ class FloatField (FieldRenderFormatStringMixin , DataElementField ):
221246 type = 'float'
222247
223248class BinaryField (DataElementField ):
224249 type = 'bin'
225250
251+ def _render_value (self , value ):
252+ retval = bytes (value )
253+ self ._check_value_length (retval )
254+
255+ return retval
256+
226257 def _parse_value (self , value ): return bytes (value )
227258
228259
0 commit comments