Skip to content

Commit aca15df

Browse files
committed
#562 - Remove the requirement for about_resource
* `about_resource` is now not a mandatory field * Updated docs (spec, references, changelog etc...) * Updated version and spec version Signed-off-by: Chin Yeung Li <[email protected]>
1 parent 35d1047 commit aca15df

File tree

11 files changed

+56
-97
lines changed

11 files changed

+56
-97
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
==============================
22
Changelog
33

4-
20xx-xx-xx
5-
Release 10.2.0
4+
2024-xx-xx
5+
Release 11.0.0
66

77
* Add character support (at most 2 characters) for `attribute` field
88
* Strip empty newline characters when loading an inventory
99
* Catch invalid license_expression
1010
* Update the specification to 3.3.2
1111
* Support declared_license_expression" and "other_license_expression"
12+
* Updated "about_resource" to be an optional field
13+
* Updated spec to v4.0.0 as moving `about_resource` from mandatory to optional
1214

1315

1416
2023-09-25

about.ABOUT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
about_resource: .
22
name: AboutCode-toolkit
3-
version: 10.1.0
3+
version: 11.0.0
44
author: Jillian Daguil, Chin Yeung Li, Philippe Ombredanne, Thomas Druez
55
copyright: Copyright (c) nexB Inc.
66
description: |

docs/source/general.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ it will copy and store next to the .ABOUT files.
7979
* - Standard Field Name
8080
- Description
8181
- Notes
82-
* - about_resource
83-
- Name/path of the component resource
84-
- Mandatory
8582
* - name
8683
- Component name
8784
- Mandatory
85+
* - about_resource
86+
- Name/path of the component resource
87+
- Optional
8888
* - ignored_resources
8989
- List of paths ignored from the ``about_resource``
9090
- Optional

docs/source/reference.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ output.csv
824824
Special Notes
825825
-------------
826826
When using the field_filters configuration, all the standard required
827-
columns (about_resource and name) and the user defined required_fields
827+
columns (name) and the user defined required_fields
828828
need to be included.
829829

830830
Notes

docs/source/specification.rst

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.. _specification:
22

33
===============================
4-
ABOUT File Specification v3.3.2
4+
ABOUT File Specification v4.0.0
55
===============================
66

77
Purpose
@@ -228,15 +228,12 @@ in any case combination.
228228
Referencing the file or directory documented by an ABOUT file
229229
-------------------------------------------------------------
230230

231-
An ABOUT file documents one file or directory. The mandatory ``about_resource``
231+
An ABOUT file documents one file or directory. The ``about_resource``
232232
field reference the documented file or directory. The value of the ``about_resource``
233233
field is the name or path of the referenced file or directory. There is also a
234234
``ignored_resources`` field which can be used to ignore a set of subpaths inside the
235235
directory which is being documented in the ABOUT file.
236236

237-
A tool processing an ABOUT file must report an error if the ``about_resource``
238-
field is missing.
239-
240237
By convention, an ABOUT file is often stored in the same directory side-by-side
241238
to the file or directory that it documents, but this is not mandatory.
242239

@@ -267,18 +264,18 @@ In this example, the ABOUT file documents the current directory, using a "." per
267264
268265
about_resource: .
269266
270-
Other Mandatory fields
267+
Mandatory fields
271268
----------------------
272269

273-
When a tool processes an ABOUT file, it must issue an error if these
274-
mandatory field are missing.
270+
When a tool processes an ABOUT file, it must issue an error if the
271+
mandatory field is missing.
275272

276-
- about_resource: The resource this file referencing to.
277273
- name: Component name.
278274

279275
Optional Information fields
280276
---------------------------
281277

278+
- about_resource: The resource this file referencing to.
282279
- ignored_resources: A list of paths under the ``about_resource`` path, which are
283280
not documented in the ABOUT file, and the information in the ABOUT file does not
284281
apply to these subpaths.

src/attributecode/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
import saneyaml
2222

23-
__version__ = '10.1.0'
23+
__version__ = '11.0.0'
2424

25-
__about_spec_version__ = '3.3.2'
25+
__about_spec_version__ = '4.0.0'
2626

2727
__copyright__ = """
2828
Copyright (c) nexB Inc. All rights reserved. http://dejacode.org

src/attributecode/gen.py

Lines changed: 19 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,18 @@ def load_inventory(location, from_attrib=False, base_dir=None, scancode=False, r
152152
else:
153153
inventory = load_json(location)
154154

155-
try:
156-
arp_list = []
157-
errors = []
155+
arp_list = []
156+
errors = []
158157

159-
if is_spreadsheet:
160-
# Only the .csv and .xlsx may have newline issue
161-
stripped_inv = strip_inventory_value(inventory)
162-
else:
163-
stripped_inv = inventory
158+
if is_spreadsheet:
159+
# Only the .csv and .xlsx may have newline issue
160+
stripped_inv = strip_inventory_value(inventory)
161+
else:
162+
stripped_inv = inventory
164163

165-
for component in stripped_inv:
166-
if not from_attrib:
164+
for component in stripped_inv:
165+
if not from_attrib:
166+
if 'about_resource' in component:
167167
arp = component['about_resource']
168168
dup_err = check_duplicated_about_resource(arp, arp_list)
169169
if dup_err:
@@ -176,16 +176,11 @@ def load_inventory(location, from_attrib=False, base_dir=None, scancode=False, r
176176
if invalid_about_filename and not invalid_about_filename in errors:
177177
errors.append(invalid_about_filename)
178178

179-
newline_in_file_err = check_newline_in_file_field(component)
180-
if newline_in_file_err:
181-
errors.extend(newline_in_file_err)
179+
newline_in_file_err = check_newline_in_file_field(component)
180+
if newline_in_file_err:
181+
errors.extend(newline_in_file_err)
182182

183-
if errors:
184-
return errors, abouts
185-
except Exception as e:
186-
# TODO: why catch ALL Exception
187-
msg = "The essential field 'about_resource' is not found in the <input>"
188-
errors.append(Error(CRITICAL, msg))
183+
if errors:
189184
return errors, abouts
190185

191186
custom_fields_list = []
@@ -203,8 +198,8 @@ def load_inventory(location, from_attrib=False, base_dir=None, scancode=False, r
203198
errors.append(Error(CRITICAL, msg))
204199
return errors, abouts
205200
# Set about file path to '' if no 'about_resource' is provided from
206-
# the input for `attrib`
207-
if not 'about_resource' in fields:
201+
# the input
202+
if 'about_resource' not in fields:
208203
afp = ''
209204
else:
210205
afp = fields.get(model.About.ABOUT_RESOURCE_ATTR)
@@ -228,11 +223,6 @@ def load_inventory(location, from_attrib=False, base_dir=None, scancode=False, r
228223
updated_resource_value = basename(resource_path)
229224
fields['about_resource'] = updated_resource_value
230225

231-
# Set 'about_resource' to '.' if no 'about_resource' is provided from
232-
# the input for `attrib`
233-
elif not 'about_resource' in fields and from_attrib:
234-
fields['about_resource'] = u'.'
235-
236226
ld_errors = about.load_dict(
237227
fields,
238228
base_dir,
@@ -268,7 +258,6 @@ def generate(location, base_dir, android=None, reference_dir=None, fetch_license
268258
Load ABOUT data from a CSV inventory at `location`. Write ABOUT files to
269259
base_dir. Return errors and about objects.
270260
"""
271-
not_exist_errors = []
272261
notice_dict = {}
273262
api_url = ''
274263
api_key = ''
@@ -294,7 +283,6 @@ def generate(location, base_dir, android=None, reference_dir=None, fetch_license
294283
scancode=scancode,
295284
worksheet=worksheet
296285
)
297-
298286
if gen_license:
299287
license_dict, err = model.pre_process_and_fetch_license_dict(
300288
abouts, api_url=api_url, api_key=api_key)
@@ -309,6 +297,9 @@ def generate(location, base_dir, android=None, reference_dir=None, fetch_license
309297
about.about_file_path = about.about_file_path.strip()
310298
if about.about_file_path.startswith('/'):
311299
about.about_file_path = about.about_file_path.lstrip('/')
300+
# Use the name as the ABOUT file name if about_resource is empty
301+
if not about.about_file_path:
302+
about.about_file_path = about.name.value
312303
dump_loc = join(bdir, about.about_file_path.lstrip('/'))
313304

314305
# The following code is to check if there is any directory ends with spaces
@@ -328,30 +319,6 @@ def generate(location, base_dir, android=None, reference_dir=None, fetch_license
328319
continue
329320

330321
try:
331-
# Generate value for 'about_resource' if it does not exist
332-
if not about.about_resource.value:
333-
about.about_resource.value = dict()
334-
about_resource_value = ''
335-
if about.about_file_path.endswith('/'):
336-
about_resource_value = u'.'
337-
else:
338-
about_resource_value = basename(about.about_file_path)
339-
about.about_resource.value[about_resource_value] = None
340-
about.about_resource.present = True
341-
# Check for the existence of the 'about_resource'
342-
# If the input already have the 'about_resource' field, it will
343-
# be validated when creating the about object
344-
loc = util.to_posix(dump_loc)
345-
about_file_loc = loc
346-
path = join(dirname(util.to_posix(about_file_loc)),
347-
about_resource_value)
348-
if not exists(path):
349-
path = util.to_posix(path.strip(UNC_PREFIX_POSIX))
350-
path = normpath(path)
351-
msg = (u'Field about_resource: '
352-
u'%(path)s '
353-
u'does not exist' % locals())
354-
errors.append(Error(INFO, msg))
355322

356323
licenses_dict = {}
357324
if gen_license:

src/attributecode/model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ class About(object):
874874
ABOUT_RESOURCE_ATTR = 'about_resource'
875875

876876
# Required fields
877-
required_fields = ['name', ABOUT_RESOURCE_ATTR]
877+
required_fields = ['name']
878878

879879
def get_required_fields(self):
880880
return [f for f in self.fields if f.required]
@@ -886,7 +886,7 @@ def set_standard_fields(self):
886886
is simpler.
887887
"""
888888
self.fields = dict([
889-
('about_resource', AboutResourceField(required=True)),
889+
('about_resource', AboutResourceField()),
890890
('ignored_resources', AboutResourceField()),
891891
('name', SingleLineField(required=True)),
892892
('version', SingleLineField()),

tests/test_gen.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,19 @@ def test_load_inventory_without_about_resource(self):
109109
from_attrib = False
110110
errors, abouts = gen.load_inventory(
111111
location, base_dir=base_dir, from_attrib=from_attrib)
112-
expected_error = [Error(
113-
CRITICAL, "The essential field 'about_resource' is not found in the <input>")]
112+
expected = (
113+
'''name: AboutCode
114+
version: 0.11.0
115+
license_expression: apache-2.0
116+
licenses:
117+
- key: apache-2.0
118+
name: apache-2.0
119+
'''
120+
)
114121

115-
assert errors == expected_error
116-
assert abouts == []
122+
assert errors == []
123+
result = [a.dumps() for a in abouts]
124+
assert expected == result[0]
117125

118126
def test_load_inventory_without_about_resource_from_attrib(self):
119127
location = get_test_loc('test_gen/inv_no_about_resource.csv')
@@ -126,8 +134,7 @@ def test_load_inventory_without_about_resource_from_attrib(self):
126134
assert len(errors) == expected_num_errors
127135

128136
expected = (
129-
'''about_resource: .
130-
name: AboutCode
137+
'''name: AboutCode
131138
version: 0.11.0
132139
license_expression: apache-2.0
133140
licenses:

tests/test_model.py

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -478,12 +478,10 @@ def test_About_loads_ignored_resources_field(self):
478478
result = [f.name for f in a.all_fields() if f.present]
479479
assert expected == result
480480

481-
def test_About_has_errors_when_about_resource_is_missing(self):
481+
def test_About_has_no_errors_when_about_resource_is_missing(self):
482482
test_file = get_test_loc('test_gen/parser_tests/.ABOUT')
483483
a = model.About(test_file)
484-
expected = [Error(CRITICAL, 'Field about_resource is required')]
485-
result = a.errors
486-
assert expected == result
484+
assert a.errors == []
487485

488486
def test_About_has_errors_when_about_resource_does_not_exist(self):
489487
test_file = get_test_loc(
@@ -500,7 +498,6 @@ def test_About_has_errors_when_missing_required_fields_are_missing(self):
500498
test_file = get_test_loc('test_model/parse/missing_required.ABOUT')
501499
a = model.About(test_file)
502500
expected = [
503-
Error(CRITICAL, 'Field about_resource is required'),
504501
Error(CRITICAL, 'Field name is required'),
505502
]
506503
result = a.errors
@@ -510,7 +507,6 @@ def test_About_has_errors_when_required_fields_are_empty(self):
510507
test_file = get_test_loc('test_model/parse/empty_required.ABOUT')
511508
a = model.About(test_file)
512509
expected = [
513-
Error(CRITICAL, 'Field about_resource is required and empty'),
514510
Error(CRITICAL, 'Field name is required and empty'),
515511
]
516512
result = a.errors
@@ -728,9 +724,7 @@ def test_get_field_names_only_returns_non_empties(self):
728724
abouts = [a, b]
729725
# ensure all fields (including custom fields) and
730726
# about_resource are collected in the correct order
731-
expected = [
732-
model.About.ABOUT_RESOURCE_ATTR, 'name', 'f', 'g'
733-
]
727+
expected = ['name', 'f', 'g']
734728
result = model.get_field_names(abouts)
735729
assert expected == result
736730

@@ -749,7 +743,6 @@ def test_get_field_names_does_not_return_duplicates_custom_fields(self):
749743
# ensure all fields (including custom fields) and
750744
# about_resource are collected in the correct order
751745
expected = [
752-
'about_resource',
753746
'name',
754747
'cf',
755748
'f',
@@ -1281,14 +1274,8 @@ def test_collect_inventory_with_about_resource_path_from_directory(self):
12811274

12821275
def test_collect_inventory_with_no_about_resource_from_directory(self):
12831276
location = get_test_loc('test_model/inventory/no_about_resource_key')
1284-
result = get_temp_file()
12851277
errors, abouts = model.collect_inventory(location)
1286-
1287-
model.write_output(abouts, result, format='csv')
1288-
1289-
expected_errors = [
1290-
Error(CRITICAL, 'about/about.ABOUT: Field about_resource is required')]
1291-
assert expected_errors == errors
1278+
assert errors == []
12921279

12931280
def test_collect_inventory_complex_from_directory(self):
12941281
location = get_test_loc('test_model/inventory/complex')

0 commit comments

Comments
 (0)