The function main in locust/main.py has a cyclomatic complexity of 89. The fifth-ranked function, setup_opentelemetry, scores 12. That 77-point gap makes main a different category of problem from everything else on the list. It sits in the fire quadrant with an activity-weighted risk score of 18.19, so it is both structurally extreme and still changing (6 days since last change). Across the 864 functions I analyzed in locust at commit 66279c9, 28 are in the critical band, and I would start with main before anything else.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
main | locust/main.py | 18.2 | 89 | 7 | 110 |
__init__ | locust/web.py | 16.8 | 25 | 4 | 93 |
stop_users | locust/runners.py | 14.4 | 18 | 4 | 19 |
_get_section_groups | docs/_ext/llms_txt.py | 13.1 | 18 | 4 | 11 |
setup_opentelemetry | locust/opentelemetry.py | 12.5 | 12 | 2 | 27 |
864 functions analyzed
High cyclomatic complexity — many independent execution paths, each a potential bug surface and required test case.Exit Heavy×5Exit Heavy
Multiple return or throw paths dispersed through the body — each exit needs separate test coverage.God Function×4God Function
Calls an unusually large number of distinct functions (high fan-out), making it the structural centre of gravity for a subsystem.Long Function×4Long Function
Function body is too long to review in a single pass; likely contains multiple distinct responsibilities.Deeply Nested×1Deeply Nested
Control structures nested 4+ levels deep, making it hard to reason about the full execution state at inner branches.
The distribution is worth reading before the individual functions. Of 864 functions, 23 are in the fire quadrant (complex and recently changed) and 95 are in the debt quadrant (complex but quiet). Four of my top five are fire (main, __init__, stop_users, and setup_opentelemetry) and one is debt (_get_section_groups). Most of the risk is concentrated in the startup and orchestration path: locust/main.py, locust/web.py, locust/runners.py, and locust/opentelemetry.py account for four of the five entries.
main — main.py
I would start with main because it combines CC 89, nesting depth 7, and fan-out of 110 with an activity-weighted risk score of 18.19. That CC means roughly 89 independent paths that each need a test case to cover properly. From the source excerpt, it handles locustfile discovery, argument parsing, option validation, logging setup, OpenTelemetry setup, and a multi-process fork path that adjusts options for child workers. Those are separable concerns living in one function body. The excerpt also shows long chains of option checks that each end in sys.exit(1), which is the exit-heavy pattern: every early exit is another path to test.
The history supports prioritizing it. The file has 6 bug-linked commits out of 12 total, a bug-fix rate of 58%, and 3 distinct authors in the last 90 days, with a review-comment density of 9.5 — the highest in my top five. That is file-level context, not proof that main itself is defective. The function was touched 2 times in the last year and last changed 6 days ago, so it is actively changing, not dormant.
My recommendation is extract-method, along the seams the code already shows: one function to validate option combinations (the --autoquit, --processes, --master checks), one to handle the fork-and-configure-children logic, and one for logging and telemetry setup. Pulling out just the option validation would remove a large share of the branches and make each check unit-testable without launching a process.
__init__ — web.py
The WebUI constructor has a fan-out of 93, the second highest on the list, with CC 25 and nesting depth 4. It was touched 5 times in the last year, the most of any function in my top five, and last changed 3 days ago, which makes it the most frequently edited hotspot. In Python, a fan-out this high usually understates the coupling, since types resolve at runtime. The excerpt shows the constructor storing configuration, building a Flask app, enabling CORS, setting up login management, deciding whether to start the server, and then defining error handlers and routes as nested functions inside the constructor body. That makes it a god function and a long function: construction, configuration, and route registration are tangled together.
The file has 1 bug-linked commit out of 11 (a bug-fix rate of 45%) and 7 distinct authors in the last 90 days. Those author counts are file-level, but together with the 5 touches they suggest this constructor sees frequent change. I would move route and error-handler registration into separate methods or a dedicated blueprint-builder, leaving __init__ to assign state. Tests could then register routes without constructing a full server.
stop_users — runners.py
stop_users has CC 18 and a modest fan-out of 19, so its risk comes from branching rather than coupling. It was touched once in the last year and changed 5 days ago. The excerpt shows nested loops that pick greenlets to stop per user class, then three different stop strategies depending on whether the user is the current greenlet, whether a stop timeout is configured, and whether the user is already stopping. There is also a while True loop with a break and an error path for greenlets with unexpected arguments. The multiple exits and the gevent timing logic make this hard to test deterministically.
This function carries the strongest historical signal in the list. The file shows 4 bug-linked commits out of 12, a bug-fix rate of 67%, and 7 distinct authors in the last 90 days. Again, that is file-level history covering all of runners.py, but combined with the complexity it justifies stronger review. I would split selection (which users to stop) from execution (how to stop them), so the three stop strategies can be tested without constructing greenlets for the selection logic.
_get_section_groups — llms_txt.py
This is the only debt-quadrant function in my top five, and it is a documentation extension rather than runtime code. It has CC 18, nesting depth 4, and fan-out of 11, with 0 touches in the last year and 113 days since last change. It walks a Sphinx doctree to build section groups for an llms.txt index, nesting loops over child sections, toctree nodes, and entries. It is structural debt with a contained blast radius: the file has 3 commits total, no bug-linked commits, and 1 distinct author in the last 90 days. I would treat it as maintainability debt, not a regression risk. Next time someone touches the docs build, extracting the toctree-collection step into a helper would cut a nesting level and make the traversal easier to follow.
setup_opentelemetry — opentelemetry.py
setup_opentelemetry has the lowest CC of the five at 12 and shallow nesting of 2, but fan-out of 27 and 4 touches in the last year, with its last change 10 days ago. The source shows it parsing exporter environment variables for traces, metrics, and logs, building a resource, and wiring providers, and it defines event listeners inline (on_request, on_locust_init) inside the function body. That is the god-function and long-function pattern: setup, configuration parsing, and listener definitions all in one place.
The historical signal here is the weakest of the group. The file has no bug-linked commits out of 13 and a bug-fix rate of 15%, with 4 distinct authors in the last 90 days. I read this as an actively iterated feature that is growing, not one with a defect history. The remaining work is moving the inline listeners out of setup_opentelemetry, and I would start there.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
complex_branching | 8 |
exit_heavy | 5 |
god_function | 4 |
long_function | 4 |
deeply_nested | 1 |
These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
See more analyses with these patterns: complex_branching, deeply_nested, exit_heavy, god_function, long_function.
Reproduce This Analysis
git clone https://github.com/locustio/locust
cd locust
git checkout 66279c936b4b69a8a7df3ac3b11f7e47d20780de
hotspots analyze . --mode snapshot --explain-patterns --force
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
I use Hotspots to highlight structural and activity risk — not “bad code.” I treat these findings as a prioritization aid, not a bug predictor. Editorial policy →