pybind / pybind/pybind11

Raise ValueError instead of TypeError when casting negative values to an unsigned type

Open
#2,107 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Issue description

PyBind11 binding of unsigned numerical types currently seems to throw a TypeError when a negative number value is given:

// C++ binding:
void f(unsigned int i);        // Binding of function receiving and `unsigned` value

PYBIND11_EMBEDDED_MODULE(uint, m) {
    m.def("f", &f, "");
}
# Python usage:
import uint
uint.f(-1)                    # Calling with a negative value (throws TypeError)

Error output:

Exception: TypeError: f(): incompatible function arguments. The following argument types are supported:
    1. (arg0: int) -> None

Invoked with: -1

This error output does not give accurate information about what is wrong.

Also, Python documentation recommends using ValueError in this case (my emphasis):

exception TypeError
[...]
Passing arguments of the wrong type (e.g. passing a list when an int is expected) should result in a TypeError, but passing arguments with the wrong value (e.g. a number outside expected boundaries) should result in a ValueError.
https://docs.python.org/3.8/library/exceptions.html#TypeError

It would be nice if PyBind11 type casters that handle unsigned numerical types raised a ValueError instead of TypeError when a negative value is given. The ValueError message could also clearly state that the parameter value should be at least zero, so that the user can quickly understand what went wrong.

Reproducible example code

#include <iostream>

#include <pybind11/embed.h>
#include <pybind11/pybind11.h>

namespace py = pybind11;

void f(unsigned int i) {
    std::cout << __func__ << ": " << i << '\n';
}

PYBIND11_EMBEDDED_MODULE(uint, m) {
    m.def("f", &f, "");
}

int main() {
    py::scoped_interpreter guard{};

    auto tpb = py::module::import("uint");
    try {
        py::exec(R"(
            import uint
            uint.f(-1)
        )");
    }
    catch (const std::exception & e) {
        std::cerr << "Exception: " << e.what() << '\n';
    }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproducible embedded-module example in the issue and trace the type casters that handle unsigned numerical types. Confirm the current exception for a negative value, then add coverage showing that it raises ValueError with a clear nonnegative-value message; the issue is done when this behavior is consistent for unsigned types.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
backend-api-design
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.