forked from ray-project/ray
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CI] Check test files for
if __name__...
snippet (ray-project#25322)
Bazel operates by simply running the python scripts given to it in `py_test`. If the script doesn't invoke pytest on itself in the `if _name__ == "__main__"` snippet, no tests will be ran, and the script will pass. This has led to several tests (indeed, some are fixed in this PR) that, despite having been written, have never ran in CI. This PR adds a lint check to check all `py_test` sources for the presence of `if _name__ == "__main__"` snippet, and will fail CI if there are any detected without it. This system is only enabled for libraries right now (tune, train, air, rllib), but it could be trivially extended to other modules if approved.
- Loading branch information
Showing
17 changed files
with
142 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ requests | |
tabulate | ||
tensorflow | ||
black==21.12b0 | ||
yq |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import json | ||
import re | ||
import sys | ||
from pathlib import Path | ||
|
||
|
||
def check_file(file_contents: str) -> bool: | ||
return bool(re.search(r"^if __name__ == \"__main__\":", file_contents, re.M)) | ||
|
||
|
||
def parse_json(data: str) -> dict: | ||
return json.loads(data) | ||
|
||
|
||
def treat_path(path: str) -> Path: | ||
path = path[2:].replace(":", "/") | ||
return Path(path) | ||
|
||
|
||
def get_paths_from_parsed_data(parsed_data: dict) -> list: | ||
paths = [] | ||
for rule in parsed_data["query"]["rule"]: | ||
if "label" in rule and rule["label"]["@name"] == "main": | ||
paths.append(treat_path(rule["label"]["@value"])) | ||
else: | ||
list_args = {e["@name"]: e for e in rule["list"]} | ||
paths.append(treat_path(list_args["srcs"]["label"]["@value"])) | ||
return paths | ||
|
||
|
||
def main(data: str): | ||
print("Checking files for the pytest snippet...") | ||
parsed_data = parse_json(data) | ||
paths = get_paths_from_parsed_data(parsed_data) | ||
|
||
bad_paths = [] | ||
for path in paths: | ||
print(f"Checking file {path}...") | ||
with open(path, "r") as f: | ||
if not check_file(f.read()): | ||
print(f"File {path} is missing the pytest snippet.") | ||
bad_paths.append(path) | ||
if bad_paths: | ||
raise RuntimeError( | ||
'Found py_test files without `if __name__ == "__main__":` snippet:' | ||
f" {[str(x) for x in bad_paths]}\n" | ||
"If this is intentional, please add a `no_main` tag to bazel BUILD " | ||
"entry for that file." | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
# Expects a json | ||
# Invocation from workspace root: | ||
# bazel query 'kind(py_test.*, tests(python/...) intersect | ||
# attr(tags, "\bteam:ml\b", python/...) except attr(tags, "\bno_main\b", | ||
# python/...))' --output xml | xq | python scripts/pytest_checker.py | ||
data = sys.stdin.read() | ||
main(data) |