The riskiest code in boto3 looks like debt rather than active churn: all 42 high-band functions out of 348 are in the debt quadrant, and none are in the fire quadrant. The data has no touch count or days-since-last-change figures for the top five, so I can’t say how long they have sat untouched. Each file has only a single commit on record, though, and that is a shape I watch for: complex code that the next developer will meet with little change history to lean on. I would start with resource in boto3/session.py (an activity-weighted risk score of 8.91, fan-out of 15), then work through the resource model and parameter-building code.
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 |
|---|---|---|---|---|---|
resource | boto3/session.py | 8.9 | 6 | 2 | 15 |
get_resource_public_actions | boto3/docs/utils.py | 8.9 | 6 | 5 | 4 |
_get_related_resources | boto3/resources/model.py | 8.8 | 10 | 3 | 5 |
build_param_structure | boto3/resources/params.py | 8.8 | 12 | 4 | 8 |
_get_has_definition | boto3/resources/model.py | 8.7 | 7 | 4 | 7 |
348 functions analyzed
Calls an unusually large number of distinct functions (high fan-out), making it the structural centre of gravity for a subsystem.Long Function×1Long 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.Complex Branching×1Complex Branching
High cyclomatic complexity — many independent execution paths, each a potential bug surface and required test case.
This result has an unusual shape. The scores are tightly clustered, between 8.70 and 8.91 across the top five, so the ranking is a soft ordering, not a cliff. None of these functions are extreme by raw complexity: the highest cyclomatic complexity is 12. What puts them on top is the combination of branching, nesting, and fan-out, in code that sits on the path every boto3 user takes. All five have a single commit recorded against their files and no bug-linked commits, reverts, or review-comment activity, so I read this as maintainability debt, not a defect signal. The data doesn’t say these functions are broken, and I’m not claiming they are.
resource — session.py
This method creates a service resource by name, and it is where I would start. Cyclomatic complexity is only 6 and nesting depth only 2, so the control flow is simple. The problem is fan-out: it calls 15 distinct functions, the widest coupling of anything in the top five. The signature takes the service name plus ten optional parameters (region, API version, SSL settings, endpoint URL, three credential fields, and a config object), and the excerpt shows a docstring far longer than the logic. The long-function and god-function flags here come from parameter handling and coordination, not branching.
In Python, with duck typing and runtime dispatch, a fan-out of 15 likely understates the real coupling, because the types behind those calls are resolved at runtime. My recommendation: extract the credential and client-config handling into a helper that returns a prepared set of arguments, so resource reads as a short orchestration. That would cut the fan-out and make each piece testable without constructing a full session.
get_resource_public_actions — utils.py
This one is the opposite profile: low fan-out of 4, cyclomatic complexity of 6, but nesting depth of 5. The excerpt shows why. It filters the members of a resource class through a chain of conditions (not underscore-prefixed, not capitalized, not a wait-until method, and finally an is-resource-action check), each nested inside the previous. Four sequential tests that must all pass don’t need four levels of indentation, so nesting is where I would start.
This is the cheapest fix in the list. Flatten it with guard clauses, or fold the name checks into a single predicate, and nesting drops from 5 to roughly 2 with no change in behavior. Because it lives in the docs utilities, I would expect the impact to fall mainly on documentation generation.
_get_related_resources — resources/model.py
Cyclomatic complexity of 10 is the moderate line, and this function sits right on it. Per the excerpt, a boolean switches between returning sub-resources and returning references; the function loops over the model’s relationship definitions, then runs an inner loop over identifiers to decide whether the resource requires data. That boolean flag is the design smell: one function doing two jobs, with the selection logic repeated at the end as two mirrored conditions.
I would split out one helper that determines whether a relationship requires data, and let the subresources and references properties each filter on the result. That removes the flag parameter and the mirrored branches, and each caller reads as one line of intent.
build_param_structure — resources/params.py
This has the highest cyclomatic complexity in the group at 12, with nesting depth of 4 and fan-out of 8. The docstring calls it a reverse JMESPath implementation: it turns a path-like string into a nested structure by walking down the parts, uses a regular expression to detect list indexing, and mutates the params in place. The excerpt shows the branching: wildcard indexes, explicit indexes, append-style indexes, list creation, padding with empty dicts, and a last-item check repeated in both the list and dict branches.
The complex-branching flag is earned. With in-place mutation and a moving position pointer, a bug here would be quiet and path-dependent, so every branch is a required test case. I would extract the index parsing into its own function, so the main loop only decides between list and dict, and then write tests per path shape (plain key, wildcard, explicit index, append) before changing anything else.
_get_has_definition — resources/model.py
The second function from model.py has cyclomatic complexity of 7, nesting depth of 4, and fan-out of 7. Its docstring and excerpt say the service resource gets special treatment: it synthesizes a relationship to every defined resource so calls like s3.Object('bucket-name', 'key') work even though the JSON doesn’t declare them. The code loops over resource definitions, loops again over the declared relationships to find renamed or aliased matches, and builds a fallback definition when none match. A loop inside a loop with a conditional on the inside explains the nesting.
Together with _get_related_resources, this gives resources/model.py two of the five slots, and the two are coupled: _get_related_resources consumes the output of _get_has_definition. I would pull the fallback-definition construction into its own function and refactor the pair as a unit, since changing the shape of one affects the other.
What I would do with this list
The scores are close enough that grouping matters more than order. The two model.py functions and build_param_structure form the resource-definition path, and I would review them together. get_resource_public_actions is the quick win. resource has the most coupling, so it deserves the most careful test coverage before it is split. Nothing here is on fire, which is the useful part: this is the time to do the work, while no one is mid-change in these functions.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
god_function | 1 |
long_function | 1 |
deeply_nested | 1 |
complex_branching | 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, god_function, long_function.
Reproduce This Analysis
git clone https://github.com/boto/boto3
cd boto3
git checkout 3557491c6c13cc69596d5391f77b7febef579065
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 →