Giter Club home page Giter Club logo

numerary's Introduction

beartype —[ the bare-metal type checker ]—

beartype Read The Docs (RTD) status beartype continuous integration (CI) status beartype test coverage status

Beartype documentation lives at ReadTheDocs (RTD). It's readable, structured, and soothing to the deep folds of your big galactic brain. Open your mind to an ocean of mundane knowledge that will exhaust you at work. Enter... the Bearpedia:

https://beartype.readthedocs.io

The document you are now reading was once a monolithic ~316Kb file known to induce migraines in 22% of the whole devops population. For your safety, that document no longer exists. This is how much beartype cares.

Beartype is an open-source pure-Python <beartype pure_>__ PEP-compliant near-real-time hybrid runtime-static third-generation <beartype third_>__ type checker emphasizing efficiency, usability, unsubstantiated jargon we just made up, and thrilling puns.

# Install beartype.
$ pip3 install beartype
# Edit the "{your_package}.__init__" submodule with your favourite IDE.
$ vim {your_package}/__init__.py      # <-- so, i see that you too vim
from beartype.claw import beartype_this_package       # <-- hype comes
beartype_this_package()                               # <-- hype goes

Beartype now implicitly type-checks all annotated classes, callables, and variable assignments across all submodules of your package. Congrats. This day all bugs die.

But why stop at the burning tires in only your code? Your app depends on a sprawling ghetto of other packages, modules, and services. How riddled with infectious diseases is that code? You're about to find out.

# ....................{ BIG BEAR                        }....................
# Warn about type hint violations in *OTHER* packages outside your control;
# only raise exceptions from violations in your package under your control.
# Again, at the very top of your "{your_package}.__init__" submodule:
from beartype import BeartypeConf                              # <-- this isn't your fault
from beartype.claw import beartype_all, beartype_this_package  # <-- you didn't sign up for this
beartype_this_package()                                        # <-- raise exceptions in your code
beartype_all(conf=BeartypeConf(violation_type=UserWarning))     # <-- emit warnings from other code

Beartype now implicitly type-checks all annotated classes, callables, and variable assignments across all submodules of all packages. When your package violates type safety, beartype raises an exception. When any other package violates type safety, beartype just emits a warning. The triumphal fanfare you hear is probably your userbase cheering. This is how the QA was won.

Beartype also publishes a plethora of APIs for fine-grained control over type-checking <beartype APIs>. For those who are about to QA, beartype salutes you. Would you like to know more?

# So let's do this. $ python3

# ....................{ RAISE THE PAW                   }....................
# Manually enforce type hints across individual classes and callables.
# Do this only if you want a(nother) repetitive stress injury.

# Import the @beartype decorator.
>>> from beartype import beartype      # <-- eponymous import; it's eponymous

# Annotate @beartype-decorated classes and callables with type hints.
>>> @beartype                          # <-- you too will believe in magic
... def quote_wiggum(lines: list[str]) -> None:
...     print('“{}”\n\t— Police Chief Wiggum'.format("\n ".join(lines)))

# Call those callables with valid parameters.
>>> quote_wiggum(["Okay, folks. Show's over!", " Nothing to see here. Show's…",])
“Okay, folks. Show's over!
 Nothing to see here. Show's…”
   — Police Chief Wiggum

# Call those callables with invalid parameters.
>>> quote_wiggum([b"Oh, my God! A horrible plane crash!", b"Hey, everybody! Get a load of this flaming wreckage!",])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 30, in quote_wiggum
  File "/home/springfield/beartype/lib/python3.9/site-packages/beartype/_decor/_code/_pep/_error/errormain.py", line 220, in get_beartype_violation
    raise exception_cls(
beartype.roar.BeartypeCallHintParamViolation: @beartyped
quote_wiggum() parameter lines=[b'Oh, my God! A horrible plane
crash!', b'Hey, everybody! Get a load of thi...'] violates type hint
list[str], as list item 0 value b'Oh, my God! A horrible plane crash!'
not str.

# ....................{ MAKE IT SO                      }....................
# Squash bugs by refining type hints with @beartype validators.
>>> from beartype.vale import Is  # <---- validator factory
>>> from typing import Annotated  # <---------------- if Python ≥ 3.9.0
# >>> from typing_extensions import Annotated   # <-- if Python < 3.9.0

# Validators are type hints constrained by lambda functions.
>>> ListOfStrings = Annotated[  # <----- type hint matching non-empty list of strings
...     list[str],  # <----------------- type hint matching possibly empty list of strings
...     Is[lambda lst: bool(lst)]  # <-- lambda matching non-empty object
... ]

# Annotate @beartype-decorated callables with validators.
>>> @beartype
... def quote_wiggum_safer(lines: ListOfStrings) -> None:
...     print('“{}”\n\t— Police Chief Wiggum'.format("\n ".join(lines)))

# Call those callables with invalid parameters.
>>> quote_wiggum_safer([])
beartype.roar.BeartypeCallHintParamViolation: @beartyped
quote_wiggum_safer() parameter lines=[] violates type hint
typing.Annotated[list[str], Is[lambda lst: bool(lst)]], as value []
violates validator Is[lambda lst: bool(lst)].

# ....................{ AT ANY TIME                     }....................
# Type-check anything against any type hint – anywhere at anytime.
>>> from beartype.door import (
...     is_bearable,  # <-------- like "isinstance(...)"
...     die_if_unbearable,  # <-- like "assert isinstance(...)"
... )
>>> is_bearable(['The', 'goggles', 'do', 'nothing.'], list[str])
True
>>> die_if_unbearable([0xCAFEBEEF, 0x8BADF00D], ListOfStrings)
beartype.roar.BeartypeDoorHintViolation: Object [3405692655, 2343432205]
violates type hint typing.Annotated[list[str], Is[lambda lst: bool(lst)]],
as list index 0 item 3405692655 not instance of str.

# ....................{ GO TO PLAID                     }....................
# Type-check anything in around 1µs (one millionth of a second) – including
# this list of one million 2-tuples of NumPy arrays.
>>> from beartype.door import is_bearable
>>> from numpy import array, ndarray
>>> data = [(array(i), array(i)) for i in range(1000000)]
>>> %time is_bearable(data, list[tuple[ndarray, ndarray]])
    CPU times: user 31 µs, sys: 2 µs, total: 33 µs
    Wall time: 36.7 µs
True

Beartype brings Rust- and C++-inspired zero-cost abstractions <zero-cost abstraction_>__ into the lawless world of dynamically-typed Python by enforcing type safety at the granular level of functions and methods <beartype ELI5_>__ against type hints standardized by the Python community <beartype PEPs_>__ in O(1) non-amortized worst-case time with negligible constant factors. If the prior sentence was unreadable jargon, see our friendly and approachable FAQ for a human-readable synopsis <beartype FAQ_>__.

Beartype is portably implemented in Python 3, continuously stress-tested via GitHub Actions × tox × pytest × Codecov, and permissively distributed under the MIT license. Beartype has no runtime dependencies, only one test-time dependency, and only one documentation-time dependency. Beartype supports all actively developed Python versions, all Python package managers, and multiple platform-specific package managers.

numerary's People

Contributors

posita avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

stillwater-sc

numerary's Issues

Sphinx/autodoc reports metaclass conflict

Hi again 👋

When adding numerary to phantom-types I forgot to update the dependencies of the docs build, which left two sections empty 😬 I'll need to work on the CI so that it blows up earlier for that, and obviously fix the missing imports.

However, as I'm trying to reproduce this failure locally (was a silent warning in CI), I get the traceback below. It seems to indicate that numerary has a metaclass conflict, which confuses me profoundly since both your and my test suites are passing. It's also not reproduced when I in the same environment fire up a REPL and do from phantom.sized import *.

WARNING: autodoc: failed to import module 'sized' from module 'phantom'; the following exception was raised:
Traceback (most recent call last):
  File "/Users/annevoab/.pyenv/versions/docs/lib/python3.10/site-packages/sphinx/ext/autodoc/importer.py", line 32, in import_module
    return importlib.import_module(modname)
  File "/Users/annevoab/.pyenv/versions/3.10.0/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/Users/annevoab/projects/phantom-types/src/phantom/sized.py", line 27, in <module>
    from numerary.types import RealLike
  File "/Users/annevoab/.pyenv/versions/docs/lib/python3.10/site-packages/numerary/__init__.py", line 13, in <module>
    from .types import *  # noqa: F401,F403
  File "/Users/annevoab/.pyenv/versions/docs/lib/python3.10/site-packages/numerary/types.py", line 353, in <module>
    class SupportsAbs(
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

It seems very likely that isn't really an issue with numerary but rather with my sphinx/autodoc setup, but I it seemed worth reaching out here in case someone has ran into similar issues. Feel free to instantly close this though as I doubt it's actionable within numerary.

RealLike doesn't detect a class implementing numbers.Real

consider this quick and dirty example

from numerary import RealLike
from numbers import Real

class MyNumber(Real):
    
    def __init__(self,value=0):
        self.value = value
        
    def __repr__(self):
        return f"{type(self).__name__}({self.value})"
       
    def __float__(self):
        return type(self)(self.value)

    def __neg__(self):
        return type(self)(self.value)

    def __rtruediv__(self, otro):
        return type(self)(self.value)

    def __pos__(self):
        return type(self)(self.value)

    def __abs__(self):
        return type(self)(self.value)

    def __rmul__(self, otro):
        return type(self)(self.value)

    def __floor__(self):
        return type(self)(self.value)

    def __eq__(self, otro):
        return type(self)(self.value)

    def __floordiv__(self, otro):
        return type(self)(self.value)

    def __le__(self, otro):
        return type(self)(self.value)

    def __mul__(self, otro):
        return type(self)(self.value)

    def __radd__(self, otro):
        return type(self)(self.value)

    def __add__(self, otro):
        return type(self)(self.value)

    def __truediv__(self, otro):
        return type(self)(self.value)

    def __pow__(self, otro):
        return type(self)(self.value)

    def __rfloordiv__(self, otro):
        return type(self)(self.value)

    def __round__(self, ndigits=None):
        return type(self)(self.value)

    def __rmod__(self, otro):
        return type(self)(self.value)

    def __rpow__(self, otro):
        return type(self)(self.value)

    def __lt__(self, otro):
        return type(self)(self.value)

    def __ceil__(self):
        return type(self)(self.value)

    def __mod__(self, otro):
        return type(self)(self.value)

    def __trunc__(self):
        return type(self)(self.value)

n = MyNumber(23)

print(n)

assert isinstance(n,Real),"isn't a Real"
assert isinstance(n,RealLike),"isn't a RealLike"

gives

MyNumber(23)
Traceback (most recent call last):
  File "C:\Users\ThecnoMacVZLA\Desktop\mypy_tests\mynumber.py", line 89, in <module>
    assert isinstance(n,RealLike),"isn't a RealLike"
AssertionError: isn't a RealLike

I wonder why?

AttributeError: module 'numpy' has no attribute 'float128'. Did you mean: 'float16'?

after just coming across this library, I just pip installed it and the first thing I come across is

>>> import numerary
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    import numerary
  File "C:\Python3.10.5\lib\site-packages\numerary\__init__.py", line 13, in <module>
    from .types import *  # noqa: F401,F403
  File "C:\Python3.10.5\lib\site-packages\numerary\types.py", line 1712, in <module>
    numpy.float128,
  File "C:\Python3.10.5\lib\site-packages\numpy\__init__.py", line 315, in __getattr__
    raise AttributeError("module {!r} has no attribute "
AttributeError: module 'numpy' has no attribute 'float128'. Did you mean: 'float16'?
>>> 

versions:
python: 3.10.5
numpy: 1.22.4

Help @beartype help numerary

Greetings and salacious salutations, fellow wayward traveller on the congested superhighway of questionable human experience. Per beartype/beartype#84, I'd love to promote numeric health in downstream code by elevating numerary above lesser and baser alternatives for type-checking numbers with @beartype.

Python numbers are a fathomless well of squalid darkness. I need you to man the lonely walls with me. I have no idea what I do. You do. Together, let us bring light to the dank codebases that think accepting a bool as an int is good API practice.

Consider this hypothetical FAQ entry with your keen hawk eye:

How do I type-check numbers...?

tl;dr: Prefer the third-party numerary package unless you have a compelling reason not to (e.g., you either don't want to add an additional mandatory runtime dependency to your Jenga-like app stack or you do but one of the use cases below already provides a tighter fit).

"Numbers" means many things to many people. Some people think booleans are numbers. Technically, these people are not wrong. Pragmatically, these people are wrong. Don't hire these people.

Stop! Disambiguate and listen. You really want to type-check...

...builtin numeric types covariantly?

You want to type-check int, float, or complex numbers including instances of subclasses of those types? O frabjous day! This is the trivial case, because beartype already does exactly what you want out-of-the-box.

Just annotate with any builtin numeric type as is: e.g.,

@beartype
def fawlty_towers(rare_diseases: int) -> int:
    return rare_diseases ^ 0xDEADBEEF

Be forewarned that any bool is also an int and thus satisfies the above API. If you don't want that, spoiler alert: you don't want that the next question is your codebase's BFFL.

...builtin numeric types invariantly?

Something, something, something. I got exhausted and fell down onto the bed in a dishevelled heap here. This is the toll that type-checking numbers takes on the unprepared body, @posita.

Don't let this happen to you.

it happened

Help numerary help @beartype (help numerary) by porting CachingProtocolMeta to beartype

Original proposal attributed to @leycyc. From #7 (comment):

Diversionary trainwreck alert: you have implemented something suspiciously fast and dangerously beautiful with the homegrown private caching protocol API (HPCPAPI) that is the beating heart of numerary. Would incorporating that API directly into beartype itself be feasible?

Here is what I am cogitating. typing.Protocol is slower than good ol' Southern molasses. beartype.typing.Protocol is currently just a trivial alias for typing.Protocol and thus also slower than that foodstuff. beartype.typing.Protocol doesn't need to be a trivial alias, however; in theory, beartype.typing.Protocol could be redefined to be your HPCPAPI. Every problem is now solved. Structural subtyping is now genuinely usable.

There's a caveat. If caching dramatically increases space complexity for downstream consumers in unexpected ways, the userbase will abandon @beartype after doxxing me on 4chan. That's bad. You've probably already tackled this concern (...maybe with an internal LRU cache?). If so, I have no remaining concerns and (with your generous permission and all the glory attributed directly to you as I abase myself before your complex throne of head-spinning protocols) will shortly assimilate your HPCPAPI into beartype.typing.Protocol. That's good.

Filing separately because #7 deals with a broader issue, and I got distracted by this shiny object.

help combining itertools' takewhile and count

testing typing some of my stuff with numerary I came across this example

from typing import Union, Any, Iterable
from numerary import RealLike, IntegralLike
from itertools import takewhile, count

NumberType = Union[RealLike,IntegralLike]

def irange(start:NumberType, stop:NumberType, step:NumberType=1) -> Iterable[NumberType]:   
    """Simple iterador para producir valores en [start,stop)"""
    return takewhile(lambda x: x<stop, count(start,step))                 

mypy said this

C:\Users\ThecnoMacVZLA\Desktop\mypy_tests>mypy test3.py
test3.py:9: error: Argument 2 to "takewhile" has incompatible type "count[SupportsFloat]"; expected "Iterable[RealLike[Any]]"
Found 1 error in 1 file (checked 1 source file)

C:\Users\ThecnoMacVZLA\Desktop\mypy_tests>

I can make mypy happy by changing the result type to Iterable[Any].

What would be a better way to type hint this?

Feature proposal: Expose CachingProtocolMeta

Hi posita 👋

I'm about to start using CachingProtocolMeta in phantom-types, to define narrower parameter types for comparison et cetera. Would you be willing to consider a PR that exposes (with __all__) and documents CachingProtocolMeta?

False positive on Sympy primitives and `SupportsRealImag`

Sympy primitives register with the numeric tower, but they do not provide real or imag, but they do provide as_real_imag. Is there a way we can deal with that effectively (perhaps similarly to the numerator and denominator helper functions)?

`numpy` primitives no longer validate on assignment

Apparently, numpy upped its typing game, which is cool, but it makes it very hard to validate using something as rudimentary as numerary. Currently, the work-around I've found is something like the following:

# workaround.py
from numerary.types import SupportsFloorCeil
import numpy

uint8_val_typed: SupportsFloorCeil = numpy.uint8(2)  # fails
uint8_val_asserted = numpy.uint8(2)
assert isinstance(uint8_val_asserted, SupportsFloorCeil)  # works
reveal_type(uint8_val_asserted)  # workaround.<subclass of "unsignedinteger" and "SupportsFloorCeil">

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.