Install
openclaw skills install python-plusEnhanced Python with async/await patterns, type hints, dataclasses, testing strategies, performance optimization, and project structure templates.
openclaw skills install python-plusEnhanced Python with async patterns, type hints, testing, and performance optimization.
| Task | Tool |
|---|---|
| Type checking | mypy, pyright |
| Formatting | black, ruff |
| Testing | pytest |
| Profiling | cProfile, py-spy |
| Linting | ruff, flake8 |
import asyncio
async def fetch_data(url: str) -> dict:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
# Run async function
result = asyncio.run(fetch_data("https://api.example.com"))
async def fetch_pages(url: str):
page = 1
while True:
async with aiohttp.ClientSession() as session:
async with session.get(f"{url}?page={page}") as response:
data = await response.json()
if not data:
break
yield data
page += 1
# Usage
async for page_data in fetch_pages("https://api.example.com/items"):
process(page_data)
class AsyncDatabase:
async def __aenter__(self):
self.conn = await asyncpg.connect()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.conn.close()
# Usage
async with AsyncDatabase() as db:
await db.execute("SELECT * FROM users")
async def main():
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(fetch_data(url1))
task2 = tg.create_task(fetch_data(url2))
# Both tasks completed
result1 = task1.result()
result2 = task2.result()
from typing import TypeVar, Generic
T = TypeVar('T')
class Repository(Generic[T]):
def __init__(self, items: list[T]):
self.items = items
def get(self, index: int) -> T:
return self.items[index]
# Usage
repo = Repository[int]([1, 2, 3])
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing circle")
def render(shape: Drawable) -> None:
shape.draw()
from typing import TypeGuard
def is_string_list(val: list[object]) -> TypeGuard[list[str]]:
return all(isinstance(x, str) for x in val)
def process(data: list[object]) -> None:
if is_string_list(data):
# data is now list[str]
print("\n".join(data))
from typing import Literal
def set_mode(mode: Literal["read", "write", "append"]) -> None:
pass
set_mode("read") # OK
set_mode("invalid") # Error
from pydantic import BaseModel, Field
class User(BaseModel):
name: str = Field(..., min_length=1)
email: str = Field(..., pattern=r'^[\w\.-]+@[\w\.-]+\.\w+$')
age: int = Field(..., ge=0, le=150)
# Validation
user = User(name="Alice", email="alice@example.com", age=30)
import attrs
@attrs.define
class User:
name: str
email: str
age: int = attrs.field(validator=attrs.validators.ge(0))
import pytest
from myapp import create_app
@pytest.fixture
def app():
app = create_app(testing=True)
yield app
@pytest.fixture
def client(app):
return app.test_client()
def test_homepage(client):
response = client.get("/")
assert response.status_code == 200
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("world", "WORLD"),
("", ""),
])
def test_upper(input, expected):
assert input.upper() == expected
from unittest.mock import patch, MagicMock
@patch('myapp.external_api.fetch')
def test_with_mock(mock_fetch):
mock_fetch.return_value = {"status": "ok"}
result = my_function()
assert result["status"] == "ok"
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_function(n: int) -> int:
return n * n
# Async caching
from aiocache import cached
@cached(ttl=300)
async def get_user(user_id: int) -> dict:
return await db.get_user(user_id)
import cProfile
def profile_function():
# Code to profile
pass
cProfile.run('profile_function()')
class Point:
__slots__ = ('x', 'y')
def __init__(self, x: int, y: int):
self.x = x
self.y = y
project/
├── src/
│ └── mypackage/
│ ├── __init__.py
│ ├── core.py
│ └── utils.py
├── tests/
│ ├── __init__.py
│ ├── test_core.py
│ └── test_utils.py
├── pyproject.toml
├── README.md
└── .github/
└── workflows/
└── ci.yml
[project]
name = "mypackage"
version = "0.1.0"
requires-python = ">=3.10"
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.mypy]
python_version = "3.10"
strict = true
[tool.ruff]
line-length = 88