Skip to main content

Pretty comprehensive typehint evaluator, gives your Python functions that extra bit of zazz and illegibility they always needed.

Project description

exec_hints

Pretty comprehensive typehint evaluator to give you code that extra bit of zazz and illegibility it always needed

For all examples, here's the obvious prerequisite

from exec_hints import exec_hints, check_hints, _UnionType, Literal

Alternatively, you can just import exec_hints and use the module as a callable!

Let's start off small: you can specify a hint on an argument and it'll convert it

@exec_hints
def foo(arg:int):
    print(arg*arg)

foo('12')
>>> 144
@exec_hints
def foo(arg:set):
    print(arg, arg.issubset('123'))

foo('12')
>>> {'2', '1'} True
@exec_hints
def foo(arg:set[int]):
    print(arg, arg.issubset(range(10)))

foo('12')
>>> {1, 2} True

A single argument to dict will modify all values, 2 arguments means the first applies to keys, 2nd to values

@exec_hints
def foo(arg:dict[int]):
    print(arg, arg.keys())

foo({'a':'123',12:13.2})
>>> {'a': 123, 12: 13} dict_keys(['a', 12])

Works with Unions (more on that later)

@exec_hints
def foo(arg:set[int|str]):
    print(arg, arg.issubset(range(10)))

foo('1a2')
>>> {1, 'a', 2} False

If an iterable hint is provided with a number of arguments matching what was passed, each subhint will be applied to corresponding arguments

@exec_hints
def foo(arg:list[int,str,int]):
    print(arg, arg[::-1])

foo('1a2')
>>> [1, 'a', 2] [2, 'a', 1]

...and of course, we can nest these 😎

@exec_hints
def foo(arg:list[int,int|str,tuple[int|float|str]]):
    print(arg)

foo(('1','a',['1','2.67','b']))
>>> [1, 'a', (1, 2.67, 'b')]

If several options are given, it tries each in turn

@exec_hints
def foo(arg:list[int,int|str]|tuple[int|float|str]):
    print(arg)

#first fails because there are 2 subhints and 3 args provided
foo(['1','2.67','b'])
>>> (1, 2.67, 'b')
#first works!
foo(['1','2.67'])
>>> [1, '2.67']

You can pass your own functions in here, but they cant directly be used with | Blame Python, not me.

@exec_hints
def foo(arg:lambda x: x[::2]):
    print(arg)

foo('banana')
>>> bnn

There's a workaround for that tho! list|1 isnt supported by Python, so we have a class for that: Literal Accepts a callable or a literal (ok the class name isnt the best, accepting any suggestions) If it's callable, will try call on the arg, otherwise will just return itself

@exec_hints
def foo(arg:int|Literal(0)):
    print(arg)

foo('banana')
>>> 0

We can use it to chain builtins that wouldnt normally be allowed. Also note you can use it with [] syntax too

@exec_hints
def foo(arg:int|Literal[str.upper]):
    print(arg)

foo('banana')
>>> BANANA

This documentation would have to be a few miles long to cover all of this So here's a few examples:

@exec_hints
def foo(message:int|tuple[int]|list[0], dct:dict[int,tuple[str.lower]]):
    print(message)
    print(dct)

foo('a1',{'213':'BaNaNa','444':'BoBa'})
>>> [0, 0]
>>> {213: ('b', 'a', 'n', 'a', 'n', 'a'), 444: ('b', 'o', 'b', 'a')}

Uhh, it works on a lot of stuff :) Notably you can manipulate *args and **kwargs as normal. Works with defaults too, but it will try to apply the hint to the default provided

@exec_hints
def a(a,b:str.upper,c:tuple[int],d=12,*e:lambda x:map(str,x),f:int|Literal(-3)=3,**g:dict[str]):
    print(a,b,c,d,e,f,g)

a(1,'bb',['2','3'],4,5,banana=1,apple=2)
>>> 1 BB (2, 3) 4 ('5',) 3 {'banana': '1', 'apple': '2'}

You can typehint return values too 🎉

@exec_hints
def foo(arg:int|Literal(str.upper)) -> lambda x:tuple(reversed(x)):
    print(arg)
    return arg

print(foo('banana'))
>>> BANANA
>>> ('A', 'N', 'A', 'N', 'A', 'B')

Works with classes, including dataclasses. As of 0.1.4 it's a bit scuffed as the result is a function that calls the constructor of the class, but it works.

import exec_hints
from dataclasses import dataclass

@exec_hints
@dataclass
class Bot:
    alignment: bool
    serial: int
    name: str


print(Bot(123123, '12', 2))
>>> Bot(alignment=True, serial=12, name='2')

The check_hints function is useful for debugging or making sure your hints are correct. Works as you would expect it to similar to exec_hints, but will raise an error if the hint fails. Literal checks are also done via equality, or if the literal is callable, it will be called on the arg and checked for truthiness.

from exec_hints import check_hints

@check_hints
def foo(arg:int|Literal(str.upper)):
    print(arg)

foo('banana') # FAILS
foo('BANANA') # PASSES

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

exec_hints-0.1.4.tar.gz (6.0 kB view hashes)

Uploaded Source

Built Distribution

exec_hints-0.1.4-py2.py3-none-any.whl (5.3 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page