mirror of
https://github.com/vale981/ray
synced 2025-03-06 02:21:39 -05:00
115 lines
3.1 KiB
Python
Executable file
115 lines
3.1 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import inspect
|
|
|
|
import ray
|
|
from ray.util.annotations import _is_annotated
|
|
|
|
IGNORE_PATHS = {
|
|
".impl.",
|
|
".backend.",
|
|
".experimental.",
|
|
".internal.",
|
|
".generated.",
|
|
".test_utils.",
|
|
".annotations.",
|
|
".deprecation.",
|
|
".protobuf.",
|
|
".cloudpickle.",
|
|
}
|
|
|
|
|
|
def _fullname(attr):
|
|
"""Fully qualified name of an attribute."""
|
|
fullname = ""
|
|
try:
|
|
if hasattr(attr, "__module__"):
|
|
fullname += attr.__module__
|
|
if hasattr(attr, "__name__"):
|
|
if fullname:
|
|
fullname += "."
|
|
fullname += attr.__name__
|
|
if not fullname:
|
|
fullname = str(attr)
|
|
except Exception as e:
|
|
print("Error qualifying", e)
|
|
return fullname
|
|
|
|
|
|
def _ignore(attr, extra_ignore):
|
|
"""Whether an attr should be ignored from annotation checking."""
|
|
attr = _fullname(attr)
|
|
if "ray." not in attr or "._" in attr:
|
|
return True
|
|
for path in IGNORE_PATHS:
|
|
if path in attr:
|
|
return True
|
|
for path in extra_ignore or []:
|
|
if path in attr:
|
|
return True
|
|
return False
|
|
|
|
|
|
def verify(symbol, scanned, ok, output, prefix=None, ignore=None):
|
|
"""Recursively verify all child symbols of a given module."""
|
|
if not prefix:
|
|
prefix = symbol.__name__ + "."
|
|
if symbol in scanned:
|
|
return
|
|
scanned.add(symbol)
|
|
for child in dir(symbol):
|
|
if child.startswith("_"):
|
|
continue
|
|
attr = getattr(symbol, child)
|
|
if _ignore(attr, ignore):
|
|
continue
|
|
if (inspect.isclass(attr) or inspect.isfunction(attr)) and prefix in _fullname(
|
|
attr
|
|
):
|
|
print("Scanning class", attr)
|
|
if _is_annotated(attr):
|
|
if attr not in scanned:
|
|
print("OK:", _fullname(attr))
|
|
ok.add(attr)
|
|
else:
|
|
output.add(attr)
|
|
scanned.add(attr)
|
|
elif inspect.ismodule(attr):
|
|
print("Scanning module", attr)
|
|
verify(attr, scanned, ok, output, prefix, ignore)
|
|
else:
|
|
print("Not scanning", attr, type(attr))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import ray.data
|
|
import ray.rllib
|
|
import ray.serve
|
|
import ray.train
|
|
import ray.tune
|
|
import ray.workflow
|
|
|
|
output = set()
|
|
ok = set()
|
|
verify(ray.data, set(), ok, output)
|
|
# Sanity check the lint logic.
|
|
assert len(ok) >= 60, len(ok)
|
|
|
|
verify(ray.rllib, set(), ok, output)
|
|
verify(ray.air, set(), ok, output)
|
|
verify(ray.train, set(), ok, output)
|
|
verify(ray.tune, set(), ok, output)
|
|
verify(ray, set(), ok, output, ignore=["ray.workflow", "ray.tune", "ray.serve"])
|
|
verify(ray.serve, set(), ok, output)
|
|
assert len(ok) >= 500, len(ok)
|
|
# TODO(ekl) enable it for all modules.
|
|
# verify(ray.tune, set(), ok, output)
|
|
# verify(ray.workflow, set(), ok, output)
|
|
|
|
print("Num ok", len(ok))
|
|
print("Num bad", len(output))
|
|
print("!!! No API stability annotation found for:")
|
|
for x in sorted([_fullname(x) for x in output]):
|
|
print(x)
|
|
if output:
|
|
exit(1)
|