[BUG]: Setting the `__name__` attribute changes the behaviour of error reporting
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
Description
Required prerequisites
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
2.13.6
Problem description
Suppose that a class called Pet is implemented in a module called example. If an attribute reference fails, the error message is AttributeError: 'example.Pet' object has no attribute .... However, if the __name__ attribute is specified using pet.attr("__name__") = "PseudoPet"; then the attribute errors look like AttributeError: 'PseudoPet' object has no attribute .... Notice that, in the latter, there is no module name example.
I know that the PyTypeObject.tp_name member is different depending on whether the class/type was implemented in C or Python, and I think this gets used in include/pybind11/detail/class.h to determine various strings used for reporting. Perhaps this has something to do with the issue?
PEP 737 introduces some functions like PyType_GetModuleName(), and adds formats to PyUnicode_FromFormat() which may also be useful here?
Reproducible example code
In example.cpp:
#include <pybind11/pybind11.h>
namespace py = pybind11;
struct Pet {
Pet(const std::string &name) : name(name) {}
std::string name;
};
struct Person {
Person(const std::string &name) : name(name) {}
std::string name;
};
PYBIND11_MODULE(example, m) {
// Class with explicitly set __name__
py::class_<Pet> pet(m, "Pet");
pet.def(py::init<const std::string &>());
pet.attr("__name__") = "PseudoPet";
// Class with default name
py::class_<Person> person(m, "Person");
person.def(py::init<const std::string &>());
}
In an interactive Python session:
>>> from example import Pet, Person
>>> my_pet = Pet("John")
>>> my_pet.age
AttributeError: 'PseudoPet' object has no attribute 'age'
>>> my_person = Person("Jane")
>>> my_person.age
AttributeError: 'example.Person' object has no attribute 'age'
Is this a regression? Put the last known working version here if it is.
Not a regression
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the behavior with the example.cpp binding and the interactive Python session shown in the issue. Start by reading include/pybind11/detail/class.h and trace how type names for attribute errors are selected; done means errors remain module-qualified when name is overridden, without changing the default Person behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100