question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Feature Request] @beartype option preventing "int" type hints from accepting booleans

See original GitHub issue

It would appear that beartype allows booleans to be passed into an argument when the only allowed type is int. Is there a particular reason why this is allowed, or is this a bug?

I’ve looked through the source but can’t find anything specifically relating to this.

Behaviour can be reproduced as seen below:

@beartype
def find(id: int):
    """."""
    print('hello', type(id))


def test_manager():
    """."""
    find(False)

A quick check of built-in type checking shows that Python knows the difference between int and bool;

(Pdb) type(1) == int
True
(Pdb) type(1) == bool
False
(Pdb) type(False) == int
False
(Pdb) type(False) == bool
True

According to a discussion on SO, bool is a subclass of int for historic reasons. As such, there’s a conflict when using isinstance, which could be the root cause of this behaviour?

>>> isinstance(True, int)
True
>>> isinstance(True, int)
True
>>> int(True)
1

This historic implementation of bool could lead to surprising behaviour for unsuspecting developers. It would be nice if there was a way to override type checking behaviour for this specific use case. I’d be open to submitting a PR if such an approach was approved by maintainers.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
foxxcommented, Oct 27, 2021

Thank you both for taking the time to look at this!

Based on everything said, I would concur that a documentation patch is the most appropriate fix. The showcase snippet you provided gives flexibility to deviate from default behaviour in an explicit manner and solves the specific problem I was having with bool/int.

Despite having strong experience with Python, I was blissfully unaware of this typing behaviour (or the str/seq issue), in fact it was difficult to find any discussion or documentation about it. I’m hoping this thread and documentation patch may also help educate others in future.

ps. On a side note, I’d like to say that this is one of the best responses I’ve seen on a GitHub issue. It’s well thought out, considerate of others and an excellent example of how to be a great maintainer.

1reaction
leyceccommented, Oct 27, 2021

Huzzah! I couldn’t help myself. Beartype validators do indeed appear to successfully refine standard type hints for common edge cases like this. Specifically, running the following snippet…

from beartype import beartype
from beartype.vale import Is
from typing import Annotated

# PEP-compliant type hint matching any integer
# that is *NOT* a boolean. Now actually tested.
IntNonbool = Annotated[int, Is[
    lambda number: not isinstance(number, bool)]]

@beartype
def find(id: IntNonbool):
    """."""
    print('hello', type(id))


def test_manager():
    """."""
    find(0xFEEDFACE)
    find(False)

test_manager()

…yields the following output:

hello <class 'int'>
Traceback (most recent call last):
  File "/home/leycec/tmp/mopy.py", line 24, in <module>
    test_manager()
  File "/home/leycec/tmp/mopy.py", line 22, in test_manager
    find(False)
  File "<string>", line 27, in find
  File "/home/leycec/py/beartype/beartype/_decor/_error/errormain.py", line 301, in raise_pep_call_exception
    raise exception_cls(  # type: ignore[misc]
beartype.roar.BeartypeCallHintPepParamException:
@beartyped find() parameter id="False" violates
type hint typing.Annotated[int, Is[lambda number:
not isinstance(number, bool)]], as "False" violates
validator Is[lambda number: not isinstance(number, bool)].

This is sufficiently useful that I’ll probably append the above to our existing Validator Showcase. I’m satisfied, folks. How about everyone else?

Read more comments on GitHub >

github_iconTop Results From Across the Web

The Future Sound of Beartype: Going Deep on Type-checking
Beartype 0.9.0 intends to extend deep type-checking support to parametrized type hints (i.e., type hints subscripted by one or more type variables). I...
Read more >
Python Type Checking (Guide) - Real Python
In this guide, you'll look at Python type checking. Traditionally, types have been handled by the Python interpreter in a flexible but implicit...
Read more >
Type hints cheat sheet - mypy 0.991 documentation
Type hints cheat sheet#. This document is a quick cheat sheet showing how to use type annotations for various common types in Python....
Read more >
Python Type Hints - How to Avoid “The Boolean Trap”
In this post we'll look at the trap in more detail, and several ways to avoid it in Python, with added safety from...
Read more >
PEP 484 – Type Hints - Python Enhancement Proposals
The example here uses a custom type Sequence , imported from a pure-Python module typing . The Sequence[int] notation works at runtime by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found