{"id":34107007,"url":"https://github.com/com2cloud/botowrap","last_synced_at":"2026-04-09T04:31:58.966Z","repository":{"id":290178388,"uuid":"973608000","full_name":"com2cloud/botowrap","owner":"com2cloud","description":"A modular framework for extending boto3 clients with automatic enhancements, wrappers, and developer-friendly features","archived":false,"fork":false,"pushed_at":"2026-01-20T15:25:01.000Z","size":5395,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-21T00:26:48.506Z","etag":null,"topics":["aws","boto3","dynamodb"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/botowrap/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/com2cloud.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-27T11:04:47.000Z","updated_at":"2026-01-20T15:25:57.000Z","dependencies_parsed_at":null,"dependency_job_id":"9c1ed3e0-611b-41e0-ac1c-77d5a4864cbb","html_url":"https://github.com/com2cloud/botowrap","commit_stats":null,"previous_names":["com2cloud/botowrap"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/com2cloud/botowrap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com2cloud%2Fbotowrap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com2cloud%2Fbotowrap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com2cloud%2Fbotowrap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com2cloud%2Fbotowrap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/com2cloud","download_url":"https://codeload.github.com/com2cloud/botowrap/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com2cloud%2Fbotowrap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31586403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"online","status_checked_at":"2026-04-09T02:00:06.848Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","boto3","dynamodb"],"created_at":"2025-12-14T18:04:31.496Z","updated_at":"2026-04-09T04:31:58.954Z","avatar_url":"https://github.com/com2cloud.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# botowrap\n\n[![Python Package](https://github.com/com2cloud/botowrap/actions/workflows/release.yml/badge.svg)](https://github.com/com2cloud/botowrap/actions/workflows/release.yml)\n[![PyPI version](https://badge.fury.io/py/botowrap.svg)](https://badge.fury.io/py/botowrap)\n[![PyPI downloads](https://img.shields.io/pypi/dm/botowrap.svg)](https://pypi.org/project/botowrap/)\n[![Codecov](https://codecov.io/gh/com2cloud/botowrap/branch/main/graph/badge.svg)](https://codecov.io/gh/com2cloud/botowrap)\n[![Documentation Status](https://readthedocs.org/projects/botowrap/badge/?version=latest)](https://botowrap.readthedocs.io/en/latest/?badge=latest)\n[![CodeFactor](https://www.codefactor.io/repository/github/com2cloud/botowrap/badge)](https://www.codefactor.io/repository/github/com2cloud/botowrap)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.7+](https://img.shields.io/badge/python-3.7+-blue.svg)](https://www.python.org/downloads/)\n\nA modular framework for building and distributing \"opinionated\" wrappers around\nboto3 clients. Enhance your AWS SDK experience with powerful extensions that add\ndeveloper-friendly features while maintaining the standard boto3 interface.\n\nOut of the box it provides:\n\n- **DynamoDBDocumentExtension**\n  - Python↔DynamoDB (de)serialization\n  - Auto‐`CreatedAt`/`UpdatedAt` timestamps\n  - Jittered exponential backoff on throttling\n  - `query_all`/`scan_all` pagination helpers\n  - ConsumedCapacity logging\n\n## Installation\n\n```bash\npip install botowrap\n```\n\n## Usage\n\n```python\nimport logging\nimport boto3\nfrom botowrap.core import ExtensionManager\nfrom botowrap.extensions.dynamodb import (\n    DynamoDBExtension, DynamoDBConfig\n)\n\nlogging.basicConfig(level=logging.INFO)\n\n# 1) Create the manager (uses the default boto3 session)\nmgr = ExtensionManager()\n\n# 2) Register whichever extensions you want:\nddb_config = DynamoDBConfig(\n    max_retries=8,\n    log_consumed=True,\n    add_pagination=True,\n    add_timestamps=True\n)\nmgr.register(DynamoDBExtension(ddb_config))\n\n# 3) Bootstrap: from now on, boto3.client('dynamodb') is enhanced\nmgr.bootstrap()\n\n# Use the enhanced client\nddb = boto3.client('dynamodb')\n\n# Insert item with native Python types (automatic serialization)\nddb.put_item(\n    TableName='Users',\n    Item={\n        'UserId': 'alice',\n        'Age': 30,\n        'Active': True,\n        'Data': {'joined': '2023-01-01'}\n    }\n)\n\n# Use pagination helper\nall_users = ddb.scan_all(TableName='Users')\nprint(all_users)  # All users with Python types\n```\n\n## Features\n\n### Automatic Type Conversion\n\nNo more manual serialization between Python and DynamoDB types:\n\n```python\n# Without botowrap\nfrom boto3.dynamodb.types import TypeSerializer\nserializer = TypeSerializer()\nddb.put_item(\n    TableName='Users',\n    Item={\n        'UserId': serializer.serialize('alice'),\n        'Age': serializer.serialize(30),\n        'Active': serializer.serialize(True)\n    }\n)\n\n# With botowrap\nddb.put_item(\n    TableName='Users',\n    Item={\n        'UserId': 'alice',\n        'Age': 30,\n        'Active': True\n    }\n)\n```\n\n### Automatic Timestamps\n\nKeep track of when items were created and last modified:\n\n```python\n# Creates an item with CreatedAt and UpdatedAt timestamps\nddb.put_item(TableName='Users', Item={'UserId': 'bob'})\n\n# UpdatedAt is automatically updated, CreatedAt preserved\nddb.update_item(\n    TableName='Users',\n    Key={'UserId': 'bob'},\n    UpdateExpression='SET Age = :a',\n    ExpressionAttributeValues={':a': 25}\n)\n```\n\n### Simplified Pagination\n\nNo more dealing with LastEvaluatedKey tokens manually:\n\n```python\n# With botowrap\nall_items = ddb.scan_all(TableName='MyTable')\n\n# Equivalent to:\nitems = []\nresp = ddb.scan(TableName='MyTable')\nitems.extend(resp.get('Items', []))\nwhile 'LastEvaluatedKey' in resp:\n    resp = ddb.scan(\n        TableName='MyTable',\n        ExclusiveStartKey=resp['LastEvaluatedKey']\n    )\n    items.extend(resp.get('Items', []))\n```\n\n## Configuration Options\n\nThe DynamoDB extension can be configured:\n\n```python\nddb_config = DynamoDBConfig(\n    # Number of retries for throttling (default: 5)\n    max_retries=8,\n\n    # Whether to log consumed capacity (default: True)\n    log_consumed=True,\n\n    # Whether to add pagination helpers (default: True)\n    add_pagination=True,\n\n    # Whether to add CreatedAt/UpdatedAt timestamps (default: True)\n    add_timestamps=True\n)\n```\n\n## Developing\n\n- New service wrappers live under `botowrap/extensions/`\n- Base classes and manager logic are in `core.py`\n- Extensions must implement:\n  - `attach(session)` - Adds functionality to the boto3 session\n  - `detach(session)` - Removes functionality from the boto3 session\n\n### Creating an Extension\n\n```python\nfrom botowrap.core import BaseExtension\n\nclass MyServiceExtension(BaseExtension):\n    SERVICE = 'my-service'\n\n    def __init__(self, config):\n        self.config = config\n\n    def attach(self, session):\n        # Add functionality to the session\n        pass\n\n    def detach(self, session):\n        # Remove functionality from the session\n        pass\n```\n\n## Documentation\n\nFor full documentation, visit the [documentation site](https://botowrap.readthedocs.io/).\n\n## Contributing\n\nContributions are welcome! See the [CONTRIBUTING](CONTRIBUTING.md) guide for details.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcom2cloud%2Fbotowrap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcom2cloud%2Fbotowrap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcom2cloud%2Fbotowrap/lists"}