diff --git a/python/helpers/requirements.txt b/python/helpers/requirements.txt index 4aad2ff2eb..f69bc62261 100644 --- a/python/helpers/requirements.txt +++ b/python/helpers/requirements.txt @@ -7,6 +7,7 @@ plette==2.1.0 poetry==1.8.3 # TODO: Replace 3p package `toml` with 3.11's new stdlib `tomllib` once we drop support for Python 3.10. toml==0.10.2 +uv==0.4.9 # Some dependencies will only install if Cython is present Cython==3.0.10 diff --git a/python/lib/dependabot/python/file_updater/pip_compile_file_updater.rb b/python/lib/dependabot/python/file_updater/pip_compile_file_updater.rb index 67f2121475..89d2d46f69 100644 --- a/python/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +++ b/python/lib/dependabot/python/file_updater/pip_compile_file_updater.rb @@ -96,13 +96,14 @@ def compile_new_requirement_files def compile_file(filename) # Shell out to pip-compile, generate a new set of requirements. # This is slow, as pip-compile needs to do installs. - options = pip_compile_options(filename) + + options, command = pip_compile_options(filename) options_fingerprint = pip_compile_options_fingerprint(options) - name_part = "pyenv exec pip-compile " \ + name_part = "#{command} " \ "#{options} -P " \ "#{dependency.name}" - fingerprint_name_part = "pyenv exec pip-compile " \ + fingerprint_name_part = "#{command} " \ "#{options_fingerprint} -P " \ "" @@ -453,10 +454,16 @@ def pip_compile_options(filename) options += pip_compile_index_options if (requirements_file = compiled_file_for_filename(filename)) - options += pip_compile_options_from_compiled_file(requirements_file) + if requirements_file.content.include?("uv pip compile") + options += uv_pip_compile_options_from_compiled_file(requirements_file) + command = "pyenv exec uv pip compile" + else + options += pip_compile_options_from_compiled_file(requirements_file) + command = "pyenv exec pip-compile" + end end - options.join(" ") + [options.join(" "), command] end def pip_compile_options_from_compiled_file(requirements_file) @@ -483,6 +490,32 @@ def pip_compile_options_from_compiled_file(requirements_file) options end + def uv_pip_compile_options_from_compiled_file(requirements_file) + options = ["--output-file=#{requirements_file.name}"] + + options << "--no-emit-index-url" unless requirements_file.content.include?("index-url http") + + options << "--generate-hashes" if requirements_file.content.include?("--hash=sha") + + options << "--no-annotate" unless requirements_file.content.include?("# via ") + + options << "--pre" if requirements_file.content.include?("--pre") + + options << "--no-strip-extras" if requirements_file.content.include?("--no-strip-extras") + + if requirements_file.content.include?("--no-binary") || requirements_file.content.include?("--only-binary") + options << "--emit-build-options" + end + + if (resolver = RESOLVER_REGEX.match(requirements_file.content)) + options << "--resolver=#{resolver}" + end + + options << "--universal" if requirements_file.content.include?("--universal") + + options + end + def pip_compile_index_options credentials .select { |cred| cred["type"] == "python_index" } diff --git a/python/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb b/python/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb index 1b8accb8af..3c78b99601 100644 --- a/python/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +++ b/python/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb @@ -91,12 +91,12 @@ def fetch_latest_resolvable_version_string(requirement:) def compile_file(filename) # Shell out to pip-compile. # This is slow, as pip-compile needs to do installs. - options = pip_compile_options(filename) + options, command = pip_compile_options(filename) options_fingerprint = pip_compile_options_fingerprint(options) run_pip_compile_command( - "pyenv exec pip-compile -v #{options} -P #{dependency.name} #{filename}", - fingerprint: "pyenv exec pip-compile -v #{options_fingerprint} -P " + "#{command} -v #{options} -P #{dependency.name} #{filename}", + fingerprint: "#{command} -v #{options_fingerprint} -P " ) return true if dependency.top_level? @@ -110,8 +110,8 @@ def compile_file(filename) # update_not_possible. write_original_manifest_files run_pip_compile_command( - "pyenv exec pip-compile #{options} #{filename}", - fingerprint: "pyenv exec pip-compile #{options_fingerprint} " + "#{command} #{options} #{filename}", + fingerprint: "#{command} #{options_fingerprint} " ) true @@ -201,12 +201,12 @@ def check_original_requirements_resolvable write_temporary_dependency_files(update_requirement: false) filenames_to_compile.each do |filename| - options = pip_compile_options(filename) + options, command = pip_compile_options(filename) options_fingerprint = pip_compile_options_fingerprint(options) run_pip_compile_command( - "pyenv exec pip-compile #{options} #{filename}", - fingerprint: "pyenv exec pip-compile #{options_fingerprint} " + "#{command} #{options} #{filename}", + fingerprint: "#{command} #{options_fingerprint} " ) end @@ -251,7 +251,16 @@ def pip_compile_options(filename) options << "--output-file=#{requirements_file.name}" end - options.join(" ") + if (requirements_file = compiled_file_for_filename(filename)) + if requirements_file.content.include?("uv pip compile") + options += uv_pip_compile_options_from_compiled_file(requirements_file) + command = "pyenv exec uv pip compile" + else + command = "pyenv exec pip-compile" + end + end + + [options.join(" "), command] end def pip_compile_index_options @@ -277,6 +286,32 @@ def run_pip_compile_command(command, fingerprint:) run_command(command, fingerprint: fingerprint) end + def uv_pip_compile_options_from_compiled_file(requirements_file) + options = ["--output-file=#{requirements_file.name}"] + + options << "--no-emit-index-url" unless requirements_file.content.include?("index-url http") + + options << "--generate-hashes" if requirements_file.content.include?("--hash=sha") + + options << "--no-annotate" unless requirements_file.content.include?("# via ") + + options << "--pre" if requirements_file.content.include?("--pre") + + options << "--no-strip-extras" if requirements_file.content.include?("--no-strip-extras") + + if requirements_file.content.include?("--no-binary") || requirements_file.content.include?("--only-binary") + options << "--emit-build-options" + end + + if (resolver = RESOLVER_REGEX.match(requirements_file.content)) + options << "--resolver=#{resolver}" + end + + options << "--universal" if requirements_file.content.include?("--universal") + + options + end + def python_env env = {} diff --git a/python/spec/dependabot/python/file_updater/pip_compile_file_updater_v2_spec.rb b/python/spec/dependabot/python/file_updater/pip_compile_file_updater_v2_spec.rb new file mode 100644 index 0000000000..4ad1f17dce --- /dev/null +++ b/python/spec/dependabot/python/file_updater/pip_compile_file_updater_v2_spec.rb @@ -0,0 +1,568 @@ +# typed: false +# frozen_string_literal: true + +require "spec_helper" +require "dependabot/dependency" +require "dependabot/dependency_file" +require "dependabot/python/file_updater/pip_compile_file_updater" +require "dependabot/shared_helpers" + +RSpec.describe Dependabot::Python::FileUpdater::PipCompileFileUpdater do + let(:updater) do + described_class.new( + dependency_files: dependency_files, + dependencies: [dependency], + credentials: credentials + ) + end + let(:dependency_files) { [manifest_file, generated_file] } + let(:manifest_file) do + Dependabot::DependencyFile.new( + name: "requirements/test.in", + content: fixture("pip_compile_files", manifest_fixture_name) + ) + end + let(:generated_file) do + Dependabot::DependencyFile.new( + name: "requirements/test.txt", + content: fixture("requirements", generated_fixture_name) + ) + end + let(:manifest_fixture_name) { "unpinned.in" } + let(:generated_fixture_name) { "uv_pip_compile_unpinned.txt" } + let(:dependency) do + Dependabot::Dependency.new( + name: dependency_name, + version: dependency_version, + previous_version: dependency_previous_version, + requirements: dependency_requirements, + previous_requirements: dependency_previous_requirements, + package_manager: "pip" + ) + end + let(:dependency_name) { "attrs" } + let(:dependency_version) { "18.1.0" } + let(:dependency_previous_version) { "17.3.0" } + let(:dependency_requirements) do + [{ + file: "requirements/test.in", + requirement: nil, + groups: [], + source: nil + }] + end + let(:dependency_previous_requirements) do + [{ + file: "requirements/test.in", + requirement: nil, + groups: [], + source: nil + }] + end + let(:credentials) do + [Dependabot::Credential.new({ + "type" => "git_source", + "host" => "github.com", + "username" => "x-access-token", + "password" => "token" + })] + end + let(:tmp_path) { Dependabot::Utils::BUMP_TMP_DIR_PATH } + + before { FileUtils.mkdir_p(tmp_path) } + + describe "#updated_dependency_files" do + subject(:updated_files) { updater.updated_dependency_files } + + it "updates the requirements.txt" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + expect(updated_files.first.content) + .to include("pbr==4.0.2\n # via mock") + expect(updated_files.first.content).to include("# This file was autogenerated by uv") + expect(updated_files.first.content).not_to include("--hash=sha") + end + + context "with a mismatch in filename" do + let(:generated_fixture_name) { "uv_pip_compile_unpinned_renamed.txt" } + let(:generated_file) do + Dependabot::DependencyFile.new( + name: "requirements/test-funky.txt", + content: fixture("requirements", generated_fixture_name) + ) + end + + it "updates the requirements.txt" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + expect(updated_files.first.content) + .to include("pbr==4.0.2\n # via mock") + expect(updated_files.first.content).to include("# This file was autogenerated by uv") + expect(updated_files.first.content).not_to include("--hash=sha") + end + end + + context "with uv header" do + let(:manifest_fixture_name) { "unpinned.in" } + let(:generated_fixture_name) { "uv_pip_compile.txt" } + + it "upgrades attrs to latest" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + expect(updated_files.first.content).to include("This file was autogenerated by uv") + expect(updated_files.first.content).to include("uv pip compile") + end + end + + context "with a no-binary flag" do + let(:manifest_fixture_name) { "no_binary_uv.in" } + let(:generated_fixture_name) { "uv_pip_compile_no_binary.txt" } + let(:dependency_name) { "psycopg2" } + let(:dependency_version) { "2.7.6" } + let(:dependency_previous_version) { "2.7.4" } + + it "updates the requirements.txt correctly" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("psycopg2==2.7.6") + expect(updated_files.first.content).to include("--no-binary psycopg2") + expect(updated_files.first.content) + .not_to include("--no-binary psycopg2==") + end + end + + context "with hashes" do + let(:generated_fixture_name) { "uv_pip_compile_hashes.txt" } + + it "updates the requirements.txt, keeping the hashes" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + expect(updated_files.first.content).to include("4b90b09eeeb9b88c35bc64") + expect(updated_files.first.content).to include("# This file was autogenerated by uv") + end + + context "when needing an augmented hashin" do + let(:manifest_fixture_name) { "extra_hashes.in" } + let(:generated_fixture_name) { "uv_pip_compile_extra_hashes.txt" } + let(:dependency_name) { "pyasn1-modules" } + let(:dependency_version) { "0.1.5" } + let(:dependency_previous_version) { "0.1.4" } + + it "updates the requirements.txt, keeping all the hashes" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content) + .to include("# This file was autogenerated by uv") + expect(updated_files.first.content) + .to include("pyasn1-modules==0.1.5 \\\n --hash=sha256:01") + expect(updated_files.first.content) + .to include("--hash=sha256:b437be576bdf440fc0e930") + expect(updated_files.first.content) + .to include("pyasn1==0.3.7 \\\n --hash=sha256:16") + expect(updated_files.first.content) + .to include("--hash=sha256:bb6f5d5507621e0298794b") + expect(updated_files.first.content) + .to include("# via pyasn1-modules") + expect(updated_files.first.content).not_to include("WARNING") + end + end + end + + context "with another dependency with an unmet marker" do + let(:manifest_fixture_name) { "unmet_marker.in" } + let(:generated_fixture_name) { "uv_pip_compile_unmet_marker.txt" } + + it "updates the requirements.txt, keeping the unmet dep out of it" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + expect(updated_files.first.content).not_to include("flaky") + end + end + + context "with an unsafe dependency" do + let(:manifest_fixture_name) { "unsafe.in" } + let(:dependency_name) { "flake8" } + let(:dependency_version) { "3.6.0" } + let(:dependency_previous_version) { "3.5.0" } + + context "when not including in the lockfile" do + let(:generated_fixture_name) { "uv_pip_compile_safe.txt" } + + it "does not include the unsafe dependency" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("flake8==3.6.0") + # Distinct from pip-compile, which will not include setuptools as it is considered unsafe dependency + # UV's default will include it by default. Future major pip-tools version will do the same. + expect(updated_files.first.content).to include("setuptools") + expect(updated_files.first.content).to end_with("via flake8\n") + end + end + + context "when including in the lockfile" do + let(:generated_fixture_name) { "uv_pip_compile_unsafe.txt" } + + it "includes the unsafe dependency" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("flake8==3.6.0") + expect(updated_files.first.content).to include("setuptools") + end + end + end + + context "with an import of the setup.py" do + let(:dependency_files) do + [manifest_file, generated_file, setup_file, pyproject] + end + let(:setup_file) do + Dependabot::DependencyFile.new( + name: "setup.py", + content: fixture("setup_files", setup_fixture_name) + ) + end + let(:pyproject) do + Dependabot::DependencyFile.new( + name: "pyproject.toml", + content: fixture("pyproject_files", "black_configuration.toml") + ) + end + let(:manifest_fixture_name) { "imports_setup.in" } + let(:generated_fixture_name) { "uv_pip_compile_imports_setup.txt" } + let(:setup_fixture_name) { "small.py" } + + it "updates the requirements.txt", :slow do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + expect(updated_files.first.content) + .to include("-e file:///Users/greysteil/code/python-test") + expect(updated_files.first.content).not_to include("tmp/dependabot") + expect(updated_files.first.content) + .to include("pbr==4.0.2\n # via mock") + expect(updated_files.first.content).to include("# This file was autogenerated by uv") + expect(updated_files.first.content).not_to include("--hash=sha") + end + + context "when needing sanitization", :slow do + let(:setup_fixture_name) { "small_needs_sanitizing.py" } + + it "updates the requirements.txt" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + end + end + end + + context "with vcs url dependencies" do + let(:manifest_fixture_name) { "vcs_url.in" } + let(:generated_fixture_name) { "uv_pip_compile_vcs_url.txt" } + + it "updates the requirements.txt" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==18.1.0") + expect(updated_files.first.content) + .to include("mock @ git+https://github.com/testing-cabal/mock.git@286792b2") + end + end + + context "with a subdependency" do + let(:dependency_name) { "pbr" } + let(:dependency_version) { "4.2.0" } + let(:dependency_previous_version) { "4.0.2" } + let(:dependency_requirements) { [] } + let(:dependency_previous_requirements) { [] } + + it "updates the requirements.txt" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content) + .to include("pbr==4.2.0\n # via mock") + end + end + + context "when targeting a non-latest version" do + let(:dependency_version) { "17.4.0" } + + it "updates the requirements.txt" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("attrs==17.4.0") + expect(updated_files.first.content) + .to include("pbr==4.0.2\n # via mock") + expect(updated_files.first.content).to include("# This file was autogenerated by uv") + expect(updated_files.first.content).not_to include("--hash=sha") + end + end + + context "when the requirement.in file needs to be updated" do + let(:manifest_fixture_name) { "bounded.in" } + let(:generated_fixture_name) { "uv_pip_compile_bounded.txt" } + + let(:dependency_requirements) do + [{ + file: "requirements/test.in", + requirement: "<=18.1.0", + groups: [], + source: nil + }] + end + let(:dependency_previous_requirements) do + [{ + file: "requirements/test.in", + requirement: "<=17.4.0", + groups: [], + source: nil + }] + end + + it "updates the requirements.txt and the requirements.in" do + expect(updated_files.count).to eq(2) + expect(updated_files.first.content).to include("Attrs<=18.1.0") + expect(updated_files.last.content).to include("attrs==18.1.0") + expect(updated_files.last.content).not_to include("# via mock") + end + + context "with an additional requirements.txt" do + let(:dependency_files) { [manifest_file, generated_file, other_txt] } + let(:other_txt) do + Dependabot::DependencyFile.new( + name: "requirements.txt", + content: + fixture("requirements", "uv_pip_compile_unpinned.txt") + ) + end + + let(:dependency_requirements) do + [{ + file: "requirements/test.in", + requirement: "<=18.1.0", + groups: [], + source: nil + }, { + file: "requirements.txt", + requirement: "==18.1.0", + groups: [], + source: nil + }] + end + let(:dependency_previous_requirements) do + [{ + file: "requirements/test.in", + requirement: "<=17.4.0", + groups: [], + source: nil + }, { + file: "requirements.txt", + requirement: "==17.3.0", + groups: [], + source: nil + }] + end + + it "updates the other requirements.txt, too" do + expect(updated_files.count).to eq(3) + expect(updated_files.first.content).to include("Attrs<=18.1.0") + expect(updated_files[1].content).to include("attrs==18.1.0") + expect(updated_files.last.content).to include("attrs==18.1.0") + end + end + + context "with multiple requirement.in files" do + let(:dependency_files) do + [ + manifest_file, manifest_file2, manifest_file3, manifest_file4, + generated_file, generated_file2, generated_file3, generated_file4 + ] + end + + let(:manifest_file2) do + Dependabot::DependencyFile.new( + name: "requirements/dev.in", + content: + fixture("pip_compile_files", manifest_fixture_name) + ) + end + let(:generated_file2) do + Dependabot::DependencyFile.new( + name: "requirements/dev.txt", + content: fixture("requirements", generated_fixture_name) + ) + end + + let(:manifest_file3) do + Dependabot::DependencyFile.new( + name: "requirements/mirror2.in", + content: + fixture("pip_compile_files", "imports_mirror.in") + ) + end + let(:generated_file3) do + Dependabot::DependencyFile.new( + name: "requirements/mirror2.txt", + content: fixture("requirements", generated_fixture_name) + ) + end + + let(:manifest_file4) do + Dependabot::DependencyFile.new( + name: "requirements/mirror.in", + content: + fixture("pip_compile_files", "imports_dev.in") + ) + end + let(:generated_file4) do + Dependabot::DependencyFile.new( + name: "requirements/mirror.txt", + content: fixture("requirements", generated_fixture_name) + ) + end + + let(:dependency_requirements) do + [{ + file: "requirements/test.in", + requirement: "<=18.1.0", + groups: [], + source: nil + }, { + file: "requirements/dev.in", + requirement: "<=18.1.0", + groups: [], + source: nil + }] + end + let(:dependency_previous_requirements) do + [{ + file: "requirements/test.in", + requirement: "<=17.4.0", + groups: [], + source: nil + }, { + file: "requirements/dev.in", + requirement: "<=17.4.0", + groups: [], + source: nil + }] + end + + it "updates the other manifest file, too" do + expect(updated_files.count).to eq(6) + expect(updated_files[0].name).to eq("requirements/test.in") + expect(updated_files[1].name).to eq("requirements/dev.in") + expect(updated_files[2].name).to eq("requirements/test.txt") + expect(updated_files[3].name).to eq("requirements/dev.txt") + expect(updated_files[4].name).to eq("requirements/mirror2.txt") + expect(updated_files[5].name).to eq("requirements/mirror.txt") + expect(updated_files[0].content).to include("Attrs<=18.1.0") + expect(updated_files[1].content).to include("Attrs<=18.1.0") + expect(updated_files[2].content).to include("attrs==18.1.0") + expect(updated_files[3].content).to include("attrs==18.1.0") + expect(updated_files[4].content).to include("attrs==18.1.0") + expect(updated_files[5].content).to include("attrs==18.1.0") + end + end + end + + context "with stripped extras" do + let(:manifest_fixture_name) { "strip_extras.in" } + let(:generated_fixture_name) { "uv_pip_compile_strip_extras.txt" } + let(:dependency_name) { "cachecontrol" } + let(:dependency_version) { "0.12.10" } + let(:dependency_previous_version) { "0.12.9" } + + it "doesn't add an extras annotation on cachecontrol" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("cachecontrol==0.12.10") + expect(updated_files.first.content) + .not_to include("cachecontrol[filecache]==") + end + end + + context "with no stripped extras" do + let(:manifest_fixture_name) { "strip_extras.in" } + let(:generated_fixture_name) { "uv_pip_compile_no_strip_extras.txt" } + let(:dependency_name) { "cachecontrol" } + let(:dependency_version) { "0.12.10" } + let(:dependency_previous_version) { "0.12.9" } + + it "adds an extras annotation on cachecontrol" do + expect(updated_files.count).to eq(1) + expect(updated_files.first.content).to include("cachecontrol[filecache]==0.12.10") + end + end + end + + describe "#package_hashes_for" do + let(:name) { "package_name" } + let(:version) { "1.0.0" } + let(:algorithm) { "sha256" } + + context "when index_urls is not set" do + let(:updater) do + described_class.new( + dependencies: [], + dependency_files: [], + credentials: [] + ) + end + + before do + allow(Dependabot::SharedHelpers).to receive(:run_helper_subprocess).and_return([{ "hash" => "123abc" }]) + end + + it "returns hash" do + result = updater.send(:package_hashes_for, name: name, version: version, algorithm: algorithm) + expect(result).to eq(["--hash=sha256:123abc"]) + end + end + + context "when multiple index_urls are set" do + let(:updater) do + described_class.new( + dependencies: [], + dependency_files: [], + credentials: [], + index_urls: [nil, "http://example.com"] + ) + end + + before do + allow(Dependabot::SharedHelpers).to receive(:run_helper_subprocess) + .and_return([{ "hash" => "123abc" }], [{ "hash" => "312cba" }]) + end + + it "returns returns two hashes" do + result = updater.send(:package_hashes_for, name: name, version: version, algorithm: algorithm) + expect(result).to eq(%w(--hash=sha256:123abc --hash=sha256:312cba)) + end + end + + context "when multiple index_urls are set but package does not exist in PyPI" do + let(:updater) do + described_class.new( + dependencies: [], + dependency_files: [], + credentials: [], + index_urls: [nil, "http://example.com"] + ) + end + + before do + allow(Dependabot::SharedHelpers).to receive(:run_helper_subprocess).with({ + args: %w(package_name 1.0.0 sha256), + command: "pyenv exec python3 /opt/python/run.py", + function: "get_dependency_hash" + }).and_raise( + Dependabot::SharedHelpers::HelperSubprocessFailed.new( + message: "Error message", error_context: {}, error_class: "PackageNotFoundError" + ) + ) + + allow(Dependabot::SharedHelpers).to receive(:run_helper_subprocess) + .with({ + args: %w(package_name 1.0.0 sha256 http://example.com), + command: "pyenv exec python3 /opt/python/run.py", + function: "get_dependency_hash" + }).and_return([{ "hash" => "123abc" }]) + end + + it "returns returns two hashes" do + result = updater.send(:package_hashes_for, name: name, version: version, algorithm: algorithm) + expect(result).to eq(["--hash=sha256:123abc"]) + end + end + end +end diff --git a/python/spec/fixtures/pip_compile_files/no_binary_uv.in b/python/spec/fixtures/pip_compile_files/no_binary_uv.in new file mode 100644 index 0000000000..08018c1cdc --- /dev/null +++ b/python/spec/fixtures/pip_compile_files/no_binary_uv.in @@ -0,0 +1,2 @@ +psycopg2 +--no-binary psycopg2 diff --git a/python/spec/fixtures/pip_compile_files/vcs_url.in b/python/spec/fixtures/pip_compile_files/vcs_url.in new file mode 100644 index 0000000000..cf1ae99c61 --- /dev/null +++ b/python/spec/fixtures/pip_compile_files/vcs_url.in @@ -0,0 +1,2 @@ +git+https://github.com/testing-cabal/mock.git@2.0.0 +Attrs diff --git a/python/spec/fixtures/requirements/uv_pip_compile.txt b/python/spec/fixtures/requirements/uv_pip_compile.txt new file mode 100644 index 0000000000..e47dcb2a67 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile.txt @@ -0,0 +1,22 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file uv_pip_compile.txt unpinned_uv.in +attrs==18.1.0 + # via -r unpinned_uv.in +execnet==2.1.1 + # via pytest-xdist +flaky==3.8.1 + # via -r unpinned_uv.in +iniconfig==2.0.0 + # via pytest +mock==5.1.0 + # via -r unpinned_uv.in +packaging==24.1 + # via pytest +pluggy==1.5.0 + # via pytest +pytest==8.2.2 + # via + # -r unpinned_uv.in + # pytest-xdist +pytest-xdist==3.6.1 + # via -r unpinned_uv.in diff --git a/python/spec/fixtures/requirements/uv_pip_compile_bounded.txt b/python/spec/fixtures/requirements/uv_pip_compile_bounded.txt new file mode 100644 index 0000000000..a35bb7f8e3 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_bounded.txt @@ -0,0 +1,15 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --no-annotate --output-file requirements/text.txt requirements/test.in +apipkg==1.4 +attrs==17.3.0 +execnet==1.5.0 +flaky==3.4.0 +mock==2.0.0 +more-itertools==4.1.0 +pbr==4.0.3 +pluggy==0.6.0 +py==1.5.3 +pytest-forked==0.2 +pytest-xdist==1.22.2 +pytest==3.5.1 +six==1.11.0 diff --git a/python/spec/fixtures/requirements/uv_pip_compile_extra_hashes.txt b/python/spec/fixtures/requirements/uv_pip_compile_extra_hashes.txt new file mode 100644 index 0000000000..e0b36be5e2 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_extra_hashes.txt @@ -0,0 +1,43 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --generate-hashes --output-file req.txt req.in +atomicwrites==1.2.1 \ + --hash=sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0 \ + --hash=sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee \ + # via pytest +attrs==18.2.0 \ + --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69 \ + --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb \ + # via pytest +more-itertools==5.0.0 \ + --hash=sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4 \ + --hash=sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc \ + --hash=sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9 \ + # via pytest +pluggy==0.8.0 \ + --hash=sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095 \ + --hash=sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f \ + # via pytest +py==1.7.0 \ + --hash=sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694 \ + --hash=sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6 \ + # via pytest +pyasn1-modules==0.1.4 \ + --hash=sha256:2e39aead1602e4e5aa8b796260848f9383e51bea278edf7d2b4fb686944425fa \ + --hash=sha256:34e1d014608ca4f8a0cc3164a5add93f4b8a04a3871b96d31a028ff36a6fe924 \ + --hash=sha256:529d5d509562c22877a53771c5b394d8102c98cd62f33bb5af23b475879ea6d5 \ + --hash=sha256:641cc18cf56d4a60679804aa8ae8cbc7359b3fa2d5559df064ecfaca27d15b10 \ + --hash=sha256:6ad0e6772af4b74bd63c78c0102ece7b6a775f764e395137968af575c20bbfc9 \ + --hash=sha256:7411e837c83ea4cb6088aa3bf63691d348454fcd9bb3d9cc342859282419bfcf \ + --hash=sha256:7930d0f6109a47f78e5fb88a4f7ed2bfa1073ec9ddb2657deffa92f0805568fb \ + --hash=sha256:a24f5118f41af33f13fa0c7e8419fc7380dfe2d2f2dc0f554d928141c842f924 \ + --hash=sha256:ab7e23e45f32f0515e5a084eecaff22653bb6277d0d4229cb7369117abf33baa \ + --hash=sha256:b07c17bdb34d6f64aafea6269f2e8fb306a57473f0f38d9a6ca389d6ab30ac4a \ + --hash=sha256:beb3d344fee1fa68ddf36471c5d9120665ba049900d7fccbffa50c77036581de \ + --hash=sha256:ca3cdc5d8ecc97f78a202009512254bd7aeef77069405e9e834b45c48a26a4db +pytest==4.0.2 \ + --hash=sha256:f689bf2fc18c4585403348dd56f47d87780bf217c53ed9ae7a3e2d7faa45f8e9 \ + --hash=sha256:f812ea39a0153566be53d88f8de94839db1e8a05352ed8a49525d7d7f37861e9 +six==1.12.0 \ + --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \ + --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \ + # via more-itertools, pytest diff --git a/python/spec/fixtures/requirements/uv_pip_compile_hashes.txt b/python/spec/fixtures/requirements/uv_pip_compile_hashes.txt new file mode 100644 index 0000000000..147d25f15a --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_hashes.txt @@ -0,0 +1,51 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --generate-hashes --output-file req.txt req.in +apipkg==1.4 \ + --hash=sha256:2e38399dbe842891fe85392601aab8f40a8f4cc5a9053c326de35a1cc0297ac6 \ + --hash=sha256:65d2aa68b28e7d31233bb2ba8eb31cda40e4671f8ac2d6b241e358c9652a74b9 \ + # via execnet +attrs==17.3.0 \ + --hash=sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9 \ + --hash=sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450 +execnet==1.5.0 \ + --hash=sha256:a7a84d5fa07a089186a329528f127c9d73b9de57f1a1131b82bb5320ee651f6a \ + --hash=sha256:fc155a6b553c66c838d1a22dba1dc9f5f505c43285a878c6f74a79c024750b83 \ + # via pytest-xdist +flaky==3.4.0 \ + --hash=sha256:4ad7880aef8c35a34ddb394d4fa33047765bca1e3d67d182bf6eba9c8eabf3a2 \ + --hash=sha256:d0533f473a46b916e6db6e84e20b06d8a70656600a0c14e819b0760b63f70226 +mock==2.0.0 \ + --hash=sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1 \ + --hash=sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba +more-itertools==4.1.0 \ + --hash=sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea \ + --hash=sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e \ + --hash=sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44 \ + # via pytest +pbr==4.0.3 \ + --hash=sha256:680bf5ba9b28dd56e08eb7c267991a37c7a5f90a92c2e07108829931a50ff80a \ + --hash=sha256:6874feb22334a1e9a515193cba797664e940b763440c88115009ec323a7f2df5 \ + # via mock +pluggy==0.6.0 \ + --hash=sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff \ + --hash=sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c \ + --hash=sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5 \ + # via pytest +py==1.5.3 \ + --hash=sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881 \ + --hash=sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a \ + # via pytest +pytest-forked==0.2 \ + --hash=sha256:e4500cd0509ec4a26535f7d4112a8cc0f17d3a41c29ffd4eab479d2a55b30805 \ + --hash=sha256:f275cb48a73fc61a6710726348e1da6d68a978f0ec0c54ece5a5fae5977e5a08 \ + # via pytest-xdist +pytest-xdist==1.22.2 \ + --hash=sha256:be2662264b035920ba740ed6efb1c816a83c8a22253df7766d129f6a7bfdbd35 \ + --hash=sha256:e8f5744acc270b3e7d915bdb4d5f471670f049b6fbd163d4cbd52203b075d30f +pytest==3.5.1 \ + --hash=sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8 \ + --hash=sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526 +six==1.11.0 \ + --hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \ + --hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb \ + # via mock, more-itertools, pytest diff --git a/python/spec/fixtures/requirements/uv_pip_compile_imports_setup.txt b/python/spec/fixtures/requirements/uv_pip_compile_imports_setup.txt new file mode 100644 index 0000000000..48b89a0277 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_imports_setup.txt @@ -0,0 +1,19 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file something.txt something.in +-e file:///Users/greysteil/code/python-test +apipkg==1.5 # via execnet +atomicwrites==1.2.1 # via pytest +attrs==18.2.0 +contextlib2==0.5.5 # via raven +execnet==1.5.0 # via pytest-xdist +flaky==3.4.0 +mock==2.0.0 +more-itertools==4.3.0 # via pytest +pbr==4.0.2 # via mock +pluggy==0.7.1 # via pytest +py==1.6.0 # via pytest +pytest-forked==0.2 # via pytest-xdist +pytest-xdist==1.23.0 +pytest==3.7.4 +raven==5.32.0 +six==1.11.0 # via mock, more-itertools, pytest, pytest-xdist diff --git a/python/spec/fixtures/requirements/uv_pip_compile_no_binary.txt b/python/spec/fixtures/requirements/uv_pip_compile_no_binary.txt new file mode 100644 index 0000000000..258ce1fdfa --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_no_binary.txt @@ -0,0 +1,5 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file requirements.txt requirements.in +--no-binary psycopg2 + +psycopg2==2.7.4 diff --git a/python/spec/fixtures/requirements/uv_pip_compile_no_strip_extras.txt b/python/spec/fixtures/requirements/uv_pip_compile_no_strip_extras.txt new file mode 100644 index 0000000000..e26439ba89 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_no_strip_extras.txt @@ -0,0 +1,18 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --no-strip-extras --output-file=constraints.txt constraints.in +cachecontrol==0.12.10 + # via -r constraints.in +certifi==2021.10.8 + # via requests +charset-normalizer==2.0.7 + # via requests +idna==3.3 + # via requests +lockfile==0.12.2 + # via cachecontrol +msgpack==1.0.2 + # via cachecontrol +requests==2.26.0 + # via cachecontrol +urllib3==1.26.7 + # via requests diff --git a/python/spec/fixtures/requirements/uv_pip_compile_safe.txt b/python/spec/fixtures/requirements/uv_pip_compile_safe.txt new file mode 100644 index 0000000000..5151446181 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_safe.txt @@ -0,0 +1,6 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file dev-requirements.txt dev-requirements.in +flake8==3.5.0 +mccabe==0.6.1 # via flake8 +pycodestyle==2.4.0 # via flake8 +pyflakes==2.0.0 # via flake8 diff --git a/python/spec/fixtures/requirements/uv_pip_compile_strip_extras.txt b/python/spec/fixtures/requirements/uv_pip_compile_strip_extras.txt new file mode 100644 index 0000000000..7c21fe5e45 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_strip_extras.txt @@ -0,0 +1,18 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file=constraints.txt constraints.in +cachecontrol==0.12.10 + # via -r constraints.in +certifi==2021.10.8 + # via requests +charset-normalizer==2.0.7 + # via requests +idna==3.3 + # via requests +lockfile==0.12.2 + # via cachecontrol +msgpack==1.0.2 + # via cachecontrol +requests==2.26.0 + # via cachecontrol +urllib3==1.26.7 + # via requests diff --git a/python/spec/fixtures/requirements/uv_pip_compile_unmet_marker.txt b/python/spec/fixtures/requirements/uv_pip_compile_unmet_marker.txt new file mode 100644 index 0000000000..cd2d87df5f --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_unmet_marker.txt @@ -0,0 +1,15 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file=requirements.txt requirements.in +apipkg==1.5 # via execnet +atomicwrites==1.1.5 # via pytest +attrs==17.3.0 +execnet==1.5.0 # via pytest-xdist +mock==2.0.0 +more-itertools==4.3.0 # via pytest +pbr==4.2.0 # via mock +pluggy==0.7.1 # via pytest +py==1.5.4 # via pytest +pytest-forked==0.2 # via pytest-xdist +pytest-xdist==1.22.5 +pytest==3.7.2 +six==1.11.0 # via mock, more-itertools, pytest, pytest-xdist diff --git a/python/spec/fixtures/requirements/uv_pip_compile_unpinned.txt b/python/spec/fixtures/requirements/uv_pip_compile_unpinned.txt new file mode 100644 index 0000000000..a776c74089 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_unpinned.txt @@ -0,0 +1,15 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file=requirements/test.txt requirements/test.in +apipkg==1.4 # via execnet +attrs==17.3.0 +execnet==1.5.0 # via pytest-xdist +flaky==3.4.0 +mock==2.0.0 +more-itertools==4.1.0 # via pytest +pbr==4.0.2 # via mock +pluggy==0.6.0 # via pytest +py==1.5.3 # via pytest +pytest-forked==0.2 # via pytest-xdist +pytest-xdist==1.22.2 +pytest==3.5.1 +six==1.11.0 # via mock, more-itertools, pytest diff --git a/python/spec/fixtures/requirements/uv_pip_compile_unpinned_renamed.txt b/python/spec/fixtures/requirements/uv_pip_compile_unpinned_renamed.txt new file mode 100644 index 0000000000..5c455cda2c --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_unpinned_renamed.txt @@ -0,0 +1,15 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file=requirements/test-funky.txt requirements/test.in +apipkg==1.4 # via execnet +attrs==17.3.0 +execnet==1.5.0 # via pytest-xdist +flaky==3.4.0 +mock==2.0.0 +more-itertools==4.1.0 # via pytest +pbr==4.0.2 # via mock +pluggy==0.6.0 # via pytest +py==1.5.3 # via pytest +pytest-forked==0.2 # via pytest-xdist +pytest-xdist==1.22.2 +pytest==3.5.1 +six==1.11.0 # via mock, more-itertools, pytest diff --git a/python/spec/fixtures/requirements/uv_pip_compile_unsafe.txt b/python/spec/fixtures/requirements/uv_pip_compile_unsafe.txt new file mode 100644 index 0000000000..c037e652c0 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_unsafe.txt @@ -0,0 +1,10 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file dev-requirements.txt dev-requirements.in + +flake8==3.5.0 +mccabe==0.6.1 # via flake8 +pycodestyle==2.4.0 # via flake8 +pyflakes==2.0.0 # via flake8 + +# The following packages are considered to be unsafe by pip-compile by default, but not by uv, in a requirements file: +setuptools==40.4.3 # via flake8 diff --git a/python/spec/fixtures/requirements/uv_pip_compile_vcs_url.txt b/python/spec/fixtures/requirements/uv_pip_compile_vcs_url.txt new file mode 100644 index 0000000000..3a0ace2a81 --- /dev/null +++ b/python/spec/fixtures/requirements/uv_pip_compile_vcs_url.txt @@ -0,0 +1,6 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --output-file req.txt req.in +mock @ git+https://github.com/testing-cabal/mock.git@286792b2cd5b5baa8338260538ed207391280e34 +attrs==17.3.0 +pbr==5.1.1 +six==1.12.0