scanoss 1.40.0__py3-none-any.whl → 1.41.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. scanoss/__init__.py +1 -1
  2. scanoss/cli.py +22 -9
  3. scanoss/constants.py +3 -0
  4. scanoss/data/build_date.txt +1 -1
  5. scanoss/data/osadl-copyleft.json +133 -0
  6. scanoss/filecount.py +37 -38
  7. scanoss/gitlabqualityreport.py +33 -4
  8. scanoss/inspection/policy_check/dependency_track/__init__.py +0 -0
  9. scanoss/inspection/{dependency_track → policy_check/dependency_track}/project_violation.py +24 -24
  10. scanoss/inspection/{policy_check.py → policy_check/policy_check.py} +22 -18
  11. scanoss/inspection/policy_check/scanoss/__init__.py +0 -0
  12. scanoss/inspection/{raw → policy_check/scanoss}/copyleft.py +42 -36
  13. scanoss/inspection/{raw → policy_check/scanoss}/undeclared_component.py +30 -29
  14. scanoss/inspection/summary/__init__.py +0 -0
  15. scanoss/inspection/{raw → summary}/component_summary.py +34 -9
  16. scanoss/inspection/{raw → summary}/license_summary.py +46 -44
  17. scanoss/inspection/{raw → summary}/match_summary.py +51 -0
  18. scanoss/inspection/utils/license_utils.py +57 -71
  19. scanoss/inspection/{raw/raw_base.py → utils/scan_result_processor.py} +47 -59
  20. scanoss/osadl.py +125 -0
  21. scanoss/scanner.py +191 -189
  22. scanoss/scanners/folder_hasher.py +24 -24
  23. scanoss/scanners/scanner_hfh.py +20 -15
  24. scanoss/threadedscanning.py +10 -0
  25. {scanoss-1.40.0.dist-info → scanoss-1.41.0.dist-info}/METADATA +1 -1
  26. {scanoss-1.40.0.dist-info → scanoss-1.41.0.dist-info}/RECORD +31 -26
  27. /scanoss/inspection/{raw → policy_check}/__init__.py +0 -0
  28. {scanoss-1.40.0.dist-info → scanoss-1.41.0.dist-info}/WHEEL +0 -0
  29. {scanoss-1.40.0.dist-info → scanoss-1.41.0.dist-info}/entry_points.txt +0 -0
  30. {scanoss-1.40.0.dist-info → scanoss-1.41.0.dist-info}/licenses/LICENSE +0 -0
  31. {scanoss-1.40.0.dist-info → scanoss-1.41.0.dist-info}/top_level.txt +0 -0
@@ -22,12 +22,12 @@ SPDX-License-Identifier: MIT
22
22
  THE SOFTWARE.
23
23
  """
24
24
 
25
- from abc import abstractmethod
25
+ from abc import ABC, abstractmethod
26
26
  from enum import Enum
27
- from typing import Any, Callable, Dict, Generic, List, TypeVar
27
+ from typing import Callable, Dict, Generic, List, NamedTuple, TypeVar
28
28
 
29
- from ..scanossbase import ScanossBase
30
- from .utils.license_utils import LicenseUtil
29
+ from ...scanossbase import ScanossBase
30
+ from ..utils.license_utils import LicenseUtil
31
31
 
32
32
 
33
33
  class PolicyStatus(Enum):
@@ -46,9 +46,13 @@ class PolicyStatus(Enum):
46
46
  # End of PolicyStatus Class
47
47
  #
48
48
 
49
+ class PolicyOutput(NamedTuple):
50
+ details: str
51
+ summary: str
52
+
49
53
  T = TypeVar('T')
50
54
 
51
- class PolicyCheck(ScanossBase, Generic[T]):
55
+ class PolicyCheck(ScanossBase, Generic[T], ABC):
52
56
  """
53
57
  A base class for implementing various software policy checks.
54
58
 
@@ -80,7 +84,7 @@ class PolicyCheck(ScanossBase, Generic[T]):
80
84
  self.output = output
81
85
 
82
86
  @abstractmethod
83
- def run(self):
87
+ def run(self)-> tuple[int,PolicyOutput]:
84
88
  """
85
89
  Execute the policy check process.
86
90
 
@@ -91,14 +95,14 @@ class PolicyCheck(ScanossBase, Generic[T]):
91
95
  3. Formatting the results
92
96
  4. Saving the output to files if required
93
97
 
94
- :return: A tuple containing:
98
+ :return: A named tuple containing two elements:
95
99
  - First element: PolicyStatus enum value (SUCCESS, FAIL, or ERROR)
96
- - Second element: Dictionary containing the inspection results
100
+ - Second element: PolicyOutput A tuple containing the policy results.
97
101
  """
98
102
  pass
99
103
 
100
104
  @abstractmethod
101
- def _json(self, data: list[T]) -> Dict[str, Any]:
105
+ def _json(self, data: list[T]) -> PolicyOutput:
102
106
  """
103
107
  Format the policy checks results as JSON.
104
108
  This method should be implemented by subclasses to create a Markdown representation
@@ -112,7 +116,7 @@ class PolicyCheck(ScanossBase, Generic[T]):
112
116
  pass
113
117
 
114
118
  @abstractmethod
115
- def _markdown(self, data: list[T]) -> Dict[str, Any]:
119
+ def _markdown(self, data: list[T]) -> PolicyOutput:
116
120
  """
117
121
  Generate Markdown output for the policy check results.
118
122
 
@@ -125,7 +129,7 @@ class PolicyCheck(ScanossBase, Generic[T]):
125
129
  pass
126
130
 
127
131
  @abstractmethod
128
- def _jira_markdown(self, data: list[T]) -> Dict[str, Any]:
132
+ def _jira_markdown(self, data: list[T]) -> PolicyOutput:
129
133
  """
130
134
  Generate Markdown output for the policy check results.
131
135
 
@@ -137,7 +141,7 @@ class PolicyCheck(ScanossBase, Generic[T]):
137
141
  """
138
142
  pass
139
143
 
140
- def _get_formatter(self) -> Callable[[List[dict]], Dict[str, Any]] or None:
144
+ def _get_formatter(self) -> Callable[[List[dict]], PolicyOutput]:
141
145
  """
142
146
  Get the appropriate formatter function based on the specified format.
143
147
 
@@ -145,7 +149,7 @@ class PolicyCheck(ScanossBase, Generic[T]):
145
149
  """
146
150
  valid_format = self._is_valid_format()
147
151
  if not valid_format:
148
- return None
152
+ raise ValueError('Invalid format specified')
149
153
  # a map of which format function to return
150
154
  function_map = {
151
155
  'json': self._json,
@@ -205,14 +209,14 @@ class PolicyCheck(ScanossBase, Generic[T]):
205
209
  if formatter is None:
206
210
  return PolicyStatus.ERROR.value, {}
207
211
  # Format the results
208
- data = formatter(components)
212
+ policy_output = formatter(components)
209
213
  ## Save outputs if required
210
- self.print_to_file_or_stdout(data['details'], self.output)
211
- self.print_to_file_or_stderr(data['summary'], self.status)
214
+ self.print_to_file_or_stdout(policy_output.details, self.output)
215
+ self.print_to_file_or_stderr(policy_output.summary, self.status)
212
216
  # Check to see if we have policy violations
213
217
  if len(components) > 0:
214
- return PolicyStatus.POLICY_FAIL.value, data
215
- return PolicyStatus.POLICY_SUCCESS.value, data
218
+ return PolicyStatus.POLICY_FAIL.value, policy_output
219
+ return PolicyStatus.POLICY_SUCCESS.value, policy_output
216
220
  #
217
221
  # End of PolicyCheck Class
218
222
  #
File without changes
@@ -24,11 +24,13 @@ SPDX-License-Identifier: MIT
24
24
 
25
25
  import json
26
26
  from dataclasses import dataclass
27
- from typing import Any, Dict, List
27
+ from typing import Dict, List
28
28
 
29
- from ..policy_check import PolicyStatus
30
- from ..utils.markdown_utils import generate_jira_table, generate_table
31
- from .raw_base import RawBase
29
+ from scanoss.constants import DEFAULT_COPYLEFT_LICENSE_SOURCES
30
+
31
+ from ...policy_check.policy_check import PolicyCheck, PolicyOutput, PolicyStatus
32
+ from ...utils.markdown_utils import generate_jira_table, generate_table
33
+ from ...utils.scan_result_processor import ScanResultProcessor
32
34
 
33
35
 
34
36
  @dataclass
@@ -45,7 +47,7 @@ class Component:
45
47
  licenses: List[License]
46
48
  status: str
47
49
 
48
- class Copyleft(RawBase[Component]):
50
+ class Copyleft(PolicyCheck[Component]):
49
51
  """
50
52
  SCANOSS Copyleft class
51
53
  Inspects components for copyleft licenses
@@ -63,6 +65,7 @@ class Copyleft(RawBase[Component]):
63
65
  include: str = None,
64
66
  exclude: str = None,
65
67
  explicit: str = None,
68
+ license_sources: list = None,
66
69
  ):
67
70
  """
68
71
  Initialise the Copyleft class.
@@ -77,18 +80,27 @@ class Copyleft(RawBase[Component]):
77
80
  :param include: Licenses to include in the analysis
78
81
  :param exclude: Licenses to exclude from the analysis
79
82
  :param explicit: Explicitly defined licenses
83
+ :param license_sources: List of license sources to check
80
84
  """
81
- super().__init__(debug, trace, quiet, format_type,filepath, output ,status, name='Copyleft Policy')
85
+ super().__init__(
86
+ debug, trace, quiet, format_type, status, name='Copyleft Policy', output=output
87
+ )
82
88
  self.license_util.init(include, exclude, explicit)
83
89
  self.filepath = filepath
84
- self.format = format
85
90
  self.output = output
86
91
  self.status = status
87
- self.include = include
88
- self.exclude = exclude
89
- self.explicit = explicit
90
-
91
- def _json(self, components: list[Component]) -> Dict[str, Any]:
92
+ self.license_sources = license_sources or DEFAULT_COPYLEFT_LICENSE_SOURCES
93
+ self.results_processor = ScanResultProcessor(
94
+ self.debug,
95
+ self.trace,
96
+ self.quiet,
97
+ self.filepath,
98
+ include,
99
+ exclude,
100
+ explicit,
101
+ self.license_sources)
102
+
103
+ def _json(self, components: list[Component]) -> PolicyOutput:
92
104
  """
93
105
  Format the components with copyleft licenses as JSON.
94
106
 
@@ -96,16 +108,16 @@ class Copyleft(RawBase[Component]):
96
108
  :return: Dictionary with formatted JSON details and summary
97
109
  """
98
110
  # A component is considered unique by its combination of PURL (Package URL) and license
99
- component_licenses = self._group_components_by_license(components)
111
+ component_licenses = self.results_processor.group_components_by_license(components)
100
112
  details = {}
101
113
  if len(components) > 0:
102
114
  details = {'components': components}
103
- return {
104
- 'details': f'{json.dumps(details, indent=2)}\n',
105
- 'summary': f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
106
- }
115
+ return PolicyOutput(
116
+ details= f'{json.dumps(details, indent=2)}\n',
117
+ summary= f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
118
+ )
107
119
 
108
- def _markdown(self, components: list[Component]) -> Dict[str, Any]:
120
+ def _markdown(self, components: list[Component]) -> PolicyOutput:
109
121
  """
110
122
  Format the components with copyleft licenses as Markdown.
111
123
 
@@ -114,7 +126,7 @@ class Copyleft(RawBase[Component]):
114
126
  """
115
127
  return self._md_summary_generator(components, generate_table)
116
128
 
117
- def _jira_markdown(self, components: list[Component]) -> Dict[str, Any]:
129
+ def _jira_markdown(self, components: list[Component]) -> PolicyOutput:
118
130
  """
119
131
  Format the components with copyleft licenses as Markdown.
120
132
 
@@ -123,7 +135,7 @@ class Copyleft(RawBase[Component]):
123
135
  """
124
136
  return self._md_summary_generator(components, generate_jira_table)
125
137
 
126
- def _md_summary_generator(self, components: list[Component], table_generator):
138
+ def _md_summary_generator(self, components: list[Component], table_generator) -> PolicyOutput:
127
139
  """
128
140
  Generates a Markdown summary for components with a focus on copyleft licenses.
129
141
 
@@ -138,15 +150,10 @@ class Copyleft(RawBase[Component]):
138
150
  A callable function to generate tabular data for components.
139
151
 
140
152
  Returns:
141
- dict
142
- A dictionary containing two keys:
143
- - 'details': A detailed Markdown representation including a table of components
144
- and associated copyleft license data.
145
- - 'summary': A textual summary highlighting the total number of components
146
- with copyleft licenses.
153
+ PolicyOutput
147
154
  """
148
155
  # A component is considered unique by its combination of PURL (Package URL) and license
149
- component_licenses = self._group_components_by_license(components)
156
+ component_licenses = self.results_processor.group_components_by_license(components)
150
157
  headers = ['Component', 'License', 'URL', 'Copyleft']
151
158
  centered_columns = [1, 4]
152
159
  rows = []
@@ -160,10 +167,10 @@ class Copyleft(RawBase[Component]):
160
167
  rows.append(row)
161
168
  # End license loop
162
169
  # End component loop
163
- return {
164
- 'details': f'### Copyleft Licenses\n{table_generator(headers, rows, centered_columns)}',
165
- 'summary': f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
166
- }
170
+ return PolicyOutput(
171
+ details= f'### Copyleft Licenses\n{table_generator(headers, rows, centered_columns)}',
172
+ summary= f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
173
+ )
167
174
 
168
175
  def _get_components_with_copyleft_licenses(self, components: list) -> list[Dict]:
169
176
  """
@@ -202,14 +209,13 @@ class Copyleft(RawBase[Component]):
202
209
 
203
210
  :return: A list of processed components with license data, or `None` if `self.results` is not set.
204
211
  """
205
- if self.results is None:
212
+ if self.results_processor.get_results() is None:
206
213
  return None
207
-
208
214
  components: dict = {}
209
215
  # Extract component and license data from file and dependency results. Both helpers mutate `components`
210
- self._get_components_data(self.results, components)
211
- self._get_dependencies_data(self.results, components)
212
- return self._convert_components_to_list(components)
216
+ self.results_processor.get_components_data(components)
217
+ self.results_processor.get_dependencies_data(components)
218
+ return self.results_processor.convert_components_to_list(components)
213
219
 
214
220
  def run(self):
215
221
  """
@@ -24,11 +24,11 @@ SPDX-License-Identifier: MIT
24
24
 
25
25
  import json
26
26
  from dataclasses import dataclass
27
- from typing import Any, Dict, List
27
+ from typing import List
28
28
 
29
- from ..policy_check import PolicyStatus
30
- from ..utils.markdown_utils import generate_jira_table, generate_table
31
- from .raw_base import RawBase
29
+ from ...policy_check.policy_check import PolicyCheck, PolicyOutput, PolicyStatus
30
+ from ...utils.markdown_utils import generate_jira_table, generate_table
31
+ from ...utils.scan_result_processor import ScanResultProcessor
32
32
 
33
33
 
34
34
  @dataclass
@@ -44,7 +44,7 @@ class Component:
44
44
  licenses: List[License]
45
45
  status: str
46
46
 
47
- class UndeclaredComponent(RawBase[Component]):
47
+ class UndeclaredComponent(PolicyCheck[Component]):
48
48
  """
49
49
  SCANOSS UndeclaredComponent class
50
50
  Inspects for undeclared components
@@ -59,7 +59,7 @@ class UndeclaredComponent(RawBase[Component]):
59
59
  format_type: str = 'json',
60
60
  status: str = None,
61
61
  output: str = None,
62
- sbom_format: str = 'settings',
62
+ sbom_format: str = 'settings'
63
63
  ):
64
64
  """
65
65
  Initialize the UndeclaredComponent class.
@@ -74,13 +74,14 @@ class UndeclaredComponent(RawBase[Component]):
74
74
  :param sbom_format: Sbom format for status output (default 'settings')
75
75
  """
76
76
  super().__init__(
77
- debug, trace, quiet,format_type, filepath, output, status, name='Undeclared Components Policy'
77
+ debug, trace, quiet, format_type, status, name='Undeclared Components Policy', output=output
78
78
  )
79
79
  self.filepath = filepath
80
- self.format = format
81
80
  self.output = output
82
81
  self.status = status
83
82
  self.sbom_format = sbom_format
83
+ self.results_processor = ScanResultProcessor(self.debug, self.trace, self.quiet, self.filepath)
84
+
84
85
 
85
86
  def _get_undeclared_components(self, components: list[Component]) -> list or None:
86
87
  """
@@ -163,7 +164,7 @@ class UndeclaredComponent(RawBase[Component]):
163
164
 
164
165
  return summary
165
166
 
166
- def _json(self, components: list[Component]) -> Dict[str, Any]:
167
+ def _json(self, components: list[Component]) -> PolicyOutput:
167
168
  """
168
169
  Format the undeclared components as JSON.
169
170
 
@@ -171,16 +172,16 @@ class UndeclaredComponent(RawBase[Component]):
171
172
  :return: Dictionary with formatted JSON details and summary
172
173
  """
173
174
  # Use component grouped by licenses to generate the summary
174
- component_licenses = self._group_components_by_license(components)
175
+ component_licenses = self.results_processor.group_components_by_license(components)
175
176
  details = {}
176
177
  if len(components) > 0:
177
178
  details = {'components': components}
178
- return {
179
- 'details': f'{json.dumps(details, indent=2)}\n',
180
- 'summary': self._get_summary(component_licenses),
181
- }
179
+ return PolicyOutput(
180
+ details=f'{json.dumps(details, indent=2)}\n',
181
+ summary=self._get_summary(component_licenses)
182
+ )
182
183
 
183
- def _markdown(self, components: list[Component]) -> Dict[str, Any]:
184
+ def _markdown(self, components: list[Component]) -> PolicyOutput:
184
185
  """
185
186
  Format the undeclared components as Markdown.
186
187
 
@@ -190,15 +191,15 @@ class UndeclaredComponent(RawBase[Component]):
190
191
  headers = ['Component', 'License']
191
192
  rows = []
192
193
  # TODO look at using SpdxLite license name lookup method
193
- component_licenses = self._group_components_by_license(components)
194
+ component_licenses = self.results_processor.group_components_by_license(components)
194
195
  for component in component_licenses:
195
196
  rows.append([component.get('purl'), component.get('spdxid')])
196
- return {
197
- 'details': f'### Undeclared components\n{generate_table(headers, rows)}\n',
198
- 'summary': self._get_summary(component_licenses),
199
- }
197
+ return PolicyOutput(
198
+ details= f'### Undeclared components\n{generate_table(headers, rows)}\n',
199
+ summary= self._get_summary(component_licenses),
200
+ )
200
201
 
201
- def _jira_markdown(self, components: list) -> Dict[str, Any]:
202
+ def _jira_markdown(self, components: list) -> PolicyOutput:
202
203
  """
203
204
  Format the undeclared components as Markdown.
204
205
 
@@ -208,13 +209,13 @@ class UndeclaredComponent(RawBase[Component]):
208
209
  headers = ['Component', 'License']
209
210
  rows = []
210
211
  # TODO look at using SpdxLite license name lookup method
211
- component_licenses = self._group_components_by_license(components)
212
+ component_licenses = self.results_processor.group_components_by_license(components)
212
213
  for component in component_licenses:
213
214
  rows.append([component.get('purl'), component.get('spdxid')])
214
- return {
215
- 'details': f'{generate_jira_table(headers, rows)}',
216
- 'summary': self._get_jira_summary(component_licenses),
217
- }
215
+ return PolicyOutput(
216
+ details= f'{generate_jira_table(headers, rows)}',
217
+ summary= self._get_jira_summary(component_licenses),
218
+ )
218
219
 
219
220
  def _get_unique_components(self, components: list) -> list:
220
221
  """
@@ -272,13 +273,13 @@ class UndeclaredComponent(RawBase[Component]):
272
273
 
273
274
  :return: A list of processed components with their licenses, or `None` if `self.results` is not set.
274
275
  """
275
- if self.results is None:
276
+ if self.results_processor.get_results() is None:
276
277
  return None
277
278
  components: dict = {}
278
279
  # Extract file and snippet components
279
- components = self._get_components_data(self.results, components)
280
+ components = self.results_processor.get_components_data(components)
280
281
  # Convert to list and process licenses
281
- return self._convert_components_to_list(components)
282
+ return self.results_processor.convert_components_to_list(components)
282
283
 
283
284
  def run(self):
284
285
  """
File without changes
@@ -24,11 +24,36 @@ SPDX-License-Identifier: MIT
24
24
  import json
25
25
  from typing import Any
26
26
 
27
- from ..policy_check import T
28
- from .raw_base import RawBase
27
+ from ...scanossbase import ScanossBase
28
+ from ..policy_check.policy_check import T
29
+ from ..utils.scan_result_processor import ScanResultProcessor
30
+
31
+
32
+ class ComponentSummary(ScanossBase):
33
+
34
+ def __init__( # noqa: PLR0913
35
+ self,
36
+ debug: bool = False,
37
+ trace: bool = False,
38
+ quiet: bool = False,
39
+ filepath: str = None,
40
+ format_type: str = 'json',
41
+ output: str = None,
42
+ ):
43
+ """
44
+ Initialize the ComponentSummary class.
29
45
 
46
+ :param debug: Enable debug mode
47
+ :param trace: Enable trace mode
48
+ :param quiet: Enable quiet mode
49
+ :param filepath: Path to the file containing component data
50
+ :param format_type: Output format ('json' or 'md')
51
+ """
52
+ super().__init__(debug, trace, quiet)
53
+ self.filepath = filepath
54
+ self.output = output
55
+ self.results_processor = ScanResultProcessor(debug, trace, quiet, filepath)
30
56
 
31
- class ComponentSummary(RawBase):
32
57
 
33
58
  def _json(self, data: dict[str,Any]) -> dict[str,Any]:
34
59
  """
@@ -77,11 +102,11 @@ class ComponentSummary(RawBase):
77
102
  """
78
103
  Get a component summary from detected components.
79
104
 
80
- :param components: List of all components
105
+ :param scan_components: List of all components
81
106
  :return: Dict with license summary information
82
107
  """
83
108
  # A component is considered unique by its combination of PURL (Package URL) and license
84
- component_licenses = self._group_components_by_license(scan_components)
109
+ component_licenses = self.results_processor.group_components_by_license(scan_components)
85
110
  total_components = len(component_licenses)
86
111
  # Get undeclared components
87
112
  undeclared_components = len([c for c in component_licenses if c['status'] == 'pending'])
@@ -121,13 +146,13 @@ class ComponentSummary(RawBase):
121
146
 
122
147
  :return: A list of processed components with license data, or `None` if `self.results` is not set.
123
148
  """
124
- if self.results is None:
125
- raise ValueError(f'Error: No results found in ${self.filepath}')
149
+ if self.results_processor.get_results() is None:
150
+ raise ValueError(f'Error: No results found in {self.filepath}')
126
151
 
127
152
  components: dict = {}
128
153
  # Extract component and license data from file and dependency results. Both helpers mutate `components`
129
- self._get_components_data(self.results, components)
130
- return self._convert_components_to_list(components)
154
+ self.results_processor.get_components_data(components)
155
+ return self.results_processor.convert_components_to_list(components)
131
156
 
132
157
  def _format(self, component_summary) -> str:
133
158
  # TODO: Implement formatter to support dynamic outputs
@@ -25,11 +25,12 @@ SPDX-License-Identifier: MIT
25
25
  import json
26
26
  from typing import Any
27
27
 
28
- from ..policy_check import T
29
- from .raw_base import RawBase
28
+ from ...scanossbase import ScanossBase
29
+ from ..policy_check.policy_check import T
30
+ from ..utils.scan_result_processor import ScanResultProcessor
30
31
 
31
32
 
32
- class LicenseSummary(RawBase):
33
+ class LicenseSummary(ScanossBase):
33
34
  """
34
35
  SCANOSS LicenseSummary class
35
36
  Inspects results and generates comprehensive license summaries from detected components.
@@ -38,6 +39,42 @@ class LicenseSummary(RawBase):
38
39
  information, providing detailed summaries including copyleft analysis and license statistics.
39
40
  """
40
41
 
42
+ # Define required license fields as class constants
43
+ REQUIRED_LICENSE_FIELDS = ['spdxid', 'url', 'copyleft', 'source']
44
+
45
+ def __init__( # noqa: PLR0913
46
+ self,
47
+ debug: bool = False,
48
+ trace: bool = False,
49
+ quiet: bool = False,
50
+ filepath: str = None,
51
+ status: str = None,
52
+ output: str = None,
53
+ include: str = None,
54
+ exclude: str = None,
55
+ explicit: str = None,
56
+ ):
57
+ """
58
+ Initialize the LicenseSummary class.
59
+
60
+ :param debug: Enable debug mode
61
+ :param trace: Enable trace mode
62
+ :param quiet: Enable quiet mode
63
+ :param filepath: Path to the file containing component data
64
+ :param output: Path to save detailed output
65
+ :param include: Licenses to include in the analysis
66
+ :param exclude: Licenses to exclude from the analysis
67
+ :param explicit: Explicitly defined licenses
68
+ """
69
+ super().__init__(debug=debug, trace=trace, quiet=quiet)
70
+ self.results_processor = ScanResultProcessor(debug, trace, quiet, filepath, include, exclude, explicit)
71
+ self.filepath = filepath
72
+ self.output = output
73
+ self.status = status
74
+ self.include = include
75
+ self.exclude = exclude
76
+ self.explicit = explicit
77
+
41
78
  def _json(self, data: dict[str,Any]) -> dict[str, Any]:
42
79
  """
43
80
  Format license summary data as JSON.
@@ -78,41 +115,6 @@ class LicenseSummary(RawBase):
78
115
  """
79
116
  pass
80
117
 
81
- # Define required license fields as class constants
82
- REQUIRED_LICENSE_FIELDS = ['spdxid', 'url', 'copyleft', 'source']
83
-
84
- def __init__( # noqa: PLR0913
85
- self,
86
- debug: bool = False,
87
- trace: bool = False,
88
- quiet: bool = False,
89
- filepath: str = None,
90
- status: str = None,
91
- output: str = None,
92
- include: str = None,
93
- exclude: str = None,
94
- explicit: str = None,
95
- ):
96
- """
97
- Initialize the LicenseSummary class.
98
-
99
- :param debug: Enable debug mode
100
- :param trace: Enable trace mode (default True)
101
- :param quiet: Enable quiet mode
102
- :param filepath: Path to the file containing component data
103
- :param output: Path to save detailed output
104
- :param include: Licenses to include in the analysis
105
- :param exclude: Licenses to exclude from the analysis
106
- :param explicit: Explicitly defined licenses
107
- """
108
- super().__init__(debug, trace, quiet, filepath = filepath, output=output)
109
- self.license_util.init(include, exclude, explicit)
110
- self.filepath = filepath
111
- self.output = output
112
- self.status = status
113
- self.include = include
114
- self.exclude = exclude
115
- self.explicit = explicit
116
118
 
117
119
  def _get_licenses_summary_from_components(self, components: list)-> dict:
118
120
  """
@@ -122,7 +124,7 @@ class LicenseSummary(RawBase):
122
124
  :return: Dict with license summary information
123
125
  """
124
126
  # A component is considered unique by its combination of PURL (Package URL) and license
125
- component_licenses = self._group_components_by_license(components)
127
+ component_licenses = self.results_processor.group_components_by_license(components)
126
128
  license_component_count = {}
127
129
  # Count license per component
128
130
  for lic in component_licenses:
@@ -164,14 +166,14 @@ class LicenseSummary(RawBase):
164
166
 
165
167
  :return: A list of processed components with license data, or `None` if `self.results` is not set.
166
168
  """
167
- if self.results is None:
168
- raise ValueError(f'Error: No results found in ${self.filepath}')
169
+ if self.results_processor.get_results() is None:
170
+ raise ValueError(f'Error: No results found in {self.filepath}')
169
171
 
170
172
  components: dict = {}
171
173
  # Extract component and license data from file and dependency results. Both helpers mutate `components`
172
- self._get_components_data(self.results, components)
173
- self._get_dependencies_data(self.results, components)
174
- return self._convert_components_to_list(components)
174
+ self.results_processor.get_components_data(components)
175
+ self.results_processor.get_dependencies_data(components)
176
+ return self.results_processor.convert_components_to_list(components)
175
177
 
176
178
  def _format(self, license_summary) -> str:
177
179
  # TODO: Implement formatter to support dynamic outputs