{"id":29244089,"url":"https://github.com/cospectrum/boxdrive","last_synced_at":"2026-01-20T16:37:53.943Z","repository":{"id":301999051,"uuid":"1010860012","full_name":"cospectrum/boxdrive","owner":"cospectrum","description":"Generic object store with S3 compatible API","archived":false,"fork":false,"pushed_at":"2025-06-30T03:29:48.000Z","size":70,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-30T03:30:57.472Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cospectrum.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-30T00:08:24.000Z","updated_at":"2025-06-30T00:08:28.000Z","dependencies_parsed_at":"2025-06-30T03:31:44.047Z","dependency_job_id":"a8a142e1-1aa2-4ab7-9cbf-2d80ec657f1c","html_url":"https://github.com/cospectrum/boxdrive","commit_stats":null,"previous_names":["cospectrum/boxdrive"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cospectrum/boxdrive","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cospectrum%2Fboxdrive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cospectrum%2Fboxdrive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cospectrum%2Fboxdrive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cospectrum%2Fboxdrive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cospectrum","download_url":"https://codeload.github.com/cospectrum/boxdrive/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cospectrum%2Fboxdrive/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263403945,"owners_count":23461231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2025-07-03T21:06:47.145Z","updated_at":"2026-01-20T16:37:53.937Z","avatar_url":"https://github.com/cospectrum.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# BoxDrive\n[![github]](https://github.com/cospectrum/boxdrive)\n[![ci]](https://github.com/cospectrum/boxdrive/actions)\n\n[github]: https://img.shields.io/badge/github-cospectrum/boxdrive-8da0cb?logo=github\n[ci]: https://github.com/cospectrum/boxdrive/workflows/ci/badge.svg\n\nS3-compatible API with **Abstract Object Store** in Python (FastAPI).\nWork in progress.\n\n## Built-in stores\n- `InMemoryStore`\n- `GitlabStore` (with some limitations)\n\n## Quick Start\n\n0. Install `boxdrive` from [PyPI](https://pypi.org/project/boxdrive/) using your preferred package manager:\n```bash\nuv add boxdrive\n```\n\n1. Create `main.py`:\n```python\nfrom boxdrive import create_app\nfrom boxdrive.stores import InMemoryStore\n\nstore = InMemoryStore()\napp = create_app(store)\n```\n\n2. Start the API (in development mode):\n```bash\nfastapi dev main.py\n```\n\u003e By default, Swagger UI will be available at http://localhost:8000/docs\n\n## API Endpoints\n\nThe API exposes the following S3-compatible endpoints:\n\n- `GET /` - List buckets\n- `PUT /{bucket}` - Create a bucket\n- `DELETE /{bucket}` - Delete a bucket\n- `GET /{bucket}` - List objects in a bucket\n- `GET /{bucket}/{key}` - Get an object\n- `PUT /{bucket}/{key}` - Put an object\n- `DELETE /{bucket}/{key}` - Delete an object\n\n## Creating Custom Object Stores\n\nTo use a custom object store, implement the `ObjectStore` interface and provide an instance to `create_app`:\n\n```python\nfrom boxdrive import (\n    BucketInfo,\n    BucketName,\n    ContentType,\n    Key,\n    ListObjectsInfo,\n    ListObjectsV2Info,\n    MaxKeys,\n    Object,\n    ObjectInfo,\n    ObjectStore,\n)\n\nclass MyCustomStore(ObjectStore):\n    async def list_buckets(self) -\u003e list[BucketInfo]: ...\n    async def create_bucket(self, bucket_name: BucketName) -\u003e None: ...\n    async def delete_bucket(self, bucket_name: BucketName) -\u003e None: ...\n    async def get_object(self, bucket_name: BucketName, key: Key) -\u003e Object: ...\n    async def put_object(\n        self, bucket_name: BucketName, key: Key, data: bytes, content_type: ContentType | None = None\n    ) -\u003e ObjectInfo: ...\n    async def delete_object(self, bucket_name: BucketName, key: Key) -\u003e None: ...\n    async def head_object(self, bucket_name: BucketName, key: Key) -\u003e ObjectInfo: ...\n    async def list_objects(\n        self,\n        bucket_name: BucketName,\n        *,\n        prefix: str | None = None,\n        delimiter: str | None = None,\n        max_keys: MaxKeys = 1000,\n        marker: str | None = None,\n        encoding_type: str | None = None,\n    ) -\u003e ListObjectsInfo: ...\n    async def list_objects_v2(\n        self,\n        bucket_name: BucketName,\n        *,\n        continuation_token: Key | None = None,\n        delimiter: str | None = None,\n        encoding_type: str | None = None,\n        max_keys: MaxKeys = 1000,\n        prefix: str | None = None,\n        start_after: Key | None = None,\n    ) -\u003e ListObjectsV2Info: ...\n```\n\u003e Use exceptions from [boxdrive.exceptions](./src/boxdrive/exceptions.py)\n\u003e (e.g., NoSuchBucket, NoSuchKey) in your custom store implementation.\n\n## Development\n\n### API\n\n0. Start the monitoring pipeline:\n```sh\ndocker compose -f docker-compose-monitoring.yaml up --detach --wait\n```\n\u003e Telemetry data will be saved in ClickHouse, which is exposed at localhost:8123.\n\n1. Start the API:\n```sh\nexport OTEL_EXPORTER_HTTP_ENDPOINT=http://localhost:4318\nuv run fastapi dev examples/inmemory.py\n```\n\n### Tests\n\n#### Unit tests\n```bash\nuv run pytest tests/unit\n```\n\n#### End-to-end (e2e) tests  \nThe API should be running in the background.\n```bash\nexport S3_ENDPOINT_URL=http://127.0.0.1:8000\nuv run run pytest tests/e2e\n```\n\n#### Third-party S3 tests  \nThe API should be running in the background.\n```bash\ncd tests/third_party/s3-tests\nexport S3TEST_CONF=s3tests.conf\nuv run tox -- s3tests_boto3/functional/test_s3.py -m boxdrive\n```\nSee [tests/third_party/s3-tests/boxdrive.md](./tests/third_party/s3-tests/boxdrive.md)\nfor additional information.\n\n### Code Quality\n\n```bash\nuv run ruff format .\nuv run ruff check . --fix\nuv run mypy .\n```\n\n## License\n\nApache 2.0 – see the [LICENSE](./LICENSE) file for details.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcospectrum%2Fboxdrive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcospectrum%2Fboxdrive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcospectrum%2Fboxdrive/lists"}