@@ -720,6 +720,108 @@ def __eq__(self, other):
720720 and self .value == other .value )
721721
722722
723+ class BooleanAndNumbericField (SingleLineField ):
724+ """
725+ Field with either a boolean value or a numeric value. Validated value is
726+ False, True, None or numeric value.
727+ """
728+
729+ def default_value (self ):
730+ return None
731+
732+ true_flags = ('yes' , 'y' , 'true' , 'x' )
733+ false_flags = ('no' , 'n' , 'false' )
734+ flag_values = true_flags + false_flags
735+
736+ def _validate (self , * args , ** kwargs ):
737+ """
738+ Check that flag are valid with either boolean value or numeric value. Default flag to
739+ False. Return a list of errors.
740+ """
741+ errors = super (BooleanAndNumbericField ,
742+ self )._validate (* args , ** kwargs )
743+ self .about_file_path = kwargs .get ('about_file_path' )
744+ flag = self .get_value (self .original_value )
745+ if flag is False :
746+ name = self .name
747+ val = self .original_value
748+ about_file_path = self .about_file_path
749+ flag_values = self .flag_values
750+ msg = (u'Path: %(about_file_path)s - Field %(name)s: Invalid value: %(val)r is not '
751+ u'one of: %(flag_values)s and it is not a numeric value.' % locals ())
752+ errors .append (Error (ERROR , msg ))
753+ self .value = None
754+ elif flag is None :
755+ name = self .name
756+ msg = (u'Field %(name)s: field is present but empty. ' % locals ())
757+ errors .append (Error (INFO , msg ))
758+ self .value = None
759+ else :
760+ if flag == u'yes' or flag is True :
761+ self .value = True
762+ elif flag == u'no' :
763+ self .value = False
764+ else :
765+ self .value = flag
766+ return errors
767+
768+ def get_value (self , value ):
769+ """
770+ Return a normalized existing value if found in the list of
771+ possible values or None if empty or False if not found or original value
772+ if it is not a boolean value
773+ """
774+ if value is None or value == '' :
775+ return None
776+
777+ if isinstance (value , bool ):
778+ return value
779+ else :
780+ if isinstance (value , str ):
781+ value = value .strip ()
782+ if not value :
783+ return None
784+
785+ value = value .lower ()
786+ if value in self .flag_values :
787+ if value in self .true_flags :
788+ return u'yes'
789+ else :
790+ return u'no'
791+ else :
792+ if value .isdigit ():
793+ return value
794+ else :
795+ return False
796+ elif isinstance (value , int ):
797+ return value
798+ else :
799+ return False
800+
801+ @property
802+ def has_content (self ):
803+ """
804+ Return true if it has content regardless of what value, False otherwise
805+ """
806+ if self .original_value :
807+ return True
808+ return False
809+
810+ def _serialized_value (self ):
811+ # default normalized values for serialization
812+ if self .value :
813+ if isinstance (self .value , bool ):
814+ return u'yes'
815+ else :
816+ return self .value
817+ elif self .value is False :
818+ return u'no'
819+ else :
820+ # self.value is None
821+ # TODO: should we serialize to No for None???
822+ return u''
823+
824+
723825def validate_fields (fields , about_file_path , running_inventory , base_dir ,
724826 reference_dir = None ):
725827 """
@@ -810,7 +912,7 @@ def set_standard_fields(self):
810912 ('notice_url' , UrlField ()),
811913
812914 ('redistribute' , BooleanField ()),
813- ('attribute' , BooleanField ()),
915+ ('attribute' , BooleanAndNumbericField ()),
814916 ('track_changes' , BooleanField ()),
815917 ('modified' , BooleanField ()),
816918 ('internal_use_only' , BooleanField ()),
0 commit comments