Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for python2 #411

Merged
merged 3 commits into from
Mar 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,21 @@ cache:

matrix:
include:
- name: Python 2.7
python: "2.7"
env: FEATURES=python2
- name: Python 3.5
python: "3.5"
env: FEATURES="python3 test-doc"
env: FEATURES="test-doc"
- name: Python 3.6
python: "3.6"
env: FEATURES=python3
- name: Python 3.7
python: "3.7"
env: FEATURES=python3
- name: Python 3.8-dev
python: "3.8-dev"
env: FEATURES=python3
- name: Minimum nightly
python: "3.7"
# Keep this synced up with build.rs
env: FEATURES=python3 TRAVIS_RUST_VERSION=nightly-2019-02-07
env: TRAVIS_RUST_VERSION=nightly-2019-02-07
allow_failures:
- python: "3.8-dev"
env: FEATURES=python3

env:
global:
Expand Down
5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ version_check = "0.1.5"
[features]
default = []

# Use this feature when building python2 binding.
python2 = []

# Use this feature when building python3 binding.
# this is no longer needed internally, but setuptools-rust assumes this feature
python3 = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a python3 without the python2 feature

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setuptools-rust apparently assumes it. I've left it in for now with a note.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right. I've created PyO3/setuptools-rust#53 for fixing that long term, but for now a comment is good


# Use this feature when building an extension module.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste

## Usage

PyO3 supports python 2.7 as well as python 3.5 and up. The minimum required rust version is 1.34.0-nightly 2019-02-06.
PyO3 supports python 3.5 and up. The minimum required rust version is 1.34.0-nightly 2019-02-06.

You can either write a native python module in rust or use python from a rust binary.

Expand Down
8 changes: 2 additions & 6 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ version: 0.2.{build}
environment:
TARGET: x86_64-pc-windows-msvc
matrix:
- PYTHON: "C:/Python27-x64"
FEATURES: python2
- PYTHON: "C:/Python35-x64"
FEATURES: python3
- PYTHON: "C:/Python36-x64"
FEATURES: python3

install:
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
Expand All @@ -21,9 +17,9 @@ install:
- set RUST_BACKTRACE=1

build_script:
- cargo build --verbose --features %FEATURES%
- cargo build --verbose

test_script:
- cargo test --verbose --features %FEATURES%
- cargo test --verbose
- pip install setuptools-rust pytest pytest-benchmark
- cd examples/word-count && python setup.py install && pytest -v tests
15 changes: 11 additions & 4 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use version_check::{is_min_date, is_min_version, supports_features};
Expand Down Expand Up @@ -482,11 +483,10 @@ fn configure(interpreter_version: &PythonVersion, lines: Vec<String>) -> Result<
println!("cargo:rustc-cfg=Py_3_{}", i);
flags += format!("CFG_Py_3_{},", i).as_ref();
}
println!("cargo:rustc-cfg=Py_3");
}
} else {
println!("cargo:rustc-cfg=Py_2");
flags += format!("CFG_Py_2,").as_ref();
// fail PYTHON_SYS_EXECUTABLE=python2 cargo ...
return Err("Python 2 is not supported".to_string());
}
return Ok(flags);
}
Expand Down Expand Up @@ -580,7 +580,14 @@ fn main() -> Result<(), String> {
find_interpreter_and_get_config()?
};

let flags = configure(&interpreter_version, lines)?;
let flags;
match configure(&interpreter_version, lines) {
Ok(val) => flags = val,
Err(err) => {
eprintln!("{}", err);
exit(1);
}
}

// WITH_THREAD is always on for 3.7
if interpreter_version.major == 3 && interpreter_version.minor.unwrap_or(0) >= 7 {
Expand Down
4 changes: 0 additions & 4 deletions examples/rustapi_module/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ def run(self):
def get_py_version_cfgs():
# For now each Cfg Py_3_X flag is interpreted as "at least 3.X"
version = sys.version_info[0:2]

if version[0] == 2:
return ["--cfg=Py_2"]

py3_min = 5
out_cfg = []
for minor in range(py3_min, version[1] + 1):
Expand Down
3 changes: 1 addition & 2 deletions examples/rustapi_module/tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[tox]
envlist = py27,
py35,
envlist = py35,
py36,
py37,
minversion = 2.9.0
Expand Down
4 changes: 2 additions & 2 deletions examples/word-count/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# word-count

Demonstrates searching for a file in plain python, with rust singlethreaded and with rust multithreaded.
Demonstrates searching for a file in plain python, with rust singlethreaded and with rust multithreaded.

## Build

Expand Down Expand Up @@ -35,7 +35,7 @@ pytest -v tests

## Testing

To test python 2.7, 3.5, 3.6 and 3.7, install tox globally and run
To test python 3.5, 3.6 and 3.7, install tox globally and run

```shell
tox
Expand Down
3 changes: 1 addition & 2 deletions examples/word-count/tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[tox]
envlist = py27,
py35,
envlist = py35,
py36,
py37,
minversion = 3.4.0
Expand Down
2 changes: 1 addition & 1 deletion guide/src/building-and-distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Python version

PyO3 uses a build script to determine the python version and set the correct linker arguments. By default it uses the `python3` executable. With the `python2` feature it uses the `python2` executable. You can override the python interpreter by setting `PYTHON_SYS_EXECUTABLE`.
PyO3 uses a build script to determine the python version and set the correct linker arguments. By default it uses the `python3` executable. You can override the python interpreter by setting `PYTHON_SYS_EXECUTABLE`, e.g., `PYTHON_SYS_EXECUTABLE=python3.6`.

## Linking

Expand Down
14 changes: 2 additions & 12 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,18 +503,10 @@ Each methods corresponds to python's `self.attr`, `self.attr = value` and `del s
* `fn __str__(&self) -> PyResult<impl ToPyObject<ObjectType=PyString>>`

Possible return types for `__str__` and `__repr__` are `PyResult<String>` or `PyResult<PyString>`.
In Python 2.7, Unicode strings returned by `__str__` and `__repr__` will be converted to byte strings
by the Python runtime, which results in an exception if the string contains non-ASCII characters.

* `fn __bytes__(&self) -> PyResult<PyBytes>`

On Python 3.x, provides the conversion to `bytes`.
On Python 2.7, `__bytes__` is allowed but has no effect.

* `fn __unicode__(&self) -> PyResult<PyUnicode>`

On Python 2.7, provides the conversion to `unicode`.
On Python 3.x, `__unicode__` is allowed but has no effect.
Provides the conversion to `bytes`.

* `fn __format__(&self, format_spec: &str) -> PyResult<impl ToPyObject<ObjectType=PyString>>`

Expand All @@ -540,9 +532,7 @@ Each methods corresponds to python's `self.attr`, `self.attr = value` and `del s

* `fn __bool__(&self) -> PyResult<bool>`

Determines the "truthiness" of the object.
This method works for both python 3 and python 2,
even on Python 2.7 where the Python spelling was `__nonzero__`.
Determines the "truthyness" of the object.

### Garbage Collector Integration

Expand Down
2 changes: 1 addition & 1 deletion guide/src/get_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste

## Usage

PyO3 supports python 2.7 as well as python 3.5 and up. The minimum required rust version is 1.30.0-nightly 2018-08-18.
PyO3 supports python 3.5 and up. The minimum required rust version is 1.34.0-nightly 2019-02-06.

You can either write a native python module in rust or use python from a rust binary.

Expand Down
8 changes: 2 additions & 6 deletions guide/src/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,35 +56,31 @@ In python, modules are first class objects. This means can store them as values
# extern crate pyo3;
use pyo3::prelude::*;
use pyo3::{wrap_pyfunction, wrap_pymodule};
use pyo3::types::PyDict;
use pyo3::types::IntoPyDict;

#[pyfunction]
#[cfg(Py_3)]
fn subfunction() -> String {
"Subfunction".to_string()
}

#[pymodule]
#[cfg(Py_3)]
fn submodule(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_wrapped(wrap_pyfunction!(subfunction))?;
Ok(())
}

#[pymodule]
#[cfg(Py_3)]
fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_wrapped(wrap_pymodule!(submodule))?;
Ok(())
}

#[cfg(Py_3)]
fn nested_call() {
let gil = GILGuard::acquire();
let py = gil.python();
let supermodule = wrap_pymodule!(supermodule)(py);
let ctx = [("supermodule", supermodule)].into_py_dict(py);

py.run("assert supermodule.submodule.subfuntion() == 'Subfunction'", None, Some(&ctx)).unwrap();
py.run("assert supermodule.submodule.subfunction() == 'Subfunction'", None, Some(&ctx)).unwrap();
}
```
5 changes: 0 additions & 5 deletions pyo3-derive-backend/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ pub const OBJECT: Proto = Proto {
pyres: true,
proto: "pyo3::class::basic::PyObjectBytesProtocol",
},
MethodProto::Unary {
name: "__unicode__",
pyres: true,
proto: "pyo3::class::basic::PyObjectUnicodeProtocol",
},
MethodProto::Unary {
name: "__bool__",
pyres: false,
Expand Down
2 changes: 1 addition & 1 deletion pyo3-derive-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod pymethod;
mod pyproto;
mod utils;

pub use module::{add_fn_to_module, process_functions_in_module, py2_init, py3_init};
pub use module::{add_fn_to_module, process_functions_in_module, py_init};
pub use pyclass::{build_py_class, PyClassArgs};
pub use pyfunction::PyFunctionAttr;
pub use pyimpl::{build_py_methods, impl_methods};
Expand Down
14 changes: 1 addition & 13 deletions pyo3-derive-backend/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use syn::Ident;

/// Generates the function that is called by the python interpreter to initialize the native
/// module
pub fn py3_init(fnname: &Ident, name: &Ident, doc: syn::Lit) -> TokenStream {
pub fn py_init(fnname: &Ident, name: &Ident, doc: syn::Lit) -> TokenStream {
let cb_name = Ident::new(&format!("PyInit_{}", name), Span::call_site());

quote! {
Expand All @@ -27,18 +27,6 @@ pub fn py3_init(fnname: &Ident, name: &Ident, doc: syn::Lit) -> TokenStream {
}
}

pub fn py2_init(fnname: &Ident, name: &Ident, doc: syn::Lit) -> TokenStream {
let cb_name = Ident::new(&format!("init{}", name), Span::call_site());

quote! {
#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern "C" fn #cb_name() {
pyo3::derive_utils::make_module(concat!(stringify!(#name), "\0"), #doc, #fnname)
}
}
}

/// Finds and takes care of the #[pyfn(...)] in `#[pymodule]`
pub fn process_functions_in_module(func: &mut syn::ItemFn) {
let mut stmts: Vec<syn::Stmt> = Vec::new();
Expand Down
27 changes: 3 additions & 24 deletions pyo3cls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,15 @@ use proc_macro::TokenStream;
use proc_macro2::Span;
use pyo3_derive_backend::{
add_fn_to_module, build_py_class, build_py_methods, build_py_proto, get_doc,
process_functions_in_module, py2_init, py3_init, PyClassArgs, PyFunctionAttr,
process_functions_in_module, py_init, PyClassArgs, PyFunctionAttr,
};
use quote::quote;
use syn::parse_macro_input;

#[proc_macro_attribute]
pub fn pymodule2(attr: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as syn::ItemFn);

let modname = if attr.is_empty() {
ast.ident.clone()
} else {
parse_macro_input!(attr as syn::Ident)
};

process_functions_in_module(&mut ast);

let expanded = py2_init(&ast.ident, &modname, get_doc(&ast.attrs, false));

quote!(
#ast
#expanded
)
.into()
}

/// Internally, this proc macro create a new c function called `PyInit_{my_module}`
/// that then calls the init function you provided
#[proc_macro_attribute]
pub fn pymodule3(attr: TokenStream, input: TokenStream) -> TokenStream {
pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as syn::ItemFn);

let modname = if attr.is_empty() {
Expand All @@ -47,7 +26,7 @@ pub fn pymodule3(attr: TokenStream, input: TokenStream) -> TokenStream {

process_functions_in_module(&mut ast);

let expanded = py3_init(&ast.ident, &modname, get_doc(&ast.attrs, false));
let expanded = py_init(&ast.ident, &modname, get_doc(&ast.attrs, false));

quote!(
#ast
Expand Down
13 changes: 2 additions & 11 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,23 +289,15 @@ impl PyBuffer {
#[inline]
pub fn is_c_contiguous(&self) -> bool {
unsafe {
// Python 2.7 is not const-correct, so we need the cast to *mut
ffi::PyBuffer_IsContiguous(
&*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer,
b'C' as libc::c_char,
) != 0
ffi::PyBuffer_IsContiguous(&*self.0 as *const ffi::Py_buffer, b'C' as libc::c_char) != 0
}
}

/// Gets whether the buffer is contiguous in Fortran-style order (first index varies fastest when visiting items in order of memory address).
#[inline]
pub fn is_fortran_contiguous(&self) -> bool {
unsafe {
// Python 2.7 is not const-correct, so we need the cast to *mut
ffi::PyBuffer_IsContiguous(
&*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer,
b'F' as libc::c_char,
) != 0
ffi::PyBuffer_IsContiguous(&*self.0 as *const ffi::Py_buffer, b'F' as libc::c_char) != 0
}
}

Expand Down Expand Up @@ -713,7 +705,6 @@ mod test {
}

#[test]
#[cfg(Py_3)] // array.array doesn't implement the buffer protocol in python 2.7
fn test_array_buffer() {
let gil = Python::acquire_gil();
let py = gil.python();
Expand Down
Loading