Determine functions nesting levels
"""
Determine the nesting level of each function in the input text by analyzing
indentation.
Example:
Given this file as input, the expected output is:
Nesting levels for functions:
Levels Function
------ -------------------------------------
1 main
2 scan
4 measure_nesting
2 print_report
"""
import alex
OPERATORS = (
("PLUS", "+"),
("MINUS", "-"),
("MUL", "*"),
("DIV", "/"),
("DOT", "."),
("COMMA", ","),
("COLON", ":"),
("SEMI", ";"),
("AT", "@"),
("MOD", "%"),
("EQ", "="),
("GT", ">"),
("LT", "<"),
("LP", "("),
("RP", ")"),
("LBR", "["),
("RBR", "]"),
("LCBR", "{"),
("RCBR", "}"),
("OR", "|"),
("XOR", "^"),
("NOT", "~"),
("AND", "&"),
("ADDEQ", "+="),
("SUBEQ", "-="),
("MULEQ", "*="),
("DIVEQ", "/="),
("IDIVEQ", "//="),
("MODEQ", "%="),
("LSHIFT", "<<"),
("RSHIFT", ">>"),
("IDIV", "//"),
("EXP", "**"),
("GE", ">="),
("LE", "<="),
("TYPE", "->"),
("NEQ", "!="),
("EQEQ", "=="),
("OREQ", "|="),
("XOREQ", "^="),
("ANDEQ", "&="),
("WALRUS", ":="),
("EXPEQ", "**="),
("LSHIFTEQ", "<<="),
("RSHIFTEQ", ">>="),
)
REGEXPS = (
("TSTR", r'^f?"""(?:\\.|(?!""").)*?"""|^f?\'\'\'(?:\\.|(?!\'\'\').)*?\'\'\''),
("STR", r'^f?"(?:\\.|[^"\\])*"|^f?\'(?:\\.|[^\'\\])*\''),
("NUM", '^["0123456789"]*'),
("REM", "^#[^\n]*"),
("ID", f"^[a-zA-Z_0-9]*"),
)
KEYWORDS = [
"False",
"None",
"True",
"and",
"as",
"assert",
"async",
"await",
"break",
"class",
"continue",
"def",
"del",
"elif",
"else",
"except",
"finally",
"for",
"from",
"global",
"if",
"import",
"in",
"is",
"lambda",
"nonlocal",
"not",
"or",
"pass",
"raise",
"return",
"try",
"while",
"with",
"yield",
]
class Const:
START_STATE = 0
IN_FUNCTION_DEF = 1
INDENT_COUNTING = 2
DEF = "def"
INDENT = "INDENT"
def main():
lexer = scan()
functions_nesting_levels = measure_nesting(lexer)
print_report(functions_nesting_levels)
def scan():
lexer = alex.Alex(
operators=OPERATORS,
regexps=REGEXPS,
keywords=KEYWORDS,
scan_python_indents=True,
)
lexer.scan_file("python_function_complexity.py")
return lexer
def measure_nesting(lexer):
functions_nesting_levels = {}
state = Const.START_STATE
current_function_name = None
for token in lexer.tokens:
if state == Const.START_STATE:
if token.lexeme == Const.DEF:
state = Const.IN_FUNCTION_DEF
elif state == Const.IN_FUNCTION_DEF:
current_function_name = token.lexeme
functions_nesting_levels[current_function_name] = set()
state = Const.INDENT_COUNTING
elif state == Const.INDENT_COUNTING:
if token.name == Const.INDENT:
functions_nesting_levels[current_function_name].add(token.lexeme)
elif token.lexeme == Const.DEF:
state = 1
return functions_nesting_levels
def print_report(nestings):
print("Nesting levels for functions:")
print("Levels Function")
print("------ -------------------------------------")
for key in nestings:
print(f"{len(nestings[key]):4} {key}")
if __name__ == "__main__":
main()