Skip to content

Commit

Permalink
review: kngwyu
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Dec 17, 2020
1 parent 77ef5ad commit 44727d2
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 65 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add FFI definitions for `PyBuffer_SizeFromFormat`, `PyObject_LengthHint`, `PyObject_CallNoArgs`, `PyObject_CallOneArg`, `PyObject_CallMethodNoArgs`, `PyObject_CallMethodOneArg`, `PyObject_VectorcallDict`, and `PyObject_VectorcallMethod`. [#1287](https://github.com/PyO3/pyo3/pull/1287)
- Add section about Python::check_signals to the FAQ page of the user guide. [#1301](https://github.com/PyO3/pyo3/pull/1301)
- Add conversions between u128/i128 and PyLong for PyPy. [#1310](https://github.com/PyO3/pyo3/pull/1310)
- Add `Python::version()` to get the running interpreter version. [#1322](https://github.com/PyO3/pyo3/pull/1322)
- Add `Python::version()` and `Python::version_info()` to get the running interpreter version. [#1322](https://github.com/PyO3/pyo3/pull/1322)

### Changed
- Change return type `PyType::name()` from `Cow<str>` to `PyResult<&str>`. [#1152](https://github.com/PyO3/pyo3/pull/1152)
Expand Down
2 changes: 1 addition & 1 deletion src/err/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ mod tests {
.split(", ");

assert_eq!(fields.next().unwrap(), "type: <class 'Exception'>");
if py.version() >= (3, 7) {
if py.version_info() >= (3, 7) {
assert_eq!(fields.next().unwrap(), "value: Exception('banana')");
} else {
// Python 3.6 and below formats the repr differently
Expand Down
4 changes: 2 additions & 2 deletions src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,15 +599,15 @@ mod test {
.into_instance(py)
.into_ref(py);

if py.version() >= (3, 7) {
if py.version_info() >= (3, 7) {
assert_eq!(format!("{:?}", exc), "Exception('banana')");
} else {
assert_eq!(format!("{:?}", exc), "Exception('banana',)");
}

let source = exc.source().expect("cause should exist");

if py.version() >= (3, 7) {
if py.version_info() >= (3, 7) {
assert_eq!(format!("{:?}", source), "TypeError('peach')");
} else {
assert_eq!(format!("{:?}", source), "TypeError('peach',)");
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pub use crate::instance::{Py, PyNativeType, PyObject};
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
pub use crate::pyclass::PyClass;
pub use crate::pyclass_init::PyClassInitializer;
pub use crate::python::{prepare_freethreaded_python, Python, PythonVersion};
pub use crate::python::{prepare_freethreaded_python, Python, PythonVersionInfo};
pub use crate::type_object::{type_flags, PyTypeInfo};
// Since PyAny is as important as PyObject, we expose it to the top level.
pub use crate::types::PyAny;
Expand Down
123 changes: 63 additions & 60 deletions src/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,15 @@ pub use gil::prepare_freethreaded_python;
///
/// See [Python::version].
#[derive(Debug)]
pub struct PythonVersion {
major: u8,
minor: (u8, Option<&'static str>),
patch: Option<(u8, Option<&'static str>)>,
pub struct PythonVersionInfo {
pub major: u8,
pub minor: u8,
pub patch: u8,
pub suffix: Option<&'static str>,
}

impl PythonVersion {
/// Gets the major version.
pub fn major(&self) -> u8 {
self.major
}

/// Gets the minor version.
pub fn minor(&self) -> u8 {
self.minor.0
}

/// Gets the patch version, if any.
pub fn patch(&self) -> Option<u8> {
self.patch.as_ref().map(|patch| patch.0)
}

/// Parses a hard-coded Python interpreter version string.
impl PythonVersionInfo {
/// Parses a hard-coded Python interpreter version string (e.g. 3.9.0a4+).
///
/// Panics if the string is ill-formatted.
fn from_str(version_number_str: &'static str) -> Self {
Expand All @@ -67,55 +53,54 @@ impl PythonVersion {
let major = major_str
.parse()
.expect("Python major version not an integer");
let minor = split_and_parse_number(minor_str);
if minor.1.is_some() {
let (minor, suffix) = split_and_parse_number(minor_str);
if suffix.is_some() {
assert!(patch_str.is_none());
return PythonVersion {
return PythonVersionInfo {
major,
minor,
patch: None,
patch: 0,
suffix,
};
}

let patch = patch_str.map(split_and_parse_number);
PythonVersion {
let (patch, suffix) = patch_str.map(split_and_parse_number).unwrap_or_default();
PythonVersionInfo {
major,
minor,
patch,
suffix
}
}
}

impl PartialEq<(u8, u8)> for PythonVersion {
impl PartialEq<(u8, u8)> for PythonVersionInfo {
fn eq(&self, other: &(u8, u8)) -> bool {
self.major == other.0 && self.minor.0 == other.1
self.major == other.0 && self.minor == other.1
}
}

impl PartialEq<(u8, u8, u8)> for PythonVersion {
impl PartialEq<(u8, u8, u8)> for PythonVersionInfo {
fn eq(&self, other: &(u8, u8, u8)) -> bool {
self.major == other.0
&& self.minor.0 == other.1
&& match self.patch {
Some((patch, _)) => patch == other.2,
_ => other.2 == 0,
}
&& self.minor == other.1
&& self.patch == other.2
}
}

impl PartialOrd<(u8, u8)> for PythonVersion {
impl PartialOrd<(u8, u8)> for PythonVersionInfo {
fn partial_cmp(&self, other: &(u8, u8)) -> Option<std::cmp::Ordering> {
match self.major.cmp(&other.0) {
Ordering::Less => return Some(Ordering::Less),
Ordering::Greater => return Some(Ordering::Greater),
Ordering::Equal => {}
};

Some(self.minor.0.cmp(&other.1))
Some(self.minor.cmp(&other.1))
}
}

impl PartialOrd<(u8, u8, u8)> for PythonVersion {
impl PartialOrd<(u8, u8, u8)> for PythonVersionInfo {
fn partial_cmp(&self, other: &(u8, u8, u8)) -> Option<std::cmp::Ordering> {
match self
.partial_cmp(&(other.0, other.1))
Expand All @@ -126,7 +111,7 @@ impl PartialOrd<(u8, u8, u8)> for PythonVersion {
Ordering::Equal => {}
};

Some(self.patch.map_or(0, |patch| patch.0).cmp(&other.2))
Some(self.patch.cmp(&other.2))
}
}

Expand Down Expand Up @@ -419,29 +404,47 @@ impl<'p> Python<'p> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_NotImplemented()) }
}

/// Gets the running Python interpreter version.
/// Gets the running Python interpreter version as a string.
///
/// This is a wrapper around the ffi call Py_GetVersion.
///
/// # Example
/// ```rust
/// # use pyo3::Python;
/// Python::with_gil(|py| {
/// // PyO3 supports Python 3.6 and up.
/// assert!(py.version() >= (3, 6));
/// assert!(py.version() >= (3, 6, 0));
/// // The full string could be, for example:
/// // "3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
/// assert!(py.version().starts_with("3."));
/// });
/// ```
pub fn version(self) -> PythonVersion {
let version_str = unsafe {
pub fn version(self) -> &'static str {
unsafe {
CStr::from_ptr(ffi::Py_GetVersion() as *const c_char)
.to_str()
.expect("Python version string not UTF-8")
};
}
}

/// Gets the running Python interpreter version as a struct similar to
/// `sys.version_info`.
///
/// # Example
/// ```rust
/// # use pyo3::Python;
/// Python::with_gil(|py| {
/// // PyO3 supports Python 3.6 and up.
/// assert!(py.version_info() >= (3, 6));
/// assert!(py.version_info() >= (3, 6, 0));
/// });
/// ```
pub fn version_info(self) -> PythonVersionInfo {
let version_str = self.version();

// Portion of the version string returned by Py_GetVersion up to the first space is the
// version number.
let version_number_str = version_str.split(' ').next().unwrap_or(version_str);

PythonVersion::from_str(version_number_str)
PythonVersionInfo::from_str(version_number_str)
}

/// Registers the object in the release pool, and tries to downcast to specific type.
Expand Down Expand Up @@ -762,8 +765,8 @@ mod test {
}

#[test]
fn test_python_version() {
let version = Python::with_gil(|py| py.version());
fn test_python_version_info() {
let version = Python::with_gil(|py| py.version_info());
#[cfg(Py_3_6)]
assert!(version >= (3, 6));
#[cfg(Py_3_6)]
Expand All @@ -783,16 +786,16 @@ mod test {
}

#[test]
fn test_python_version_parse() {
assert!(PythonVersion::from_str("3.5.0a1") >= (3, 5, 0));
assert!(PythonVersion::from_str("3.5+") >= (3, 5, 0));
assert!(PythonVersion::from_str("3.5+") == (3, 5, 0));
assert!(PythonVersion::from_str("3.5+") != (3, 5, 1));
assert!(PythonVersion::from_str("3.5+") == (3, 5, 0));
assert!(PythonVersion::from_str("3.5.2a1+") < (3, 5, 3));
assert!(PythonVersion::from_str("3.5.2a1+") == (3, 5, 2));
assert!(PythonVersion::from_str("3.5.2a1+") == (3, 5));
assert!(PythonVersion::from_str("3.5.2a1+") < (3, 6));
assert!(PythonVersion::from_str("3.5.2a1+") > (3, 4));
fn test_python_version_info_parse() {
assert!(PythonVersionInfo::from_str("3.5.0a1") >= (3, 5, 0));
assert!(PythonVersionInfo::from_str("3.5+") >= (3, 5, 0));
assert!(PythonVersionInfo::from_str("3.5+") == (3, 5, 0));
assert!(PythonVersionInfo::from_str("3.5+") != (3, 5, 1));
assert!(PythonVersionInfo::from_str("3.5.2a1+") < (3, 5, 3));
assert!(PythonVersionInfo::from_str("3.5.2a1+") == (3, 5, 2));
assert!(PythonVersionInfo::from_str("3.5.2a1+") == (3, 5));
assert!(PythonVersionInfo::from_str("3.5+") == (3, 5));
assert!(PythonVersionInfo::from_str("3.5.2a1+") < (3, 6));
assert!(PythonVersionInfo::from_str("3.5.2a1+") > (3, 4));
}
}

0 comments on commit 44727d2

Please sign in to comment.