Skip to content

Commit c938bbf

Browse files
Cache library detection to prevent redundant PyPI API calls (#13529)
* Add memoization to library? check to reduce redundant PyPI calls Co-authored-by: AbhishekBhaskar <[email protected]> * Add test for library? memoization behavior Co-authored-by: AbhishekBhaskar <[email protected]> * Fix missing sig annotation for updating_pipfile? method Co-authored-by: AbhishekBhaskar <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: AbhishekBhaskar <[email protected]>
1 parent 327b55b commit c938bbf

File tree

2 files changed

+29
-13
lines changed

2 files changed

+29
-13
lines changed

python/lib/dependabot/python/update_checker.rb

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -336,24 +336,23 @@ def poetry_based?
336336

337337
sig { returns(T::Boolean) }
338338
def library?
339-
return false unless updating_pyproject?
340-
return false unless library_details
339+
return @is_library unless @is_library.nil?
341340

342-
return false if T.must(library_details)["name"].nil?
341+
@is_library = T.let(check_pypi_for_library_match, T.nilable(T::Boolean))
342+
@is_library || false
343+
end
344+
345+
sig { returns(T::Boolean) }
346+
def check_pypi_for_library_match
347+
return false unless updating_pyproject? && library_details && !T.must(library_details)["name"].nil?
343348

344-
# Hit PyPi and check whether there are details for a library with a
345-
# matching name and description
346-
index_response = Dependabot::RegistryClient.get(
349+
response = Dependabot::RegistryClient.get(
347350
url: "https://pypi.org/pypi/#{normalised_name(T.must(library_details)['name'])}/json/"
348351
)
352+
return false unless response.status == 200
349353

350-
return false unless index_response.status == 200
351-
352-
pypi_info = JSON.parse(index_response.body)["info"] || {}
353-
pypi_info["summary"] == T.must(library_details)["description"]
354-
rescue Excon::Error::Timeout, Excon::Error::Socket
355-
false
356-
rescue URI::InvalidURIError
354+
(JSON.parse(response.body)["info"] || {})["summary"] == T.must(library_details)["description"]
355+
rescue Excon::Error::Timeout, Excon::Error::Socket, URI::InvalidURIError
357356
false
358357
end
359358

python/spec/dependabot/python/update_checker_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,23 @@
739739

740740
its([:requirement]) { is_expected.to eq("~2.19.1") }
741741
end
742+
743+
context "when checking library status multiple times" do
744+
before do
745+
stub_request(:get, "https://pypi.org/pypi/pendulum/json/")
746+
.to_return(status: 404)
747+
end
748+
749+
it "caches the PyPI check result to avoid redundant calls" do
750+
# Call requirements_update_strategy multiple times
751+
checker.send(:requirements_update_strategy)
752+
checker.send(:requirements_update_strategy)
753+
754+
# Verify PyPI was only called once (memoization working)
755+
expect(a_request(:get, "https://pypi.org/pypi/pendulum/json/"))
756+
.to have_been_made.once
757+
end
758+
end
742759
end
743760

744761
context "when updating a dependency in an additional requirements file" do

0 commit comments

Comments
 (0)