Beispiel #1
0
def analyze(in_path: Path, out_path: Path):
    """Analyze the user's solution and give feedback.

    Outputs a JSON that conforms to
    https://github.com/exercism/docs/blob/main/building/tooling/analyzers/interface.md#output-format
    """

    # List of Comment objects to process
    comments = []

    output_file = out_path.parent.joinpath("analysis.json")

    # input file - if it can't be found, fail and bail
    try:
        user_solution = in_path.read_text()
    except OSError as err:
        # fail out fast with an ESSENTIAL (required) type comment for the student
        comments.append(
            Comment(type=CommentTypes.ESSENTIAL,
                    params={},
                    comment=Comments.MALFORMED_CODE))
    finally:
        if comments:
            return Analysis.require(comments).dump(output_file)

    # AST - if an AST can't be made, fail and bail
    try:
        tree = ast.parse(user_solution)
    except Exception:
        # If ast.parse fails, assume malformed code and fail with an ESSENTIAL (required) type comment for the student
        comments.append(
            Comment(type=CommentTypes.ESSENTIAL,
                    params={},
                    comment=Comments.MALFORMED_CODE))
    finally:
        if comments:
            return Analysis.require(comments).dump(output_file)

    # Generate PyLint comments for additional feedback.
    comments.extend(
        generate_pylint_comments(
            in_path,
            pylint_spec='/opt/analyzer/lib/ellens-alien-game/.pylintrc'))

    return Analysis.summarize_comments(comments, output_file)
Beispiel #2
0
    def monitor(self, info):
        worksheet = self.wd.add_worksheet("Analysis")
        worksheet.set_column("A:A", 15)
        worksheet.set_column("B:B", 10)
        worksheet.set_column("C:C", 10)
        worksheet.set_column("D:D", 10)
        worksheet.set_column("E:E", 10)
        worksheet.set_column("F:F", 10)
        worksheet.set_column("G:G", 10)
        worksheet.set_column("H:H", 10)
        worksheet.set_column("I:I", 10)
        worksheet.set_column("J:J", 10)
        worksheet.set_column("K:K", 10)
        worksheet.set_column("L:L", 10)
        worksheet.set_column("L:L", 10)
        worksheet.set_column("M:M", 10)
        worksheet.set_column("N:N", 10)
        worksheet.set_column("O:O", 10)
        worksheet.set_column("P:P", 10)
        worksheet.set_column("Q:Q", 10)
        worksheet.set_column("R:R", 10)

        worksheet.set_row(1, 30)
        worksheet.set_row(2, 30)
        worksheet.set_row(3, 30)
        worksheet.set_row(4, 30)
        worksheet.set_row(5, 30)
        worksheet.set_row(6, 30)
        worksheet.set_row(7, 30)
        worksheet.set_row(8, 30)
        worksheet.set_row(9, 30)
        worksheet.set_row(10, 30)
        worksheet.set_row(11, 30)
        worksheet.set_row(12, 30)

        define_format_H1 = get_format(self.wd, {'bold': True, 'font_size': 18})
        define_format_H2 = get_format(self.wd, {'bold': True, 'font_size': 14})
        define_format_H1.set_border(1)

        define_format_H2.set_border(1)
        define_format_H1.set_align("center")
        define_format_H2.set_align("center")
        define_format_H2.set_bg_color("blue")
        define_format_H2.set_color("#ffffff")
        worksheet.merge_range('A1:Q1', 'monkey性能监控', define_format_H1)
        _write_center(worksheet, "A2", '设备名', self.wd)
        _write_center(worksheet, "B2", 'CPU', self.wd)
        _write_center(worksheet, "C2", '内存', self.wd)
        _write_center(worksheet, "D2", '分辨率', self.wd)
        _write_center(worksheet, "E2", "耗时", self.wd)
        _write_center(worksheet, "F2", "CPU峰值", self.wd)
        _write_center(worksheet, "G2", "CPU均值", self.wd)
        _write_center(worksheet, "H2", "内存峰值", self.wd)
        _write_center(worksheet, "I2", "内存均值", self.wd)
        _write_center(worksheet, "J2", "fps峰值", self.wd)
        _write_center(worksheet, "K2", "fps均值", self.wd)
        _write_center(worksheet, "L2", "电量测试之前", self.wd)
        _write_center(worksheet, "M2", "电量测试之后", self.wd)
        _write_center(worksheet, "N2", "上行流量峰值", self.wd)
        _write_center(worksheet, "O2", "上行流量均值", self.wd)
        _write_center(worksheet, "P2", "下行流量峰值", self.wd)
        _write_center(worksheet, "Q2", "下行流量均值", self.wd)

        temp = 3
        for t in info:
            for wrap in t:
                for item in t[wrap]:
                    self.get_crash_msg(t[wrap]["header"]["monkey_log"])
                    _write_center(worksheet, "A" + str(temp),
                                  t[wrap]["header"]["phone_name"], self.wd)
                    _write_center(worksheet, "B" + str(temp),
                                  t[wrap]["header"]["kel"], self.wd)
                    _write_center(
                        worksheet, "C" + str(temp),
                        str(math.ceil(t[wrap]["header"]["rom"] / 1024)) + "M",
                        self.wd)
                    _write_center(worksheet, "D" + str(temp),
                                  t[wrap]["header"]["pix"], self.wd)
                    _write_center(worksheet, "E" + str(temp),
                                  t[wrap]["header"]["time"], self.wd)

                    cpu = Pickle.read_info(t[wrap]["cpu"])
                    men = Pickle.read_info(t[wrap]["men"])
                    fps = Pickle.read_info(t[wrap]["fps"])
                    flow = Pickle.read_info(t[wrap]["flow"])
                    _write_center(worksheet, "F" + str(temp),
                                  Analysis.max_cpu(cpu), self.wd)
                    _write_center(worksheet, "G" + str(temp),
                                  Analysis.avg_cpu(cpu), self.wd)
                    _write_center(worksheet, "H" + str(temp),
                                  Analysis.max_men(men), self.wd)
                    _write_center(worksheet, "I" + str(temp),
                                  Analysis.avg_men(men), self.wd)
                    _write_center(worksheet, "J" + str(temp),
                                  Analysis.max_fps(fps), self.wd)
                    _write_center(worksheet, "K" + str(temp),
                                  Analysis.avg_fps(fps), self.wd)
                    _write_center(worksheet, "L" + str(temp),
                                  t[wrap]["header"]["beforeBattery"], self.wd)
                    _write_center(worksheet, "M" + str(temp),
                                  t[wrap]["header"]["afterBattery"], self.wd)
                    _maxFlow = Analysis.max_flow(flow)
                    _avgFLow = Analysis.avg_flow(flow)
                    _write_center(worksheet, "N" + str(temp), _maxFlow[0],
                                  self.wd)
                    _write_center(worksheet, "O" + str(temp), _maxFlow[1],
                                  self.wd)
                    _write_center(worksheet, "P" + str(temp), _avgFLow[1],
                                  self.wd)
                    _write_center(worksheet, "Q" + str(temp), _avgFLow[1],
                                  self.wd)

                    break
                temp = temp + 1
Beispiel #3
0
def analyze(in_path: Path, out_path: Path):
    """
    Analyze the user's Two Fer solution to give feedback. Outputs a JSON that

    conforms to https://github.com/exercism/docs/blob/main/building/tooling/analyzers/interface.md#output-format
    """

    # List of Comment objects to process
    comments = []

    output_file = out_path.parent.joinpath("analysis.json")

    # input file - if it can't be found, fail and bail
    try:
        user_solution = in_path.read_text()
    except OSError as err:
        # fail out fast with an ESSENTIAL (required) type comment for the student
        comments.append(
            Comment(type=CommentTypes.ESSENTIAL,
                    params={},
                    comment=Comments.MALFORMED_CODE))
    finally:
        if comments:
            return Analysis.require(comments).dump(output_file)

    # AST - if an AST can't be made, fail and bail
    try:
        tree = ast.parse(user_solution)
    except Exception:
        # If ast.parse fails, assume malformed code and fail with an ESSENTIAL (required) type comment for the student
        comments.append(
            Comment(type=CommentTypes.ESSENTIAL,
                    params={},
                    comment=Comments.MALFORMED_CODE))
    finally:
        if comments:
            return Analysis.require(comments).dump(output_file)

    # Does the solution have a method called two_fer?
    has_method = False

    # Does the solution correctly use a default argument?
    uses_def_arg = False

    # Does the solution have a return value?
    has_return = False

    # Does the solution use str.format?
    uses_format = False

    # Does the solution use f-strings?
    uses_f_string = False

    for node in ast.walk(tree):

        # Check for method called two_fer
        if isinstance(node, ast.FunctionDef):
            has_method = node.name == "two_fer"

        # Check for the use of string concatenation with + operator
        elif isinstance(node,
                        ast.Add) and Comments.SIMPLE_CONCAT not in comments:
            comments.append(
                Comment(type=CommentTypes.ACTIONABLE,
                        params={},
                        comment=Comments.SIMPLE_CONCAT))

        # Check for use of default arguments
        elif isinstance(node, ast.arguments):
            if node.defaults:
                uses_def_arg = True
                # Check if the default argument use is correct
                try:
                    if (node.defaults[0].s != "you"
                            and Comments.WRONG_DEF_ARG not in comments):
                        comments.append(
                            Comment(type=CommentTypes.ESSENTIAL,
                                    params={},
                                    comment=Comments.WRONG_DEF_ARG))
                except Exception:
                    if Comments.WRONG_DEF_ARG not in comments:
                        comments.append(
                            Comment(type=CommentTypes.ESSENTIAL,
                                    params={},
                                    comment=Comments.WRONG_DEF_ARG))

        # Check for use of unnecessary conditionals
        elif isinstance(node,
                        ast.If) and Comments.CONDITIONALS not in comments:
            comments.append(
                Comment(type=CommentTypes.ACTIONABLE,
                        params={},
                        comment=Comments.CONDITIONALS))

        # Check for use of %-formatting
        elif isinstance(
                node, ast.Mod) and Comments.PERCENT_FORMATTING not in comments:
            comments.append(
                Comment(type=CommentTypes.ACTIONABLE,
                        params={},
                        comment=Comments.PERCENT_FORMATTING))

        # Check for a return statement
        elif isinstance(node, ast.Return):
            has_return = True

        # Search for use of str.format
        elif isinstance(node, ast.Call):
            try:
                uses_format = node.func.attr == "format"
            except Exception:
                pass

        # Search for use of f-strings
        try:
            if isinstance(node, ast.FormattedValue):
                uses_f_string = True
        except AttributeError:
            pass  # Fail if python version is too low

    if not has_method:
        comments.append(
            Comment(type=CommentTypes.ESSENTIAL,
                    params={},
                    comment=Comments.NO_METHOD))

    if not uses_def_arg:
        comments.append(
            Comment(type=CommentTypes.ESSENTIAL,
                    params={},
                    comment=Comments.NO_DEF_ARG))

    if not has_return:
        comments.append(
            Comment(type=CommentTypes.ESSENTIAL,
                    params={},
                    comment=Comments.NO_RETURN))

    # Generate PyLint comments for additional feedback.
    comments.extend(generate_pylint_comments(in_path))

    # Process all comments and write out feedback.
    if uses_format or uses_f_string:
        return Analysis.summarize_comments(comments, output_file, ideal=True)
    else:
        return Analysis.summarize_comments(comments, output_file)
Beispiel #4
0
def analyze(path: Path):
    """
    Analyze the user's Two Fer solution to give feedback and disapprove malformed solutions. Outputs a JSON that
    conforms to Exercism's Auto-Mentor project interface.

    :return: A tuple containing a list of feedback comments as its first entry, a bool indicating whether a
        solution should be approved as its second entry, a list of comments generated by Pylint as its third entry,
        and a 'status' string corresponding to the value of the status key in the generated JSON, as its fourth
        entry.
    """
    output_file = path.parent.joinpath("analysis.json")

    # Input file
    try:
        user_solution = path.read_text()
    except OSError as err:
        # If the proper file cannot be found, disapprove this solution
        return Analysis.disapprove([Comments.NO_MODULE]).dump(output_file)

    try:
        # Parse file to abstract syntax tree
        tree = ast.parse(user_solution)
    except Exception:
        # If ast.parse fails, the code is malformed and this solution is disapproved
        return Analysis.disapprove([Comments.MALFORMED_CODE]).dump(output_file)

    # List of comments to return at end, each comment is a string
    comments = []

    # Whether user's solution is considered approvable based on analysis. Note that this only denotes if it's POSSIBLE for the
    # user's solution to be approved; just because the user didn't submit something that automatically makes it get
    # disapproved, like an empty file or missing method header, doesn't mean it's actually correct. Final assessment
    # of the user's solution must be done by a mentor (unless the solution is one of the optimal solutions we check for).
    approvable = True
    # Does the solution have a method called two_fer?
    has_method = False
    # Does the solution correctly use a default argument?
    uses_def_arg = False
    # Does the solution have a return value?
    has_return = False
    # Does the solution use str.format?
    uses_format = False
    # Does the solution use f-strings?
    uses_f_string = False

    for node in ast.walk(tree):

        # Search for method called two_fer
        if isinstance(node, ast.FunctionDef):
            has_method = node.name == "two_fer"

        # Search for use of string concatenation with + operator
        elif isinstance(node,
                        ast.Add) and Comments.SIMPLE_CONCAT not in comments:
            comments.append(Comments.SIMPLE_CONCAT)

        # Search for use of default arguments
        elif isinstance(node, ast.arguments):
            if node.defaults:
                uses_def_arg = True
                # Search for use of incorrect default argument
                try:
                    if (node.defaults[0].s != "you"
                            and Comments.WRONG_DEF_ARG not in comments):
                        comments.append(Comments.WRONG_DEF_ARG)
                except Exception:
                    if Comments.WRONG_DEF_ARG not in comments:
                        comments.append(Comments.WRONG_DEF_ARG)

        # Search for use of unnecessary conditionals
        elif isinstance(node,
                        ast.If) and Comments.CONDITIONALS not in comments:
            comments.append(Comments.CONDITIONALS)

        # Search for use of %-formatting
        elif isinstance(
                node, ast.Mod) and Comments.PERCENT_FORMATTING not in comments:
            comments.append(Comments.PERCENT_FORMATTING)

        # Search for return
        elif isinstance(node, ast.Return):
            has_return = True

        # Search for use of str.format
        elif isinstance(node, ast.Call):
            try:
                uses_format = node.func.attr == "format"
            except Exception:
                pass

        # Search for use of f-strings
        try:
            if isinstance(node, ast.FormattedValue):
                uses_f_string = True
        except AttributeError:
            pass  # Fail if python version is too low

    if not has_method:
        comments.append(Comments.NO_METHOD)
        approvable = False

    if not uses_def_arg:
        comments.append(Comments.NO_DEF_ARG)

    if not has_return:
        comments.append(Comments.NO_RETURN)
        approvable = False

    # Use Pylint to generate comments for code, e.g. if code follows PEP8 Style Convention
    pylint_stdout, _ = lint.py_run(str(path), return_std=True)
    pylint_comments = [pylint_stdout.getvalue()]

    # Handle a known optimal solution
    if approvable and (not comments) and (uses_format or uses_f_string):
        return Analysis.approve(comments, pylint_comments).dump(output_file)

    # Handle a known inadequate solution
    if not approvable:
        return Analysis.disapprove(comments, pylint_comments).dump(output_file)

    # In all other cases refer to the Mentor
    return Analysis.refer_to_mentor(comments,
                                    pylint_comments,
                                    approvable=approvable).dump(output_file)