Skip to content

Commit

Permalink
Merge pull request #174 from cs50/develop
Browse files Browse the repository at this point in the history
v3.0.5
  • Loading branch information
Kareem Zidane authored Aug 7, 2019
2 parents af8af44 + 52279f5 commit 9f8d8b0
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 42 deletions.
87 changes: 50 additions & 37 deletions check50/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
SLUG = None


class RemoteCheckError(internal.Error):
def __init__(self, remote_json):
super().__init__("check50 ran into an error while running checks! Please contact [email protected]!")
self.payload = {"remote_json": remote_json}


@contextlib.contextmanager
def nullcontext(entry_result=None):
"""This is just contextlib.nullcontext but that function is only available in 3.7+."""
Expand All @@ -41,9 +47,8 @@ def excepthook(cls, exc, tb):
outputs = excepthook.outputs

for output in excepthook.outputs:
outputs.remove(output)
if output == "json":
outputs.remove("json")

ctxmanager = open(excepthook.output_file, "w") if excepthook.output_file else nullcontext(sys.stdout)
with ctxmanager as output_file:
json.dump({
Expand All @@ -59,11 +64,6 @@ def excepthook(cls, exc, tb):
output_file.write("\n")

elif output == "ansi" or output == "html":
if output == "ansi":
outputs.remove("ansi")
else:
outputs.remove("html")

if (issubclass(cls, internal.Error) or issubclass(cls, lib50.Error)) and exc.args:
termcolor.cprint(str(exc), "red", file=sys.stderr)
elif issubclass(cls, FileNotFoundError):
Expand All @@ -78,6 +78,8 @@ def excepthook(cls, exc, tb):

if excepthook.verbose:
traceback.print_exception(cls, exc, tb)
if hasattr(exc, "payload"):
print("Exception payload:", exc.payload)

sys.exit(1)

Expand Down Expand Up @@ -157,34 +159,43 @@ def compile_checks(checks, prompt=False):



def await_results(url, pings=45, sleep=2):
def await_results(commit_hash, slug, pings=45, sleep=2):
"""
Ping {url} until it returns a results payload, timing out after
{pings} pings and waiting {sleep} seconds between pings.
"""

print("Checking...", end="", flush=True)
for _ in range(pings):
for _i in range(pings):
# Query for check results.
res = requests.post(url, params={"format": "json"})
if res.status_code == 200:
print()
res = requests.get(f"https://submit.cs50.io/api/results/check50?check50", params={"commit_hash": commit_hash, "slug": slug})
results = res.json()

if res.status_code not in [404, 200]:
raise RemoteCheckError(results)

if res.status_code == 200 and results["received_at"] is not None:
break
print(".", end="", flush=True)
time.sleep(sleep)
else:
# Terminate if no response
print()
raise internal.Error(
_("check50 is taking longer than normal!\nSee {} for more detail.").format(url))
_("check50 is taking longer than normal!\n"
"See https://submit.cs50.io/check50/{} for more detail").format(commit_hash))


if not results["check50"]:
raise RemoteCheckError(results)

if "error" in results["check50"]:
raise RemoteCheckError(results["check50"])


payload= res.json()
# TODO: Should probably check payload["version"] here to make sure major version is same as __version__
# (otherwise we may not be able to parse results)
return {
"slug": payload["slug"],
"results": list(map(CheckResult.from_dict, payload["results"])),
"version": payload["version"]
return results["tag_hash"], {
"slug": results["check50"]["slug"],
"results": list(map(CheckResult.from_dict, results["check50"]["results"])),
"version": results["check50"]["version"]
}


Expand Down Expand Up @@ -235,7 +246,7 @@ def main():
help=_("run checks completely offline (implies --local)"))
parser.add_argument("-l", "--local",
action="store_true",
help=_("run checks locally instead of uploading to cs50 (enabled by default in beta version)"))
help=_("run checks locally instead of uploading to cs50"))
parser.add_argument("--log",
action="store_true",
help=_("display more detailed information about check results"))
Expand Down Expand Up @@ -266,8 +277,6 @@ def main():
global SLUG
SLUG = args.slug

# TODO: remove this when submit.cs50.io API is stabilized
args.local = True

if args.dev:
args.offline = True
Expand All @@ -278,7 +287,7 @@ def main():

if args.verbose:
# Show lib50 commands being run in verbose mode
logging.basicConfig(level="INFO")
logging.basicConfig(level=os.environ.get("CHECK50_LOGLEVEL", "INFO"))
lib50.ProgressBar.DISABLED = True
args.log = True

Expand All @@ -291,7 +300,11 @@ def main():
excepthook.outputs = args.output
excepthook.output_file = args.output_file

if args.local:
if not args.local:
commit_hash = lib50.push("check50", SLUG, internal.CONFIG_LOADER, commit_suffix="[check50=true]")[1]
with lib50.ProgressBar("Waiting for results") if "ansi" in args.output else nullcontext():
tag_hash, results = await_results(commit_hash, SLUG)
else:
with lib50.ProgressBar("Checking") if not args.verbose and "ansi" in args.output else nullcontext():
# If developing, assume slug is a path to check_dir
if args.dev:
Expand Down Expand Up @@ -351,11 +364,6 @@ def main():
"version": __version__
}

else:
# TODO: Remove this before we ship
raise NotImplementedError("cannot run check50 remotely, until version 3.0.0 is shipped ")
commit_hash = lib50.push("check50", SLUG, commit_suffix="[submit=false]")[1]
results = await_results(f"https://check.cs50.io/{commit_hash}")

# Render output
file_manager = open(args.output_file, "w") if args.output_file else nullcontext(sys.stdout)
Expand All @@ -368,13 +376,18 @@ def main():
output_file.write(renderer.to_ansi(**results, log=args.log))
output_file.write("\n")
elif output == "html":
html = renderer.to_html(**results)
if os.environ.get("CS50_IDE_TYPE"):
subprocess.check_call(["c9", "exec", "rendercheckresults", html])
if not args.local:
url = f"https://submit.cs50.io/check50/{tag_hash}"
else:
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html") as html_file:
html_file.write(html)
termcolor.cprint(_("To see the results in your browser go to file://{}").format(html_file.name), "white", attrs=["bold"])
html = renderer.to_html(**results)
if os.environ.get("CS50_IDE_TYPE"):
subprocess.check_call(["c9", "exec", "rendercheckresults", html])
else:
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html") as html_file:
html_file.write(html)
url = f"file://{html_file.name}"
termcolor.cprint(_("To see the results in your browser go to {}").format(url), "white", attrs=["bold"])



if __name__ == "__main__":
Expand Down
7 changes: 3 additions & 4 deletions check50/renderer/_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from pexpect.exceptions import EOF
import termcolor

from .. import __version__
from ..runner import CheckResult

TEMPLATES = pathlib.Path(pkg_resources.resource_filename("check50.renderer", "templates"))
Expand All @@ -25,7 +24,7 @@ def default(self, o):
return o.__dict__


def to_html(slug, results, version=__version__):
def to_html(slug, results, version):
with open(TEMPLATES / "results.html") as f:
content = f.read()

Expand All @@ -36,13 +35,13 @@ def to_html(slug, results, version=__version__):
return html


def to_json(slug, results, version=__version__):
def to_json(slug, results, version):
return json.dumps({"slug": slug, "results": results, "version": version},
cls=Encoder,
indent=4)


def to_ansi(slug, results, version=__version__, log=False):
def to_ansi(slug, results, version, log=False):
lines = [termcolor.colored(_("Results for {} generated by check50 v{}").format(slug, version), "white", attrs=["bold"])]
for result in results:
if result.passed:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
"console_scripts": ["check50=check50.__main__:main"]
},
url="https://github.com/cs50/check50",
version="3.0.4",
version="3.0.5",
include_package_data=True
)

0 comments on commit 9f8d8b0

Please sign in to comment.