Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Feb 2, 2024. It is now read-only.
/sdcPublic archive

automatic generation of type checks for overload#911

Open
vlad-perevezentsev wants to merge12 commits intoIntelPython:numba_typing
base:numba_typing
Choose a base branch
Loading
fromvlad-perevezentsev:numba_typing

Conversation

vlad-perevezentsev
Copy link

No description provided.

@pep8speaks
Copy link

pep8speaks commentedAug 17, 2020
edited
Loading

Hello@vlad-perevezentsev! Thanks for updating this PR. We checked the lines you've touched forPEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2020-09-29 14:36:35 UTC

return self._types_dict[p_type](self, p_type, n_type)
return self._types_dict[p_type](n_type)
except KeyError:
print((f'A check for the {p_type} was not found. {n_type}'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

So we will (implicitly) returnNone frommatch in this case, is this intended behavior? Please add explicit return or throw


def choose_func_by_sig(sig_list, values_dict, defaults_dict={}):
checker = TypeChecker()
for sig in sig_list: # sig = (Signature,func)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Instead of accessingsig[0] andsig[1] each time you can writefor sig, func in sig_list:

Comment on lines 1 to 12
import numpy
import numba
from numba import types
from numba import typeof
from numba.extending import overload
from type_annotations import product_annotations, get_func_annotations
from numba import njit
import typing
from numba import NumbaDeprecationWarning, NumbaPendingDeprecationWarning
import warnings
from numba.typed import List, Dict
from inspect import getfullargspec
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

There are some unused imports here, likenumpy,typeof andnjit, please clean them up.

Comment on lines 15 to 16
warnings.simplefilter('ignore', category=NumbaDeprecationWarning)
warnings.simplefilter('ignore', category=NumbaPendingDeprecationWarning)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why is this needed?


def check_tuple_type(self, p_type, n_type):
res = False
if isinstance(n_type, types.Tuple):
Copy link
Collaborator

@AlexanderKalistratovAlexanderKalistratovSep 9, 2020
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Instead of usingn_type.key you could usen_type.types which is defined for bothTuple andUniTuple, so you can unite both branches:

Something like:

ifnotisinstance(n_type,types.Tuple,types.UniTuple):returnFalseforp_val,n_valinzip(p_type.__args__,n_type.types):ifnotself.match(p_val,n_val):returnFalsereturnTrue

And btw you need to check that size ofp_type.__args__ andn_type.types are the same.
And I believe you don't have tests for the case when they are different.

return self._types_dict[p_type](self, p_type, n_type)
return self._types_dict[p_type](n_type)
except KeyError:
print((f'A check for the {p_type} was not found.'))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We should rise an exception


def match(self, p_type, n_type):
try:
if p_type == typing.Any:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Let's do it like this:

ifp_type==typing.Any:returnTrueifself._is_generic(p_type):origin_type=self._get_origin(p_type)iforigin_type==typing.Generic:returnself.match_generic(p_type,n_type)returnself._types_dict[origin_type](self,p_type,n_type)ifisinstance(p_type,typing.TypeVar):returnself.match_typevar(p_type,n_type)ifp_typein (list,tuple):returnself._types_dict[p_type](self,p_type,n_type)returnself._types_dict[p_type](n_type)

return None

def match_typevar(self, p_type, n_type):
if not self._typevars_dict.get(p_type) and n_type not in self._typevars_dict.values():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why do you need conditionn_type not in self._typevars_dict.values() ?

if not self._typevars_dict.get(p_type) and n_type not in self._typevars_dict.values():
self._typevars_dict[p_type] = n_type
return True
return self._typevars_dict.get(p_type) == n_type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I believe it should beself.match. E.g.list and 'types.List' are synonyms but will fail equality check ('list != types.List').
And I'm assuming you don't have such tests?

def match_generic(self, p_type, n_type):
res = True
for arg in p_type.__args__:
res = res and self.match(arg, n_type)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

What's doesn't feel right. Do we have any test for this case?


if sig.defaults.get(name, False):
full_match = full_match and sig.defaults[name] == typ.literal_value
else:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Do we need thiselse?



def check_list_type(self, p_type, n_type):
res = isinstance(n_type, types.List) or isinstance(n_type, types.ListType)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

res=isinstance(n_type, (types.List,types.ListType))


def check_list_type(self, p_type, n_type):
res = isinstance(n_type, types.List) or isinstance(n_type, types.ListType)
if isinstance(p_type, type):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

isinstance(p_type, (list,typing.List))

?

elif isinstance(p_type, typing.TypeVar):
return self.match_typevar(p_type, n_type)
else:
if p_type in (list, tuple):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Shouldn't dict be here too?


class TypeChecker:

_types_dict = {int: check_int_type, float: check_float_type, bool: check_bool_type,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'd prefer this checks to be added usingadd_type_check function

@AlexanderKalistratov
Copy link
Collaborator

https://github.com/IntelPython/sdc/blob/numba_typing/numba_typing/local_variable_type_annotations.py#L11

This code actually modifies original function globals. This shouldn't happen, please fix.

TypeChecker.add_type_check(dict, check_dict_type)


def choose_func_by_sig(sig_list, values_dict, defaults_dict):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Let's do it this way:

defchoose_func_by_sig(sig_list,values_dict,defaults_dict):defcheck_signature(sig_params,types_dict):checker=TypeChecker()forname,typintypes_dict.items():# name,type = 'a',int64ifisinstance(typ,types.Literal):typ=typ.literal_typeifnotchecker.match(sig_params[name],typ):returnFalsereturnTrueforsig,funcinsig_list:# sig = (Signature,func)forparaminsig.parameters:# param = {'a':int,'b':int}ifcheck_signature(param,values_dict):returnfuncreturnNone

return typ.__name__
return typ

value_keys = ", ".join("{}".format(key) for key in values_dict.keys())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

please usef'{key}' instead. Here and everywhere

D_list['qwe'] = List([3, 4, 5])
str_1 = 'qwe'
str_2 = 'qaz'
test_cases = [('int', [1, 2], {'a': int, 'b': int}), ('float', [1.0, 2.0], {'a': float, 'b': float}),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

{'a': int, 'b': int} why do you need two parameters of the same type?
What are you actually testing?

str_2 = 'qaz'
test_cases = [('int', [1, 2], {'a': int, 'b': int}), ('float', [1.0, 2.0], {'a': float, 'b': float}),
('bool', [True, True], {'a': bool, 'b': bool}), ('str', ['str_1', 'str_2'], {'a': str, 'b': str}),
('list', [[1, 2], [3, 4]], {'a': typing.List[int], 'b':list}),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why do you need second list parameter?

('tuple', [(1, 2.0), ('3', False)], {'a': typing.Tuple[int, float], 'b':tuple}),
('dict', ['D', 'D_1'], {'a': typing.Dict[str, int], 'b': typing.Dict[int, bool]}),
('union_1', [1, False], {'a': typing.Union[int, str], 'b': typing.Union[float, bool]}),
('union_2', ['str_1', False], {'a': typing.Union[int, str], 'b': typing.Union[float, bool]}),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

And why you are not testing second Union parameter?

('TypeVar_ListT_DictK_ListT', ['L', 'D_list'], {'a': 'typing.List[T]',
'b': 'typing.Dict[K, typing.List[T]]'})]

test_cases_default = [('int_defaults', [1], {'a': int}, {'b': 0}), ('float_defaults', [1.0], {'a': float}, {'b': 0.0}),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

And what about both - annotation and default value?

('TypeVar_ListT_T', ['L', 5], {'a': 'typing.List[T]', 'b': 'T'}),
('TypeVar_ListT_DictKT', ['L', 'D'], {'a': 'typing.List[T]', 'b': 'typing.Dict[K, T]'}),
('TypeVar_ListT_DictK_ListT', ['L', 'D_list'], {'a': 'typing.List[T]',
'b': 'typing.Dict[K, typing.List[T]]'})]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Are where any tests for TypeVar with specified types restriction?

('union_2', ['str_1', False], {'a': typing.Union[int, str], 'b': typing.Union[float, bool]}),
('nested_list', ['L_int', 'L_float'], {'a': typing.List[typing.List[int]],
'b': typing.List[typing.List[typing.List[float]]]}),
('TypeVar_TT', ['L_f', [3.0, 4.0]], {'a': 'T', 'b': 'T'}),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Any negative tests for such case?

('tuple_defaults', [(1, 2)], {'a': tuple}, {'b': (0, 0)})]


for name, val, annotation in test_cases:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'd prefer you to group all cases into 4-5 tests with subtests. Something like this:

deftest_common_types():test_cases= [({'a':0}, {'a':int}),                 ({'a':0.}, {'a':float}),                ...]forcaseintest_cases:withself.Subtest(case=case):run_test(case)

result = choose_func_by_sig(sig_list, values_dict)

if result is None:
raise TypeError(f'Unsupported types a={a}, b={b}')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Looks botha andb are undefined.


for sig, _ in list_signature:
for param in sig.parameters:
if len(param) != len(values_dict.items()):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

You don't need to call methoditems() here.

for name, val in defaults_dict.items():
if sig_def.get(name) is None:
raise AttributeError(f'{name} does not match the signature of the function passed to overload_list')
if not sig_def[name] == val:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This condition looks pretty strange. Maybeif sig_def[name] != val?

@kozlov-alexeykozlov-alexey added this to thegold milestoneFeb 24, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@Hardcode84Hardcode84Hardcode84 left review comments

@AlexanderKalistratovAlexanderKalistratovAlexanderKalistratov left review comments

@densmirndensmirndensmirn left review comments

@KsanaKozlovaKsanaKozlovaAwaiting requested review from KsanaKozlova

@kozlov-alexeykozlov-alexeyAwaiting requested review from kozlov-alexey

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
gold
Development

Successfully merging this pull request may close these issues.

6 participants
@vlad-perevezentsev@pep8speaks@AlexanderKalistratov@Hardcode84@densmirn@kozlov-alexey

[8]ページ先頭

©2009-2025 Movatter.jp