uv_pep508/marker/
environment.rs

1use std::sync::Arc;
2
3use uv_pep440::{Version, VersionParseError};
4
5use crate::{CanonicalMarkerValueString, CanonicalMarkerValueVersion, StringVersion};
6
7/// The marker values for a python interpreter, normally the current one
8///
9/// <https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers>
10#[allow(missing_docs, clippy::unsafe_derive_deserialize)]
11#[derive(Clone, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
12pub struct MarkerEnvironment {
13    #[serde(flatten)]
14    inner: Arc<MarkerEnvironmentInner>,
15}
16
17#[derive(Clone, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
18struct MarkerEnvironmentInner {
19    implementation_name: String,
20    implementation_version: StringVersion,
21    os_name: String,
22    platform_machine: String,
23    platform_python_implementation: String,
24    platform_release: String,
25    platform_system: String,
26    platform_version: String,
27    python_full_version: StringVersion,
28    python_version: StringVersion,
29    sys_platform: String,
30}
31
32impl MarkerEnvironment {
33    /// Returns of the PEP 440 version typed value of the key in the current environment
34    pub fn get_version(&self, key: CanonicalMarkerValueVersion) -> &Version {
35        match key {
36            CanonicalMarkerValueVersion::ImplementationVersion => {
37                &self.implementation_version().version
38            }
39            CanonicalMarkerValueVersion::PythonFullVersion => &self.python_full_version().version,
40        }
41    }
42
43    /// Returns of the stringly typed value of the key in the current environment
44    pub fn get_string(&self, key: CanonicalMarkerValueString) -> &str {
45        match key {
46            CanonicalMarkerValueString::ImplementationName => self.implementation_name(),
47            CanonicalMarkerValueString::OsName => self.os_name(),
48            CanonicalMarkerValueString::PlatformMachine => self.platform_machine(),
49            CanonicalMarkerValueString::PlatformPythonImplementation => {
50                self.platform_python_implementation()
51            }
52            CanonicalMarkerValueString::PlatformRelease => self.platform_release(),
53            CanonicalMarkerValueString::PlatformSystem => self.platform_system(),
54            CanonicalMarkerValueString::PlatformVersion => self.platform_version(),
55            CanonicalMarkerValueString::SysPlatform => self.sys_platform(),
56        }
57    }
58}
59
60/// APIs for retrieving specific parts of a marker environment.
61impl MarkerEnvironment {
62    /// Returns the name of the Python implementation for this environment.
63    ///
64    /// This is equivalent to `sys.implementation.name`.
65    ///
66    /// Some example values are: `cpython`.
67    #[inline]
68    pub fn implementation_name(&self) -> &str {
69        &self.inner.implementation_name
70    }
71
72    /// Returns the Python implementation version for this environment.
73    ///
74    /// This value is derived from `sys.implementation.version`. See [PEP 508
75    /// environment markers] for full details.
76    ///
77    /// This is equivalent to `sys.implementation.name`.
78    ///
79    /// Some example values are: `3.4.0`, `3.5.0b1`.
80    ///
81    /// [PEP 508 environment markers]: https://peps.python.org/pep-0508/#environment-markers
82    #[inline]
83    pub fn implementation_version(&self) -> &StringVersion {
84        &self.inner.implementation_version
85    }
86
87    /// Returns the name of the operating system for this environment.
88    ///
89    /// This is equivalent to `os.name`.
90    ///
91    /// Some example values are: `posix`, `java`.
92    #[inline]
93    pub fn os_name(&self) -> &str {
94        &self.inner.os_name
95    }
96
97    /// Returns the name of the machine for this environment's platform.
98    ///
99    /// This is equivalent to `platform.machine()`.
100    ///
101    /// Some example values are: `x86_64`.
102    #[inline]
103    pub fn platform_machine(&self) -> &str {
104        &self.inner.platform_machine
105    }
106
107    /// Returns the name of the Python implementation for this environment's
108    /// platform.
109    ///
110    /// This is equivalent to `platform.python_implementation()`.
111    ///
112    /// Some example values are: `CPython`, `Jython`.
113    #[inline]
114    pub fn platform_python_implementation(&self) -> &str {
115        &self.inner.platform_python_implementation
116    }
117
118    /// Returns the release for this environment's platform.
119    ///
120    /// This is equivalent to `platform.release()`.
121    ///
122    /// Some example values are: `3.14.1-x86_64-linode39`, `14.5.0`, `1.8.0_51`.
123    #[inline]
124    pub fn platform_release(&self) -> &str {
125        &self.inner.platform_release
126    }
127
128    /// Returns the system for this environment's platform.
129    ///
130    /// This is equivalent to `platform.system()`.
131    ///
132    /// Some example values are: `Linux`, `Windows`, `Java`.
133    #[inline]
134    pub fn platform_system(&self) -> &str {
135        &self.inner.platform_system
136    }
137
138    /// Returns the version for this environment's platform.
139    ///
140    /// This is equivalent to `platform.version()`.
141    ///
142    /// Some example values are: `#1 SMP Fri Apr 25 13:07:35 EDT 2014`,
143    /// `Java HotSpot(TM) 64-Bit Server VM, 25.51-b03, Oracle Corporation`,
144    /// `Darwin Kernel Version 14.5.0: Wed Jul 29 02:18:53 PDT 2015;
145    /// root:xnu-2782.40.9~2/RELEASE_X86_64`.
146    #[inline]
147    pub fn platform_version(&self) -> &str {
148        &self.inner.platform_version
149    }
150
151    /// Returns the full version of Python for this environment.
152    ///
153    /// This is equivalent to `platform.python_version()`.
154    ///
155    /// Some example values are: `3.4.0`, `3.5.0b1`.
156    #[inline]
157    pub fn python_full_version(&self) -> &StringVersion {
158        &self.inner.python_full_version
159    }
160
161    /// Returns the version of Python for this environment.
162    ///
163    /// This is equivalent to `'.'.join(platform.python_version_tuple()[:2])`.
164    ///
165    /// Some example values are: `3.4`, `2.7`.
166    #[inline]
167    pub fn python_version(&self) -> &StringVersion {
168        &self.inner.python_version
169    }
170
171    /// Returns the name of the system platform for this environment.
172    ///
173    /// This is equivalent to `sys.platform`.
174    ///
175    /// Some example values are: `linux`, `linux2`, `darwin`, `java1.8.0_51`
176    /// (note that `linux` is from Python3 and `linux2` from Python2).
177    #[inline]
178    pub fn sys_platform(&self) -> &str {
179        &self.inner.sys_platform
180    }
181}
182
183/// APIs for setting specific parts of a marker environment.
184impl MarkerEnvironment {
185    /// Set the name of the Python implementation for this environment.
186    ///
187    /// See also [`MarkerEnvironment::implementation_name`].
188    #[inline]
189    #[must_use]
190    pub fn with_implementation_name(mut self, value: impl Into<String>) -> Self {
191        Arc::make_mut(&mut self.inner).implementation_name = value.into();
192        self
193    }
194
195    /// Set the Python implementation version for this environment.
196    ///
197    /// See also [`MarkerEnvironment::implementation_version`].
198    #[inline]
199    #[must_use]
200    pub fn with_implementation_version(mut self, value: impl Into<StringVersion>) -> Self {
201        Arc::make_mut(&mut self.inner).implementation_version = value.into();
202        self
203    }
204
205    /// Set the name of the operating system for this environment.
206    ///
207    /// See also [`MarkerEnvironment::os_name`].
208    #[inline]
209    #[must_use]
210    pub fn with_os_name(mut self, value: impl Into<String>) -> Self {
211        Arc::make_mut(&mut self.inner).os_name = value.into();
212        self
213    }
214
215    /// Set the name of the machine for this environment's platform.
216    ///
217    /// See also [`MarkerEnvironment::platform_machine`].
218    #[inline]
219    #[must_use]
220    pub fn with_platform_machine(mut self, value: impl Into<String>) -> Self {
221        Arc::make_mut(&mut self.inner).platform_machine = value.into();
222        self
223    }
224
225    /// Set the name of the Python implementation for this environment's
226    /// platform.
227    ///
228    /// See also [`MarkerEnvironment::platform_python_implementation`].
229    #[inline]
230    #[must_use]
231    pub fn with_platform_python_implementation(mut self, value: impl Into<String>) -> Self {
232        Arc::make_mut(&mut self.inner).platform_python_implementation = value.into();
233        self
234    }
235
236    /// Set the release for this environment's platform.
237    ///
238    /// See also [`MarkerEnvironment::platform_release`].
239    #[inline]
240    #[must_use]
241    pub fn with_platform_release(mut self, value: impl Into<String>) -> Self {
242        Arc::make_mut(&mut self.inner).platform_release = value.into();
243        self
244    }
245
246    /// Set the system for this environment's platform.
247    ///
248    /// See also [`MarkerEnvironment::platform_system`].
249    #[inline]
250    #[must_use]
251    pub fn with_platform_system(mut self, value: impl Into<String>) -> Self {
252        Arc::make_mut(&mut self.inner).platform_system = value.into();
253        self
254    }
255
256    /// Set the version for this environment's platform.
257    ///
258    /// See also [`MarkerEnvironment::platform_version`].
259    #[inline]
260    #[must_use]
261    pub fn with_platform_version(mut self, value: impl Into<String>) -> Self {
262        Arc::make_mut(&mut self.inner).platform_version = value.into();
263        self
264    }
265
266    /// Set the full version of Python for this environment.
267    ///
268    /// See also [`MarkerEnvironment::python_full_version`].
269    #[inline]
270    #[must_use]
271    pub fn with_python_full_version(mut self, value: impl Into<StringVersion>) -> Self {
272        Arc::make_mut(&mut self.inner).python_full_version = value.into();
273        self
274    }
275
276    /// Set the version of Python for this environment.
277    ///
278    /// See also [`MarkerEnvironment::python_full_version`].
279    #[inline]
280    #[must_use]
281    pub fn with_python_version(mut self, value: impl Into<StringVersion>) -> Self {
282        Arc::make_mut(&mut self.inner).python_version = value.into();
283        self
284    }
285
286    /// Set the name of the system platform for this environment.
287    ///
288    /// See also [`MarkerEnvironment::sys_platform`].
289    #[inline]
290    #[must_use]
291    pub fn with_sys_platform(mut self, value: impl Into<String>) -> Self {
292        Arc::make_mut(&mut self.inner).sys_platform = value.into();
293        self
294    }
295}
296
297/// A builder for constructing a marker environment.
298///
299/// A value of this type can be fallibly converted to a full
300/// [`MarkerEnvironment`] via [`MarkerEnvironment::try_from`]. This can fail when
301/// the version strings given aren't valid.
302///
303/// The main utility of this type is for constructing dummy or test environment
304/// values.
305#[allow(missing_docs)]
306#[derive(Clone, Debug, Eq, Hash, PartialEq)]
307pub struct MarkerEnvironmentBuilder<'a> {
308    pub implementation_name: &'a str,
309    pub implementation_version: &'a str,
310    pub os_name: &'a str,
311    pub platform_machine: &'a str,
312    pub platform_python_implementation: &'a str,
313    pub platform_release: &'a str,
314    pub platform_system: &'a str,
315    pub platform_version: &'a str,
316    pub python_full_version: &'a str,
317    pub python_version: &'a str,
318    pub sys_platform: &'a str,
319}
320
321impl<'a> TryFrom<MarkerEnvironmentBuilder<'a>> for MarkerEnvironment {
322    type Error = VersionParseError;
323
324    fn try_from(builder: MarkerEnvironmentBuilder<'a>) -> Result<Self, Self::Error> {
325        Ok(Self {
326            inner: Arc::new(MarkerEnvironmentInner {
327                implementation_name: builder.implementation_name.to_string(),
328                implementation_version: builder.implementation_version.parse()?,
329                os_name: builder.os_name.to_string(),
330                platform_machine: builder.platform_machine.to_string(),
331                platform_python_implementation: builder.platform_python_implementation.to_string(),
332                platform_release: builder.platform_release.to_string(),
333                platform_system: builder.platform_system.to_string(),
334                platform_version: builder.platform_version.to_string(),
335                python_full_version: builder.python_full_version.parse()?,
336                python_version: builder.python_version.parse()?,
337                sys_platform: builder.sys_platform.to_string(),
338            }),
339        })
340    }
341}