uv_resolver/
python_requirement.rs1use std::collections::Bound;
2
3use uv_distribution_types::{RequiresPython, RequiresPythonRange};
4use uv_pep440::Version;
5use uv_pep508::{MarkerEnvironment, MarkerTree};
6use uv_python::{Interpreter, PythonVersion};
7
8#[derive(Debug, Clone, Eq, PartialEq)]
9pub struct PythonRequirement {
10 source: PythonRequirementSource,
11 exact: Version,
13 installed: RequiresPython,
15 target: RequiresPython,
19}
20
21impl PythonRequirement {
22 pub fn from_python_version(interpreter: &Interpreter, python_version: &PythonVersion) -> Self {
25 let exact = interpreter.python_full_version().version.clone();
26 let installed = interpreter
27 .python_full_version()
28 .version
29 .only_release()
30 .without_trailing_zeros();
31 let target = python_version
32 .python_full_version()
33 .only_release()
34 .without_trailing_zeros();
35 Self {
36 exact,
37 installed: RequiresPython::greater_than_equal_version(&installed),
38 target: RequiresPython::greater_than_equal_version(&target),
39 source: PythonRequirementSource::PythonVersion,
40 }
41 }
42
43 pub fn from_requires_python(
46 interpreter: &Interpreter,
47 requires_python: RequiresPython,
48 ) -> Self {
49 Self::from_marker_environment(interpreter.markers(), requires_python)
50 }
51
52 pub fn from_interpreter(interpreter: &Interpreter) -> Self {
54 let exact = interpreter
55 .python_full_version()
56 .version
57 .clone()
58 .without_trailing_zeros();
59 let installed = interpreter
60 .python_full_version()
61 .version
62 .only_release()
63 .without_trailing_zeros();
64 Self {
65 exact,
66 installed: RequiresPython::greater_than_equal_version(&installed),
67 target: RequiresPython::greater_than_equal_version(&installed),
68 source: PythonRequirementSource::Interpreter,
69 }
70 }
71
72 pub fn from_marker_environment(
79 marker_env: &MarkerEnvironment,
80 requires_python: RequiresPython,
81 ) -> Self {
82 let exact = marker_env
83 .python_full_version()
84 .version
85 .clone()
86 .without_trailing_zeros();
87 let installed = marker_env
88 .python_full_version()
89 .version
90 .only_release()
91 .without_trailing_zeros();
92 Self {
93 exact,
94 installed: RequiresPython::greater_than_equal_version(&installed),
95 target: requires_python,
96 source: PythonRequirementSource::RequiresPython,
97 }
98 }
99
100 pub fn narrow(&self, target: &RequiresPythonRange) -> Option<Self> {
105 Some(Self {
106 exact: self.exact.clone(),
107 installed: self.installed.clone(),
108 target: self.target.narrow(target)?,
109 source: self.source,
110 })
111 }
112
113 pub fn split(&self, at: Bound<Version>) -> Option<(Self, Self)> {
118 let (lower, upper) = self.target.split(at)?;
119 Some((
120 Self {
121 exact: self.exact.clone(),
122 installed: self.installed.clone(),
123 target: lower,
124 source: self.source,
125 },
126 Self {
127 exact: self.exact.clone(),
128 installed: self.installed.clone(),
129 target: upper,
130 source: self.source,
131 },
132 ))
133 }
134
135 pub fn raises(&self, target: &RequiresPythonRange) -> bool {
138 target.lower() > self.target.range().lower()
139 }
140
141 pub fn exact(&self) -> &Version {
143 &self.exact
144 }
145
146 pub fn installed(&self) -> &RequiresPython {
148 &self.installed
149 }
150
151 pub fn target(&self) -> &RequiresPython {
153 &self.target
154 }
155
156 pub fn source(&self) -> PythonRequirementSource {
158 self.source
159 }
160
161 pub(crate) fn simplify_markers(&self, marker: MarkerTree) -> MarkerTree {
167 self.target.simplify_markers(marker)
168 }
169
170 pub fn to_marker_tree(&self) -> MarkerTree {
174 self.target.to_marker_tree()
175 }
176}
177
178#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash, Ord)]
179pub enum PythonRequirementSource {
180 PythonVersion,
182 RequiresPython,
184 Interpreter,
186}