# Bunnyshell Python SDK
[](https://pypi.org/project/bunnyshell/)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
Official Python SDK for Bunnyshell Sandboxes - Execute code safely in isolated microVM environments.
## Features
- 🚀 **47/47 Features** - 100% API coverage
- 🔒 **Type Safe** - Full Pydantic models with auto-complete
- ⚡ **Async Support** - Native async/await for all operations
- 🌊 **WebSocket Streaming** - Real-time code execution, terminal, file watching
- 🎨 **Rich Outputs** - Automatic capture of plots, images, DataFrames
- 🔐 **Security First** - Environment variables for secrets, execution timeouts
- 📦 **Context Managers** - Automatic cleanup with `with` statement
- 🐍 **Pythonic API** - Follows Python best practices
## Installation
```bash
pip install bunnyshell
```
For WebSocket features (optional):
```bash
pip install bunnyshell[websockets]
```
## Quick Start
```python
from bunnyshell import Sandbox
# Create sandbox
with Sandbox.create(template="code-interpreter", api_key="your-api-key") as sandbox:
# Execute Python code
result = sandbox.run_code("""
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
print(df.sum())
""")
print(result.stdout)
# Output: a 6
# b 15
```
## Environment Variables (IMPORTANT!)
**✅ ALWAYS pass secrets via environment variables:**
```python
# ✅ GOOD: Secrets via environment variables
result = sandbox.run_code(
"""
import os
api_key = os.getenv('OPENAI_API_KEY')
# Use api_key safely...
""",
env={"OPENAI_API_KEY": "sk-..."}
)
# ❌ BAD: Never hardcode secrets
# result = sandbox.run_code('api_key = "sk-..."') # DON'T DO THIS!
```
## Core Features
### Code Execution
```python
# Synchronous execution
result = sandbox.run_code("print('Hello')")
# With environment variables
result = sandbox.run_code(
"import os; print(os.getenv('MY_VAR'))",
env={"MY_VAR": "value"}
)
# Async execution (non-blocking)
execution_id = sandbox.run_code_async("import time; time.sleep(10)")
# Background execution (fire-and-forget)
execution_id = sandbox.run_code_background("# long task...")
# IPython/Jupyter-style
result = sandbox.run_ipython("df.describe()")
```
### Real-time Streaming (WebSocket)
```python
import asyncio
async def stream():
async for message in sandbox.run_code_stream("""
import time
for i in range(5):
print(f"Step {i+1}")
time.sleep(1)
"""):
if message['type'] == 'stdout':
print(message['data'], end='')
asyncio.run(stream())
```
### File Operations
```python
# Write file
sandbox.files.write('/workspace/data.txt', 'Hello, World!')
# Read file
content = sandbox.files.read('/workspace/data.txt')
# List directory
files = sandbox.files.list('/workspace')
for file in files:
print(f"{file.name} ({file.size_kb:.2f}KB)")
# Upload local file
sandbox.files.upload('./local.txt', '/workspace/remote.txt')
# Download remote file
sandbox.files.download('/workspace/remote.txt', './local.txt')
# Check existence
if sandbox.files.exists('/workspace/data.txt'):
print("File exists!")
# Remove file/directory
sandbox.files.remove('/workspace/data.txt')
# Create directory
sandbox.files.mkdir('/workspace/mydir')
# Watch filesystem (WebSocket)
async for event in sandbox.files.watch('/workspace'):
print(f"{event['event']}: {event['path']}")
```
### Commands
```python
# Run shell command
result = sandbox.commands.run('ls -la /workspace')
print(result.stdout)
# With environment variables
result = sandbox.commands.run(
'echo "Key: $API_KEY"',
env={'API_KEY': 'secret'}
)
# Custom working directory
result = sandbox.commands.run(
'pwd',
working_dir='/workspace/myproject'
)
```
### Environment Variables
```python
# Get all
env_vars = sandbox.env.get_all()
# Set all (replace)
sandbox.env.set_all({'API_KEY': 'sk-...', 'DEBUG': 'true'})
# Update (merge)
sandbox.env.update({'NEW_VAR': 'value'})
# Delete
sandbox.env.delete(['VAR_TO_DELETE'])
# Get single
value = sandbox.env.get('API_KEY')
# Set single
sandbox.env.set('API_KEY', 'sk-...')
```
### Process Management
```python
# List processes
processes = sandbox.list_processes()
for proc in processes:
print(f"{proc.pid}: {proc.name} (CPU: {proc.cpu_percent}%)")
# Kill process
sandbox.kill_process(1234)
```
### Metrics & Health
```python
# Get metrics
metrics = sandbox.get_metrics_snapshot()
print(f"Total executions: {metrics.total_executions}")
print(f"Uptime: {metrics.uptime_seconds}s")
# Health check
health = sandbox.get_health()
print(f"Status: {health.status}")
# Cache management
cache_stats = sandbox.cache.stats()
print(f"Cache size: {cache_stats.cache.size}")
sandbox.cache.clear()
```
### Desktop Automation
```python
# Note: Requires 'desktop' template
sandbox = Sandbox.create(template='desktop', api_key='...')
# Mouse operations
sandbox.desktop.mouse_click(x=500, y=300, button='left')
sandbox.desktop.mouse_move(x=600, y=400)
sandbox.desktop.drag_drop(from_x=100, from_y=100, to_x=300, to_y=300)
# Keyboard
sandbox.desktop.keyboard_type('Hello, World!')
sandbox.desktop.keyboard_press('Return')
sandbox.desktop.keyboard_press('Control_L+c') # Ctrl+C
# Clipboard
sandbox.desktop.clipboard_set('text to copy')
content = sandbox.desktop.clipboard_get()
# Screenshots
screenshot = sandbox.desktop.screenshot()
with open('screenshot.png', 'wb') as f:
f.write(screenshot)
# OCR (text recognition)
text = sandbox.desktop.ocr()
print(f"Found text: {text}")
# Find elements
element = sandbox.desktop.find_element(text='Button')
if element:
sandbox.desktop.mouse_click(x=element['x'], y=element['y'])
# VNC connection
vnc_info = sandbox.desktop.get_vnc_url()
print(f"VNC URL: {vnc_info['url']}")
```
### Interactive Terminal (WebSocket)
```python
import asyncio
async def terminal_session():
async with sandbox.terminal.connect() as term:
# Send commands
await sandbox.terminal.send_input(term, 'ls -la\n')
# Receive output
async for message in sandbox.terminal.iter_output(term):
if message['type'] == 'output':
print(message['data'], end='')
asyncio.run(terminal_session())
```
## Advanced Configuration
```python
sandbox = Sandbox.create(
template='code-interpreter',
api_key='your-api-key',
vcpu=4, # 4 vCPUs
memory_mb=4096, # 4GB RAM
disk_gb=20, # 20GB disk
region='us-west-2', # Specific region
timeout=600, # 10 minute timeout
env_vars={ # Pre-set environment variables
'DATABASE_URL': 'postgres://...',
'API_KEY': 'sk-...'
}
)
```
## Error Handling
```python
from bunnyshell.errors import (
BunnyshellError,
AuthenticationError,
NotFoundError,
FileNotFoundError,
CodeExecutionError,
RateLimitError,
ServerError
)
try:
with Sandbox.create(template='code-interpreter', api_key='...') as sandbox:
result = sandbox.run_code("print('Hello')")
except AuthenticationError as e:
print(f"Auth failed: {e.message}")
print(f"Request ID: {e.request_id}")
except FileNotFoundError as e:
print(f"File not found: {e.path}")
except CodeExecutionError as e:
print(f"Code execution failed: {e.message}")
print(f"Exit code: {e.exit_code}")
except RateLimitError as e:
print(f"Rate limited: {e.message}")
except BunnyshellError as e:
print(f"API error: {e.message}")
print(f"Status code: {e.status_code}")
```
## Best Practices
### 1. Always Use Context Managers
```python
# ✅ GOOD: Automatic cleanup
with Sandbox.create(...) as sandbox:
# Work here
pass
# Sandbox automatically deleted
# ❌ BAD: Manual cleanup (easy to forget)
sandbox = Sandbox.create(...)
# ... work ...
sandbox.kill() # Easy to forget if error occurs!
```
### 2. Set Timeouts
```python
# Prevent infinite execution
result = sandbox.run_code(code, timeout=30)
```
### 3. Optimize Performance
```python
# Set environment variables once
sandbox.env.set_all({'API_KEY': 'sk-...', 'DB_URL': '...'})
# Now available in all executions
for i in range(100):
sandbox.run_code('...') # Env vars already set
```
## Use Cases
### OpenAI: ChatGPT Code Interpreter
```python
def execute_user_code(user_code: str):
with Sandbox.create(template="code-interpreter") as sandbox:
result = sandbox.run_code(user_code, timeout=30)
return {
"output": result.stdout,
"error": result.stderr,
"rich_outputs": result.rich_outputs # Images, plots
}
```
### Stripe: Payment Reports
```python
with Sandbox.create(template="code-interpreter") as sandbox:
sandbox.env.set('STRIPE_SECRET_KEY', os.getenv('STRIPE_SECRET_KEY'))
result = sandbox.run_code("""
import stripe
stripe.api_key = os.environ['STRIPE_SECRET_KEY']
charges = stripe.Charge.list(limit=100)
# Generate report...
""")
```
## Documentation
- **Cookbook**: See [cookbook/python](../../cookbook/python/) for 10 complete examples
- **API Reference**: [docs.bunnyshell.com](https://docs.bunnyshell.com)
- **GitHub**: [github.com/bunnyshell/sandbox-sdks](https://github.com/bunnyshell/sandbox-sdks)
## License
MIT License - See [LICENSE](../LICENSE) file for details.
## Support
- **Issues**: [github.com/bunnyshell/sandbox-sdks/issues](https://github.com/bunnyshell/sandbox-sdks/issues)
- **Email**: support@bunnyshell.com
- **Documentation**: [docs.bunnyshell.com](https://docs.bunnyshell.com)
Raw data
{
"_id": null,
"home_page": null,
"name": "bunnyshell",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "bunnyshell, cloud, containers, microvm, sandbox, vm",
"author": null,
"author_email": "Bunnyshell <support@bunnyshell.com>",
"download_url": "https://files.pythonhosted.org/packages/51/e6/3962b6235692c36a94ed5e4f4f9b30122b856b5c27e2bace891c046225fb/bunnyshell-0.1.7.tar.gz",
"platform": null,
"description": "# Bunnyshell Python SDK\n\n[](https://pypi.org/project/bunnyshell/)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n\nOfficial Python SDK for Bunnyshell Sandboxes - Execute code safely in isolated microVM environments.\n\n## Features\n\n- \ud83d\ude80 **47/47 Features** - 100% API coverage\n- \ud83d\udd12 **Type Safe** - Full Pydantic models with auto-complete\n- \u26a1 **Async Support** - Native async/await for all operations\n- \ud83c\udf0a **WebSocket Streaming** - Real-time code execution, terminal, file watching\n- \ud83c\udfa8 **Rich Outputs** - Automatic capture of plots, images, DataFrames\n- \ud83d\udd10 **Security First** - Environment variables for secrets, execution timeouts\n- \ud83d\udce6 **Context Managers** - Automatic cleanup with `with` statement\n- \ud83d\udc0d **Pythonic API** - Follows Python best practices\n\n## Installation\n\n```bash\npip install bunnyshell\n```\n\nFor WebSocket features (optional):\n```bash\npip install bunnyshell[websockets]\n```\n\n## Quick Start\n\n```python\nfrom bunnyshell import Sandbox\n\n# Create sandbox\nwith Sandbox.create(template=\"code-interpreter\", api_key=\"your-api-key\") as sandbox:\n # Execute Python code\n result = sandbox.run_code(\"\"\"\nimport pandas as pd\ndf = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})\nprint(df.sum())\n \"\"\")\n \n print(result.stdout)\n # Output: a 6\n # b 15\n```\n\n## Environment Variables (IMPORTANT!)\n\n**\u2705 ALWAYS pass secrets via environment variables:**\n\n```python\n# \u2705 GOOD: Secrets via environment variables\nresult = sandbox.run_code(\n \"\"\"\nimport os\napi_key = os.getenv('OPENAI_API_KEY')\n# Use api_key safely...\n \"\"\",\n env={\"OPENAI_API_KEY\": \"sk-...\"}\n)\n\n# \u274c BAD: Never hardcode secrets\n# result = sandbox.run_code('api_key = \"sk-...\"') # DON'T DO THIS!\n```\n\n## Core Features\n\n### Code Execution\n\n```python\n# Synchronous execution\nresult = sandbox.run_code(\"print('Hello')\")\n\n# With environment variables\nresult = sandbox.run_code(\n \"import os; print(os.getenv('MY_VAR'))\",\n env={\"MY_VAR\": \"value\"}\n)\n\n# Async execution (non-blocking)\nexecution_id = sandbox.run_code_async(\"import time; time.sleep(10)\")\n\n# Background execution (fire-and-forget)\nexecution_id = sandbox.run_code_background(\"# long task...\")\n\n# IPython/Jupyter-style\nresult = sandbox.run_ipython(\"df.describe()\")\n```\n\n### Real-time Streaming (WebSocket)\n\n```python\nimport asyncio\n\nasync def stream():\n async for message in sandbox.run_code_stream(\"\"\"\nimport time\nfor i in range(5):\n print(f\"Step {i+1}\")\n time.sleep(1)\n \"\"\"):\n if message['type'] == 'stdout':\n print(message['data'], end='')\n\nasyncio.run(stream())\n```\n\n### File Operations\n\n```python\n# Write file\nsandbox.files.write('/workspace/data.txt', 'Hello, World!')\n\n# Read file\ncontent = sandbox.files.read('/workspace/data.txt')\n\n# List directory\nfiles = sandbox.files.list('/workspace')\nfor file in files:\n print(f\"{file.name} ({file.size_kb:.2f}KB)\")\n\n# Upload local file\nsandbox.files.upload('./local.txt', '/workspace/remote.txt')\n\n# Download remote file\nsandbox.files.download('/workspace/remote.txt', './local.txt')\n\n# Check existence\nif sandbox.files.exists('/workspace/data.txt'):\n print(\"File exists!\")\n\n# Remove file/directory\nsandbox.files.remove('/workspace/data.txt')\n\n# Create directory\nsandbox.files.mkdir('/workspace/mydir')\n\n# Watch filesystem (WebSocket)\nasync for event in sandbox.files.watch('/workspace'):\n print(f\"{event['event']}: {event['path']}\")\n```\n\n### Commands\n\n```python\n# Run shell command\nresult = sandbox.commands.run('ls -la /workspace')\nprint(result.stdout)\n\n# With environment variables\nresult = sandbox.commands.run(\n 'echo \"Key: $API_KEY\"',\n env={'API_KEY': 'secret'}\n)\n\n# Custom working directory\nresult = sandbox.commands.run(\n 'pwd',\n working_dir='/workspace/myproject'\n)\n```\n\n### Environment Variables\n\n```python\n# Get all\nenv_vars = sandbox.env.get_all()\n\n# Set all (replace)\nsandbox.env.set_all({'API_KEY': 'sk-...', 'DEBUG': 'true'})\n\n# Update (merge)\nsandbox.env.update({'NEW_VAR': 'value'})\n\n# Delete\nsandbox.env.delete(['VAR_TO_DELETE'])\n\n# Get single\nvalue = sandbox.env.get('API_KEY')\n\n# Set single\nsandbox.env.set('API_KEY', 'sk-...')\n```\n\n### Process Management\n\n```python\n# List processes\nprocesses = sandbox.list_processes()\nfor proc in processes:\n print(f\"{proc.pid}: {proc.name} (CPU: {proc.cpu_percent}%)\")\n\n# Kill process\nsandbox.kill_process(1234)\n```\n\n### Metrics & Health\n\n```python\n# Get metrics\nmetrics = sandbox.get_metrics_snapshot()\nprint(f\"Total executions: {metrics.total_executions}\")\nprint(f\"Uptime: {metrics.uptime_seconds}s\")\n\n# Health check\nhealth = sandbox.get_health()\nprint(f\"Status: {health.status}\")\n\n# Cache management\ncache_stats = sandbox.cache.stats()\nprint(f\"Cache size: {cache_stats.cache.size}\")\n\nsandbox.cache.clear()\n```\n\n### Desktop Automation\n\n```python\n# Note: Requires 'desktop' template\nsandbox = Sandbox.create(template='desktop', api_key='...')\n\n# Mouse operations\nsandbox.desktop.mouse_click(x=500, y=300, button='left')\nsandbox.desktop.mouse_move(x=600, y=400)\nsandbox.desktop.drag_drop(from_x=100, from_y=100, to_x=300, to_y=300)\n\n# Keyboard\nsandbox.desktop.keyboard_type('Hello, World!')\nsandbox.desktop.keyboard_press('Return')\nsandbox.desktop.keyboard_press('Control_L+c') # Ctrl+C\n\n# Clipboard\nsandbox.desktop.clipboard_set('text to copy')\ncontent = sandbox.desktop.clipboard_get()\n\n# Screenshots\nscreenshot = sandbox.desktop.screenshot()\nwith open('screenshot.png', 'wb') as f:\n f.write(screenshot)\n\n# OCR (text recognition)\ntext = sandbox.desktop.ocr()\nprint(f\"Found text: {text}\")\n\n# Find elements\nelement = sandbox.desktop.find_element(text='Button')\nif element:\n sandbox.desktop.mouse_click(x=element['x'], y=element['y'])\n\n# VNC connection\nvnc_info = sandbox.desktop.get_vnc_url()\nprint(f\"VNC URL: {vnc_info['url']}\")\n```\n\n### Interactive Terminal (WebSocket)\n\n```python\nimport asyncio\n\nasync def terminal_session():\n async with sandbox.terminal.connect() as term:\n # Send commands\n await sandbox.terminal.send_input(term, 'ls -la\\n')\n \n # Receive output\n async for message in sandbox.terminal.iter_output(term):\n if message['type'] == 'output':\n print(message['data'], end='')\n\nasyncio.run(terminal_session())\n```\n\n## Advanced Configuration\n\n```python\nsandbox = Sandbox.create(\n template='code-interpreter',\n api_key='your-api-key',\n vcpu=4, # 4 vCPUs\n memory_mb=4096, # 4GB RAM\n disk_gb=20, # 20GB disk\n region='us-west-2', # Specific region\n timeout=600, # 10 minute timeout\n env_vars={ # Pre-set environment variables\n 'DATABASE_URL': 'postgres://...',\n 'API_KEY': 'sk-...'\n }\n)\n```\n\n## Error Handling\n\n```python\nfrom bunnyshell.errors import (\n BunnyshellError,\n AuthenticationError,\n NotFoundError,\n FileNotFoundError,\n CodeExecutionError,\n RateLimitError,\n ServerError\n)\n\ntry:\n with Sandbox.create(template='code-interpreter', api_key='...') as sandbox:\n result = sandbox.run_code(\"print('Hello')\")\n \nexcept AuthenticationError as e:\n print(f\"Auth failed: {e.message}\")\n print(f\"Request ID: {e.request_id}\")\n \nexcept FileNotFoundError as e:\n print(f\"File not found: {e.path}\")\n \nexcept CodeExecutionError as e:\n print(f\"Code execution failed: {e.message}\")\n print(f\"Exit code: {e.exit_code}\")\n \nexcept RateLimitError as e:\n print(f\"Rate limited: {e.message}\")\n \nexcept BunnyshellError as e:\n print(f\"API error: {e.message}\")\n print(f\"Status code: {e.status_code}\")\n```\n\n## Best Practices\n\n### 1. Always Use Context Managers\n\n```python\n# \u2705 GOOD: Automatic cleanup\nwith Sandbox.create(...) as sandbox:\n # Work here\n pass\n# Sandbox automatically deleted\n\n# \u274c BAD: Manual cleanup (easy to forget)\nsandbox = Sandbox.create(...)\n# ... work ...\nsandbox.kill() # Easy to forget if error occurs!\n```\n\n### 2. Set Timeouts\n\n```python\n# Prevent infinite execution\nresult = sandbox.run_code(code, timeout=30)\n```\n\n### 3. Optimize Performance\n\n```python\n# Set environment variables once\nsandbox.env.set_all({'API_KEY': 'sk-...', 'DB_URL': '...'})\n\n# Now available in all executions\nfor i in range(100):\n sandbox.run_code('...') # Env vars already set\n```\n\n## Use Cases\n\n### OpenAI: ChatGPT Code Interpreter\n\n```python\ndef execute_user_code(user_code: str):\n with Sandbox.create(template=\"code-interpreter\") as sandbox:\n result = sandbox.run_code(user_code, timeout=30)\n return {\n \"output\": result.stdout,\n \"error\": result.stderr,\n \"rich_outputs\": result.rich_outputs # Images, plots\n }\n```\n\n### Stripe: Payment Reports\n\n```python\nwith Sandbox.create(template=\"code-interpreter\") as sandbox:\n sandbox.env.set('STRIPE_SECRET_KEY', os.getenv('STRIPE_SECRET_KEY'))\n \n result = sandbox.run_code(\"\"\"\nimport stripe\nstripe.api_key = os.environ['STRIPE_SECRET_KEY']\ncharges = stripe.Charge.list(limit=100)\n# Generate report...\n \"\"\")\n```\n\n## Documentation\n\n- **Cookbook**: See [cookbook/python](../../cookbook/python/) for 10 complete examples\n- **API Reference**: [docs.bunnyshell.com](https://docs.bunnyshell.com)\n- **GitHub**: [github.com/bunnyshell/sandbox-sdks](https://github.com/bunnyshell/sandbox-sdks)\n\n## License\n\nMIT License - See [LICENSE](../LICENSE) file for details.\n\n## Support\n\n- **Issues**: [github.com/bunnyshell/sandbox-sdks/issues](https://github.com/bunnyshell/sandbox-sdks/issues)\n- **Email**: support@bunnyshell.com\n- **Documentation**: [docs.bunnyshell.com](https://docs.bunnyshell.com)\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Official Python SDK for Bunnyshell Sandboxes",
"version": "0.1.7",
"project_urls": {
"Documentation": "https://docs.bunnyshell.com",
"Homepage": "https://bunnyshell.com",
"Issues": "https://github.com/bunnyshell/bunnyshell-python/issues",
"Repository": "https://github.com/bunnyshell/bunnyshell-python"
},
"split_keywords": [
"bunnyshell",
" cloud",
" containers",
" microvm",
" sandbox",
" vm"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "ebb8610c0cc87a6186f8bca3e9b151f2699c9ec737d8753f309bf7b940583363",
"md5": "8cabcb35fbf2b27c9576b0eeea3612bb",
"sha256": "f279e834600bd0c080c3b083abdb6d2d4252245eb4a667c42b9486b6c00e2b6c"
},
"downloads": -1,
"filename": "bunnyshell-0.1.7-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8cabcb35fbf2b27c9576b0eeea3612bb",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 66718,
"upload_time": "2025-11-05T22:31:48",
"upload_time_iso_8601": "2025-11-05T22:31:48.320375Z",
"url": "https://files.pythonhosted.org/packages/eb/b8/610c0cc87a6186f8bca3e9b151f2699c9ec737d8753f309bf7b940583363/bunnyshell-0.1.7-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "51e63962b6235692c36a94ed5e4f4f9b30122b856b5c27e2bace891c046225fb",
"md5": "96a1ef3b72be866e3a4b3c79d8602c20",
"sha256": "837419eb971fe7e30d2c29977f43091454e4096e31f27c87c35b3d638d0bf0d2"
},
"downloads": -1,
"filename": "bunnyshell-0.1.7.tar.gz",
"has_sig": false,
"md5_digest": "96a1ef3b72be866e3a4b3c79d8602c20",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 119582,
"upload_time": "2025-11-05T22:31:50",
"upload_time_iso_8601": "2025-11-05T22:31:50.018289Z",
"url": "https://files.pythonhosted.org/packages/51/e6/3962b6235692c36a94ed5e4f4f9b30122b856b5c27e2bace891c046225fb/bunnyshell-0.1.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-11-05 22:31:50",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "bunnyshell",
"github_project": "bunnyshell-python",
"github_not_found": true,
"lcname": "bunnyshell"
}