Skip to content

♻️ refactor(infra): drop unmaintained aioboto3 for aiobotocore#426

Merged
sodre merged 13 commits into
mainfrom
refactor/aiobotocore-migration
Jun 23, 2026
Merged

♻️ refactor(infra): drop unmaintained aioboto3 for aiobotocore#426
sodre merged 13 commits into
mainfrom
refactor/aiobotocore-migration

Conversation

@sodre

@sodre sodre commented Jun 22, 2026

Copy link
Copy Markdown
Member

Summary

Replaces the unmaintained aioboto3 with aiobotocore for all async AWS clients, with zero impact on the generated sync code.

  • Migrate async DynamoDB/CFN/Lambda/STS client construction from aioboto3.Session().client(...) to aiobotocore.session.get_session().create_client(...) in repository.py, infra/stack_manager.py, and infra/discovery.py.
  • Teach scripts/generate_sync.py to map the aiobotocore constructs back to boto3 so the generated sync_*.py files remain byte-identical (no churn in generated sync code).
  • Remove aioboto3 from dependencies, mypy overrides, and the sync transformer.

Design and plan:

  • docs/plans/2026-06-22-aiobotocore-migration-design.md
  • docs/plans/2026-06-22-aiobotocore-migration-plan.md

Test plan

All run locally and passing:

  • Unit suite: 2615 passed
  • mypy: clean
  • pre-commit: all hooks pass
  • generate-sync idempotent: zero drift in generated sync_*.py
  • Patch coverage: 100% on changed lines
  • aioboto3 uninstalled from env (import fails as expected)
  • LocalStack integration: 96 passed
  • e2e LocalStack: 18 passed / 1 skipped

Known caveat (environmental, unrelated)

3 tests/integration/test_lambda_builder.py::TestLambdaInDocker tests fail on the local ARM64 host because they pull the amd64 public.ecr.aws/lambda/python:3.12 image (exec format error). This is environmental and not caused by this change — they fail identically on main, and CI runs on amd64.

Closes #425

🤖 Generated with Claude Code

sodre and others added 12 commits June 22, 2026 14:43
Capture the approved design for dropping the unmaintained aioboto3
dependency in favor of calling aiobotocore directly. The async data path
uses only the low-level client API, so the change is a near-mechanical
session/client swap plus updates to the sync-code transformer and test
patch targets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record the project convention that superpowers brainstorming specs and
implementation plans live under docs/plans/, overriding the skill default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Task-by-task plan: add aiobotocore, teach the sync transformer (additive
rules), migrate repository/stack_manager/discovery async clients +
tests, drop aioboto3, and verify on LocalStack.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First step of the aioboto3 → aiobotocore migration. Both libraries
coexist until all async call sites are moved over.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Additive rules: from aiobotocore.session import → import boto3,
get_session() → boto3.Session(), AioSession → boto3.Session,
create_client → client, and the matching async-with unwrap plus test
patch-target rewrite. No-ops until async source adopts aiobotocore, so
regeneration produces zero drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use aiobotocore.session.get_session().create_client(...) instead of
aioboto3.Session().client(...). Generated sync_repository.py is
unchanged (transformer maps it back to boto3).

Update test mock from session.client() to session.create_client()
to match the new aiobotocore API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate StackManager off aioboto3 to aiobotocore get_session()/
create_client(); update async tests to patch get_session and wire
create_client mocks. Generated sync code is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate InfrastructureDiscovery off aioboto3; update the three
_get_client tests to patch get_session and wire create_client mocks.
Generated sync code is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the aioboto3 runtime dep, mypy override, and transformer rule now
that all async clients use aiobotocore. Update Lambda zip-content tests
to assert aiobotocore is excluded, and refresh stale comments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test_discovery.py mocked session.client, but discovery.py now calls
session.create_client after the aiobotocore migration. Rewire the
tagging-API mocks/assertions to create_client and regenerate the sync
test. Fixes 4 TestDiscoverViaTaggingAPI failures missed because the
Task 5 test command omitted test_discovery.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address final-review minors: note the test patch-target rewrite loops
assume non-overlapping domains, mention create_client in the
visit_AsyncWith docstring, and correct the capacity-counter comment to
boto3 (the fixture wraps the sync client).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The migration changed the _get_caller_identity_arn session-creation line
(self._session = get_session()), but the existing test pre-set _session,
leaving that branch uncovered and failing the 100% patch-coverage gate.
Add a success-path test that forces _session=None so the branch runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sodre sodre added this to the v1.0.0 milestone Jun 22, 2026
@sodre sodre added the area/infra CloudFormation, IAM, infrastructure label Jun 22, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 3a96f60 Previous: 1277a70 Ratio
tests/benchmark/test_localstack.py::TestLocalStackBenchmarks::test_acquire_release_localstack 12.822211500517165 iter/sec (stddev: 0.10358861514783008) 28.261398663363888 iter/sec (stddev: 0.007473620253362297) 2.20
tests/benchmark/test_localstack.py::TestLocalStackBenchmarks::test_cascade_localstack 3.9397276386228235 iter/sec (stddev: 0.255987008601226) 17.94619119402238 iter/sec (stddev: 0.010913351939176376) 4.56
tests/benchmark/test_localstack.py::TestLocalStackLatencyBenchmarks::test_acquire_realistic_latency 23.253224567580258 iter/sec (stddev: 0.05703670001169005) 41.61139237175817 iter/sec (stddev: 0.004395338221300227) 1.79
tests/benchmark/test_localstack.py::TestLocalStackLatencyBenchmarks::test_acquire_two_limits_realistic_latency 12.842194758926851 iter/sec (stddev: 0.12693271365570236) 37.478937530469864 iter/sec (stddev: 0.004750277911597605) 2.92
tests/benchmark/test_localstack.py::TestLocalStackLatencyBenchmarks::test_cascade_realistic_latency 11.843236358663896 iter/sec (stddev: 0.15212791175222667) 21.629694817525973 iter/sec (stddev: 0.00851805482734921) 1.83
tests/benchmark/test_localstack.py::TestCascadeOptimizationBenchmarks::test_cascade_with_batchgetitem_optimization 7.8453775451130845 iter/sec (stddev: 0.16373801897267368) 27.53182362600158 iter/sec (stddev: 0.004956432041025181) 3.51
tests/benchmark/test_localstack.py::TestCascadeOptimizationBenchmarks::test_cascade_multiple_resources 14.599476474755367 iter/sec (stddev: 0.06253387443140371) 29.3784534843057 iter/sec (stddev: 0.004507321197810405) 2.01
tests/benchmark/test_localstack.py::TestCascadeOptimizationBenchmarks::test_cascade_with_config_cache_optimization 9.614348281085356 iter/sec (stddev: 0.10609934223597903) 25.953841727493185 iter/sec (stddev: 0.004858324504510212) 2.70
tests/benchmark/test_localstack.py::TestLocalStackOptimizationComparison::test_cascade_cache_disabled_localstack 4.174262563178421 iter/sec (stddev: 0.1667903270639639) 26.95233043122925 iter/sec (stddev: 0.006675805767489581) 6.46
tests/benchmark/test_localstack.py::TestLocalStackOptimizationComparison::test_cascade_cache_enabled_localstack 8.772756464472884 iter/sec (stddev: 0.11675590823437959) 28.427387330726027 iter/sec (stddev: 0.006130653965032979) 3.24
tests/benchmark/test_localstack.py::TestLocalStackCascadeSpeculativeComparison::test_cascade_speculative_cache_cold_localstack 6.075944462032801 iter/sec (stddev: 0.20151836030402526) 25.351326881841022 iter/sec (stddev: 0.009117454290139316) 4.17
tests/benchmark/test_localstack.py::TestLocalStackCascadeSpeculativeComparison::test_cascade_speculative_cache_warm_localstack 9.363210158119676 iter/sec (stddev: 0.1553677018193417) 33.01986143608592 iter/sec (stddev: 0.0031760279928269002) 3.53
tests/benchmark/test_localstack.py::TestLambdaColdStartBenchmarks::test_lambda_cold_start_multiple_concurrent_events 0.6064289832208789 iter/sec (stddev: 0.5454170171089536) 0.9484260225510546 iter/sec (stddev: 0.004361756402117692) 1.56

This comment was automatically generated by workflow using github-action-benchmark.

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.39%. Comparing base (1277a70) to head (3a96f60).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #426      +/-   ##
==========================================
+ Coverage   92.38%   92.39%   +0.01%     
==========================================
  Files          37       37              
  Lines        7854     7854              
==========================================
+ Hits         7256     7257       +1     
+ Misses        598      597       -1     
Flag Coverage Δ
doctest 29.14% <63.63%> (ø)
e2e 42.36% <72.72%> (ø)
integration 50.76% <72.72%> (ø)
unit 92.19% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

The migration helper example in namespace-keys.md still did
`import aioboto3` / `session.client(...)`, which broke the doctest run
(`No module named 'aioboto3'`) after aioboto3 was removed. Swap it to
`aiobotocore.session.get_session()` / `create_client(...)`, mirroring the
production change. Other aioboto3 mentions in docs/ are historical ADR/
plan artifacts (not executed) and are intentionally left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sodre sodre marked this pull request as ready for review June 23, 2026 18:43
@sodre sodre merged commit 4f7cd02 into main Jun 23, 2026
25 checks passed
@sodre sodre deleted the refactor/aiobotocore-migration branch June 23, 2026 19:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/infra CloudFormation, IAM, infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

♻️ Drop unmaintained aioboto3 in favor of aiobotocore

1 participant