@@ -81,63 +81,62 @@ def get_dependencies_from_manifest(resource):
8181 return dependencies
8282
8383
84- def get_data_from_manifests (project , package_registry , manifest_resources , model = None ):
85- """
86- Get package and dependency data from package manifests/lockfiles/SBOMs or
87- for resolved packages from package requirements.
88- """
89- resolved_packages = []
90- resolved_dependencies = []
91- sboms_headers = {}
92-
93- if not manifest_resources .exists ():
94- project .add_warning (
95- description = "No resources containing package data found in codebase." ,
96- model = model ,
97- )
98- return []
99-
84+ def _group_manifests_by_type (manifest_resources ):
85+ """Group manifest resources by their package type."""
10086 manifests_by_type = {}
10187 for resource in manifest_resources :
10288 package_type = get_default_package_type (resource .location )
10389 if package_type :
10490 if package_type not in manifests_by_type :
10591 manifests_by_type [package_type ] = []
10692 manifests_by_type [package_type ].append (resource )
93+ return manifests_by_type
10794
108- if "pypi" in manifests_by_type :
109- pypi_resources = manifests_by_type ["pypi" ]
110- pypi_locations = [resource .location for resource in pypi_resources ]
111-
112- resolver = package_registry .get ("pypi" )
113- if resolver :
114- try :
115- packages = resolver (input_locations = pypi_locations )
116- if packages :
117- for package_data in packages :
118- package_data ["codebase_resources" ] = pypi_resources
119- resolved_packages .extend (packages )
120-
121- for resource in pypi_resources :
122- if headers := get_manifest_headers (resource ):
123- sboms_headers [resource .name ] = headers
124- else :
125- for resource in pypi_resources :
126- project .add_error (
127- description = "No packages could be resolved" ,
128- model = model ,
129- object_instance = resource ,
130- )
131- except Exception as e :
132- for resource in pypi_resources :
133- project .add_error (
134- description = f"Error resolving packages: { e } " ,
135- model = model ,
136- object_instance = resource ,
137- )
138-
139- del manifests_by_type ["pypi" ]
14095
96+ def _resolve_pypi_manifests (
97+ project , package_registry , pypi_resources , model , resolved_packages , sboms_headers
98+ ):
99+ """Resolve PyPI packages from requirement files."""
100+ pypi_locations = [resource .location for resource in pypi_resources ]
101+ resolver = package_registry .get ("pypi" )
102+ if not resolver :
103+ return
104+
105+ try :
106+ packages = resolver (input_locations = pypi_locations )
107+ if packages :
108+ for package_data in packages :
109+ package_data ["codebase_resources" ] = pypi_resources
110+ resolved_packages .extend (packages )
111+ for resource in pypi_resources :
112+ if headers := get_manifest_headers (resource ):
113+ sboms_headers [resource .name ] = headers
114+ else :
115+ for resource in pypi_resources :
116+ project .add_error (
117+ description = "No packages could be resolved" ,
118+ model = model ,
119+ object_instance = resource ,
120+ )
121+ except Exception as e :
122+ for resource in pypi_resources :
123+ project .add_error (
124+ description = f"Error resolving packages: { e } " ,
125+ model = model ,
126+ object_instance = resource ,
127+ )
128+
129+
130+ def _resolve_other_manifests (
131+ project ,
132+ package_registry ,
133+ manifests_by_type ,
134+ model ,
135+ resolved_packages ,
136+ resolved_dependencies ,
137+ sboms_headers ,
138+ ):
139+ """Resolve non-PyPI packages from manifest files."""
141140 for package_type , resources in manifests_by_type .items ():
142141 for resource in resources :
143142 packages = resolve_manifest_resources (resource , package_registry )
@@ -156,6 +155,46 @@ def get_data_from_manifests(project, package_registry, manifest_resources, model
156155 if dependencies :
157156 resolved_dependencies .extend (dependencies )
158157
158+
159+ def get_data_from_manifests (project , package_registry , manifest_resources , model = None ):
160+ """
161+ Get package and dependency data from package manifests/lockfiles/SBOMs or
162+ for resolved packages from package requirements.
163+ """
164+ resolved_packages = []
165+ resolved_dependencies = []
166+ sboms_headers = {}
167+
168+ if not manifest_resources .exists ():
169+ project .add_warning (
170+ description = "No resources containing package data found in codebase." ,
171+ model = model ,
172+ )
173+ return []
174+
175+ manifests_by_type = _group_manifests_by_type (manifest_resources )
176+
177+ if "pypi" in manifests_by_type :
178+ _resolve_pypi_manifests (
179+ project ,
180+ package_registry ,
181+ manifests_by_type ["pypi" ],
182+ model ,
183+ resolved_packages ,
184+ sboms_headers ,
185+ )
186+ del manifests_by_type ["pypi" ]
187+
188+ _resolve_other_manifests (
189+ project ,
190+ package_registry ,
191+ manifests_by_type ,
192+ model ,
193+ resolved_packages ,
194+ resolved_dependencies ,
195+ sboms_headers ,
196+ )
197+
159198 if sboms_headers :
160199 project .update_extra_data ({"sboms_headers" : sboms_headers })
161200
@@ -267,13 +306,14 @@ def get_manifest_resources(project):
267306def resolve_pypi_packages (input_location = None , input_locations = None ):
268307 """
269308 Resolve the PyPI packages from requirement file(s).
270-
309+
271310 Args:
272311 input_location: Single requirement file path (for backward compatibility)
273312 input_locations: List of requirement file paths (for batch processing)
274-
313+
275314 Returns:
276315 List of resolved package data dictionaries
316+
277317 """
278318 # Handle both single file and multiple files
279319 if input_locations :
@@ -282,7 +322,7 @@ def resolve_pypi_packages(input_location=None, input_locations=None):
282322 requirement_files = [input_location ]
283323 else :
284324 raise ValueError ("Either input_location or input_locations must be provided" )
285-
325+
286326 python_version = f"{ sys .version_info .major } { sys .version_info .minor } "
287327 operating_system = "linux"
288328
0 commit comments