Skip to content

Commit fbeeb07

Browse files
committed
Fixed #327 and #341
* Correct the boolean output behavior * Support 'x' as the "True" value for boolean field * Add test code Signed-off-by: Chin Yeung Li <[email protected]>
1 parent 23594c1 commit fbeeb07

File tree

5 files changed

+91
-27
lines changed

5 files changed

+91
-27
lines changed

src/attributecode/model.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Field(object):
7575
An ABOUT file field. The initial value is a string. Subclasses can and
7676
will alter the value type as needed.
7777
"""
78+
7879
def __init__(self, name=None, value=None, required=False, present=False):
7980
# normalized names are lowercased per specification
8081
self.name = name
@@ -113,6 +114,8 @@ def validate(self, *args, **kwargs):
113114
return errors
114115
else:
115116
# present fields should have content ...
117+
# The boolean value can be True, False and None
118+
# The value True or False is the content of boolean fields
116119
if not self.has_content:
117120
# ... especially if required
118121
if self.required:
@@ -542,9 +545,9 @@ class BooleanField(SingleLineField):
542545
def default_value(self):
543546
return None
544547

545-
flags = {'yes': True, 'y': True, 'no': False, 'n': False, 'true' : True, 'false': False, }
546-
547-
flag_values = ', '.join(flags)
548+
true_flags = ('yes', 'y', 'true', 'x')
549+
false_flags = ('no', 'n', 'false')
550+
flag_values = true_flags + false_flags
548551

549552
def _validate(self, *args, **kwargs):
550553
"""
@@ -568,7 +571,10 @@ def _validate(self, *args, **kwargs):
568571
errors.append(Error(INFO, msg))
569572
self.value = None
570573
else:
571-
self.value = self.flags.get(flag)
574+
if flag == u'yes' or flag is True:
575+
self.value = True
576+
else:
577+
self.value = False
572578
return errors
573579

574580
def get_flag(self, value):
@@ -590,8 +596,10 @@ def get_flag(self, value):
590596

591597
value = value.lower()
592598
if value in self.flag_values:
593-
# of of yes, no, true, etc.
594-
return value
599+
if value in self.true_flags:
600+
return u'yes'
601+
else:
602+
return u'no'
595603
else:
596604
return False
597605
else:
@@ -793,6 +801,7 @@ def all_fields(self, with_absent=True, with_empty=True):
793801
If with_empty, include empty fields.
794802
"""
795803
all_fields = []
804+
bool_fields = ['redistribute', 'attribute', 'track_changes', 'modified']
796805
for field in list(self.fields.values()) + list(self.custom_fields.values()):
797806
if field.required:
798807
all_fields.append(field)
@@ -805,7 +814,10 @@ def all_fields(self, with_absent=True, with_empty=True):
805814
all_fields.append(field)
806815
elif field.present and field.value:
807816
all_fields.append(field)
808-
817+
elif field.name in bool_fields:
818+
# Check is the value valid
819+
if not field.value == None:
820+
all_fields.append(field)
809821
else:
810822
if field.present:
811823
if not field.value:
@@ -1005,7 +1017,10 @@ def load(self, location, use_mapping=False, mapping_file=None):
10051017
and then join with the 'about_resource_path'
10061018
"""
10071019
running_inventory = True
1008-
errs = self.load_dict(saneyaml.load(input_text), base_dir, running_inventory, use_mapping, mapping_file)
1020+
# wrap the value of the boolean field in quote to avoid
1021+
# automatically convertion from yaml.load
1022+
input = util.wrap_boolean_value(input_text)
1023+
errs = self.load_dict(saneyaml.load(input), base_dir, running_inventory, use_mapping, mapping_file)
10091024
errors.extend(errs)
10101025
except Exception as e:
10111026
msg = 'Cannot load invalid ABOUT file: %(location)r: %(e)r\n' + str(e)
@@ -1043,22 +1058,6 @@ def load_dict(self, fields_dict, base_dir, running_inventory=False,
10431058
# 'Field licenses is not a supported field and is ignored.'
10441059
licenses_field = (key, value)
10451060
fields.remove(licenses_field)
1046-
"""
1047-
# Generate about_resource_path if not present so that it can be validate
1048-
# the existence of the about_resource
1049-
arp_present = False
1050-
about_resource_value = u''
1051-
about_parent = u''
1052-
for n, v in fields:
1053-
about_parent = dirname(self.about_file_path)
1054-
if n == u'about_resource_path':
1055-
arp_present = True
1056-
elif n == u'about_resource':
1057-
about_resource_value = v
1058-
if not arp_present:
1059-
#about_parent = dirname(self.about_file_path)
1060-
fields.append((u'about_resource_path', u'.' + posixpath.join(about_parent, about_resource_value)))
1061-
"""
10621061
errors = self.process(
10631062
fields, about_file_path, running_inventory, base_dir,
10641063
license_notice_text_location, use_mapping, mapping_file)
@@ -1079,7 +1078,7 @@ def dumps(self, with_absent=False, with_empty=True):
10791078
license_file = []
10801079
license_url = []
10811080
file_fields = ['about_resource_path', 'notice_file', 'changelog_file', 'author_file']
1082-
1081+
bool_fields = ['redistribute', 'attribute', 'track_changes', 'modified']
10831082
for field in self.all_fields(with_absent, with_empty):
10841083
if field.name == 'license_key' and field.value:
10851084
license_key = field.value
@@ -1097,7 +1096,9 @@ def dumps(self, with_absent=False, with_empty=True):
10971096
elif field.name in file_fields and field.value:
10981097
about_data[field.name] = list(field.value.keys())[0]
10991098
else:
1100-
about_data[field.name] = field.value
1099+
if field.value or (field.name in bool_fields and not field.value == None):
1100+
about_data[field.name] = field.value
1101+
11011102
# Group the same license information in a list
11021103
license_group = list(zip_longest(license_key, license_name, license_file, license_url))
11031104
for lic_group in license_group:

src/attributecode/util.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,21 @@ def check_duplicate_keys_about_file(context):
151151
return dup_keys
152152

153153

154+
def wrap_boolean_value(context):
155+
bool_fields = ['redistribute', 'attribute', 'track_changes', 'modified']
156+
input = []
157+
for line in context.splitlines():
158+
key = line.partition(':')[0]
159+
if key in bool_fields:
160+
value = "'" + line.partition(':')[2].strip() + "'"
161+
updated_line = key + ': ' + value
162+
input.append(updated_line)
163+
else:
164+
input.append(line)
165+
updated_context = '\n'.join(input)
166+
return updated_context
167+
168+
154169
def get_absolute(location):
155170
"""
156171
Return an absolute normalized location.

tests/test_model.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,6 @@ def test_About_dumps(self):
706706
a = model.About(test_file)
707707
assert [] == a.errors
708708

709-
# Since the licenses group was not processed,
710709
expected = u'''about_resource: .
711710
author:
712711
- Jillian Daguil
@@ -797,6 +796,27 @@ def test_About_dumps_does_not_dump_not_present_with_absent_False(self):
797796
result = a.dumps(with_absent=False)
798797
assert set(expected) == set(result)
799798

799+
def test_About_dumps_with_different_boolean_value(self):
800+
test_file = get_test_loc('parse/complete2/about2.ABOUT')
801+
a = model.About(test_file)
802+
expected_error_msg = "Field track_changes: Invalid flag value: 'blah' is not one of"
803+
assert len(a.errors) == 1
804+
assert expected_error_msg in a.errors[0].message
805+
806+
expected = u'''about_resource: .
807+
808+
name: AboutCode
809+
version: 0.11.0
810+
811+
redistribute: no
812+
attribute: yes
813+
modified: yes
814+
'''
815+
816+
result = a.dumps()
817+
assert set(expected) == set(result)
818+
819+
800820
def test_About_dumps_does_not_dump_present__empty_with_absent_False(self):
801821
test_file = get_test_loc('parse/complete2/about.ABOUT')
802822
a = model.About(test_file)

tests/test_util.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,25 @@ def test_check_duplicate_keys_about_file(self):
457457
expected = ['notes']
458458
assert expected == util.check_duplicate_keys_about_file(test)
459459

460+
def test_wrap_boolean_value(self):
461+
test = '''
462+
name: test
463+
notes: some notes
464+
465+
license_expression: mit
466+
modified: yes
467+
track_changes: no
468+
'''
469+
expected = '''
470+
name: test
471+
notes: some notes
472+
473+
license_expression: mit
474+
modified: 'yes'
475+
track_changes: 'no'
476+
'''
477+
assert expected == util.wrap_boolean_value(test)
478+
460479
def test_check_duplicate_keys_about_file_with_multiline(self):
461480
test = '''
462481
name: test
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
about_resource: .
2+
3+
name: AboutCode
4+
version: 0.11.1
5+
6+
redistribute: n
7+
attribute: yes
8+
track_changes: blah
9+
modified: True

0 commit comments

Comments
 (0)