also check class methods
This commit is contained in:
parent
7f98bceb6b
commit
db4c6de1b7
1 changed files with 56 additions and 2 deletions
|
|
@ -78,8 +78,14 @@ def read_api():
|
||||||
if '__future__' in _type:
|
if '__future__' in _type:
|
||||||
continue
|
continue
|
||||||
vinfo['type'] = str(type(value))
|
vinfo['type'] = str(type(value))
|
||||||
if isinstance(value, types.FunctionType):
|
if inspect.isclass(value):
|
||||||
|
vinfo['is_class'] = True
|
||||||
|
vinfo.update(dump_class(value))
|
||||||
|
elif inspect.isfunction(value):
|
||||||
|
vinfo['is_function'] = True
|
||||||
vinfo.update(dump_func(value))
|
vinfo.update(dump_func(value))
|
||||||
|
elif inspect.ismodule(value):
|
||||||
|
vinfo['is_module'] = True
|
||||||
info[name] = vinfo
|
info[name] = vinfo
|
||||||
|
|
||||||
# hub rpc calls (no plugins)
|
# hub rpc calls (no plugins)
|
||||||
|
|
@ -94,6 +100,10 @@ def read_api():
|
||||||
|
|
||||||
def dump_func(func):
|
def dump_func(func):
|
||||||
info = OrderedDict()
|
info = OrderedDict()
|
||||||
|
if inspect.isbuiltin(func):
|
||||||
|
info['is_builtin'] = True
|
||||||
|
if inspect.isgeneratorfunction(func):
|
||||||
|
info['is_generator_function'] = True
|
||||||
sig = inspect.signature(func)
|
sig = inspect.signature(func)
|
||||||
info['desc'] = '(%s)' % ', '.join([str(x) for x in sig.parameters.values()])
|
info['desc'] = '(%s)' % ', '.join([str(x) for x in sig.parameters.values()])
|
||||||
args = []
|
args = []
|
||||||
|
|
@ -116,6 +126,22 @@ def dump_func(func):
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def dump_class(cls):
|
||||||
|
members = OrderedDict()
|
||||||
|
names = [n for n in vars(cls) if not n.startswith('_')]
|
||||||
|
names.sort()
|
||||||
|
for name in names:
|
||||||
|
value = getattr(cls, name)
|
||||||
|
vinfo = OrderedDict()
|
||||||
|
_type = str(type(value))
|
||||||
|
vinfo['type'] = str(type(value))
|
||||||
|
if inspect.isfunction(value):
|
||||||
|
vinfo['is_function'] = True
|
||||||
|
vinfo.update(dump_func(value))
|
||||||
|
members[name] = vinfo
|
||||||
|
return {'members': members}
|
||||||
|
|
||||||
|
|
||||||
def compare(old, new):
|
def compare(old, new):
|
||||||
top_keys = {'version', 'lib', 'rpc'}
|
top_keys = {'version', 'lib', 'rpc'}
|
||||||
if set(old) != top_keys:
|
if set(old) != top_keys:
|
||||||
|
|
@ -178,7 +204,35 @@ def compare_mod_global(mod, name, old, new):
|
||||||
# this prevents further comparison
|
# this prevents further comparison
|
||||||
return
|
return
|
||||||
desc = f'{mod}.{name}'
|
desc = f'{mod}.{name}'
|
||||||
if 'args' in old:
|
if old.get('is_function'):
|
||||||
|
compare_function(desc, old, new)
|
||||||
|
elif old.get('is_class'):
|
||||||
|
compare_class(desc, old, new)
|
||||||
|
|
||||||
|
|
||||||
|
def compare_class(cls, old, new):
|
||||||
|
names1 = set(old['members'])
|
||||||
|
names2 = set(new['members'])
|
||||||
|
added = names2 - names1
|
||||||
|
dropped = names1 - names2
|
||||||
|
both = names1.intersection(names2)
|
||||||
|
|
||||||
|
for name in sorted(added):
|
||||||
|
warn(f'Added class variable: {cls}.{name}')
|
||||||
|
for name in sorted(dropped):
|
||||||
|
# TODO figure out a way to distinguish deprecations
|
||||||
|
error(f'Dropped class variable: {cls}.{name}')
|
||||||
|
for name in sorted(both):
|
||||||
|
compare_class_var(cls, name, old['members'][name], new['members'][name])
|
||||||
|
|
||||||
|
|
||||||
|
def compare_class_var(cls, name, old, new):
|
||||||
|
if old['type'] != new['type']:
|
||||||
|
error(f'{cls}.{name} changed type: {old["type"]} -> {new["type"]}')
|
||||||
|
# this prevents further comparison
|
||||||
|
return
|
||||||
|
desc = f'{cls}.{name}'
|
||||||
|
if old.get('is_function'):
|
||||||
compare_function(desc, old, new)
|
compare_function(desc, old, new)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue