Return a list of DependentPackage built from a dparse2-supported dependency manifest such as Conda manifest or Pipfile.lock files, or return an empty list.
(location, file_name=None)
| 2331 | |
| 2332 | |
| 2333 | def parse_with_dparse2(location, file_name=None): |
| 2334 | """ |
| 2335 | Return a list of DependentPackage built from a dparse2-supported dependency |
| 2336 | manifest such as Conda manifest or Pipfile.lock files, or return an empty |
| 2337 | list. |
| 2338 | """ |
| 2339 | with open(location) as f: |
| 2340 | content = f.read() |
| 2341 | |
| 2342 | dep_file = dparse2.parse(content, file_name=file_name) |
| 2343 | if not dep_file: |
| 2344 | return [] |
| 2345 | |
| 2346 | dependent_packages = [] |
| 2347 | |
| 2348 | for dependency in dep_file.dependencies: |
| 2349 | requirement = dependency.name |
| 2350 | is_pinned = False |
| 2351 | purl = PackageURL(type='pypi', name=dependency.name) |
| 2352 | |
| 2353 | # note: dparse2.dependencies.Dependency.specs comes from |
| 2354 | # packaging.requirements.Requirement.specifier |
| 2355 | # which in turn is a packaging.specifiers.SpecifierSet objects |
| 2356 | # and a SpecifierSet._specs is a set of either: |
| 2357 | # packaging.specifiers.Specifier or packaging.specifiers.LegacySpecifier |
| 2358 | # and each of these have a .operator and .version property |
| 2359 | |
| 2360 | # a packaging.specifiers.SpecifierSet |
| 2361 | specifiers_set = dependency.specs |
| 2362 | # a list of packaging.specifiers.Specifier |
| 2363 | specifiers = specifiers_set._specs |
| 2364 | |
| 2365 | if specifiers: |
| 2366 | # SpecifierSet stringifies to comma-separated sorted Specifiers |
| 2367 | requirement = str(specifiers_set) |
| 2368 | # are we pinned e.g. resolved? |
| 2369 | if len(specifiers) == 1: |
| 2370 | specifier = list(specifiers)[0] |
| 2371 | if specifier.operator in ('==', '==='): |
| 2372 | is_pinned = True |
| 2373 | purl = purl._replace(version=specifier.version) |
| 2374 | |
| 2375 | dependent_packages.append( |
| 2376 | models.DependentPackage( |
| 2377 | purl=purl.to_string(), |
| 2378 | # are we always this scope? what if we have requirements-dev.txt? |
| 2379 | scope='install', |
| 2380 | is_runtime=True, |
| 2381 | is_optional=False, |
| 2382 | is_pinned=is_pinned, |
| 2383 | extracted_requirement=requirement |
| 2384 | ) |
| 2385 | ) |
| 2386 | |
| 2387 | return dependent_packages |
| 2388 | |
| 2389 | |
| 2390 | def is_setup_call(statement): |