Metadata-Version: 2.3
Name: aiomoto
Version: 0.1.1
Summary: Moto-style AWS service mocks for aiobotocore/aioboto3
Keywords: aws,moto,aioboto3,aiobotocore,asyncio,testing,mocks
Author: Owen Lamont
Author-email: Owen Lamont <owenrlamont@gmail.com>
License: MIT License
         
         Copyright (c) 2025 Owen Lamont
         
         Permission is hereby granted, free of charge, to any person obtaining a copy
         of this software and associated documentation files (the "Software"), to deal
         in the Software without restriction, including without limitation the rights
         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         copies of the Software, and to permit persons to whom the Software is
         furnished to do so, subject to the following conditions:
         
         The above copyright notice and this permission notice shall be included in all
         copies or substantial portions of the Software.
         
         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         SOFTWARE.
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Testing
Requires-Dist: aiobotocore>=2.24.1,<=2.25.1
Requires-Dist: moto>=5.1.5,<=5.1.17
Requires-Dist: moto[acm]>=5.1.5,<=5.1.17 ; extra == 'acm'
Requires-Dist: moto[acmpca]>=5.1.5,<=5.1.17 ; extra == 'acmpca'
Requires-Dist: moto[all]>=5.1.5,<=5.1.17 ; extra == 'all'
Requires-Dist: moto[amp]>=5.1.5,<=5.1.17 ; extra == 'amp'
Requires-Dist: moto[apigateway]>=5.1.5,<=5.1.17 ; extra == 'apigateway'
Requires-Dist: moto[apigatewayv2]>=5.1.5,<=5.1.17 ; extra == 'apigatewayv2'
Requires-Dist: moto[applicationautoscaling]>=5.1.5,<=5.1.17 ; extra == 'applicationautoscaling'
Requires-Dist: moto[appsync]>=5.1.5,<=5.1.17 ; extra == 'appsync'
Requires-Dist: moto[athena]>=5.1.5,<=5.1.17 ; extra == 'athena'
Requires-Dist: moto[autoscaling]>=5.1.5,<=5.1.17 ; extra == 'autoscaling'
Requires-Dist: moto[awslambda]>=5.1.5,<=5.1.17 ; extra == 'awslambda'
Requires-Dist: moto[awslambda-simple]>=5.1.5,<=5.1.17 ; extra == 'awslambda-simple'
Requires-Dist: moto[backup]>=5.1.5,<=5.1.17 ; extra == 'backup'
Requires-Dist: moto[batch]>=5.1.5,<=5.1.17 ; extra == 'batch'
Requires-Dist: moto[batch-simple]>=5.1.5,<=5.1.17 ; extra == 'batch-simple'
Requires-Dist: moto[budgets]>=5.1.5,<=5.1.17 ; extra == 'budgets'
Requires-Dist: moto[ce]>=5.1.5,<=5.1.17 ; extra == 'ce'
Requires-Dist: moto[cloudformation]>=5.1.5,<=5.1.17 ; extra == 'cloudformation'
Requires-Dist: moto[cloudfront]>=5.1.5,<=5.1.17 ; extra == 'cloudfront'
Requires-Dist: moto[cloudtrail]>=5.1.5,<=5.1.17 ; extra == 'cloudtrail'
Requires-Dist: moto[cloudwatch]>=5.1.5,<=5.1.17 ; extra == 'cloudwatch'
Requires-Dist: moto[codebuild]>=5.1.5,<=5.1.17 ; extra == 'codebuild'
Requires-Dist: moto[codecommit]>=5.1.5,<=5.1.17 ; extra == 'codecommit'
Requires-Dist: moto[codepipeline]>=5.1.5,<=5.1.17 ; extra == 'codepipeline'
Requires-Dist: moto[cognitoidentity]>=5.1.5,<=5.1.17 ; extra == 'cognitoidentity'
Requires-Dist: moto[cognitoidp]>=5.1.5,<=5.1.17 ; extra == 'cognitoidp'
Requires-Dist: moto[comprehend]>=5.1.5,<=5.1.17 ; extra == 'comprehend'
Requires-Dist: moto[config]>=5.1.5,<=5.1.17 ; extra == 'config'
Requires-Dist: moto[databrew]>=5.1.5,<=5.1.17 ; extra == 'databrew'
Requires-Dist: moto[datapipeline]>=5.1.5,<=5.1.17 ; extra == 'datapipeline'
Requires-Dist: moto[datasync]>=5.1.5,<=5.1.17 ; extra == 'datasync'
Requires-Dist: moto[dax]>=5.1.5,<=5.1.17 ; extra == 'dax'
Requires-Dist: moto[dms]>=5.1.5,<=5.1.17 ; extra == 'dms'
Requires-Dist: moto[ds]>=5.1.5,<=5.1.17 ; extra == 'ds'
Requires-Dist: moto[dynamodb]>=5.1.5,<=5.1.17 ; extra == 'dynamodb'
Requires-Dist: moto[dynamodbstreams]>=5.1.5,<=5.1.17 ; extra == 'dynamodbstreams'
Requires-Dist: moto[ebs]>=5.1.5,<=5.1.17 ; extra == 'ebs'
Requires-Dist: moto[ec2]>=5.1.5,<=5.1.17 ; extra == 'ec2'
Requires-Dist: moto[ec2instanceconnect]>=5.1.5,<=5.1.17 ; extra == 'ec2instanceconnect'
Requires-Dist: moto[ecr]>=5.1.5,<=5.1.17 ; extra == 'ecr'
Requires-Dist: moto[ecs]>=5.1.5,<=5.1.17 ; extra == 'ecs'
Requires-Dist: moto[efs]>=5.1.5,<=5.1.17 ; extra == 'efs'
Requires-Dist: moto[eks]>=5.1.5,<=5.1.17 ; extra == 'eks'
Requires-Dist: moto[elasticache]>=5.1.5,<=5.1.17 ; extra == 'elasticache'
Requires-Dist: moto[elasticbeanstalk]>=5.1.5,<=5.1.17 ; extra == 'elasticbeanstalk'
Requires-Dist: moto[elastictranscoder]>=5.1.5,<=5.1.17 ; extra == 'elastictranscoder'
Requires-Dist: moto[elb]>=5.1.5,<=5.1.17 ; extra == 'elb'
Requires-Dist: moto[elbv2]>=5.1.5,<=5.1.17 ; extra == 'elbv2'
Requires-Dist: moto[emr]>=5.1.5,<=5.1.17 ; extra == 'emr'
Requires-Dist: moto[emrcontainers]>=5.1.5,<=5.1.17 ; extra == 'emrcontainers'
Requires-Dist: moto[emrserverless]>=5.1.5,<=5.1.17 ; extra == 'emrserverless'
Requires-Dist: moto[es]>=5.1.5,<=5.1.17 ; extra == 'es'
Requires-Dist: moto[events]>=5.1.5,<=5.1.17 ; extra == 'events'
Requires-Dist: moto[firehose]>=5.1.5,<=5.1.17 ; extra == 'firehose'
Requires-Dist: moto[forecast]>=5.1.5,<=5.1.17 ; extra == 'forecast'
Requires-Dist: moto[glacier]>=5.1.5,<=5.1.17 ; extra == 'glacier'
Requires-Dist: moto[glue]>=5.1.5,<=5.1.17 ; extra == 'glue'
Requires-Dist: moto[greengrass]>=5.1.5,<=5.1.17 ; extra == 'greengrass'
Requires-Dist: moto[guardduty]>=5.1.5,<=5.1.17 ; extra == 'guardduty'
Requires-Dist: moto[iam]>=5.1.5,<=5.1.17 ; extra == 'iam'
Requires-Dist: moto[inspector2]>=5.1.5,<=5.1.17 ; extra == 'inspector2'
Requires-Dist: moto[iot]>=5.1.5,<=5.1.17 ; extra == 'iot'
Requires-Dist: moto[iotdata]>=5.1.5,<=5.1.17 ; extra == 'iotdata'
Requires-Dist: moto[ivs]>=5.1.5,<=5.1.17 ; extra == 'ivs'
Requires-Dist: moto[kinesis]>=5.1.5,<=5.1.17 ; extra == 'kinesis'
Requires-Dist: moto[kinesisvideo]>=5.1.5,<=5.1.17 ; extra == 'kinesisvideo'
Requires-Dist: moto[kinesisvideoarchivedmedia]>=5.1.5,<=5.1.17 ; extra == 'kinesisvideoarchivedmedia'
Requires-Dist: moto[kms]>=5.1.5,<=5.1.17 ; extra == 'kms'
Requires-Dist: moto[logs]>=5.1.5,<=5.1.17 ; extra == 'logs'
Requires-Dist: moto[managedblockchain]>=5.1.5,<=5.1.17 ; extra == 'managedblockchain'
Requires-Dist: moto[mediaconnect]>=5.1.5,<=5.1.17 ; extra == 'mediaconnect'
Requires-Dist: moto[medialive]>=5.1.5,<=5.1.17 ; extra == 'medialive'
Requires-Dist: moto[mediapackage]>=5.1.5,<=5.1.17 ; extra == 'mediapackage'
Requires-Dist: moto[mediastore]>=5.1.5,<=5.1.17 ; extra == 'mediastore'
Requires-Dist: moto[mediastoredata]>=5.1.5,<=5.1.17 ; extra == 'mediastoredata'
Requires-Dist: moto[meteringmarketplace]>=5.1.5,<=5.1.17 ; extra == 'meteringmarketplace'
Requires-Dist: moto[mq]>=5.1.5,<=5.1.17 ; extra == 'mq'
Requires-Dist: moto[opsworks]>=5.1.5,<=5.1.17 ; extra == 'opsworks'
Requires-Dist: moto[organizations]>=5.1.5,<=5.1.17 ; extra == 'organizations'
Requires-Dist: moto[panorama]>=5.1.5,<=5.1.17 ; extra == 'panorama'
Requires-Dist: moto[personalize]>=5.1.5,<=5.1.17 ; extra == 'personalize'
Requires-Dist: moto[pinpoint]>=5.1.5,<=5.1.17 ; extra == 'pinpoint'
Requires-Dist: moto[polly]>=5.1.5,<=5.1.17 ; extra == 'polly'
Requires-Dist: moto[proxy]>=5.1.5,<=5.1.17 ; extra == 'proxy'
Requires-Dist: moto[quicksight]>=5.1.5,<=5.1.17 ; extra == 'quicksight'
Requires-Dist: moto[ram]>=5.1.5,<=5.1.17 ; extra == 'ram'
Requires-Dist: moto[rds]>=5.1.5,<=5.1.17 ; extra == 'rds'
Requires-Dist: moto[redshift]>=5.1.5,<=5.1.17 ; extra == 'redshift'
Requires-Dist: moto[redshiftdata]>=5.1.5,<=5.1.17 ; extra == 'redshiftdata'
Requires-Dist: moto[rekognition]>=5.1.5,<=5.1.17 ; extra == 'rekognition'
Requires-Dist: moto[resourcegroups]>=5.1.5,<=5.1.17 ; extra == 'resourcegroups'
Requires-Dist: moto[resourcegroupstaggingapi]>=5.1.5,<=5.1.17 ; extra == 'resourcegroupstaggingapi'
Requires-Dist: moto[route53]>=5.1.5,<=5.1.17 ; extra == 'route53'
Requires-Dist: moto[route53resolver]>=5.1.5,<=5.1.17 ; extra == 'route53resolver'
Requires-Dist: moto[s3]>=5.1.5,<=5.1.17 ; extra == 's3'
Requires-Dist: moto[s3control]>=5.1.5,<=5.1.17 ; extra == 's3control'
Requires-Dist: moto[s3crc32c]>=5.1.5,<=5.1.17 ; extra == 's3crc32c'
Requires-Dist: moto[sagemaker]>=5.1.5,<=5.1.17 ; extra == 'sagemaker'
Requires-Dist: moto[scheduler]>=5.1.5,<=5.1.17 ; extra == 'scheduler'
Requires-Dist: moto[sdb]>=5.1.5,<=5.1.17 ; extra == 'sdb'
Requires-Dist: moto[secretsmanager]>=5.1.5,<=5.1.17 ; extra == 'secretsmanager'
Requires-Dist: moto[server]>=5.1.5,<=5.1.17 ; extra == 'server'
Requires-Dist: moto[servicediscovery]>=5.1.5,<=5.1.17 ; extra == 'servicediscovery'
Requires-Dist: moto[servicequotas]>=5.1.5,<=5.1.17 ; extra == 'servicequotas'
Requires-Dist: moto[ses]>=5.1.5,<=5.1.17 ; extra == 'ses'
Requires-Dist: moto[signer]>=5.1.5,<=5.1.17 ; extra == 'signer'
Requires-Dist: moto[sns]>=5.1.5,<=5.1.17 ; extra == 'sns'
Requires-Dist: moto[sqs]>=5.1.5,<=5.1.17 ; extra == 'sqs'
Requires-Dist: moto[ssm]>=5.1.5,<=5.1.17 ; extra == 'ssm'
Requires-Dist: moto[ssoadmin]>=5.1.5,<=5.1.17 ; extra == 'ssoadmin'
Requires-Dist: moto[stepfunctions]>=5.1.5,<=5.1.17 ; extra == 'stepfunctions'
Requires-Dist: moto[sts]>=5.1.5,<=5.1.17 ; extra == 'sts'
Requires-Dist: moto[support]>=5.1.5,<=5.1.17 ; extra == 'support'
Requires-Dist: moto[swf]>=5.1.5,<=5.1.17 ; extra == 'swf'
Requires-Dist: moto[textract]>=5.1.5,<=5.1.17 ; extra == 'textract'
Requires-Dist: moto[timestreamwrite]>=5.1.5,<=5.1.17 ; extra == 'timestreamwrite'
Requires-Dist: moto[transcribe]>=5.1.5,<=5.1.17 ; extra == 'transcribe'
Requires-Dist: moto[wafv2]>=5.1.5,<=5.1.17 ; extra == 'wafv2'
Requires-Dist: moto[xray]>=5.1.5,<=5.1.17 ; extra == 'xray'
Requires-Python: >=3.10
Project-URL: Issues, https://github.com/owenlamont/aiomoto/issues
Project-URL: Repository, https://github.com/owenlamont/aiomoto
Provides-Extra: acm
Provides-Extra: acmpca
Provides-Extra: all
Provides-Extra: amp
Provides-Extra: apigateway
Provides-Extra: apigatewayv2
Provides-Extra: applicationautoscaling
Provides-Extra: appsync
Provides-Extra: athena
Provides-Extra: autoscaling
Provides-Extra: awslambda
Provides-Extra: awslambda-simple
Provides-Extra: backup
Provides-Extra: batch
Provides-Extra: batch-simple
Provides-Extra: budgets
Provides-Extra: ce
Provides-Extra: cloudformation
Provides-Extra: cloudfront
Provides-Extra: cloudtrail
Provides-Extra: cloudwatch
Provides-Extra: codebuild
Provides-Extra: codecommit
Provides-Extra: codepipeline
Provides-Extra: cognitoidentity
Provides-Extra: cognitoidp
Provides-Extra: comprehend
Provides-Extra: config
Provides-Extra: databrew
Provides-Extra: datapipeline
Provides-Extra: datasync
Provides-Extra: dax
Provides-Extra: dms
Provides-Extra: ds
Provides-Extra: dynamodb
Provides-Extra: dynamodbstreams
Provides-Extra: ebs
Provides-Extra: ec2
Provides-Extra: ec2instanceconnect
Provides-Extra: ecr
Provides-Extra: ecs
Provides-Extra: efs
Provides-Extra: eks
Provides-Extra: elasticache
Provides-Extra: elasticbeanstalk
Provides-Extra: elastictranscoder
Provides-Extra: elb
Provides-Extra: elbv2
Provides-Extra: emr
Provides-Extra: emrcontainers
Provides-Extra: emrserverless
Provides-Extra: es
Provides-Extra: events
Provides-Extra: firehose
Provides-Extra: forecast
Provides-Extra: glacier
Provides-Extra: glue
Provides-Extra: greengrass
Provides-Extra: guardduty
Provides-Extra: iam
Provides-Extra: inspector2
Provides-Extra: iot
Provides-Extra: iotdata
Provides-Extra: ivs
Provides-Extra: kinesis
Provides-Extra: kinesisvideo
Provides-Extra: kinesisvideoarchivedmedia
Provides-Extra: kms
Provides-Extra: logs
Provides-Extra: managedblockchain
Provides-Extra: mediaconnect
Provides-Extra: medialive
Provides-Extra: mediapackage
Provides-Extra: mediastore
Provides-Extra: mediastoredata
Provides-Extra: meteringmarketplace
Provides-Extra: mq
Provides-Extra: opsworks
Provides-Extra: organizations
Provides-Extra: panorama
Provides-Extra: personalize
Provides-Extra: pinpoint
Provides-Extra: polly
Provides-Extra: proxy
Provides-Extra: quicksight
Provides-Extra: ram
Provides-Extra: rds
Provides-Extra: redshift
Provides-Extra: redshiftdata
Provides-Extra: rekognition
Provides-Extra: resourcegroups
Provides-Extra: resourcegroupstaggingapi
Provides-Extra: route53
Provides-Extra: route53resolver
Provides-Extra: s3
Provides-Extra: s3control
Provides-Extra: s3crc32c
Provides-Extra: sagemaker
Provides-Extra: scheduler
Provides-Extra: sdb
Provides-Extra: secretsmanager
Provides-Extra: server
Provides-Extra: servicediscovery
Provides-Extra: servicequotas
Provides-Extra: ses
Provides-Extra: signer
Provides-Extra: sns
Provides-Extra: sqs
Provides-Extra: ssm
Provides-Extra: ssoadmin
Provides-Extra: stepfunctions
Provides-Extra: sts
Provides-Extra: support
Provides-Extra: swf
Provides-Extra: textract
Provides-Extra: timestreamwrite
Provides-Extra: transcribe
Provides-Extra: wafv2
Provides-Extra: xray
Description-Content-Type: text/markdown

# aiomoto

`aiomoto` is Moto for aiobotocore / aioboto3 (while staying compatible with classic
botocore / boto3). It adapts Moto's stubber so async and sync clients share the same
in-memory backend: you can write to a mock S3 bucket with boto3 and read it back via
aiobotocore or aioboto3 in the same process.

## Supported today

- `mock_aws()` usable as `with` or `async with`, guarding against real HTTP requests.
- Actively exercised in tests: S3 (CRUD + listings + streaming reads), DynamoDB
  (create/describe/put/get), Secrets Manager, SES, SNS, SQS, KMS, STS, Lambda, Events,
  Kafka/MSK, and s3fs async integration — all sharing one Moto backend between sync
  boto3/botocore and async aiobotocore/aioboto3 clients.
- Other Moto services often work out of the box through the same patch layer; if you
  hit a service-specific gap, open an issue with a minimal repro so we can add a
  focused slice.

For the evolving project roadmap, see the wiki: <https://github.com/owenlamont/aiomoto/wiki/Roadmap>

## Motivation

Like many others I've wanted to use Moto with aiobotocore and aioboto3 but found that
wasn't supported, see:

- <https://github.com/getmoto/moto/issues/2039>
- <https://github.com/getmoto/moto/issues/8694>

The primary motivation for attempting to create an aiomoto repo came from this issue
<https://github.com/getmoto/moto/issues/8513>
which states aiobotocore support is out of scope for moto and the current primary moto
maintainer suggested creating an aiomoto repo.

## Related Work

<https://github.com/dazza-codes/pytest-aiomoto> was an earlier attempt at this but not
really maintained now.

There is discussion on aiobotocore repo about moto support here
<https://github.com/aio-libs/aiobotocore/discussions/1300>

Both the above approaches as far as I'm aware rely on the Moto's
[server mode](https://docs.getmoto.org/en/latest/docs/server_mode.html) which I don't
want to use (mainly as I found server mode was slower than other local AWS services
like dynamodb-local in-memory and I also wanted to run tests in parallel without
worrying about port clashes or race conditions). In short I don't want any server and I
want aiomoto to support the moto like mock contexts in the same thread / process as the
tests run in.

## Usage

Use `aiomoto.mock_aws` as a drop-in replacement for Moto's `mock_aws` that works
with both synchronous boto3/botocore clients and asynchronous aiobotocore/aioboto3
clients in the same process. It supports `with` and `async with` (and can decorate
sync/async callables).

### Use as a decorator

Use `@mock_aws` as a decorator when you want Moto started/stopped for the span of
a test function. Both sync and async callables are supported; omit parentheses
when you are not passing arguments (they remain optional to match Moto’s examples).
`mock_aws_decorator`
is also exported for teams that prefer an explicitly decorator-only name (or want
to preconfigure `reset` / `remove_data` once and reuse it) while leaving `mock_aws`
for context-manager usage.

```python
import boto3
from aiobotocore.session import AioSession
from aiomoto import mock_aws, mock_aws_decorator


@mock_aws
def test_sync_bucket() -> None:
    client = boto3.client("s3", region_name="us-east-1")
    client.create_bucket(Bucket="decorator-demo")


@mock_aws_decorator
async def test_async_bucket() -> None:
    async with AioSession().create_client("s3", region_name="us-east-1") as client:
        await client.create_bucket(Bucket="decorator-demo")
```

### Use as a context manager

```python
import boto3
from aiobotocore.session import AioSession
from aiomoto import mock_aws

async def demo():
    async with mock_aws():
        s3_sync = boto3.client("s3", region_name="us-east-1")
        s3_sync.create_bucket(Bucket="example")

        session = AioSession()
        async with session.create_client("s3", region_name="us-east-1") as s3_async:
            result = await s3_async.list_buckets()
            assert any(b["Name"] == "example" for b in result["Buckets"])
```

While aiomoto is active it prevents aiobotocore from issuing real HTTP calls; any
attempts fall back to Moto and will raise if they escape the stubber. Avoid mixing
raw Moto decorators with aiomoto contexts in the same test to keep state aligned.

> aiomoto supports Moto’s **in-process** mode only. Moto server/proxy modes
> (`TEST_SERVER_MODE`, proxy mode) will raise at `mock_aws()` time so you don’t
> accidentally depend on real network calls.

### s3fs example

```python
import s3fs
from aiomoto import mock_aws


def test_s3fs_sync_usage() -> None:
    with mock_aws():
        fs = s3fs.S3FileSystem(asynchronous=False, anon=False)
        fs.call_s3("create_bucket", Bucket="bucket-123")
        fs.call_s3("put_object", Bucket="bucket-123", Key="test.txt", Body=b"hi")
        assert fs.cat("bucket-123/test.txt") == b"hi"
```

### DynamoDB example

```python
import boto3
from aiobotocore.session import AioSession
from aiomoto import mock_aws

AWS_REGION = "us-west-2"

async def demo():
    with mock_aws():
        # Sync write
        ddb_sync = boto3.client("dynamodb", region_name=AWS_REGION)
        ddb_sync.create_table(
            TableName="items",
            KeySchema=[{"AttributeName": "pk", "KeyType": "HASH"}],
            AttributeDefinitions=[{"AttributeName": "pk", "AttributeType": "S"}],
            BillingMode="PAY_PER_REQUEST",
        )
        ddb_sync.put_item(TableName="items", Item={"pk": {"S": "from-sync"}})

        # Async read (aiobotocore)
        async with AioSession().create_client(
            "dynamodb", region_name=AWS_REGION
        ) as ddb_async:
            item = await ddb_async.get_item(
                TableName="items", Key={"pk": {"S": "from-sync"}}
            )
            assert item["Item"]["pk"]["S"] == "from-sync"
```

### Pandas parquet example (mockable path)

```python
import pandas as pd
import s3fs
from aiomoto import mock_aws

df = pd.DataFrame({"a": [1, 2], "b": ["x", "y"]})
path = "s3://my-bucket/data.parquet"

with mock_aws():
    fs = s3fs.S3FileSystem(anon=False, asynchronous=False)
    fs.call_s3("create_bucket", Bucket="my-bucket")

    # Passing the filesystem instance forces pandas to use fsspec/s3fs instead of
    # pyarrow.fs.S3FileSystem.
    df.to_parquet(path, filesystem=fs)
    roundtrip = pd.read_parquet(path, filesystem=fs)

assert roundtrip.equals(df)
```

## Roadmap

The living roadmap sits in the wiki [Roadmap](https://github.com/owenlamont/aiomoto/wiki/Roadmap)

## Limitations

- Mixing raw Moto decorators with `aiomoto.mock_aws` in the same test is unsupported;
  the contexts manage shared state differently and can diverge.
- aiomoto wraps moto and patches aiobotocore; aioboto3 and s3fs should be covered
  automatically as they use aiobotocore clients/resources.
- We keep version ranges narrow and tested together, if you notice a new version of
  aiobotocore or moto that doesn't get covered feel free to raise an issue for this.
- s3fs caches filesystem instances; create them inside `mock_aws` and close them so
  finalizers don’t hit a closed or different event loop.
- Pandas parquet on S3: when pyarrow is available the default path uses
  `pyarrow.fs.S3FileSystem`, which bypasses aiobotocore/moto entirely. To stay
  mockable, callers must force the fsspec path (e.g., pass `storage_options` or an
  explicit `s3fs.S3FileSystem`). Native pyarrow S3 access is out of scope for aiomoto.
- Polars parquet on S3 uses its Rust `object_store` S3 backend even when
  `storage_options` are provided, so aiomoto cannot intercept those calls.
