class MyPrecious::PyPackageInfo
Constants
- ACCEPTED_URI_SCHEMES
- CODE_CACHE_DIR
- COMMON_REQ_FILE_NAMES
- MIN_RELEASED_DAYS
- MIN_STABLE_DAYS
- PACKAGE_CACHE_DIR
- VERSION_PATTERN
Attributes
Public Class Methods
Get an appropriate, human friendly column title for an attribute
# File lib/myprecious/python_packages.rb, line 51 def self.col_title(attr) case attr when :name then 'Package' else Reporting.common_col_title(attr) end end
Guess the name of the requirements file in the given directory
Best effort (currently, consulting a static list of likely file names for existence), and may return nil
.
# File lib/myprecious/python_packages.rb, line 42 def self.guess_req_file(fpath) COMMON_REQ_FILE_NAMES.find do |fname| fpath.join(fname).exist? end end
Construct an instance
At least one of the keywords name:
or url:
MUST be provided.
# File lib/myprecious/python_packages.rb, line 63 def initialize(name: nil, version_reqs: [], url: nil, install: false) super() if name.nil? and url.nil? raise ArgumentError, "At least one of name: or url: must be specified" end @name = name @version_reqs = version_reqs @url = url && URI(url) @install = install if pinning_req = self.version_reqs.find(&:determinative?) current_version = pinning_req.vernum end end
Public Instance Methods
Age in days of the current version
# File lib/myprecious/python_packages.rb, line 207 def age return @age if defined? @age @age = get_age end
# File lib/myprecious/python_packages.rb, line 274 def changelog # This is wrong info = get_package_info['info'] return info['project_url'] end
# File lib/myprecious/python_packages.rb, line 153 def current_version @current_version end
# File lib/myprecious/python_packages.rb, line 157 def current_version=(val) @current_version = val.kind_of?(Version) ? val : parse_version_str(val) end
# File lib/myprecious/python_packages.rb, line 265 def cves resolve_name! resolve_version! CVEs.get_for(name, current_version.to_s).map do |cve, applicability| cve end end
# File lib/myprecious/python_packages.rb, line 284 def days_between_current_and_recommended v, cv_rel = versions_with_release.find do |v, r| case when current_version.prerelease? v < current_version else v == current_version end end || [] v, rv_rel = versions_with_release.find {|v, r| v == recommended_version} || [] return nil if cv_rel.nil? || rv_rel.nil? return ((rv_rel - cv_rel) / ONE_DAY).to_i end
# File lib/myprecious/python_packages.rb, line 679 def dev_comp @dev || Float::INFINITY end
Was this requirement specified as a direct reference to a URL providing the package?
# File lib/myprecious/python_packages.rb, line 84 def direct_reference? !url.nil? end
# File lib/myprecious/python_packages.rb, line 256 def homepage_uri get_package_info['info']['home_page'] end
Incorporate the requirements for this package specified in another object into this instance
# File lib/myprecious/python_packages.rb, line 141 def incorporate(other_req) if other_req.name != self.name raise ArgumentError, "Cannot incorporate requirements for #{other_req.name} into #{self.name}" end self.version_reqs.concat(other_req.version_reqs) self.install ||= other_req.install if current_version.nil? && (pinning_req = self.version_reqs.find(&:determinative?)) current_version = pinning_req.vernum end end
# File lib/myprecious/python_packages.rb, line 216 def latest_released Date.parse(versions_with_release[0][1].to_s).to_s end
# File lib/myprecious/python_packages.rb, line 212 def latest_version versions_with_release[0][0].to_s end
# File lib/myprecious/python_packages.rb, line 196 def latest_version_satisfying_reqs versions_with_release.each do |ver, rel_date| return ver if self.satisfied_by?(ver.to_s) return ver if version_reqs.all? {|req| req.satisfied_by?(ver.to_s)} end return nil end
# File lib/myprecious/python_packages.rb, line 260 def license # TODO: Implement better, showing difference between current and recommended LicenseDescription.new(get_package_info['info']['license']) end
# File lib/myprecious/python_packages.rb, line 299 def obsolescence at_least_moderate = false if current_version.kind_of?(Version) && recommended_version cv_major = [current_version.epoch, current_version.final.first] rv_major = [recommended_version.epoch, recommended_version.final.first] case when rv_major[0] < cv_major[0] return nil when cv_major[0] < rv_major[0] # Can't compare, rely on days_between_current_and_recommended when cv_major[1] + 1 < rv_major[1] return :severe when cv_major[1] < rv_major[1] at_least_moderate = true end days_between = days_between_current_and_recommended return Reporting.obsolescence_by_age( days_between, at_least_moderate: at_least_moderate, ) end end
# File lib/myprecious/python_packages.rb, line 675 def post_comp @post || [] end
# File lib/myprecious/python_packages.rb, line 671 def pre_comp @pre || NOT_PRE end
Version
number recommended based on stability criteria
May return nil
if no version meets the established criteria
# File lib/myprecious/python_packages.rb, line 225 def recommended_version return nil if versions_with_release.empty? return @recommended_version if defined? @recommended_version orig_time_horizon = time_horizon = \ Time.now - (MIN_RELEASED_DAYS * ONE_DAY) horizon_versegs = nil versions_with_release.each do |vn, rd| if vn.kind_of?(Version) horizon_versegs = nonpatch_versegs(vn) break end end versions_with_release.each do |ver, released| next if ver.kind_of?(String) || ver.prerelease? return (@recommended_version = current_version) if current_version && current_version >= ver # Reset the time-horizon clock if moving back into previous patch-series if (nonpatch_versegs(ver) <=> horizon_versegs) < 0 time_horizon = orig_time_horizon end if released < time_horizon && version_reqs.all? {|r| r.satisfied_by?(ver, strict: false)} return (@recommended_version = ver) end time_horizon = [time_horizon, released - (MIN_STABLE_DAYS * ONE_DAY)].min end return (@recommended_version = nil) end
# File lib/myprecious/python_packages.rb, line 280 def release_history_url "https://pypi.org/project/#{name}/#history" end
For packages specified without a name, do what is necessary to find the name
# File lib/myprecious/python_packages.rb, line 92 def resolve_name! return unless direct_reference? name_from_setup = setup_data['name'] if !@name.nil? && @name != name_from_setup warn("Requirement file entry for #{@name} points to archive for #{name_from_setup}") else @name = name_from_setup end end
For requirements not deterministically specifying a version, determine which version would be installed
# File lib/myprecious/python_packages.rb, line 107 def resolve_version! return @current_version if @current_version if direct_reference? # Use setup_data @current_version = parse_version_str(setup_data['version'] || '0a0.dev0') elsif pinning_req = self.version_reqs.find(&:determinative?) @current_version = parse_version_str(pinning_req.vernum) else # Use data from pypi puts "Resolving current version of #{name}..." if inferred_ver = latest_version_satisfying_reqs self.current_version = inferred_ver puts " -> #{inferred_ver}" else puts " (unknown)" end end end
Test if the version constraints on this package are satisfied by the given version
All current version requirements are in version_reqs
.
# File lib/myprecious/python_packages.rb, line 133 def satisfied_by?(version) version_reqs.all? {|r| r.satisfied_by?(version)} end
# File lib/myprecious/python_packages.rb, line 663 def try_to_i(s) if /^\d+$/ =~ s s.to_i else s end end
An Array of Arrays containing version (MyPrecious::PyPackageInfo::Version
or String) and release date (Time)
The returned Array is sorted in order of descending version number, with strings not conforming to PEP-440 sorted lexicographically following all PEP-440 conformant versions, the latter presented as MyPrecious::PyPackageInfo::Version
objects.
# File lib/myprecious/python_packages.rb, line 170 def versions_with_release @versions ||= begin all_releases = get_package_info.fetch('releases', {}) ver_release_pairs = all_releases.each_pair.map do |ver, info| [ parse_version_str(ver), info.select {|f| f['packagetype'] == 'sdist'}.map do |f| Time.parse(f['upload_time_iso_8601']) end.min ].freeze end ver_release_pairs.reject! do |vn, rd| (vn.kind_of?(Version) && vn.prerelease?) || rd.nil? end ver_release_pairs.sort! do |l, r| case when l[0].kind_of?(String) && r[0].kind_of?(Version) then -1 when l[0].kind_of?(Version) && r[0].kind_of?(String) then 1 else l <=> r end end ver_release_pairs.reverse! ver_release_pairs.freeze end end