Skip to content

Commit 726d8a8

Browse files
committed
Fix dependency parsing
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 8de76d3 commit 726d8a8

4 files changed

Lines changed: 69 additions & 815 deletions

File tree

src/_packagedcode/pypi.py

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from pathlib import Path
2020

2121
import dparse2
22+
import packaging
2223
import pip_requirements_parser
2324
import pkginfo2
2425
from commoncode import fileutils
@@ -684,10 +685,17 @@ def parse(cls, location):
684685

685686
metadata = {}
686687
parser = ConfigParser()
688+
dependent_packages = []
687689
with open(location) as f:
688690
parser.read_file(f)
689-
690691
for section in parser.values():
692+
if section.name == 'options':
693+
reqs = list(get_requirement_from_section(section=section, sub_section="install_requires"))
694+
dependent_packages.extend(cls.parse_reqs(reqs, "install"))
695+
if section.name == "options.extras_require":
696+
for sub_section in section:
697+
reqs = list(get_requirement_from_section(section=section, sub_section=sub_section))
698+
dependent_packages.extend(cls.parse_reqs(reqs, sub_section))
691699
if section.name == 'metadata':
692700
options = (
693701
'name',
@@ -719,10 +727,6 @@ def parse(cls, location):
719727
if not dependency_type:
720728
return
721729

722-
dependencies = parse_with_dparse2(
723-
location=location,
724-
file_name=dependency_type,
725-
)
726730
yield models.PackageData(
727731
datasource_id=cls.datasource_id,
728732
type=cls.default_package_type,
@@ -731,9 +735,33 @@ def parse(cls, location):
731735
parties=parties,
732736
homepage_url=metadata.get('url'),
733737
primary_language=cls.default_primary_language,
734-
dependencies=dependencies,
738+
dependencies=dependent_packages,
735739
)
736740

741+
@classmethod
742+
def parse_reqs(cls, reqs, scope):
743+
dependent_packages = []
744+
for req in reqs:
745+
is_resolved = False
746+
req_parsed = packaging.requirements.Requirement(str(req))
747+
purl = PackageURL(type="pypi", name=req_parsed.name)
748+
specifiers = req_parsed.specifier._specs
749+
if len(specifiers) == 1:
750+
specifier = list(specifiers)[0]
751+
if specifier.operator in ('==', '==='):
752+
is_resolved = True
753+
purl = purl._replace(version=specifier.version)
754+
dependent_packages.append(
755+
models.DependentPackage(
756+
purl=purl,
757+
scope=scope,
758+
is_runtime=True,
759+
is_optional=False,
760+
is_resolved=is_resolved,
761+
extracted_requirement=req
762+
)
763+
)
764+
return dependent_packages
737765

738766
class PipfileHandler(BaseDependencyFileHandler):
739767
datasource_id = 'pipfile'
@@ -1017,10 +1045,11 @@ def get_classifiers(metainfo):
10171045
license_classifiers = []
10181046
other_classifiers = []
10191047
for classifier in classifiers:
1020-
if classifier.startswith('License'):
1021-
license_classifiers.append(classifier)
1022-
else:
1023-
other_classifiers.append(classifier)
1048+
if classifier:
1049+
if classifier.startswith('License'):
1050+
license_classifiers.append(classifier)
1051+
else:
1052+
other_classifiers.append(classifier)
10241053
return license_classifiers, other_classifiers
10251054

10261055

@@ -1272,6 +1301,7 @@ def parse_with_dparse2(location, file_name=None):
12721301
dependent_packages = []
12731302

12741303
for dependency in dep_file.dependencies:
1304+
# print(dependency.serialize())
12751305
name = dependency.name
12761306
is_resolved = False
12771307
purl = PackageURL(type='pypi', name=dependency.name)
@@ -1899,3 +1929,22 @@ def compute_normalized_license(declared_license):
18991929

19001930
if detected_licenses:
19011931
return combine_expressions(detected_licenses)
1932+
1933+
1934+
def get_requirement_from_section(section, sub_section):
1935+
content = section.get(sub_section)
1936+
if content:
1937+
for req in content.splitlines():
1938+
if req:
1939+
req = req.replace("; \\", "")
1940+
if "#" in req:
1941+
req , _ = req.rsplit("#")
1942+
req_split_by_semi_colon = req.split(";")
1943+
req_split_by_semi_colon = [req.strip() for req in req_split_by_semi_colon]
1944+
if len(req_split_by_semi_colon) >= 2 and not(req_split_by_semi_colon[1].startswith("python_version")
1945+
or req_split_by_semi_colon[1].startswith("sys_platform")
1946+
or req_split_by_semi_colon[1].startswith("platform_system")):
1947+
for temp_req in req_split_by_semi_colon:
1948+
yield temp_req
1949+
else:
1950+
yield req

src/python_inspector/resolution.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ def get_requirements_for_package_from_pypi_simple(self, candidate):
201201
"setup-cfg": SetupCfgHandler,
202202
"requirement": PipRequirementsFileHandler,
203203
}
204-
205204
for format in ["pkginfo", "setup-py", "setup-cfg", "requirement"]:
206205
path = path_by_format[format]
207206
if os.path.exists(path):

0 commit comments

Comments
 (0)