Skip to content

Commit

Permalink
Parse both setup.py and setup.cfg
Browse files Browse the repository at this point in the history
  • Loading branch information
honnix committed Apr 16, 2021
1 parent 433fe24 commit ca4d292
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 347 deletions.
11 changes: 1 addition & 10 deletions python/lib/dependabot/python/file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class FileParser < Dependabot::FileParsers::Base
require_relative "file_parser/pipfile_files_parser"
require_relative "file_parser/poetry_files_parser"
require_relative "file_parser/setup_file_parser"
require_relative "file_parser/setup_cfg_file_parser"

POETRY_DEPENDENCY_TYPES =
%w(tool.poetry.dependencies tool.poetry.dev-dependencies).freeze
Expand Down Expand Up @@ -45,8 +44,7 @@ def parse
dependency_set += pipenv_dependencies if pipfile
dependency_set += poetry_dependencies if using_poetry?
dependency_set += requirement_dependencies if requirement_files.any?
dependency_set += setup_file_dependencies if setup_file
dependency_set += setup_cfg_file_dependencies if setup_cfg_file
dependency_set += setup_file_dependencies if setup_file || setup_cfg_file

dependency_set.dependencies
end
Expand Down Expand Up @@ -139,13 +137,6 @@ def setup_file_dependencies
dependency_set
end

def setup_cfg_file_dependencies
@setup_cfg_file_dependencies ||=
SetupCfgFileParser.
new(dependency_files: dependency_files).
dependency_set
end

def lockfile_for_pip_compile_file?(filename)
return false unless pip_compile_files.any?
return false unless filename.end_with?(".txt")
Expand Down
89 changes: 87 additions & 2 deletions python/lib/dependabot/python/file_parser/setup_file_parser.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,81 @@
# frozen_string_literal: true

require_relative "setup_file_parser_base"
require "dependabot/dependency"
require "dependabot/errors"
require "dependabot/file_parsers/base/dependency_set"
require "dependabot/shared_helpers"
require "dependabot/python/file_parser"
require "dependabot/python/native_helpers"
require "dependabot/python/name_normaliser"

module Dependabot
module Python
class FileParser
class SetupFileParser < SetupFileParserBase
class SetupFileParser
INSTALL_REQUIRES_REGEX = /install_requires\s*=\s*\[/m.freeze
SETUP_REQUIRES_REGEX = /setup_requires\s*=\s*\[/m.freeze
TESTS_REQUIRE_REGEX = /tests_require\s*=\s*\[/m.freeze
EXTRAS_REQUIRE_REGEX = /extras_require\s*=\s*\{/m.freeze

CLOSING_BRACKET = { "[" => "]", "{" => "}" }.freeze

def initialize(dependency_files:)
@dependency_files = dependency_files
end

def dependency_set
dependencies = Dependabot::FileParsers::Base::DependencySet.new

parsed_setup_file.each do |dep|
# If a requirement has a `<` or `<=` marker then updating it is
# probably blocked. Ignore it.
next if dep["markers"].include?("<")

# If the requirement is our inserted version, ignore it
# (we wouldn't be able to update it)
next if dep["version"] == "0.0.1+dependabot"

dependencies <<
Dependency.new(
name: normalised_name(dep["name"], dep["extras"]),
version: dep["version"]&.include?("*") ? nil : dep["version"],
requirements: [{
requirement: dep["requirement"],
file: Pathname.new(dep["file"]).cleanpath.to_path,
source: nil,
groups: [dep["requirement_type"]]
}],
package_manager: "pip"
)
end
dependencies
end

private

attr_reader :dependency_files

def parsed_setup_file
SharedHelpers.in_a_temporary_directory do
write_temporary_dependency_files

requirements = SharedHelpers.run_helper_subprocess(
command: "pyenv exec python #{NativeHelpers.python_helper_path}",
function: "parse_setup",
args: [Dir.pwd]
)

check_requirements(requirements)
requirements
end
rescue SharedHelpers::HelperSubprocessFailed => e
raise Dependabot::DependencyFileNotEvaluatable, e.message if e.message.start_with?("InstallationError")

return [] unless setup_file

parsed_sanitized_setup_file
end

def parsed_sanitized_setup_file
SharedHelpers.in_a_temporary_directory do
write_sanitized_setup_file
Expand All @@ -36,6 +97,26 @@ def parsed_sanitized_setup_file
[]
end

def check_requirements(requirements)
requirements.each do |dep|
next unless dep["requirement"]

Python::Requirement.new(dep["requirement"].split(","))
rescue Gem::Requirement::BadRequirementError => e
raise Dependabot::DependencyFileNotEvaluatable, e.message
end
end

def write_temporary_dependency_files
dependency_files.
reject { |f| f.name == ".python-version" }.
each do |file|
path = file.name
FileUtils.mkdir_p(Pathname.new(path).dirname)
File.write(path, file.content)
end
end

# Write a setup.py with only entries for the requires fields.
#
# This sanitization is far from perfect (it will fail if any of the
Expand Down Expand Up @@ -83,6 +164,10 @@ def closing_bracket_index(string, bracket)
0
end

def normalised_name(name, extras)
NameNormaliser.normalise_including_extras(name, extras)
end

def setup_file
dependency_files.find { |f| f.name == "setup.py" }
end
Expand Down
104 changes: 0 additions & 104 deletions python/lib/dependabot/python/file_parser/setup_file_parser_base.rb

This file was deleted.

This file was deleted.

Loading

0 comments on commit ca4d292

Please sign in to comment.