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)
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
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)
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)