Skip to content

Commit

Permalink
...
Browse files Browse the repository at this point in the history
  • Loading branch information
ken-morel committed Jun 5, 2024
1 parent 6877d37 commit 4f668ae
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 35 deletions.
7 changes: 7 additions & 0 deletions logs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
typeMatch vs isinstance on int:True 0.10954592ms
typeMatch vs isinstance on int:False 0.14949867ms
typeMatch on dict[str, int]*50:True 26.902279449999998ms
typeMatch on dict[str, int]*50:False 2.8174787300000004ms
Cast str->int: 1.4734708ms
Cast complex->int | str: 0.0892422ms
Cast dict[int, list[str]*10]*10->dict[str, tuple[float]]: 1.583452671ms
Empty file added src/logs.yaml
Empty file.
61 changes: 29 additions & 32 deletions src/pyoload/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,10 @@ def typeMatch(val: Any, spec: Any) -> bool:
:return: A boolean
"""
try:
return isinstance(val, spec)
except TypeError:
pass
if spec == any:
raise TypeError("May be have you confused `Any` and `any`")

Expand Down Expand Up @@ -501,8 +505,6 @@ def typeMatch(val: Any, spec: Any) -> bool:
return False
else:
return True
else:
return isinstance(val, spec)


def resolveAnnotations(obj: Type | Callable) -> None:
Expand Down Expand Up @@ -583,47 +585,38 @@ def wrapper(*pargs, **kw):
errors = []
for k, v in args.arguments.items():
param = sign.parameters.get(k)

if param.annotation is None:
continue
if isinstance(param.annotation, Cast):
args.arguments["k"] = param.annotation(v)
continue
try:
isinstance(v, param.annotation)
except TypeError:
if not typeMatch(v, param.annotation):
if oload:
raise InternalAnnotationError()
errors.append(
AnnotationError(
f"Value: {v!r} does not match annotation:"
f" {param.annotation!r} for "
f"argument {k!r} of function {get_name(func)}",
),
)
else:
args.arguments[k] = param.annotation(v)
continue
if not typeMatch(v, param.annotation):
if oload:
raise InternalAnnotationError()
errors.append(
AnnotationError(
f"Value: {v!r} does not match annotation:"
f" {param.annotation!r} for "
f"argument {k!r} of function {get_name(func)}",
),
)
if len(errors) > 0:
raise AnnotationErrors(errors)

ret = func(*pargs, **kw)
if "return" in func.__annotations__:

if sign.return_annotation is not _empty:
ann = sign.return_annotation
if ann is _empty:
return ret

if isinstance(ann, Cast):
return ann(ret)
try:
isinstance(ret, ann)
except TypeError:
if not typeMatch(ret, ann):
errors.append(
AnnotationError(
f"return value: {ret!r} does not match annotation:"
f" {ann!r} for "
f"of function {get_name(func)}",
),
)
if not typeMatch(ret, ann):
raise AnnotationError(
f"return value: {ret!r} does not match annotation:"
f" {ann!r} for "
f"of function {get_name(func)}",
)
return ret

wrapper.__pyod_annotate__ = func
Expand All @@ -650,6 +643,10 @@ def is_annotable(func):
return not hasattr(func, '__pyod_annotable__') or func.__pyod_annotable__


def is_annoted(func):
return hasattr(func, '__pyod_annotate__')


__overloads__: dict[str, list[Callable]] = {}


Expand Down
6 changes: 3 additions & 3 deletions src/tests/test_overload.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ def div____(a: float, b: float):


def test_overload():
#assert div("4", "2") == "2.0"
#assert div(..., 0) == "Infinity"
assert div("4", "2") == "2.0"
assert div(..., 0) == "Infinity"
assert div("4", 2) == 2
#assert div(3.0, 1.0) == 3.0
assert div(3.0, 1.0) == 3.0


if __name__ == "__main__":
Expand Down
92 changes: 92 additions & 0 deletions src/tests/test_speed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from pyoload import typeMatch, Cast
from time import perf_counter_ns as nanos
from pathlib import Path


N = 100000
NS = 10
src = Path('.').resolve().parent


def test_speed():
f = open(src / "logs.yaml", 'w')
speedTypeMatch(f)
speedCast(f)
f.close()


def speedTypeMatch(f):
begin = nanos()
for _ in range(N):
typeMatch(3, int)
end = nanos()
begin2 = nanos()
for _ in range(N):
isinstance(3, int)
end2 = nanos()
dt = (end - begin) - (end2 - begin2)
dt = dt / 1000 / N
print(f'typeMatch vs isinstance on int:True {dt}ms', file=f)

begin = nanos()
for _ in range(N):
typeMatch(3, str)
end = nanos()
begin2 = nanos()
for _ in range(N):
isinstance(3, int)
end2 = nanos()
dt = (end - begin) - (end2 - begin2)
dt = dt / 1000 / N
print(f'typeMatch vs isinstance on int:False {dt}ms', file=f)

obj = {str(x): x for x in range(50)}
t = dict[str, int]
begin = nanos()
for _ in range(N):
typeMatch(obj, t)
end = nanos()
dt = (end - begin)
dt = dt / 1000 / N
print(f'typeMatch on dict[str, int]*50:True {dt}ms', file=f)

obj = {complex(x): float(x) for x in range(50)}
t = dict[str, int]
begin = nanos()
for _ in range(N):
typeMatch(obj, t)
end = nanos()
dt = (end - begin)
dt = dt / 1000 / N
print(f'typeMatch on dict[str, int]*50:False {dt}ms', file=f)


def speedCast(f):
ct = Cast(int)

begin = nanos()
for x in range(N):
ct('3')
end = nanos()
dt = (end - begin) / N / 1000
print(f'Cast str->int: {dt}ms', file=f)

ct = Cast(int | str)
begin = nanos()
for x in range(N // NS):
ct(3j)
end = nanos()
dt = (end - begin) / N / NS / 1000
print(f'Cast complex->int | str: {dt}ms', file=f)

v = {x: [str(x)] * NS for x in range(NS)}
ct = Cast(dict[str, tuple[float]])
begin = nanos()
for x in range(N // NS):
ct(v)
end = nanos()
dt = (end - begin) / N / NS / 1000
print(
f'Cast dict[int,list[str]*{NS}]*{NS}->dict[str,tuple[float]]: {dt}ms',
file=f,
)

0 comments on commit 4f668ae

Please sign in to comment.