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