Type stubs for python-socketio. This repo contains only .pyi files, no runtime code.
uv sync # Install dependencies
uv run poe lint # Ruff lint + format
uv run poe pyrefly # Type check (strict, pyrefly)
uv run poe mypy # Type check (strict, mypy)src/
└── socketio-stubs/ # Main stub package
├── __init__.pyi # Public API re-exports
├── _types.pyi # Internal type definitions
├── server.pyi # Module stubs
├── async_server.pyi
├── client.pyi
├── async_client.pyi
└── ...
- Use
...for function bodies and default values - Add type hints to all parameters and return types
- Use
assyntax for re-exports:from mod import X as X - Define internal types in
_types.pyi - Avoid
Incomplete- use concrete types - Prefer Python 3.12 type parameter syntax over direct
TypeVar/ParamSpecdeclarations unless direct declarations are required
This repository targets Python 3.12+. Prefer PEP 695 type parameter syntax for new generic stubs:
from collections.abc import Callable
class Box[T]:
def get(self) -> T: ...
def decorator[**P, T](func: Callable[P, T]) -> Callable[P, T]: ...Use direct TypeVar/ParamSpec only when the 3.12 syntax cannot express the type. The main required case is a type parameter default, because default values for type parameters are only supported by syntax in Python 3.13+:
from typing import Generic, Literal
from typing_extensions import TypeVar
_IsAsyncio = TypeVar("_IsAsyncio", bound=bool, default=Literal[False])
class BaseNamespace(Generic[_IsAsyncio]): ...Naming convention:
- PEP 695 syntax: use non-underscored names (
T,P), not_T/_P - Direct
TypeVar/ParamSpec: keep underscored variables (_T,_P)
socketio-stub-updater skill located in .agents/skills/socketio-stub-updater/SKILL.md
def func(param: str, optional: int = ...) -> bool: ...
class Example:
attr: ClassVar[int]
def method(self) -> None: ...| Tool | Mode | Notes |
|---|---|---|
| Mypy | strict | See pyproject.toml for disabled error codes |
| Pyrefly | strict | See pyrefly.toml |
| Ruff | ALL | Python 3.12 target |
uv run python instead of python
This project uses uv for dependency management. Running Python scripts directly will fail due to missing dependencies.
# ✓ Correct
uv run python -c "import socketio; print(socketio.__version__)"
uv run python script.py
# ✗ Wrong - dependencies not available
python -c "import socketio; print(socketio.__version__)"
python script.pyAll Python commands in this document follow this convention.
Read the affected module's tests and related tests first; match their scope and style. Confirm runtime signatures and behavior before updating stubs, using upstream source and temporary checks as needed. Do not turn those checks into permanent upstream behavior tests (connections, room state, transitions) in this repository.
Follow existing patterns for API presence, signatures, and types, including
return types (assert_type before isinstance). Checking a returned value's
type is stub validation, not a reason to add upstream behavior scenarios.
Do not replace the existing test structure with TYPE_CHECKING-only helpers.
# 1. Confirm runtime signatures and behavior (source/temporary checks)
uv run python -c "import inspect; from socketio.mod import X; print(inspect.signature(X))"
# 2. Write/update stub (.pyi)
# 3. Write tests
# 4. Validate (ALL must pass)
uv run poe lint
uv run poe mypy
uv run poe pyrefly
uv run pytest src/tests/test_<module>.py -v"""Tests for socketio.<module> stub types."""
from __future__ import annotations
import inspect
from typing import Any, assert_type
import socketio.<module> as modImport Rule: Use single module alias (mod). Only import from other modules when needed for type comparisons.
class TestClassName:
"""Test ClassName type hints."""
def test_exists(self) -> None:
assert hasattr(mod, "ClassName")
assert inspect.isclass(mod.ClassName)
def test_inherits(self) -> None: # if applicable
assert issubclass(mod.ClassName, mod.ParentClass)
def test_init_signature(self) -> None:
sig = inspect.signature(mod.ClassName.__init__)
params = list(sig.parameters.keys())
assert params == ["self", "param1", "param2"]
def test_attributes(self) -> None:
obj = mod.ClassName(...)
assert_type(obj.attr, int) # stub check FIRST
assert isinstance(obj.attr, int) # runtime check SECOND- Missing parameters in stubs
- Extra parameters in stubs that don't exist at runtime
- Wrong parameter order
def test_init_signature(self) -> None:
sig = inspect.signature(mod.ClassName.__init__)
params = list(sig.parameters.keys())
# EXACT match - catches stub/runtime mismatches
assert params == ["self", "param1", "param2", "kwargs"]
def test_method_signature(self) -> None:
sig = inspect.signature(mod.ClassName.method_name)
params = list(sig.parameters.keys())
assert params == ["self", "arg1", "arg2"]Test instance attributes to ensure stub types match runtime types:
def test_instance_attributes(self) -> None:
obj = mod.ClassName(...)
# Test each attribute declared in the stub
assert hasattr(obj, "attr_name")
assert_type(obj.attr_name, ExpectedType) # stub check
# Runtime type check (when value is not None)
if obj.attr_name is not None:
assert isinstance(obj.attr_name, ExpectedType)
def test_optional_attribute(self) -> None:
obj = mod.ClassName(...)
# For Optional[X] or X | None types
assert_type(obj.optional_attr, ExpectedType | None)class TestFunctionName:
"""Test function_name type hints."""
def test_exists(self) -> None:
assert hasattr(mod, "function_name")
assert callable(mod.function_name)
def test_signature(self) -> None:
sig = inspect.signature(mod.function_name)
params = list(sig.parameters.keys())
# EXACT match required
assert params == ["param1", "param2", "kwargs"]
def test_return_type(self) -> None:
result = mod.function_name(...)
assert_type(result, ExpectedType) # stub check FIRST
assert isinstance(result, ExpectedType) # runtime check SECONDFor class methods, verify signatures match runtime exactly:
def test_method_signature(self) -> None:
sig = inspect.signature(mod.ClassName.method_name)
params = list(sig.parameters.keys())
# Verify exact parameter list
assert params == ["self", "event", "data", "namespace", "timeout"]
def test_method_has_parameter(self) -> None:
sig = inspect.signature(mod.ClassName.method_name)
# Check specific parameter exists
assert "timeout" in sig.parameters
# Check parameter default if relevant
param = sig.parameters["timeout"]
assert param.default is None # Verify default matches stubType aliases require both type and identity verification:
class TestTypeAlias:
"""Test TypeAlias assignment."""
def test_exists(self) -> None:
assert hasattr(mod, "TypeAlias")
def test_type(self) -> None:
assert_type(mod.TypeAlias, type[expected_type])
assert mod.TypeAlias is expected_typeCustom NamedTuples require thorough field and attribute testing:
class TestCustomNamedTuple:
"""Test CustomNamedTuple type."""
def test_exists(self) -> None:
assert hasattr(mod, "CustomNamedTuple")
def test_is_namedtuple(self) -> None:
assert hasattr(mod.CustomNamedTuple, "_fields")
assert issubclass(mod.CustomNamedTuple, tuple)
def test_fields(self) -> None:
assert mod.CustomNamedTuple._fields == ("field1", "field2", "field3")
def test_field1_type(self) -> None:
instance = mod.CustomNamedTuple(field1=..., field2=..., field3=...)
assert_type(instance.field1, ExpectedType)
# Runtime check if applicable
def test_field2_type(self) -> None:
instance = mod.CustomNamedTuple(field1=..., field2=..., field3=...)
assert_type(instance.field2, ExpectedType)Test both the callable and what it returns:
class TestFactory:
"""Test factory function."""
def test_exists(self) -> None:
assert hasattr(mod, "factory")
assert callable(mod.factory)
def test_returns_callable(self) -> None:
result = mod.factory(...)
assert callable(result)
def test_returned_callable_result(self) -> None:
wrapper = mod.factory(...)
result = wrapper(...)
assert_type(result, ExpectedType)
assert isinstance(result, ExpectedType)| Rule | Description |
|---|---|
| assert_type first | Always before isinstance (narrowing hides errors) |
| Dual validation | assert_type (stub) + isinstance (runtime) for values |
| Exact signature match | Signature tests must use == ["param1", "param2"], not in params |
| Runtime-only | hasattr, issubclass, inspect.isclass (boolean results) |
| Single import | import socketio.x as mod, access via mod.Y |
| Test all fields | NamedTuples: test each field's type individually |
| Test instance attrs | Verify all stub-declared instance attributes exist and have correct types |
# ❌ WRONG - "in" doesn't catch extra/missing params
assert "param1" in params
# ✅ CORRECT - exact match catches stub/runtime mismatches
assert params == ["self", "param1", "param2"]
# ❌ WRONG - doesn't verify attribute exists at runtime
assert_type(obj.attr, int)
# ✅ CORRECT - verify both existence and type
assert hasattr(obj, "attr")
assert_type(obj.attr, int)All must pass before completion:
uv run poe lint # ✓ Ruff lint + format
uv run poe mypy # ✓ Type check (mypy)
uv run poe pyrefly # ✓ Type check (pyrefly)
uv run pytest tests/test_<module>.py -v # ✓ Tests pass