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::Interpreter;
7use uv_python_types::PythonVersion;
8
9#[derive(Debug, Clone, Eq, PartialEq)]
10pub struct PythonRequirement {
11 source: PythonRequirementSource,
12 exact: Version,
14 installed: RequiresPython,
16 target: RequiresPython,
20 target_marker: MarkerTree,
22}
23
24impl PythonRequirement {
25 fn new(
26 source: PythonRequirementSource,
27 exact: Version,
28 installed: RequiresPython,
29 target: RequiresPython,
30 ) -> Self {
31 let target_marker = target.to_marker_tree();
32 Self {
33 source,
34 exact,
35 installed,
36 target,
37 target_marker,
38 }
39 }
40
41 pub fn from_python_version(interpreter: &Interpreter, python_version: &PythonVersion) -> Self {
44 let exact = interpreter.python_full_version().version.clone();
45 let installed = interpreter
46 .python_full_version()
47 .version
48 .only_release()
49 .without_trailing_zeros();
50 let target = python_version
51 .python_full_version()
52 .only_release()
53 .without_trailing_zeros();
54 Self::new(
55 PythonRequirementSource::PythonVersion,
56 exact,
57 RequiresPython::greater_than_equal_version(&installed),
58 RequiresPython::greater_than_equal_version(&target),
59 )
60 }
61
62 pub fn from_requires_python(
65 interpreter: &Interpreter,
66 requires_python: RequiresPython,
67 ) -> Self {
68 Self::from_marker_environment(interpreter.markers(), requires_python)
69 }
70
71 pub fn from_interpreter(interpreter: &Interpreter) -> Self {
73 let exact = interpreter
74 .python_full_version()
75 .version
76 .clone()
77 .without_trailing_zeros();
78 let installed = interpreter
79 .python_full_version()
80 .version
81 .only_release()
82 .without_trailing_zeros();
83 Self::new(
84 PythonRequirementSource::Interpreter,
85 exact,
86 RequiresPython::greater_than_equal_version(&installed),
87 RequiresPython::greater_than_equal_version(&installed),
88 )
89 }
90
91 pub fn from_marker_environment(
98 marker_env: &MarkerEnvironment,
99 requires_python: RequiresPython,
100 ) -> Self {
101 let exact = marker_env
102 .python_full_version()
103 .version
104 .clone()
105 .without_trailing_zeros();
106 let installed = marker_env
107 .python_full_version()
108 .version
109 .only_release()
110 .without_trailing_zeros();
111 Self::new(
112 PythonRequirementSource::RequiresPython,
113 exact,
114 RequiresPython::greater_than_equal_version(&installed),
115 requires_python,
116 )
117 }
118
119 pub(crate) fn narrow(&self, target: &RequiresPythonRange) -> Option<Self> {
124 Some(Self::new(
125 self.source,
126 self.exact.clone(),
127 self.installed.clone(),
128 self.target.narrow(target)?,
129 ))
130 }
131
132 pub(crate) fn split(&self, at: Bound<Version>) -> Option<(Self, Self)> {
137 let (lower, upper) = self.target.split(at)?;
138 Some((
139 Self::new(
140 self.source,
141 self.exact.clone(),
142 self.installed.clone(),
143 lower,
144 ),
145 Self::new(
146 self.source,
147 self.exact.clone(),
148 self.installed.clone(),
149 upper,
150 ),
151 ))
152 }
153
154 pub(crate) fn raises(&self, target: &RequiresPythonRange) -> bool {
157 target.lower() > self.target.range().lower()
158 }
159
160 pub(crate) fn exact(&self) -> &Version {
162 &self.exact
163 }
164
165 pub(crate) fn installed(&self) -> &RequiresPython {
167 &self.installed
168 }
169
170 pub(crate) fn target(&self) -> &RequiresPython {
172 &self.target
173 }
174
175 pub(crate) fn source(&self) -> PythonRequirementSource {
177 self.source
178 }
179
180 pub(crate) fn simplify_markers(&self, marker: MarkerTree) -> MarkerTree {
186 self.target.simplify_markers(marker)
187 }
188
189 pub(crate) fn to_marker_tree(&self) -> MarkerTree {
193 self.target_marker
194 }
195}
196
197#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash, Ord)]
198pub enum PythonRequirementSource {
199 PythonVersion,
201 RequiresPython,
203 Interpreter,
205}