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 pyright # Type check (strict, pyright)
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
socketio-stub-updater skill located in .github/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 |
| Pyright | strict | See pyrightconfig.json |
| 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.
# 1. Check runtime behavior first
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 pyright
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 pyright # ✓ Type check (pyright)
uv run pytest tests/test_<module>.py -v # ✓ Tests pass