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

change PyModule::add_class to return an error if class creation fails #2947

Merged
merged 3 commits into from
Feb 18, 2023

Conversation

davidhewitt
Copy link
Member

Related to #2942

At the moment there are panics deep in the #[pyclass] machinery when initialising the type fails. This PR adjusts a number of these functions to return PyResult instead, so that we can handle the error more appropriately further down the pipeline.

For example, take the following snippet:

#[pyclass(extends = PyBool)]
struct ExtendsBool;

#[pymodule]
fn pyo3_scratch(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<ExtendsBool>()?;
    Ok(())
}

Currently, importing this module will fail with a panic:

TypeError: type 'bool' is not an acceptable base type
thread '<unnamed>' panicked at 'An error occurred while initializing class ExtendsBool', /Users/david/Dev/pyo3/src/pyclass.rs:412:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
pyo3_runtime.PanicException: An error occurred while initializing class ExtendsBool

After this PR, this import still fails, but with a slightly cleaner, more Pythonic error:

TypeError: type 'bool' is not an acceptable base type

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
RuntimeError: An error occurred while initializing class ExtendsBool

@davidhewitt
Copy link
Member Author

On reflection I've renamed StaticTypeObject to LazyTypeObject (was LazyStaticType before this PR). It's got nothing to do with "static" any more now that we use heap types, and the &'static reference is encoded elsewhere in the PyClassImpl implementation (but this would function perfectly fine without being static).

I've also pushed a follow-up commit which switches this to store Py<PyType> instead of *mut ffi::PyTypeObject to track ownership properly, and adjusts the internals to make use of this and &PyType so there's less unsafe.

Copy link
Member

@adamreichold adamreichold left a comment

Choose a reason for hiding this comment

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

I think this looks much better with the follow-up commit! Just one question where I am not sure about the performance characteristics.

@davidhewitt
Copy link
Member Author

Thanks! I've adjusted the comment around the code you've questioned, replied, and will proceed to merge.

If we think there's follow-up work I'll open a new PR.

@davidhewitt
Copy link
Member Author

bors r=adamreichold

bors bot added a commit that referenced this pull request Feb 16, 2023
2947: change PyModule::add_class to return an error if class creation fails r=adamreichold a=davidhewitt

Related to #2942 

At the moment there are panics deep in the `#[pyclass]` machinery when initialising the type fails. This PR adjusts a number of these functions to return `PyResult` instead, so that we can handle the error more appropriately further down the pipeline.

For example, take the following snippet:

```rust
#[pyclass(extends = PyBool)]
struct ExtendsBool;

#[pymodule]
fn pyo3_scratch(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<ExtendsBool>()?;
    Ok(())
}
```

Currently, importing this module will fail with a panic:

```
TypeError: type 'bool' is not an acceptable base type
thread '<unnamed>' panicked at 'An error occurred while initializing class ExtendsBool', /Users/david/Dev/pyo3/src/pyclass.rs:412:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
pyo3_runtime.PanicException: An error occurred while initializing class ExtendsBool
```

After this PR, this import still fails, but with a slightly cleaner, more Pythonic error:

```
TypeError: type 'bool' is not an acceptable base type

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
RuntimeError: An error occurred while initializing class ExtendsBool
```

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
@bors
Copy link
Contributor

bors bot commented Feb 16, 2023

Build failed:

@davidhewitt
Copy link
Member Author

bors retry

bors bot added a commit that referenced this pull request Feb 18, 2023
2947: change PyModule::add_class to return an error if class creation fails r=adamreichold a=davidhewitt

Related to #2942 

At the moment there are panics deep in the `#[pyclass]` machinery when initialising the type fails. This PR adjusts a number of these functions to return `PyResult` instead, so that we can handle the error more appropriately further down the pipeline.

For example, take the following snippet:

```rust
#[pyclass(extends = PyBool)]
struct ExtendsBool;

#[pymodule]
fn pyo3_scratch(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<ExtendsBool>()?;
    Ok(())
}
```

Currently, importing this module will fail with a panic:

```
TypeError: type 'bool' is not an acceptable base type
thread '<unnamed>' panicked at 'An error occurred while initializing class ExtendsBool', /Users/david/Dev/pyo3/src/pyclass.rs:412:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
pyo3_runtime.PanicException: An error occurred while initializing class ExtendsBool
```

After this PR, this import still fails, but with a slightly cleaner, more Pythonic error:

```
TypeError: type 'bool' is not an acceptable base type

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
RuntimeError: An error occurred while initializing class ExtendsBool
```

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
@bors
Copy link
Contributor

bors bot commented Feb 18, 2023

Build failed:

@adamreichold
Copy link
Member

bors r+

bors bot added a commit that referenced this pull request Feb 18, 2023
2947: change PyModule::add_class to return an error if class creation fails r=adamreichold a=davidhewitt

Related to #2942 

At the moment there are panics deep in the `#[pyclass]` machinery when initialising the type fails. This PR adjusts a number of these functions to return `PyResult` instead, so that we can handle the error more appropriately further down the pipeline.

For example, take the following snippet:

```rust
#[pyclass(extends = PyBool)]
struct ExtendsBool;

#[pymodule]
fn pyo3_scratch(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<ExtendsBool>()?;
    Ok(())
}
```

Currently, importing this module will fail with a panic:

```
TypeError: type 'bool' is not an acceptable base type
thread '<unnamed>' panicked at 'An error occurred while initializing class ExtendsBool', /Users/david/Dev/pyo3/src/pyclass.rs:412:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
pyo3_runtime.PanicException: An error occurred while initializing class ExtendsBool
```

After this PR, this import still fails, but with a slightly cleaner, more Pythonic error:

```
TypeError: type 'bool' is not an acceptable base type

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
RuntimeError: An error occurred while initializing class ExtendsBool
```

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
@bors
Copy link
Contributor

bors bot commented Feb 18, 2023

Canceled.

@adamreichold
Copy link
Member

bors retry

@bors
Copy link
Contributor

bors bot commented Feb 18, 2023

Build succeeded:

@bors bors bot merged commit 3b2c175 into PyO3:main Feb 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants