164 lines
5.9 KiB
Python
164 lines
5.9 KiB
Python
import sys
|
|
|
|
import click
|
|
|
|
from ci.ray_ci.doc.api import API
|
|
from ci.ray_ci.doc.autodoc import Autodoc
|
|
from ci.ray_ci.doc.module import Module
|
|
|
|
TEAM_API_CONFIGS = {
|
|
"data": {
|
|
"head_modules": {"ray.data", "ray.data.grouped_data"},
|
|
"head_doc_file": "doc/source/data/api/api.rst",
|
|
# List of APIs that are not following our API policy, and we will be fixing, or
|
|
# we cannot deprecate them although we want to
|
|
"white_list_apis": {
|
|
# not sure what to do
|
|
"ray.data.dataset.MaterializedDataset",
|
|
# special case where we cannot deprecate although we want to
|
|
"ray.data.random_access_dataset.RandomAccessDataset",
|
|
},
|
|
},
|
|
"serve": {
|
|
"head_modules": {"ray.serve"},
|
|
"head_doc_file": "doc/source/serve/api/index.md",
|
|
"white_list_apis": {
|
|
# private versions of request router APIs
|
|
"ray.serve._private.common.ReplicaID",
|
|
"ray.serve._private.request_router.common.PendingRequest",
|
|
"ray.serve._private.request_router.pow_2_router.PowerOfTwoChoicesRequestRouter",
|
|
"ray.serve._private.request_router.request_router.RequestRouter",
|
|
"ray.serve._private.request_router.replica_wrapper.RunningReplica",
|
|
"ray.serve._private.request_router.request_router.FIFOMixin",
|
|
"ray.serve._private.request_router.request_router.LocalityMixin",
|
|
"ray.serve._private.request_router.request_router.MultiplexMixin",
|
|
},
|
|
},
|
|
"core": {
|
|
"head_modules": {"ray"},
|
|
"head_doc_file": "doc/source/ray-core/api/index.rst",
|
|
"white_list_apis": {
|
|
# These APIs will be documented in near future
|
|
"ray.util.scheduling_strategies.DoesNotExist",
|
|
"ray.util.scheduling_strategies.Exists",
|
|
"ray.util.scheduling_strategies.NodeLabelSchedulingStrategy",
|
|
"ray.util.scheduling_strategies.In",
|
|
"ray.util.scheduling_strategies.NotIn",
|
|
# TODO(jjyao): document this API
|
|
"ray.ObjectRefGenerator",
|
|
# TODO(jjyao): document or deprecate these APIs
|
|
"ray.experimental.compiled_dag_ref.CompiledDAGFuture",
|
|
"ray.experimental.compiled_dag_ref.CompiledDAGRef",
|
|
"ray.cross_language.cpp_actor_class",
|
|
"ray.cross_language.cpp_function",
|
|
"ray.client_builder.ClientContext",
|
|
"ray.remote_function.RemoteFunction",
|
|
},
|
|
},
|
|
"train": {
|
|
"head_modules": {"ray.train"},
|
|
"head_doc_file": "doc/source/train/api/api.rst",
|
|
"white_list_apis": {
|
|
# NOTE: These APIs are documented in a separate file (deprecated.rst).
|
|
# These are deprecated APIs, so just white-listing them here for CI.
|
|
"ray.train.error.SessionMisuseError",
|
|
"ray.train.base_trainer.TrainingFailedError",
|
|
"ray.train.TrainingFailedError",
|
|
"ray.train.context.TrainContext",
|
|
"ray.train.context.get_context",
|
|
},
|
|
},
|
|
"tune": {
|
|
"head_modules": {"ray.tune"},
|
|
"head_doc_file": "doc/source/tune/api/api.rst",
|
|
"white_list_apis": {
|
|
# Already documented as ray.tune.search.ConcurrencyLimiter
|
|
"ray.tune.search.searcher.ConcurrencyLimiter",
|
|
# TODO(ml-team): deprecate these APIs
|
|
"ray.tune.utils.log.Verbosity",
|
|
},
|
|
},
|
|
"rllib": {
|
|
"head_modules": {"ray.rllib"},
|
|
"head_doc_file": "doc/source/rllib/package_ref/index.rst",
|
|
"white_list_apis": {},
|
|
},
|
|
}
|
|
|
|
|
|
def _check_team(ray_checkout_dir: str, team: str) -> bool:
|
|
# Load all APIs from the codebase
|
|
api_in_codes = {}
|
|
for module in TEAM_API_CONFIGS[team]["head_modules"]:
|
|
module = Module(module)
|
|
api_in_codes.update(
|
|
{api.get_canonical_name(): api for api in module.get_apis()}
|
|
)
|
|
|
|
# Load all APIs from the documentation
|
|
autodoc = Autodoc(f"{ray_checkout_dir}/{TEAM_API_CONFIGS[team]['head_doc_file']}")
|
|
api_in_docs = {api.get_canonical_name() for api in autodoc.get_apis()}
|
|
|
|
# Load the white list APIs
|
|
white_list_apis = TEAM_API_CONFIGS[team]["white_list_apis"]
|
|
|
|
# Policy 01: all public APIs should be documented
|
|
print(
|
|
f"--- Validating that public {team} APIs should be documented...",
|
|
file=sys.stderr,
|
|
)
|
|
good_apis, bad_apis = API.split_good_and_bad_apis(
|
|
api_in_codes, api_in_docs, white_list_apis
|
|
)
|
|
|
|
if good_apis:
|
|
print("Public APIs that are documented:", file=sys.stderr)
|
|
for api in good_apis:
|
|
print(f"\t{api}", file=sys.stderr)
|
|
|
|
if bad_apis:
|
|
print("Public APIs that are NOT documented:", file=sys.stderr)
|
|
for api in bad_apis:
|
|
print(f"\t{api}", file=sys.stderr)
|
|
|
|
if bad_apis:
|
|
print(
|
|
f"Some public {team} APIs are not documented. Please document them.",
|
|
file=sys.stderr,
|
|
)
|
|
return False
|
|
return True
|
|
|
|
|
|
@click.command()
|
|
@click.argument("ray_checkout_dir", required=True, type=str)
|
|
@click.argument(
|
|
"team", default="ALL", type=click.Choice(list(TEAM_API_CONFIGS.keys()) + ["ALL"])
|
|
)
|
|
def main(ray_checkout_dir: str, team: str) -> None:
|
|
"""
|
|
This script checks for annotated classes and functions in a module, and finds
|
|
discrepancies between the annotations and the documentation.
|
|
"""
|
|
if team != "ALL":
|
|
if not _check_team(ray_checkout_dir, team):
|
|
exit(1)
|
|
return
|
|
|
|
all_pass = True
|
|
# Needs to do core first, otherwise, the APIs in other teams may be covered by core.
|
|
# This is due to the side effect of "importlib" and walking through the modules.
|
|
if not _check_team(ray_checkout_dir, "core"):
|
|
all_pass = False
|
|
for team in TEAM_API_CONFIGS:
|
|
if team == "core":
|
|
continue
|
|
if not _check_team(ray_checkout_dir, team):
|
|
all_pass = False
|
|
if not all_pass:
|
|
exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|