Skip to content

Commit e95636b

Browse files
author
Andrew J Westlake
committed
Removed test_main! macro and suite_name argument, updated docs to reflect changes
1 parent 04531e4 commit e95636b

File tree

5 files changed

+72
-191
lines changed

5 files changed

+72
-191
lines changed

pyo3-asyncio-macros/src/lib.rs

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ mod tokio;
66

77
use proc_macro::TokenStream;
88
use quote::{quote, quote_spanned};
9-
use syn::{
10-
parse::{Parse, ParseStream, Result},
11-
spanned::Spanned,
12-
Attribute,
13-
};
9+
use syn::spanned::Spanned;
1410

1511
/// Enables an async main function that uses the async-std runtime.
1612
///
@@ -264,76 +260,3 @@ pub fn tokio_test(_attr: TokenStream, item: TokenStream) -> TokenStream {
264260

265261
result.into()
266262
}
267-
268-
enum Item {
269-
Attribute(Vec<Attribute>),
270-
String(syn::LitStr),
271-
}
272-
273-
impl Parse for Item {
274-
fn parse(input: ParseStream<'_>) -> Result<Self> {
275-
let lookahead = input.lookahead1();
276-
277-
if lookahead.peek(syn::Token![#]) {
278-
Attribute::parse_outer(input).map(Item::Attribute)
279-
} else {
280-
input.parse().map(Item::String)
281-
}
282-
}
283-
}
284-
285-
struct TestMainArgs {
286-
attrs: Vec<Attribute>,
287-
suite_name: String,
288-
}
289-
290-
impl Parse for TestMainArgs {
291-
fn parse(input: ParseStream<'_>) -> Result<Self> {
292-
let mut args: syn::punctuated::Punctuated<Item, syn::Token![,]> =
293-
input.parse_terminated(Item::parse)?;
294-
295-
let suite_name = match args.pop().unwrap() {
296-
syn::punctuated::Pair::Punctuated(Item::String(s), _)
297-
| syn::punctuated::Pair::End(Item::String(s)) => s.value(),
298-
_ => panic!(),
299-
};
300-
301-
let attrs = match args.pop().unwrap() {
302-
syn::punctuated::Pair::Punctuated(Item::Attribute(attrs), _) => attrs,
303-
_ => panic!(),
304-
};
305-
306-
Ok(Self { attrs, suite_name })
307-
}
308-
}
309-
310-
/// The standard `pyo3-asyncio` test harness `main` fn boilerplate.
311-
///
312-
/// This macro provides the full boilerplate for the `pyo3-asyncio` test harness in one line.
313-
///
314-
/// # Examples
315-
///
316-
/// `test_main!` for the `tokio` runtime:
317-
/// ```ignore
318-
/// # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
319-
/// pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::tokio::main], "Example Test Suite");
320-
/// ```
321-
///
322-
/// `test_main!` for the `async-std` runtime:
323-
/// ```ignore
324-
/// # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
325-
/// pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::async_std::main], "Example Test Suite");
326-
/// ```
327-
#[cfg(not(test))]
328-
#[proc_macro]
329-
pub fn test_main(args: TokenStream) -> TokenStream {
330-
let TestMainArgs { attrs, suite_name } = syn::parse_macro_input!(args as TestMainArgs);
331-
332-
let result = quote! {
333-
#(#attrs)*
334-
async fn main() -> pyo3::PyResult<()> {
335-
pyo3_asyncio::testing::main(#suite_name).await
336-
}
337-
};
338-
result.into()
339-
}

pytests/test_async_std_asyncio.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ async fn test_into_future() -> PyResult<()> {
6464
common::test_into_future().await
6565
}
6666

67-
pyo3_asyncio::testing::test_main!(
68-
#[pyo3_asyncio::async_std::main],
69-
"PyO3 Asyncio Test Suite for Async-Std Runtime"
70-
);
67+
#[pyo3_asyncio::async_std::main]
68+
async fn main() -> pyo3::PyResult<()> {
69+
pyo3_asyncio::testing::main().await
70+
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod common;
22
mod tokio_asyncio;
33

4-
pyo3_asyncio::testing::test_main!(
5-
#[pyo3_asyncio::tokio::main(flavor = "current_thread")],
6-
"PyO3 Asyncio Tokio Current Thread Test Suite"
7-
);
4+
#[pyo3_asyncio::tokio::main(flavor = "current_thread")]
5+
async fn main() -> pyo3::PyResult<()> {
6+
pyo3_asyncio::testing::main().await
7+
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod common;
22
mod tokio_asyncio;
33

4-
pyo3_asyncio::testing::test_main!(
5-
#[pyo3_asyncio::tokio::main],
6-
"PyO3 Asyncio Tokio Multi Thread Test Suite"
7-
);
4+
#[pyo3_asyncio::tokio::main]
5+
async fn main() -> pyo3::PyResult<()> {
6+
pyo3_asyncio::testing::main().await
7+
}

src/testing.rs

Lines changed: 59 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,29 @@
2424
//! Cargo. Instead, we put our tests in a `pytests` directory, although the name `pytests` is just
2525
//! a convention.
2626
//!
27-
//! We'll also want to provide the test's main function. It's highly recommended that you use the
28-
//! [`pyo3_asyncio::testing::test_main!`](pyo3_asyncio_macros::test_main) macro as it will take all of the tests marked with
29-
//! [`#[pyo3_asyncio::tokio::test]`](crate::tokio::test) or
30-
//! [`#[pyo3_asyncio::async_std::test]`](crate::async_std::test) and run them automatically.
27+
//! We'll also want to provide the test's main function. Most of the functionality that the test
28+
//! harness needs is packed in this module's [`main`](crate::testing::main) function. It will parse
29+
//! the test's CLI arguments, collect and pass the functions marked with
30+
//! [`#[pyo3_asyncio::async_std::test]`](crate::async_std::test) or
31+
//! [`#[pyo3_asyncio::tokio::test]`](crate::tokio::test) and pass them into the test harness for
32+
//! running and filtering.
3133
//!
3234
//! `pytests/test_example.rs` for the `tokio` runtime:
33-
//! ```ignore
35+
//! ```
3436
//! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
35-
//! pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::tokio::main], "Example Test Suite");
37+
//! #[pyo3_asyncio::tokio::main]
38+
//! async fn main() -> pyo3::PyResult<()> {
39+
//! pyo3_asyncio::testing::main().await
40+
//! }
3641
//! ```
3742
//!
3843
//! `pytests/test_example.rs` for the `async-std` runtime:
39-
//! ```ignore
44+
//! ```
4045
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
41-
//! pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::async_std::main], "Example Test Suite");
46+
//! #[pyo3_asyncio::async_std::main]
47+
//! async fn main() -> pyo3::PyResult<()> {
48+
//! pyo3_asyncio::testing::main().await
49+
//! }
4250
//! ```
4351
//!
4452
//! ### Cargo Configuration
@@ -64,77 +72,64 @@
6472
//!
6573
//! ### Adding Tests to the PyO3 Asyncio Test Harness
6674
//!
75+
//! We can add tests anywhere in the test crate with the runtime's corresponding `#[test]` attribute:
76+
//!
6777
//! For `async-std` use the [`pyo3_asyncio::async_std::test`](crate::async_std::test) attribute:
6878
//! ```
6979
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
70-
//! # mod tests {
71-
//! use std::{time::Duration, thread};
80+
//! mod tests {
81+
//! use std::{time::Duration, thread};
7282
//!
73-
//! use pyo3::prelude::*;
83+
//! use pyo3::prelude::*;
7484
//!
75-
//! #[pyo3_asyncio::async_std::test]
76-
//! async fn test_async_sleep() -> PyResult<()> {
77-
//! async_std::task::sleep(Duration::from_secs(1)).await;
78-
//! Ok(())
79-
//! }
85+
//! #[pyo3_asyncio::async_std::test]
86+
//! async fn test_async_sleep() -> PyResult<()> {
87+
//! async_std::task::sleep(Duration::from_secs(1)).await;
88+
//! Ok(())
89+
//! }
8090
//!
81-
//! #[pyo3_asyncio::async_std::test]
82-
//! fn test_blocking_sleep() -> PyResult<()> {
83-
//! thread::sleep(Duration::from_secs(1));
84-
//! Ok(())
91+
//! #[pyo3_asyncio::async_std::test]
92+
//! fn test_blocking_sleep() -> PyResult<()> {
93+
//! thread::sleep(Duration::from_secs(1));
94+
//! Ok(())
95+
//! }
8596
//! }
86-
//! # }
8797
//!
88-
//! // ...
89-
//! #
90-
//! # // Doctests don't detect main fn when using the test_main!() macro, so we expand it into the
91-
//! # // components of that macro instead.
92-
//! #
9398
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
94-
//! # use pyo3::prelude::*;
95-
//! #
96-
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
97-
//! # #[pyo3_asyncio::async_std::main]
98-
//! # async fn main() -> pyo3::PyResult<()> {
99-
//! # pyo3_asyncio::testing::main("Example Test Suite").await
100-
//! # }
99+
//! #[pyo3_asyncio::async_std::main]
100+
//! async fn main() -> pyo3::PyResult<()> {
101+
//! pyo3_asyncio::testing::main().await
102+
//! }
101103
//! # #[cfg(not(all(feature = "async-std-runtime", feature = "attributes")))]
102104
//! # fn main() {}
103105
//! ```
104106
//!
105107
//! For `tokio` use the [`pyo3_asyncio::tokio::test`](crate::tokio::test) attribute:
106108
//! ```
107109
//! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
108-
//! # mod tests {
109-
//! use std::{time::Duration, thread};
110+
//! mod tests {
111+
//! use std::{time::Duration, thread};
110112
//!
111-
//! use pyo3::prelude::*;
113+
//! use pyo3::prelude::*;
112114
//!
113-
//! #[pyo3_asyncio::tokio::test]
114-
//! async fn test_async_sleep() -> PyResult<()> {
115-
//! tokio::time::sleep(Duration::from_secs(1)).await;
116-
//! Ok(())
117-
//! }
115+
//! #[pyo3_asyncio::tokio::test]
116+
//! async fn test_async_sleep() -> PyResult<()> {
117+
//! tokio::time::sleep(Duration::from_secs(1)).await;
118+
//! Ok(())
119+
//! }
118120
//!
119-
//! #[pyo3_asyncio::tokio::test]
120-
//! fn test_blocking_sleep() -> PyResult<()> {
121-
//! thread::sleep(Duration::from_secs(1));
122-
//! Ok(())
121+
//! #[pyo3_asyncio::tokio::test]
122+
//! fn test_blocking_sleep() -> PyResult<()> {
123+
//! thread::sleep(Duration::from_secs(1));
124+
//! Ok(())
125+
//! }
123126
//! }
124-
//! # }
125127
//!
126-
//! // ...
127-
//! #
128-
//! # // Doctests don't detect main fn when using the test_main!() macro, so we expand it into the
129-
//! # // components of that macro instead.
130128
//! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
131-
//! # use pyo3::prelude::*;
132-
//! #
133-
//! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
134-
//! # #[pyo3_asyncio::tokio::main]
135-
//! # async fn main() -> PyResult<()> {
136-
//! # pyo3_asyncio::testing::main("Example Test Suite").await
137-
//! # }
129+
//! #[pyo3_asyncio::tokio::main]
130+
//! async fn main() -> pyo3::PyResult<()> {
131+
//! pyo3_asyncio::testing::main().await
132+
//! }
138133
//! # #[cfg(not(all(feature = "tokio-runtime", feature = "attributes")))]
139134
//! # fn main() {}
140135
//! ```
@@ -180,48 +175,11 @@
180175
//!
181176
//! # fn main() {}
182177
//! ```
183-
//!
184-
//! ### Expanding `test_main!()` for Doc Tests
185-
//!
186-
//! This is probably a pretty niche topic, and there's really no reason you would _need_ to do this
187-
//! since usually you'd probably just want to use the `#[main]` attributes for your doc tests like we
188-
//! mentioned at the beginning of this page. But since we had to do it for _this particular module_
189-
//! of the docs, it's probably worth mentioning as a footnote.
190-
//!
191-
//! For some reason, doc tests don't interpret the `test_main!()` macro as providing `fn main()` and
192-
//! will wrap the test body in another `fn main()`. To get around this, we can instead expand
193-
//! `test_main!()` into its components for the doc test:
194-
//!
195-
//! The following `test_main!()` macro:
196-
//!
197-
//! ```ignore
198-
//! pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::async_std::main], "Example Test Suite");
199-
//! ```
200-
//!
201-
//! Is equivalent to this expansion:
202-
//!
203-
//! ```
204-
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
205-
//! use pyo3::prelude::*;
206-
//!
207-
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
208-
//! #[pyo3_asyncio::async_std::main]
209-
//! async fn main() -> PyResult<()> {
210-
//! pyo3_asyncio::testing::main("Example Test Suite").await
211-
//! }
212-
//! # #[cfg(not(all(feature = "async-std-runtime", feature = "attributes")))]
213-
//! # fn main() {}
214-
//! ```
215178
216179
use clap::{App, Arg};
217180
use futures::stream::{self, StreamExt};
218181
use pyo3::prelude::*;
219182

220-
/// <span class="module-item stab portability" style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"><code>attributes</code></span>
221-
/// Provides the boilerplate for the `pyo3-asyncio` test harness in one line
222-
#[cfg(feature = "attributes")]
223-
pub use pyo3_asyncio_macros::test_main;
224-
225183
/// Args that should be provided to the test program
226184
///
227185
/// These args are meant to mirror the default test harness's args.
@@ -251,13 +209,13 @@ impl Default for Args {
251209
/// Running the following function:
252210
/// ```
253211
/// # use pyo3_asyncio::testing::parse_args;
254-
/// let args = parse_args("PyO3 Asyncio Example Test Suite");
212+
/// let args = parse_args();
255213
/// ```
256214
///
257215
/// Produces the following usage string:
258216
///
259217
/// ```bash
260-
/// Pyo3 Asyncio Example Test Suite
218+
/// Pyo3 Asyncio Test Suite
261219
/// USAGE:
262220
/// test_example [TESTNAME]
263221
///
@@ -268,8 +226,8 @@ impl Default for Args {
268226
/// ARGS:
269227
/// <TESTNAME> If specified, only run tests containing this string in their names
270228
/// ```
271-
pub fn parse_args(suite_name: &str) -> Args {
272-
let matches = App::new(suite_name)
229+
pub fn parse_args() -> Args {
230+
let matches = App::new("PyO3 Asyncio Test Suite")
273231
.arg(
274232
Arg::with_name("TESTNAME")
275233
.help("If specified, only run tests containing this string in their names"),
@@ -345,13 +303,13 @@ pub async fn test_harness(tests: Vec<Test>, args: Args) -> PyResult<()> {
345303
/// # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
346304
/// #[pyo3_asyncio::async_std::main]
347305
/// async fn main() -> PyResult<()> {
348-
/// pyo3_asyncio::testing::main("Example Test Suite").await
306+
/// pyo3_asyncio::testing::main().await
349307
/// }
350308
/// # #[cfg(not(all(feature = "async-std-runtime", feature = "attributes")))]
351309
/// fn main() { }
352310
/// ```
353-
pub async fn main(suite_name: &str) -> PyResult<()> {
354-
let args = parse_args(suite_name);
311+
pub async fn main() -> PyResult<()> {
312+
let args = parse_args();
355313

356314
test_harness(
357315
inventory::iter::<Test>().map(|test| test.clone()).collect(),

0 commit comments

Comments
 (0)