123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- #!/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)
|