From c0b00efca3f23e640dd681f8d7bbf19d76b0ac72 Mon Sep 17 00:00:00 2001 From: Alfred Mazimbe Date: Tue, 24 Dec 2024 14:38:01 +0000 Subject: [PATCH] Add support for python 3.8 deprecation warning and unsupported error (#11166) --- python/lib/dependabot/python/language.rb | 35 ++++- .../spec/dependabot/python/language_spec.rb | 121 ++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 python/spec/dependabot/python/language_spec.rb diff --git a/python/lib/dependabot/python/language.rb b/python/lib/dependabot/python/language.rb index c301428d92..7fe6294b0e 100644 --- a/python/lib/dependabot/python/language.rb +++ b/python/lib/dependabot/python/language.rb @@ -11,10 +11,43 @@ module Python class Language < Dependabot::Ecosystem::VersionManager extend T::Sig + # These versions should match the versions specified at the top of `python/Dockerfile` + PYTHON_3_13 = "3.13" + PYTHON_3_12 = "3.12" + PYTHON_3_11 = "3.11" + PYTHON_3_10 = "3.10" + PYTHON_3_9 = "3.9" + PYTHON_3_8 = "3.8" + + DEPRECATED_VERSIONS = T.let([Version.new(PYTHON_3_8)].freeze, T::Array[Dependabot::Version]) + + # Keep versions in ascending order + SUPPORTED_VERSIONS = T.let([ + Version.new(PYTHON_3_9), + Version.new(PYTHON_3_10), + Version.new(PYTHON_3_11), + Version.new(PYTHON_3_12), + Version.new(PYTHON_3_13) + ].freeze, T::Array[Dependabot::Version]) sig { params(raw_version: String, requirement: T.nilable(Requirement)).void } def initialize(raw_version, requirement = nil) - super(LANGUAGE, Version.new(raw_version), [], [], requirement) + super(LANGUAGE, Version.new(raw_version), DEPRECATED_VERSIONS, SUPPORTED_VERSIONS, requirement) + end + + sig { override.returns(T::Boolean) } + def deprecated? + return false if unsupported? + return false unless Dependabot::Experiments.enabled?(:python_3_8_deprecation_warning) + + deprecated_versions.include?(version) + end + + sig { override.returns(T::Boolean) } + def unsupported? + return false unless Dependabot::Experiments.enabled?(:python_3_8_unsupported_error) + + supported_versions.all? { |supported| supported > version } end end end diff --git a/python/spec/dependabot/python/language_spec.rb b/python/spec/dependabot/python/language_spec.rb new file mode 100644 index 0000000000..f50b3d09cc --- /dev/null +++ b/python/spec/dependabot/python/language_spec.rb @@ -0,0 +1,121 @@ +# typed: false +# frozen_string_literal: true + +require "dependabot/python/language" +require "dependabot/ecosystem" +require_relative "../../spec_helper" + +RSpec.describe Dependabot::Python::Language do + subject(:language) { described_class.new(version) } + + describe "#deprecated?" do + let(:version) { "3.8" } + + before do + allow(::Dependabot::Experiments).to receive(:enabled?) + .with(:python_3_8_deprecation_warning) + .and_return(deprecation_enabled) + allow(::Dependabot::Experiments).to receive(:enabled?) + .with(:python_3_8_unsupported_error) + .and_return(unsupported_enabled) + end + + context "when python_3_8_deprecation_warning is enabled and version is deprecated" do + let(:deprecation_enabled) { true } + let(:unsupported_enabled) { false } + + it "returns true" do + expect(language.deprecated?).to be true + end + end + + context "when python_3_8_deprecation_warning is enabled but version is not deprecated" do + let(:version) { "3.13" } + let(:deprecation_enabled) { true } + let(:unsupported_enabled) { false } + + it "returns false" do + expect(language.deprecated?).to be false + end + end + + context "when python_3_8_deprecation_warning is disabled" do + let(:deprecation_enabled) { false } + let(:unsupported_enabled) { false } + + it "returns false" do + expect(language.deprecated?).to be false + end + end + + context "when version is unsupported" do + let(:deprecation_enabled) { true } + let(:unsupported_enabled) { true } + + it "returns false, as unsupported takes precedence" do + expect(language.deprecated?).to be false + end + end + end + + describe "#unsupported?" do + let(:version) { "3.8" } + + before do + allow(::Dependabot::Experiments).to receive(:enabled?) + .with(:python_3_8_unsupported_error) + .and_return(unsupported_enabled) + end + + context "when python_3_8_unsupported_error is enabled and version is unsupported" do + let(:unsupported_enabled) { true } + + it "returns true" do + expect(language.unsupported?).to be true + end + end + + context "when python_3_8_unsupported_error is enabled but version is supported" do + let(:version) { "3.13" } + let(:unsupported_enabled) { true } + + it "returns false" do + expect(language.unsupported?).to be false + end + end + + context "when python_3_8_unsupported_error is disabled" do + let(:unsupported_enabled) { false } + + it "returns false" do + expect(language.unsupported?).to be false + end + end + end + + describe "#raise_if_unsupported!" do + let(:version) { "3.8" } + + before do + allow(Dependabot::Experiments).to receive(:enabled?) + .with(:python_3_8_unsupported_error) + .and_return(unsupported_enabled) + end + + context "when python_3_8_unsupported_error is enabled and version is unsupported" do + let(:unsupported_enabled) { true } + + it "raises a ToolVersionNotSupported error" do + expect { language.raise_if_unsupported! }.to raise_error(Dependabot::ToolVersionNotSupported) + end + end + + context "when python_3_8_unsupported_error is disabled" do + let(:unsupported_enabled) { false } + + it "does not raise an error" do + expect { language.raise_if_unsupported! }.not_to raise_error + end + end + end +end