♻️ refactor(infra): drop unmaintained aioboto3 for aiobotocore#426
Merged
Conversation
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>
Contributor
There was a problem hiding this comment.
⚠️ 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 Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the unmaintained
aioboto3withaiobotocorefor all async AWS clients, with zero impact on the generated sync code.aioboto3.Session().client(...)toaiobotocore.session.get_session().create_client(...)inrepository.py,infra/stack_manager.py, andinfra/discovery.py.scripts/generate_sync.pyto map theaiobotocoreconstructs back toboto3so the generatedsync_*.pyfiles remain byte-identical (no churn in generated sync code).aioboto3from dependencies, mypy overrides, and the sync transformer.Design and plan:
docs/plans/2026-06-22-aiobotocore-migration-design.mddocs/plans/2026-06-22-aiobotocore-migration-plan.mdTest plan
All run locally and passing:
mypy: cleanpre-commit: all hooks passgenerate-syncidempotent: zero drift in generatedsync_*.pyaioboto3uninstalled from env (import fails as expected)Known caveat (environmental, unrelated)
3
tests/integration/test_lambda_builder.py::TestLambdaInDockertests fail on the local ARM64 host because they pull the amd64public.ecr.aws/lambda/python:3.12image (exec format error). This is environmental and not caused by this change — they fail identically onmain, and CI runs on amd64.Closes #425
🤖 Generated with Claude Code