pybind11 icon indicating copy to clipboard operation
pybind11 copied to clipboard

[BUG]: Setting the `__name__` attribute changes the behaviour of error reporting

Open Joseph-Edwards opened this issue 9 months ago • 0 comments

Required prerequisites

  • [x] Make sure you've read the documentation. Your issue may be addressed there.
  • [x] Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
  • [x] 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

Joseph-Edwards avatar Mar 05 '25 23:03 Joseph-Edwards