Edit this page Backlinks This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== Code Quality check ====== The project will be evaluated for code quality using a set of automated tools, but additional inspection may be done during the presentation by your TA. The code quality features we will be testing can be divided in two categories: bad practices and improvement suggestions. ===== Error-prone practices ===== This category encapsulates code which is very vulnerable to errors, even if, in the case of your submission, the code behaves as expected. <note important> The presence of too may of these will lead to your submission being penalised with up to 0.1 points per stage. (You will still be able to obtain the rest of 0.9 point on functionality alone). </note> The following are the types of errors which WILL be flagged from this category: ==== Using a variable before its definition ==== This covers all cases of accessing a variable before a value is assigned to it for the first time. Due to the lack of a compile-time type check, such errors may slip in undetected in the code. <hidden > <code python example.py> x = a + 1 # a is not yet defined a = x + 1 class A: def __init__(self, rarely_used_parameter=False): if rarely_used_parameter: self.m += 1 # the member 'm' is not yet initialised, but if the testing happens to never set the 'rarely_used_parameter' to True, this error may go undetected self.m = 0 def inc(self): self.m += self.n # A does not have a member named 'n'. </code> </hidden> ==== Import, variable, member or method redefinitions and shadow-ing ==== This covers cases where an already-defined object is redefined in an erronous way: <hidden import and variable shadowing and redefinitions> <code python> import re as regex matches = set() def is_digits(input_string): regex = '(0|1|2|3|4|5|6|7|8|9)*' # the 'regex' variable defined here 'shadows' or hides the name of the module re match = regex.fullmatch(regex, input_string) # this should thow an error, but if the 'regex' variable happened to thave the fullmatch method, this could slip in undetected if match is not None: matches = matches.union({match}) # this does NOT update the global variable return True return False def process_matches(matches): # the parameter name shadows the global variable for m in matches: m = get_some_value() # this redefines the loop variable ... </code> </hidden> <hidden function or method refefinitions and shadowing> <code python> def f(): print(1) def g(): x = 2 def f(): # this shadows the global function 'f' print(x) f() def f(): # this is an error print(3) class A: def g(self): print(6) def __init__(self): self.g = 5 # this attribute hides the method g def f(self): # this is ok, as it is a method so it will never be confused with the outer 'f' print(4) def f(self): print(5) # this is an error </code> </hidden> ==== Import errors ==== The imports should be placed at module-level, at the beggining of the file (not inside function or class definitions or within control blocks), should ideally import either the module as an object (optionally renamed) or only the required objects from that module, should not cause import cycles, and should not contain additional errors <hidden possible types of errors> <code python incorrect_imports.py> import nonexistent_module # module does not exist, remove this or replace with correct module from time import * # only import what is needed. for example, 'form time import perf_counter' form typing import Generic # unused import from re import DFA # no object called 'DFA' exists in re from numpy import * # if you use many different things from a module, consider importing the module (qualified import): 'import numpy' or 'import numpy as np' import pandas as pandas # useless renaming using 'as' import cyclic ... </code> <code python cyclic.py> import incorrect_imports # this will cause a cyclic import. python knows how to handle this most of the time, but it WILL cause some errors in certain situations </code> </hidden> ==== Global variables ==== While global variables may not cause issues in isolated cases, when producing code which is meant to be used by other codebases, like the case of our project, the use of global variables may cause issues in multithreaded or multiprocess applications. As such, the use of such variables is strongly discouraged. Exceptions to these cases are global constant definitions and type variables and aliases. <hidden acceptable uses> <code python> PI = 3.1416 # constants are a good use of global variables T = typeVar('T') # typeVars will almost always need to be global def GenericClass(Generic[T]): pass </code> </hidden> <hidden error-prone uses> <code python> global_stack = [] def exported_function(param): global global_stack global_stack = [] fill_global_stack_with_possible_solutions(param) for sol in global_stack: check_solution(sol, param) # if exported_function is called by 2 or more concurrent threads, they may interfere with each other, and there is a strong possibility that it will be called like that </code> </hidden>