Skip to content

Commit 9f2afbc

Browse files
authored
Merge pull request #411 from ijl/rm-python2
Drop support for python2
2 parents bc7776e + 80179be commit 9f2afbc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+342
-6170
lines changed

.travis.yml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,21 @@ cache:
1010

1111
matrix:
1212
include:
13-
- name: Python 2.7
14-
python: "2.7"
15-
env: FEATURES=python2
1613
- name: Python 3.5
1714
python: "3.5"
18-
env: FEATURES="python3 test-doc"
15+
env: FEATURES="test-doc"
1916
- name: Python 3.6
2017
python: "3.6"
21-
env: FEATURES=python3
2218
- name: Python 3.7
2319
python: "3.7"
24-
env: FEATURES=python3
2520
- name: Python 3.8-dev
2621
python: "3.8-dev"
27-
env: FEATURES=python3
2822
- name: Minimum nightly
2923
python: "3.7"
3024
# Keep this synced up with build.rs
31-
env: FEATURES=python3 TRAVIS_RUST_VERSION=nightly-2019-02-07
25+
env: TRAVIS_RUST_VERSION=nightly-2019-02-07
3226
allow_failures:
3327
- python: "3.8-dev"
34-
env: FEATURES=python3
3528

3629
env:
3730
global:

Cargo.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@ version_check = "0.1.5"
3939
[features]
4040
default = []
4141

42-
# Use this feature when building python2 binding.
43-
python2 = []
44-
45-
# Use this feature when building python3 binding.
42+
# this is no longer needed internally, but setuptools-rust assumes this feature
4643
python3 = []
4744

4845
# Use this feature when building an extension module.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste
1616

1717
## Usage
1818

19-
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.
19+
PyO3 supports python 3.5 and up. The minimum required rust version is 1.34.0-nightly 2019-02-06.
2020

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

appveyor.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@ version: 0.2.{build}
22
environment:
33
TARGET: x86_64-pc-windows-msvc
44
matrix:
5-
- PYTHON: "C:/Python27-x64"
6-
FEATURES: python2
75
- PYTHON: "C:/Python35-x64"
8-
FEATURES: python3
96
- PYTHON: "C:/Python36-x64"
10-
FEATURES: python3
117

128
install:
139
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
@@ -21,9 +17,9 @@ install:
2117
- set RUST_BACKTRACE=1
2218

2319
build_script:
24-
- cargo build --verbose --features %FEATURES%
20+
- cargo build --verbose
2521

2622
test_script:
27-
- cargo test --verbose --features %FEATURES%
23+
- cargo test --verbose
2824
- pip install setuptools-rust pytest pytest-benchmark
2925
- cd examples/word-count && python setup.py install && pytest -v tests

build.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::fs::File;
77
use std::io;
88
use std::io::{BufRead, BufReader};
99
use std::path::Path;
10+
use std::process::exit;
1011
use std::process::Command;
1112
use std::process::Stdio;
1213
use version_check::{is_min_date, is_min_version, supports_features};
@@ -482,11 +483,10 @@ fn configure(interpreter_version: &PythonVersion, lines: Vec<String>) -> Result<
482483
println!("cargo:rustc-cfg=Py_3_{}", i);
483484
flags += format!("CFG_Py_3_{},", i).as_ref();
484485
}
485-
println!("cargo:rustc-cfg=Py_3");
486486
}
487487
} else {
488-
println!("cargo:rustc-cfg=Py_2");
489-
flags += format!("CFG_Py_2,").as_ref();
488+
// fail PYTHON_SYS_EXECUTABLE=python2 cargo ...
489+
return Err("Python 2 is not supported".to_string());
490490
}
491491
return Ok(flags);
492492
}
@@ -580,7 +580,14 @@ fn main() -> Result<(), String> {
580580
find_interpreter_and_get_config()?
581581
};
582582

583-
let flags = configure(&interpreter_version, lines)?;
583+
let flags;
584+
match configure(&interpreter_version, lines) {
585+
Ok(val) => flags = val,
586+
Err(err) => {
587+
eprintln!("{}", err);
588+
exit(1);
589+
}
590+
}
584591

585592
// WITH_THREAD is always on for 3.7
586593
if interpreter_version.major == 3 && interpreter_version.minor.unwrap_or(0) >= 7 {

examples/rustapi_module/setup.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ def run(self):
2020
def get_py_version_cfgs():
2121
# For now each Cfg Py_3_X flag is interpreted as "at least 3.X"
2222
version = sys.version_info[0:2]
23-
24-
if version[0] == 2:
25-
return ["--cfg=Py_2"]
26-
2723
py3_min = 5
2824
out_cfg = []
2925
for minor in range(py3_min, version[1] + 1):

examples/rustapi_module/tox.ini

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[tox]
2-
envlist = py27,
3-
py35,
2+
envlist = py35,
43
py36,
54
py37,
65
minversion = 2.9.0

examples/word-count/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# word-count
22

3-
Demonstrates searching for a file in plain python, with rust singlethreaded and with rust multithreaded.
3+
Demonstrates searching for a file in plain python, with rust singlethreaded and with rust multithreaded.
44

55
## Build
66

@@ -35,7 +35,7 @@ pytest -v tests
3535

3636
## Testing
3737

38-
To test python 2.7, 3.5, 3.6 and 3.7, install tox globally and run
38+
To test python 3.5, 3.6 and 3.7, install tox globally and run
3939

4040
```shell
4141
tox

examples/word-count/tox.ini

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[tox]
2-
envlist = py27,
3-
py35,
2+
envlist = py35,
43
py36,
54
py37,
65
minversion = 3.4.0

guide/src/building-and-distribution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Python version
44

5-
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`.
5+
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`.
66

77
## Linking
88

guide/src/class.md

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -503,18 +503,10 @@ Each methods corresponds to python's `self.attr`, `self.attr = value` and `del s
503503
* `fn __str__(&self) -> PyResult<impl ToPyObject<ObjectType=PyString>>`
504504

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

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

511-
On Python 3.x, provides the conversion to `bytes`.
512-
On Python 2.7, `__bytes__` is allowed but has no effect.
513-
514-
* `fn __unicode__(&self) -> PyResult<PyUnicode>`
515-
516-
On Python 2.7, provides the conversion to `unicode`.
517-
On Python 3.x, `__unicode__` is allowed but has no effect.
509+
Provides the conversion to `bytes`.
518510

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

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

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

543-
Determines the "truthiness" of the object.
544-
This method works for both python 3 and python 2,
545-
even on Python 2.7 where the Python spelling was `__nonzero__`.
535+
Determines the "truthyness" of the object.
546536

547537
### Garbage Collector Integration
548538

guide/src/get_started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste
1010

1111
## Usage
1212

13-
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.
13+
PyO3 supports python 3.5 and up. The minimum required rust version is 1.34.0-nightly 2019-02-06.
1414

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

guide/src/module.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,35 +56,31 @@ In python, modules are first class objects. This means can store them as values
5656
# extern crate pyo3;
5757
use pyo3::prelude::*;
5858
use pyo3::{wrap_pyfunction, wrap_pymodule};
59-
use pyo3::types::PyDict;
59+
use pyo3::types::IntoPyDict;
6060

6161
#[pyfunction]
62-
#[cfg(Py_3)]
6362
fn subfunction() -> String {
6463
"Subfunction".to_string()
6564
}
6665

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

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

81-
#[cfg(Py_3)]
8278
fn nested_call() {
8379
let gil = GILGuard::acquire();
8480
let py = gil.python();
8581
let supermodule = wrap_pymodule!(supermodule)(py);
8682
let ctx = [("supermodule", supermodule)].into_py_dict(py);
8783

88-
py.run("assert supermodule.submodule.subfuntion() == 'Subfunction'", None, Some(&ctx)).unwrap();
84+
py.run("assert supermodule.submodule.subfunction() == 'Subfunction'", None, Some(&ctx)).unwrap();
8985
}
9086
```

pyo3-derive-backend/src/defs.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,6 @@ pub const OBJECT: Proto = Proto {
6060
pyres: true,
6161
proto: "pyo3::class::basic::PyObjectBytesProtocol",
6262
},
63-
MethodProto::Unary {
64-
name: "__unicode__",
65-
pyres: true,
66-
proto: "pyo3::class::basic::PyObjectUnicodeProtocol",
67-
},
6863
MethodProto::Unary {
6964
name: "__bool__",
7065
pyres: false,

pyo3-derive-backend/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod pymethod;
1414
mod pyproto;
1515
mod utils;
1616

17-
pub use module::{add_fn_to_module, process_functions_in_module, py2_init, py3_init};
17+
pub use module::{add_fn_to_module, process_functions_in_module, py_init};
1818
pub use pyclass::{build_py_class, PyClassArgs};
1919
pub use pyfunction::PyFunctionAttr;
2020
pub use pyimpl::{build_py_methods, impl_methods};

pyo3-derive-backend/src/module.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use syn::Ident;
1313

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

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

30-
pub fn py2_init(fnname: &Ident, name: &Ident, doc: syn::Lit) -> TokenStream {
31-
let cb_name = Ident::new(&format!("init{}", name), Span::call_site());
32-
33-
quote! {
34-
#[no_mangle]
35-
#[allow(non_snake_case)]
36-
pub unsafe extern "C" fn #cb_name() {
37-
pyo3::derive_utils::make_module(concat!(stringify!(#name), "\0"), #doc, #fnname)
38-
}
39-
}
40-
}
41-
4230
/// Finds and takes care of the #[pyfn(...)] in `#[pymodule]`
4331
pub fn process_functions_in_module(func: &mut syn::ItemFn) {
4432
let mut stmts: Vec<syn::Stmt> = Vec::new();

pyo3cls/src/lib.rs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,15 @@ use proc_macro::TokenStream;
77
use proc_macro2::Span;
88
use pyo3_derive_backend::{
99
add_fn_to_module, build_py_class, build_py_methods, build_py_proto, get_doc,
10-
process_functions_in_module, py2_init, py3_init, PyClassArgs, PyFunctionAttr,
10+
process_functions_in_module, py_init, PyClassArgs, PyFunctionAttr,
1111
};
1212
use quote::quote;
1313
use syn::parse_macro_input;
1414

15-
#[proc_macro_attribute]
16-
pub fn pymodule2(attr: TokenStream, input: TokenStream) -> TokenStream {
17-
let mut ast = parse_macro_input!(input as syn::ItemFn);
18-
19-
let modname = if attr.is_empty() {
20-
ast.ident.clone()
21-
} else {
22-
parse_macro_input!(attr as syn::Ident)
23-
};
24-
25-
process_functions_in_module(&mut ast);
26-
27-
let expanded = py2_init(&ast.ident, &modname, get_doc(&ast.attrs, false));
28-
29-
quote!(
30-
#ast
31-
#expanded
32-
)
33-
.into()
34-
}
35-
3615
/// Internally, this proc macro create a new c function called `PyInit_{my_module}`
3716
/// that then calls the init function you provided
3817
#[proc_macro_attribute]
39-
pub fn pymodule3(attr: TokenStream, input: TokenStream) -> TokenStream {
18+
pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream {
4019
let mut ast = parse_macro_input!(input as syn::ItemFn);
4120

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

4827
process_functions_in_module(&mut ast);
4928

50-
let expanded = py3_init(&ast.ident, &modname, get_doc(&ast.attrs, false));
29+
let expanded = py_init(&ast.ident, &modname, get_doc(&ast.attrs, false));
5130

5231
quote!(
5332
#ast

src/buffer.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -289,23 +289,15 @@ impl PyBuffer {
289289
#[inline]
290290
pub fn is_c_contiguous(&self) -> bool {
291291
unsafe {
292-
// Python 2.7 is not const-correct, so we need the cast to *mut
293-
ffi::PyBuffer_IsContiguous(
294-
&*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer,
295-
b'C' as libc::c_char,
296-
) != 0
292+
ffi::PyBuffer_IsContiguous(&*self.0 as *const ffi::Py_buffer, b'C' as libc::c_char) != 0
297293
}
298294
}
299295

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

@@ -713,7 +705,6 @@ mod test {
713705
}
714706

715707
#[test]
716-
#[cfg(Py_3)] // array.array doesn't implement the buffer protocol in python 2.7
717708
fn test_array_buffer() {
718709
let gil = Python::acquire_gil();
719710
let py = gil.python();

0 commit comments

Comments
 (0)