| Name | infer-return-type JSON |
| Version |
0.1.0
JSON |
| download |
| home_page | None |
| Summary | Type inference for generic function return types using formal unification algorithms |
| upload_time | 2025-10-21 21:16:11 |
| maintainer | None |
| docs_url | None |
| author | None |
| requires_python | >=3.11 |
| license | MIT License
Copyright (c) 2025 Andreas Kirsch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. |
| keywords |
generics
python
type-inference
typing
unification
|
| VCS |
 |
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
# Type Inference for Generic Function Return Types
A sophisticated type inference system for Python generic functions that infers concrete return types from runtime arguments using formal unification algorithms. This library solves the fundamental problem of determining what `TypeVar` parameters should be bound to based on actual function arguments.
## Overview
Python's type system allows you to write generic functions with `TypeVar` parameters, but it doesn't provide runtime type inference. This library bridges that gap by analyzing function signatures and runtime arguments to determine concrete return types.
### The Problem
```python
from typing import TypeVar, List
A = TypeVar('A')
def head(items: List[A]) -> A:
"""Get first item from list."""
return items[0]
# What should the return type be?
result = head([1, 2, 3]) # Should be int
result = head(['a', 'b']) # Should be str
```
### The Solution
```python
from infer_return_type import infer_return_type
# Infer that return type is int
result_type = infer_return_type(head, [1, 2, 3])
assert result_type is int
# Infer that return type is str
result_type = infer_return_type(head, ['hello', 'world'])
assert result_type is str
```
## Features
- ✅ **Formal Unification Algorithm**: Implements constraint-based type unification with variance awareness
- ✅ **Comprehensive Generic Support**: Works with built-ins, dataclasses, Pydantic models, and custom generics
- ✅ **Automatic Union Formation**: Creates unions for mixed-type containers (e.g., `int | str`)
- ✅ **Deep Structure Handling**: Supports arbitrarily nested generic structures
- ✅ **TypeVar Validation**: Enforces bounds and constraints with detailed error messages
- ✅ **Type Overrides**: Manual type specification for edge cases (empty containers, etc.)
- ✅ **Variance Awareness**: Handles covariant, contravariant, and invariant positions correctly
- ✅ **Rich Error Messages**: Detailed diagnostics for unification failures and type errors
## Installation
```bash
# Using uv (recommended)
uv pip install -e .
# Or using pip
pip install -e .
# For development
git clone <repository-url>
cd infer_return_type
uv sync # Install dependencies
```
## Usage
### Basic Examples
```python
from typing import TypeVar, List, Dict, Tuple
from infer_return_type import infer_return_type
A = TypeVar('A')
B = TypeVar('B')
# Simple list inference
def merge_lists(a: List[A], b: List[A]) -> List[A]:
return a + b
result_type = infer_return_type(merge_lists, [1, 2], [3, 4])
print(result_type) # <class 'list[int]'>
# Dict with multiple TypeVars
def invert_dict(d: Dict[A, B]) -> Dict[B, A]:
return {v: k for k, v in d.items()}
result_type = infer_return_type(invert_dict, {1: 'a', 2: 'b'})
print(result_type) # <class 'dict[str, int]'>
# Tuple inference
def pair_values(x: A, y: B) -> Tuple[A, B]:
return (x, y)
result_type = infer_return_type(pair_values, 42, "hello")
print(result_type) # <class 'tuple[int, str]'>
```
### Mixed Type Containers
The system automatically creates union types when containers have mixed element types:
```python
def process_mixed(items: List[A]) -> A:
return items[0]
# Automatically creates union types
result_type = infer_return_type(process_mixed, [1, 'hello', 3.14])
print(result_type) # int | str | float
# Works with sets too
def process_set(items: Set[A]) -> A:
return next(iter(items))
result_type = infer_return_type(process_set, {1, 'hello', 3.14})
print(result_type) # int | str | float
```
### Generic Classes
Works seamlessly with dataclasses and Pydantic models:
```python
from dataclasses import dataclass
from pydantic import BaseModel
import typing
# Dataclass example
@dataclass
class Wrap(typing.Generic[A]):
value: A
def unwrap(w: Wrap[A]) -> A:
return w.value
result_type = infer_return_type(unwrap, Wrap[int](42))
print(result_type) # <class 'int'>
# Pydantic example
class Box(BaseModel, typing.Generic[A]):
item: A
def unbox(boxes: List[Box[A]]) -> List[A]:
return [b.item for b in boxes]
result_type = infer_return_type(unbox, [Box[str](item='hello')])
print(result_type) # <class 'list[str]'>
# Nested generic structures
def extract_nested(data: Dict[str, List[Box[A]]]) -> List[A]:
result = []
for boxes in data.values():
result.extend([box.item for box in boxes])
return result
result_type = infer_return_type(
extract_nested,
{"key": [Box[int](item=42), Box[int](item=24)]}
)
print(result_type) # <class 'list[int]'>
```
### Type Overrides
For edge cases like empty containers, you can provide manual type overrides:
```python
# Empty containers - no type information available
def head(items: List[A]) -> A:
return items[0]
# Use type overrides to specify the expected type
result_type = infer_return_type(head, [], type_overrides={A: int})
print(result_type) # <class 'int'>
# Multiple TypeVars
def extract_keys_values(d: Dict[A, B]) -> Tuple[List[A], List[B]]:
return list(d.keys()), list(d.values())
# Override both TypeVars
result_type = infer_return_type(
extract_keys_values,
{},
type_overrides={A: str, B: int}
)
print(result_type) # <class 'tuple[list[str], list[int]]'>
```
### Complex Nested Structures
Handles arbitrarily deep and complex generic structures:
```python
def complex_nested(data: Dict[A, List[B]]) -> Tuple[A, B]:
key = next(iter(data.keys()))
value = data[key][0]
return key, value
result_type = infer_return_type(
complex_nested,
{'key': [1, 2, 3]}
)
print(result_type) # <class 'tuple[str, int]'>
# Multi-level nesting
def deeply_nested(data: Dict[A, List[Dict[B, List[C]]]]) -> Tuple[A, B, C]:
key = next(iter(data.keys()))
inner_dict = data[key][0]
inner_key = next(iter(inner_dict.keys()))
inner_value = inner_dict[inner_key][0]
return key, inner_key, inner_value
result_type = infer_return_type(
deeply_nested,
{'outer': [{'inner': [42]}]}
)
print(result_type) # <class 'tuple[str, str, int]'>
```
## API Reference
### Main Function
```python
infer_return_type(
fn: callable,
*args,
type_overrides: Optional[Dict[TypeVar, type]] = None,
**kwargs
) -> type
```
**Parameters**:
- `fn`: Function with generic type annotations (must have return type annotation)
- `*args`: Positional arguments to the function
- `type_overrides`: Optional dict mapping TypeVars to concrete types for edge cases
- `**kwargs`: Keyword arguments to the function
**Returns**: Concrete type for the return type annotation
**Raises**:
- `ValueError`: If function lacks return type annotation
- `TypeInferenceError`: If types cannot be inferred
### Error Handling
The system provides detailed error messages for common issues:
```python
# Missing return annotation
def no_return_annotation(x: int):
return x
try:
infer_return_type(no_return_annotation, 42)
except ValueError as e:
print(e) # "Function must have return type annotation"
# Type conflicts
def conflicting_types(x: A, y: A) -> A:
return x
try:
infer_return_type(conflicting_types, 1, "hello")
except TypeInferenceError as e:
print(e) # Detailed unification error message
```
## Algorithm
The unification-based algorithm implements formal type inference through constraint solving:
### 1. Constraint Collection
Extracts type constraints by analyzing the structural relationship between annotations and runtime values:
- Direct TypeVar bindings: `A` in annotation matches `int` in value
- Container element constraints: `List[A]` with `[1, 2, 3]` creates `A ~ int`
- Nested structure analysis: Recursively processes complex generic types
### 2. Constraint Solving
Solves the constraint system using unification with variance awareness:
- **Invariant constraints**: Must be exactly the same type
- **Covariant constraints**: Allow union formation for mixed types
- **Override constraints**: Take precedence over other constraints
### 3. Union Formation
Automatically creates unions when multiple types are valid:
- Mixed container elements: `[1, 'hello']` → `int | str`
- Conflicting constraints: `A ~ int` and `A ~ str` → `A ~ int | str`
### 4. Bounds and Constraints Validation
Enforces TypeVar bounds and explicit constraints:
- Bound checking: `TypeVar('T', bound=int)` ensures `T` is a subtype of `int`
- Constraint validation: `TypeVar('T', int, str)` ensures `T` is exactly `int` or `str`
### 5. Type Substitution
Applies solved TypeVar bindings to return type annotations to produce concrete types.
## Current Limitations
Some advanced features are not yet implemented (see skipped tests):
- ⚠️ **Callable Type Inference**: Cannot infer from function signatures yet
- ⚠️ **ForwardRef Handling**: String-based forward references not fully supported
- ⚠️ **typing.Any Support**: The `Any` type is not supported
- ⚠️ **PEP Features**: Literal types (PEP 586), Final annotations (PEP 591), and Annotated types (PEP 593) are not supported
See `test_infer_return_type.py` for tests marked with `@pytest.mark.skip` for detailed examples of current limitations.
## Testing
Run the comprehensive test suite:
```bash
# Run all tests
uv run pytest test_infer_return_type.py -v
# Run only passing tests (skip known limitations)
uv run pytest test_infer_return_type.py -v -k "not skip"
# Run specific test
uv run pytest test_infer_return_type.py::test_basic_containers -v
# Run with coverage
uv run pytest test_infer_return_type.py --cov=. --cov-report=html
# Run all test files
uv run pytest -v
```
**Test Statistics**:
- **50+ passing tests** covering core functionality
- **5 skipped tests** documenting current limitations
- **Total: 55+ comprehensive tests** with detailed examples
**Test Categories**:
- Basic container types (list, dict, tuple, set)
- Generic classes (dataclasses, Pydantic models)
- Union type handling
- TypeVar bounds and constraints
- Complex nested structures
- Error handling and edge cases
## Project Structure
```
infer_return_type/
├── infer_return_type.py # Main implementation (unification algorithm)
├── generic_utils.py # Generic type utilities (structural extraction)
├── test_infer_return_type.py # Main test suite (55+ tests: 50+ passing, 5 skipped)
├── test_generic_utils.py # Utility tests (55 tests passing)
├── test_optimization_pydantic_models.py # Complex Pydantic model tests
├── README.md # This file
├── pyproject.toml # Project configuration
├── uv.lock # Dependency lock file
└── docs/ # Documentation
├── CLEANUP_PLAN.md # Cleanup planning
├── CLEANUP_SUMMARY.md # Cleanup results
├── FINAL_VERIFICATION_REPORT.md # Complete verification
├── IMPLEMENTATION_COMPARISON_SUMMARY.md # Historical comparison
├── MIGRATION_TO_UNIFICATION_GUIDE.md # Migration roadmap
├── TEST_MIGRATION_VERIFICATION.md # Test coverage verification
├── UNIFICATION_GAPS_ANALYSIS.md # Known gaps and fixes needed
└── UNIFICATION_TEST_SUMMARY.md # Test documentation
```
**Key Files**:
- `infer_return_type.py`: Core unification algorithm and type inference engine
- `generic_utils.py`: Structural type extraction utilities for different type systems
- `test_infer_return_type.py`: Comprehensive test suite with examples and edge cases
## Contributing
We welcome contributions! See `docs/MIGRATION_TO_UNIFICATION_GUIDE.md` for the roadmap to address current limitations.
**Priority fixes needed**:
1. **Callable type inference**: Infer from function signatures
2. **ForwardRef handling**: Improve string-based forward reference resolution
3. **typing.Any support**: Add support for the `Any` type
4. **PEP features**: Add support for Literal, Final, and Annotated types
**Development Guidelines**:
- Follow the existing code style and patterns
- Add comprehensive tests for new features
- Update documentation for API changes
- Use `uv` for dependency management
## Development History
This project evolved through three major implementations:
1. **Original**: Simple direct binding approach (removed)
2. **CSP**: Constraint satisfaction problem solver (removed)
3. **Unification**: Current implementation using formal unification algorithms
See `docs/IMPLEMENTATION_COMPARISON_SUMMARY.md` for detailed comparison of approaches.
## License
MIT License
## Related Work
- [PEP 484](https://www.python.org/dev/peps/pep-0484/) - Type Hints
- [PEP 544](https://www.python.org/dev/peps/pep-0544/) - Protocols
- [PEP 585](https://www.python.org/dev/peps/pep-0585/) - Type Hint Generics In Standard Collections
- [Python typing module](https://docs.python.org/3/library/typing.html)
- [Pydantic](https://docs.pydantic.dev/) - Generic model support
- [mypy](https://mypy.readthedocs.io/) - Static type checker
- [pyright](https://github.com/microsoft/pyright) - Type checker for Python
Raw data
{
"_id": null,
"home_page": null,
"name": "infer-return-type",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "generics, python, type-inference, typing, unification",
"author": null,
"author_email": "Andreas Kirsch <andreas.kirsch@example.com>",
"download_url": "https://files.pythonhosted.org/packages/ed/a0/1aa84adaa984bdd5c9b585ce921a0ced103175478cf3e90093f8cb2b7c17/infer_return_type-0.1.0.tar.gz",
"platform": null,
"description": "# Type Inference for Generic Function Return Types\n\nA sophisticated type inference system for Python generic functions that infers concrete return types from runtime arguments using formal unification algorithms. This library solves the fundamental problem of determining what `TypeVar` parameters should be bound to based on actual function arguments.\n\n## Overview\n\nPython's type system allows you to write generic functions with `TypeVar` parameters, but it doesn't provide runtime type inference. This library bridges that gap by analyzing function signatures and runtime arguments to determine concrete return types.\n\n### The Problem\n\n```python\nfrom typing import TypeVar, List\n\nA = TypeVar('A')\n\ndef head(items: List[A]) -> A:\n \"\"\"Get first item from list.\"\"\"\n return items[0]\n\n# What should the return type be?\nresult = head([1, 2, 3]) # Should be int\nresult = head(['a', 'b']) # Should be str\n```\n\n### The Solution\n\n```python\nfrom infer_return_type import infer_return_type\n\n# Infer that return type is int\nresult_type = infer_return_type(head, [1, 2, 3])\nassert result_type is int\n\n# Infer that return type is str \nresult_type = infer_return_type(head, ['hello', 'world'])\nassert result_type is str\n```\n\n## Features\n\n- \u2705 **Formal Unification Algorithm**: Implements constraint-based type unification with variance awareness\n- \u2705 **Comprehensive Generic Support**: Works with built-ins, dataclasses, Pydantic models, and custom generics\n- \u2705 **Automatic Union Formation**: Creates unions for mixed-type containers (e.g., `int | str`)\n- \u2705 **Deep Structure Handling**: Supports arbitrarily nested generic structures\n- \u2705 **TypeVar Validation**: Enforces bounds and constraints with detailed error messages\n- \u2705 **Type Overrides**: Manual type specification for edge cases (empty containers, etc.)\n- \u2705 **Variance Awareness**: Handles covariant, contravariant, and invariant positions correctly\n- \u2705 **Rich Error Messages**: Detailed diagnostics for unification failures and type errors\n\n## Installation\n\n```bash\n# Using uv (recommended)\nuv pip install -e .\n\n# Or using pip\npip install -e .\n\n# For development\ngit clone <repository-url>\ncd infer_return_type\nuv sync # Install dependencies\n```\n\n## Usage\n\n### Basic Examples\n\n```python\nfrom typing import TypeVar, List, Dict, Tuple\nfrom infer_return_type import infer_return_type\n\nA = TypeVar('A')\nB = TypeVar('B')\n\n# Simple list inference\ndef merge_lists(a: List[A], b: List[A]) -> List[A]:\n return a + b\n\nresult_type = infer_return_type(merge_lists, [1, 2], [3, 4])\nprint(result_type) # <class 'list[int]'>\n\n# Dict with multiple TypeVars\ndef invert_dict(d: Dict[A, B]) -> Dict[B, A]:\n return {v: k for k, v in d.items()}\n\nresult_type = infer_return_type(invert_dict, {1: 'a', 2: 'b'})\nprint(result_type) # <class 'dict[str, int]'>\n\n# Tuple inference\ndef pair_values(x: A, y: B) -> Tuple[A, B]:\n return (x, y)\n\nresult_type = infer_return_type(pair_values, 42, \"hello\")\nprint(result_type) # <class 'tuple[int, str]'>\n```\n\n### Mixed Type Containers\n\nThe system automatically creates union types when containers have mixed element types:\n\n```python\ndef process_mixed(items: List[A]) -> A:\n return items[0]\n\n# Automatically creates union types\nresult_type = infer_return_type(process_mixed, [1, 'hello', 3.14])\nprint(result_type) # int | str | float\n\n# Works with sets too\ndef process_set(items: Set[A]) -> A:\n return next(iter(items))\n\nresult_type = infer_return_type(process_set, {1, 'hello', 3.14})\nprint(result_type) # int | str | float\n```\n\n### Generic Classes\n\nWorks seamlessly with dataclasses and Pydantic models:\n\n```python\nfrom dataclasses import dataclass\nfrom pydantic import BaseModel\nimport typing\n\n# Dataclass example\n@dataclass\nclass Wrap(typing.Generic[A]):\n value: A\n\ndef unwrap(w: Wrap[A]) -> A:\n return w.value\n\nresult_type = infer_return_type(unwrap, Wrap[int](42))\nprint(result_type) # <class 'int'>\n\n# Pydantic example\nclass Box(BaseModel, typing.Generic[A]):\n item: A\n\ndef unbox(boxes: List[Box[A]]) -> List[A]:\n return [b.item for b in boxes]\n\nresult_type = infer_return_type(unbox, [Box[str](item='hello')])\nprint(result_type) # <class 'list[str]'>\n\n# Nested generic structures\ndef extract_nested(data: Dict[str, List[Box[A]]]) -> List[A]:\n result = []\n for boxes in data.values():\n result.extend([box.item for box in boxes])\n return result\n\nresult_type = infer_return_type(\n extract_nested, \n {\"key\": [Box[int](item=42), Box[int](item=24)]}\n)\nprint(result_type) # <class 'list[int]'>\n```\n\n### Type Overrides\n\nFor edge cases like empty containers, you can provide manual type overrides:\n\n```python\n# Empty containers - no type information available\ndef head(items: List[A]) -> A:\n return items[0]\n\n# Use type overrides to specify the expected type\nresult_type = infer_return_type(head, [], type_overrides={A: int})\nprint(result_type) # <class 'int'>\n\n# Multiple TypeVars\ndef extract_keys_values(d: Dict[A, B]) -> Tuple[List[A], List[B]]:\n return list(d.keys()), list(d.values())\n\n# Override both TypeVars\nresult_type = infer_return_type(\n extract_keys_values, \n {}, \n type_overrides={A: str, B: int}\n)\nprint(result_type) # <class 'tuple[list[str], list[int]]'>\n```\n\n### Complex Nested Structures\n\nHandles arbitrarily deep and complex generic structures:\n\n```python\ndef complex_nested(data: Dict[A, List[B]]) -> Tuple[A, B]:\n key = next(iter(data.keys()))\n value = data[key][0]\n return key, value\n\nresult_type = infer_return_type(\n complex_nested, \n {'key': [1, 2, 3]}\n)\nprint(result_type) # <class 'tuple[str, int]'>\n\n# Multi-level nesting\ndef deeply_nested(data: Dict[A, List[Dict[B, List[C]]]]) -> Tuple[A, B, C]:\n key = next(iter(data.keys()))\n inner_dict = data[key][0]\n inner_key = next(iter(inner_dict.keys()))\n inner_value = inner_dict[inner_key][0]\n return key, inner_key, inner_value\n\nresult_type = infer_return_type(\n deeply_nested,\n {'outer': [{'inner': [42]}]}\n)\nprint(result_type) # <class 'tuple[str, str, int]'>\n```\n\n## API Reference\n\n### Main Function\n\n```python\ninfer_return_type(\n fn: callable,\n *args,\n type_overrides: Optional[Dict[TypeVar, type]] = None,\n **kwargs\n) -> type\n```\n\n**Parameters**:\n- `fn`: Function with generic type annotations (must have return type annotation)\n- `*args`: Positional arguments to the function\n- `type_overrides`: Optional dict mapping TypeVars to concrete types for edge cases\n- `**kwargs`: Keyword arguments to the function\n\n**Returns**: Concrete type for the return type annotation\n\n**Raises**: \n- `ValueError`: If function lacks return type annotation\n- `TypeInferenceError`: If types cannot be inferred\n\n### Error Handling\n\nThe system provides detailed error messages for common issues:\n\n```python\n# Missing return annotation\ndef no_return_annotation(x: int):\n return x\n\ntry:\n infer_return_type(no_return_annotation, 42)\nexcept ValueError as e:\n print(e) # \"Function must have return type annotation\"\n\n# Type conflicts\ndef conflicting_types(x: A, y: A) -> A:\n return x\n\ntry:\n infer_return_type(conflicting_types, 1, \"hello\")\nexcept TypeInferenceError as e:\n print(e) # Detailed unification error message\n```\n\n## Algorithm\n\nThe unification-based algorithm implements formal type inference through constraint solving:\n\n### 1. Constraint Collection\nExtracts type constraints by analyzing the structural relationship between annotations and runtime values:\n- Direct TypeVar bindings: `A` in annotation matches `int` in value\n- Container element constraints: `List[A]` with `[1, 2, 3]` creates `A ~ int`\n- Nested structure analysis: Recursively processes complex generic types\n\n### 2. Constraint Solving\nSolves the constraint system using unification with variance awareness:\n- **Invariant constraints**: Must be exactly the same type\n- **Covariant constraints**: Allow union formation for mixed types\n- **Override constraints**: Take precedence over other constraints\n\n### 3. Union Formation\nAutomatically creates unions when multiple types are valid:\n- Mixed container elements: `[1, 'hello']` \u2192 `int | str`\n- Conflicting constraints: `A ~ int` and `A ~ str` \u2192 `A ~ int | str`\n\n### 4. Bounds and Constraints Validation\nEnforces TypeVar bounds and explicit constraints:\n- Bound checking: `TypeVar('T', bound=int)` ensures `T` is a subtype of `int`\n- Constraint validation: `TypeVar('T', int, str)` ensures `T` is exactly `int` or `str`\n\n### 5. Type Substitution\nApplies solved TypeVar bindings to return type annotations to produce concrete types.\n\n## Current Limitations\n\nSome advanced features are not yet implemented (see skipped tests):\n\n- \u26a0\ufe0f **Callable Type Inference**: Cannot infer from function signatures yet\n- \u26a0\ufe0f **ForwardRef Handling**: String-based forward references not fully supported\n- \u26a0\ufe0f **typing.Any Support**: The `Any` type is not supported\n- \u26a0\ufe0f **PEP Features**: Literal types (PEP 586), Final annotations (PEP 591), and Annotated types (PEP 593) are not supported\n\nSee `test_infer_return_type.py` for tests marked with `@pytest.mark.skip` for detailed examples of current limitations.\n\n## Testing\n\nRun the comprehensive test suite:\n\n```bash\n# Run all tests\nuv run pytest test_infer_return_type.py -v\n\n# Run only passing tests (skip known limitations)\nuv run pytest test_infer_return_type.py -v -k \"not skip\"\n\n# Run specific test\nuv run pytest test_infer_return_type.py::test_basic_containers -v\n\n# Run with coverage\nuv run pytest test_infer_return_type.py --cov=. --cov-report=html\n\n# Run all test files\nuv run pytest -v\n```\n\n**Test Statistics**:\n- **50+ passing tests** covering core functionality\n- **5 skipped tests** documenting current limitations \n- **Total: 55+ comprehensive tests** with detailed examples\n\n**Test Categories**:\n- Basic container types (list, dict, tuple, set)\n- Generic classes (dataclasses, Pydantic models)\n- Union type handling\n- TypeVar bounds and constraints\n- Complex nested structures\n- Error handling and edge cases\n\n## Project Structure\n\n```\ninfer_return_type/\n\u251c\u2500\u2500 infer_return_type.py # Main implementation (unification algorithm)\n\u251c\u2500\u2500 generic_utils.py # Generic type utilities (structural extraction)\n\u251c\u2500\u2500 test_infer_return_type.py # Main test suite (55+ tests: 50+ passing, 5 skipped)\n\u251c\u2500\u2500 test_generic_utils.py # Utility tests (55 tests passing)\n\u251c\u2500\u2500 test_optimization_pydantic_models.py # Complex Pydantic model tests\n\u251c\u2500\u2500 README.md # This file\n\u251c\u2500\u2500 pyproject.toml # Project configuration\n\u251c\u2500\u2500 uv.lock # Dependency lock file\n\u2514\u2500\u2500 docs/ # Documentation\n \u251c\u2500\u2500 CLEANUP_PLAN.md # Cleanup planning\n \u251c\u2500\u2500 CLEANUP_SUMMARY.md # Cleanup results\n \u251c\u2500\u2500 FINAL_VERIFICATION_REPORT.md # Complete verification\n \u251c\u2500\u2500 IMPLEMENTATION_COMPARISON_SUMMARY.md # Historical comparison\n \u251c\u2500\u2500 MIGRATION_TO_UNIFICATION_GUIDE.md # Migration roadmap\n \u251c\u2500\u2500 TEST_MIGRATION_VERIFICATION.md # Test coverage verification\n \u251c\u2500\u2500 UNIFICATION_GAPS_ANALYSIS.md # Known gaps and fixes needed\n \u2514\u2500\u2500 UNIFICATION_TEST_SUMMARY.md # Test documentation\n```\n\n**Key Files**:\n- `infer_return_type.py`: Core unification algorithm and type inference engine\n- `generic_utils.py`: Structural type extraction utilities for different type systems\n- `test_infer_return_type.py`: Comprehensive test suite with examples and edge cases\n\n## Contributing\n\nWe welcome contributions! See `docs/MIGRATION_TO_UNIFICATION_GUIDE.md` for the roadmap to address current limitations.\n\n**Priority fixes needed**:\n1. **Callable type inference**: Infer from function signatures\n2. **ForwardRef handling**: Improve string-based forward reference resolution\n3. **typing.Any support**: Add support for the `Any` type\n4. **PEP features**: Add support for Literal, Final, and Annotated types\n\n**Development Guidelines**:\n- Follow the existing code style and patterns\n- Add comprehensive tests for new features\n- Update documentation for API changes\n- Use `uv` for dependency management\n\n## Development History\n\nThis project evolved through three major implementations:\n\n1. **Original**: Simple direct binding approach (removed)\n2. **CSP**: Constraint satisfaction problem solver (removed) \n3. **Unification**: Current implementation using formal unification algorithms\n\nSee `docs/IMPLEMENTATION_COMPARISON_SUMMARY.md` for detailed comparison of approaches.\n\n## License\n\nMIT License\n\n## Related Work\n\n- [PEP 484](https://www.python.org/dev/peps/pep-0484/) - Type Hints\n- [PEP 544](https://www.python.org/dev/peps/pep-0544/) - Protocols \n- [PEP 585](https://www.python.org/dev/peps/pep-0585/) - Type Hint Generics In Standard Collections\n- [Python typing module](https://docs.python.org/3/library/typing.html)\n- [Pydantic](https://docs.pydantic.dev/) - Generic model support\n- [mypy](https://mypy.readthedocs.io/) - Static type checker\n- [pyright](https://github.com/microsoft/pyright) - Type checker for Python\n",
"bugtrack_url": null,
"license": "MIT License\n \n Copyright (c) 2025 Andreas Kirsch\n \n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.",
"summary": "Type inference for generic function return types using formal unification algorithms",
"version": "0.1.0",
"project_urls": {
"Homepage": "https://github.com/blackhc/infer-return-type",
"Issues": "https://github.com/blackhc/infer-return-type/issues",
"Repository": "https://github.com/blackhc/infer-return-type"
},
"split_keywords": [
"generics",
" python",
" type-inference",
" typing",
" unification"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "2b5a156bcf2a7ef20a27ee72aacd5dd8ed6804e6d01b06b51f9fcd1b42b49890",
"md5": "28bf2e746a2ee36f698bafe1f6e3efb2",
"sha256": "a563b02c350f16aa502aac3ed52c0b0ff8641153611cb8b0b4f01e0d8971dc56"
},
"downloads": -1,
"filename": "infer_return_type-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "28bf2e746a2ee36f698bafe1f6e3efb2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 28720,
"upload_time": "2025-10-21T21:16:09",
"upload_time_iso_8601": "2025-10-21T21:16:09.760281Z",
"url": "https://files.pythonhosted.org/packages/2b/5a/156bcf2a7ef20a27ee72aacd5dd8ed6804e6d01b06b51f9fcd1b42b49890/infer_return_type-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "eda01aa84adaa984bdd5c9b585ce921a0ced103175478cf3e90093f8cb2b7c17",
"md5": "404e6962ba751e9c3bdbd14cc4c6fb25",
"sha256": "d30fe2cddbf0cea39ba45c0b10bdb13214c90801cfc0daa80689c01a4d66ce27"
},
"downloads": -1,
"filename": "infer_return_type-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "404e6962ba751e9c3bdbd14cc4c6fb25",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 352037,
"upload_time": "2025-10-21T21:16:11",
"upload_time_iso_8601": "2025-10-21T21:16:11.372327Z",
"url": "https://files.pythonhosted.org/packages/ed/a0/1aa84adaa984bdd5c9b585ce921a0ced103175478cf3e90093f8cb2b7c17/infer_return_type-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-21 21:16:11",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "blackhc",
"github_project": "infer-return-type",
"github_not_found": true,
"lcname": "infer-return-type"
}