Skip to content

Commit 723841e

Browse files
committed
fix: Review comments
1 parent ac3c537 commit 723841e

4 files changed

Lines changed: 47 additions & 56 deletions

File tree

src/v2/models.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ class StackRecommendationResult(BaseModel): # noqa: D101
221221
registration_status: str
222222
recommendation_status: 'RecommendationStatus' = 'success'
223223
companion: List['RecommendedPackageData']
224-
usage_outliers: List[Dict[str, Any]]
225224

226225

227226
class RecommenderRequest(StackAggregatorRequest): # noqa: D101

src/v2/openapi.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,6 @@ components:
485485
- recommendation_status
486486
- companion
487487
- manifest_file_path
488-
- usage_outliers
489488
properties:
490489
_audit:
491490
$ref: '#/components/schemas/Audit'
@@ -511,11 +510,6 @@ components:
511510
manifest_file_path:
512511
type: string
513512
example: pom.xml
514-
usage_outliers:
515-
type: array
516-
items:
517-
type: object
518-
properties: {}
519513
description: Application stack recommendations
520514

521515
Audit:

src/v2/recommender.py

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import datetime
88
import logging
9+
import time
910
from typing import List, Dict
1011

1112
from pydantic import BaseModel
@@ -18,10 +19,8 @@
1819
from src.v2.models import (
1920
RecommenderRequest,
2021
StackRecommendationResult,
21-
PackageDetails,
2222
Ecosystem,
2323
RecommendedPackageData,
24-
Package,
2524
)
2625

2726
logger = logging.getLogger(__name__)
@@ -52,7 +51,7 @@ def _prepare_insights_url(host: str) -> str:
5251
return endpoint
5352

5453

55-
ECOSYSTEM_TO_SERVICE_HOST = {
54+
ECOSYSTEM_TO_INSIGHTS_URL = {
5655
"pypi": _prepare_insights_url(Settings().pypi_service_host),
5756
"npm": _prepare_insights_url(Settings().chester_service_host),
5857
"maven": _prepare_insights_url(Settings().maven_service_host),
@@ -69,15 +68,22 @@ def _call(payload: InsightsRequest):
6968
Calls the PGM model with the normalized manifest information to get
7069
the relevant packages.
7170
"""
72-
insights_url = ECOSYSTEM_TO_SERVICE_HOST.get(payload.ecosystem, None)
71+
insights_url = ECOSYSTEM_TO_INSIGHTS_URL.get(payload.ecosystem, None)
7372
assert insights_url
7473
try:
74+
started_at = time.time()
7575
response = get_session_retry().post(insights_url, json=[payload.dict()])
7676
response.raise_for_status()
7777
except Exception as e:
7878
raise InsightsCallException() from e
7979
else:
8080
json_response = response.json()
81+
logger.info(
82+
"Recommendation [%s] req.pkgs [%d] elapsed time [%0.2f] sec",
83+
payload.ecosystem.value,
84+
len(payload.package_list),
85+
time.time() - started_at,
86+
)
8187
return json_response
8288

8389
def _get_insights_response(self, normalized_packages: NormalizedPackages):
@@ -97,67 +103,64 @@ def _get_insights_response(self, normalized_packages: NormalizedPackages):
97103
# Call PGM and get the response
98104
return self._call(insights_payload)
99105

100-
def _get_package_details(self, insights_response) -> Dict[str, PackageDetails]:
101-
packages = list(
106+
def _get_recommended_package_details(
107+
self, insights_response
108+
) -> List[RecommendedPackageData]:
109+
companion_packages = insights_response.get("companion_packages", [])
110+
package_to_stats_map = dict(
102111
map(
103-
lambda x: x.get("package_name"),
104-
insights_response.get("companion_packages", []),
112+
lambda x: (x.get("package_name"), x),
113+
companion_packages,
105114
)
106115
)
116+
packages = list(package_to_stats_map.keys())
107117
ecosystem = insights_response["ecosystem"]
108118
query = (
109119
"""g.V().has('ecosystem', ecosystem).has('name', within(name)).valueMap()"""
110120
)
121+
started_at = time.time()
111122
result = post_gremlin(
112123
query=query, bindings={"ecosystem": ecosystem, "name": packages}
113124
)
125+
logger.info(
126+
"graph req.pkgs [%d] elapsed time [%0.2f] sec",
127+
len(packages),
128+
time.time() - started_at,
129+
)
114130

115-
def map_package(data):
116-
name = data.get("name", [""])[0]
131+
def extract_version(data):
117132
# all versions are not vulnerable if latest_non_cve_version doesn't exist.
118133
# all versions are vulnerable if latest_non_cve_version is empty.
119134
recommended_version = data.get(
120135
"latest_non_cve_version", data.get("latest_version", [""])
121136
)
122137
version = recommended_version[0] if len(recommended_version) else ""
123-
pkg = Package(name=name, version=version)
124-
return name, PackageDetails(
125-
**pkg.dict(),
126-
github=get_github_details(data),
127-
licenses=data.get("declared_licenses", []),
128-
ecosystem=ecosystem,
129-
url=get_snyk_package_link(ecosystem, name),
130-
latest_version=data.get("latest_version", [""])[0]
131-
)
138+
return version
132139

133-
return dict(map(map_package, result["result"]["data"]))
140+
def has_valid_version(data):
141+
return extract_version(data) != ""
134142

135-
def _get_recommended_package_details(
136-
self, insights_response
137-
) -> List[RecommendedPackageData]:
138-
package_details = self._get_package_details(insights_response)
143+
def get_recommendation_statistics(package_name: str) -> Dict[str, str]:
144+
# below dict has cooccurrence_probability, cooccurrence_count, topic_list
145+
return package_to_stats_map[package_name]
139146

140-
def map_response(r):
141-
package_detail = package_details[r["package_name"]]
147+
def map_to_recommendation_package_data(data):
148+
name = data.get("name", [""])[0]
149+
version = extract_version(data)
142150
return RecommendedPackageData(
143-
**package_detail.dict(),
144-
cooccurrence_probability=r.get("cooccurrence_probability", 0),
145-
cooccurrence_count=r.get("cooccurrence_count", 0),
146-
topic_list=r.get("topic_list", [])
151+
name=name,
152+
version=version,
153+
github=get_github_details(data),
154+
licenses=data.get("declared_licenses", []),
155+
ecosystem=ecosystem,
156+
url=get_snyk_package_link(ecosystem, name),
157+
latest_version=data.get("latest_version", [""])[0],
158+
# join stats from insight
159+
**get_recommendation_statistics(name),
147160
)
148161

149-
# remove recommended packages which are not in database.
150-
recommended_packages = filter(
151-
lambda r: package_details.get(r["package_name"]),
152-
insights_response["companion_packages"],
153-
)
154-
# map to RecommendedPackageData
155-
recommended_packages = map(map_response, recommended_packages)
156-
# remove packages which has empty version string.
157-
recommended_packages = filter(
158-
lambda pkg: pkg.version != "", recommended_packages
159-
)
160-
return list(recommended_packages)
162+
valid_packages = filter(has_valid_version, result["result"]["data"])
163+
return list(map(map_to_recommendation_package_data, valid_packages))
161164

162165
def execute(self, arguments=None, persist=True, check_license=False): # noqa: F841
163166
"""Execute task."""
@@ -167,15 +170,12 @@ def execute(self, arguments=None, persist=True, check_license=False): # noqa: F
167170
logging.warning("Recommendation is yet to be implemented for golang")
168171
return {}
169172

170-
external_request_id = request.external_request_id
171-
172173
normalized_packages = NormalizedPackages(request.packages, request.ecosystem)
173174
insights_response = self._get_insights_response(normalized_packages)
174175

175176
result = StackRecommendationResult(
176177
**arguments,
177178
companion=self._get_recommended_package_details(insights_response[0]),
178-
usage_outliers=[]
179179
)
180180

181181
recommendation = result.dict()
@@ -186,9 +186,10 @@ def execute(self, arguments=None, persist=True, check_license=False): # noqa: F
186186
"version": "v2",
187187
}
188188

189+
external_request_id = request.external_request_id
189190
if persist:
190191
persist_data_in_db(
191-
external_request_id=request.external_request_id,
192+
external_request_id=external_request_id,
192193
task_result=recommendation,
193194
worker="recommendation_v2",
194195
started_at=started_at,

tests/v2/test_recommender_api.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ def test_recommendation_response_with_empty_insight_response(
151151
"manifest_name": None,
152152
"recommendation_status": "success",
153153
"registration_status": "FREETIER",
154-
"usage_outliers": [],
155154
"uuid": None,
156155
},
157156
}
@@ -191,7 +190,6 @@ def test_recommendation_response_with_empty_graph(
191190
"manifest_name": None,
192191
"recommendation_status": "success",
193192
"registration_status": "FREETIER",
194-
"usage_outliers": [],
195193
"uuid": None,
196194
}
197195

@@ -322,6 +320,5 @@ def test_recommendation_response_with_2_packages_from_graph(
322320
"manifest_name": None,
323321
"recommendation_status": "success",
324322
"registration_status": "FREETIER",
325-
"usage_outliers": [],
326323
"uuid": None,
327324
}

0 commit comments

Comments
 (0)