bintoro / overloading.py Goto Github PK
View Code? Open in Web Editor NEWFunction overloading for Python 3
License: MIT License
Function overloading for Python 3
License: MIT License
While running the previous test case I've included in #5, I also came across problems in PyCharm where the builtin issubclass
is called with arguments type_
and typing.Union
(e.g. L#457, L#475, etc.). By the following example, and the source in the standard library, you cannot call issubclass
on typing.Union
, since it can't be subclassed.
>>> from typing import Union
>>> issubclass(str, Union[str])
True
>>> issubclass(str, Union[str, float])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/typing.py", line 770, in __subclasscheck__
raise TypeError("Unions cannot be used with issubclass().")
TypeError: Unions cannot be used with issubclass().
The former only works because the constructor of typing.Union
returns the single type (c.f. this comment in the docstring, and this if
-statement in the __new__
block).
for some reason my program throws this error rooted in this lib. when i try to simply overload the init of my class.
Code:
from overloading import overload
import cmath
class Quaternion:
def __init__(self, r: int, i: int, j: int, k: int):
self.r = r
self.i = i
self.j = j
self.k = k
@overload
def __init__(self, c: complex):
self.r = c.real
self.i = c.imag
print(Quaternion(1, 2, 3, 4).r)
print(Quaternion(1 + 2j).r)
Error:
Traceback (most recent call last):
File "C:...\Python\Python37\lib\site-packages\overloading.py", line 63, in overload
return register(__registry[fname], func)
KeyError: 'main.Quaternion.init'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:...\Python\Testing\quaternion.py", line 6, in
class Quaternion:
File "C:...\Python\Testing\quaternion.py", line 14, in Quaternion
def init(self, c: complex):
File "C:...\Python\Python37\lib\site-packages\overloading.py", line 65, in overload
registry[fname] = overloaded(func)
File "C:...\Python\Python37\lib\site-packages\overloading.py", line 151, in overloaded
return register(dispatcher, func)
File "C:...\Python\Python37\lib\site-packages\overloading.py", line 199, in register
signature = get_signature(fn)
File "C:...\Python\Python37\lib\site-packages\overloading.py", line 441, in get_signature
types = tuple(normalize_type(type_hints.get(param, AnyType)) for param in parameters)
File "C:...\Python\Python37\lib\site-packages\overloading.py", line 441, in
types = tuple(normalize_type(type_hints.get(param, AnyType)) for param in parameters)
File "C:...\Python\Python37\lib\site-packages\overloading.py", line 468, in normalize_type
if not typing or not isinstance(type, typing.TypingMeta) or type is AnyType:
AttributeError: module 'typing' has no attribute 'TypingMeta'
This doesn't seem to work?
Running your examples:
@overload
def biggest(items: Iterable[int]):
return max(items)
@overload
def biggest(items: Iterable[str]):
return max(items, key=len)
biggest([2, 0, 15, 8, 7])
Returns error
<ipython-input-3-4c7948311942> in biggest(items)
5 @overload
6 def biggest(items: Iterable[str]):
----> 7 return max(items, key=len)
TypeError: object of type 'int' has no len()
Or with my own example:
@overload
def f(x: int):
return x - 100
@overload
def f(x: str):
return "Hello %s" %s
print(f(3))
print(f("You"))
Traceback (most recent call last):
File "testoverload.py", line 12, in <module>
print(f(3))
File "overload.py", line 184, in f
raise TypeError('invalid call argument(s)')
TypeError: invalid call argument(s)
I'm using python3.5
EDIT: Just realized your test suite doesn't cover Python 3.6.X.
I don't have this issue when using Python 3.4.3, but when using Python 3.6.3 I receive OverloadErrors when providing overrides for class instance methods.
Here's a case that gives me an error in the newer version of Python:
Python 3.6.3 (default, Oct 5 2017, 19:38:03)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.72)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from overloading import overload
>>> class Test:
... @overload
... def m(self, n : int):
... return n + 1
... @overload
... def m(self, n1 : int, n2 : int):
... return n1 + n2
...
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/overloading.py", line 63, in overload
return register(__registry[fname], func)
KeyError: '__main__.Test.m'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in Test
File "/usr/local/lib/python3.6/site-packages/overloading.py", line 65, in overload
__registry[fname] = overloaded(func)
File "/usr/local/lib/python3.6/site-packages/overloading.py", line 151, in overloaded
return register(dispatcher, func)
File "/usr/local/lib/python3.6/site-packages/overloading.py", line 205, in register
.format(dp.__name__, signature.parameters[i]))
overloading.OverloadingError: Failed to overload function 'm': parameter 'self' has an annotation that is not a type.
What's going on?
Do this implementation have known drawback impact on performance?
Thanks for this wonderful module.
jvtrudel
That's mostly relevant for interactive usecases such as REPL or a Jupyter Notebook.
Suppose I have a function
def f(a: int):
return a
and at some point (in an interactive session, with ^ already declared), want to change it, to, for i.,
def f(a: int):
return a * 2
This would fail as of overloading==0.5.0
with OverloadingError: Failed to overload function 'f': non-unique signature
. Can I somehow force an override?
While running the following:
#! /usr/bin/env python3.6
# -*- coding: utf-8 -*-
from overloading import overload, overloaded, overloads
from unittest import TestCase, main
from typing import Union, Dict, Any, Iterable
class TestOverloading(TestCase):
# Use overloading on functions with different types
_add_types = Union[int, str, dict, set]
@overload
@staticmethod
def add(x: int, y: int) -> int:
return x + y
@overload
@staticmethod
def add(x: str, y: str) -> str:
return x + y
@overload
@staticmethod
def add(x: Dict[Any, Any], y: Dict[Any, Any]) -> Dict[Any, Any]:
return {**x, **y}
@overload
@staticmethod
def add(x: set, y: set) -> set:
return x | y
@staticmethod
def complete_add(x: _add_types, y: _add_types) -> _add_types:
class TypeMismatchError(TypeError):
pass
if type(x) != type(y):
raise TypeMismatchError(
f'complete_add expected arguments of similar type, received {type(x)}, {type(y)}'
)
if (type(x) is int and type(y) is int):
return x + y
elif type(x) is str and type(y) is str:
return x + y
elif type(x) is dict and type(y) is dict:
return {**x, **y}
elif type(x) is set and type(y) is set:
return x | y
else:
ts = ', '.join(_add_types.__args__)
raise TypeError(
f'complete_add expected arguments of type {ts} received {type(x)}'
)
def test1(self) -> None:
self.assertEqual(self.add(1, 2), self.complete_add(1, 2))
self.assertEqual(self.add('Brandon', ' Doyle'), self.complete_add('Brandon', ' Doyle'))
self.assertEqual(self.add({1: 'one'}, {2: 'two'}), self.complete_add({1: 'one'}, {2: 'two'}))
self.assertEqual(self.add({1}, {2}), self.complete_add({1}, {2}))
if __name__ == '__main__':
main()
I get the following AttributeError
:
Traceback (most recent call last):
File "./test_overloading.py", line 9, in <module>
class TestOverloading(TestCase):
File "./test_overloading.py", line 21, in TestOverloading
def add(x: str, y: str) -> str:
File "/usr/local/lib/python3.6/site-packages/overloading-0.5.0-py3.6.egg/overloading.py", line 63, in overload
return register(__registry[fname], func)
File "/usr/local/lib/python3.6/site-packages/overloading-0.5.0-py3.6.egg/overloading.py", line 207, in register
dup_sig = sig_cmp(signature, fninfo.signature)
File "/usr/local/lib/python3.6/site-packages/overloading-0.5.0-py3.6.egg/overloading.py", line 669, in sig_cmp
match = type_cmp(t1, t2)
File "/usr/local/lib/python3.6/site-packages/overloading-0.5.0-py3.6.egg/overloading.py", line 702, in type_cmp
if isinstance(t1, typing.UnionMeta) and isinstance(t2, typing.UnionMeta):
AttributeError: module 'typing' has no attribute 'UnionMeta'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.