wizedispatcher


Namewizedispatcher JSON
Version 0.1.4 PyPI version JSON
download
home_pagehttps://github.com/kairos-xx/wizedispatcher
SummaryRuntime dispatch with decorator-based overload registration.
upload_time2025-08-12 02:38:37
maintainerNone
docs_urlNone
authorJoao Lopes
requires_python>=3.9
licenseMIT License Copyright (c) 2025 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 dispatch overload typing decorator
VCS
bugtrack_url
requirements pytest pytest black ruff pyright
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">
  <img src="https://github.com/kairos-xx/wizedispatcher/raw/main/resources/icon_raster.png" alt="Tree Interval Logo" width="150"/>
    <h1>WizeDispatcher</h1>
  <p><em>A lightweight, version-robust Python runtime dispatch library with powerful overload registration and type-based selection</em></p>

  <a href="https://replit.com/@kairos/wizedispatcher">
    <img src="https://github.com/kairos-xx/wizedispatcher/raw/main/resources/replit.png" alt="Try it on Replit" width="150"/>
  </a>

</div>

## 1. โœจ Features

- ๐ŸŽฏ **Overload Registration via Decorators**  
  Register multiple implementations for the same function, method, or property setter, with **keyword** or **positional** type constraints.

- ๐Ÿ“ **Type Hint Overrides**  
  Overloads can specify types in the decorator to **override** or **partially use** type hints from the function signature.

- โš™ **Partial Type Specification**  
  Missing type constraints in an overload are automatically filled from the fallback/default implementation.

- ๐Ÿ“Š **Weighted Specificity Scoring**  
  Runtime match scoring system is heuristic-based and typing-aware (see Weight-Based Evaluation).

- ๐Ÿ›  **Full Typing Support**  
  `Union`, `Optional`, `Literal`, generic containers (`list[int]`, `tuple[int, ...]`), and callable detection.

- ๐Ÿ“ฆ **Method & Property Support**  
  Works with instance methods, `@classmethod`, `@staticmethod`, and property setters.

- ๐Ÿš€ **Fast Cached Dispatch**  
  Caches previous matches to speed up repeated calls.

- ๐Ÿงฉ **Varargs & Kwargs Handling**  
  Fully supports `*args` and `**kwargs` in overloads, resolving them according to parameter order.

- ๐Ÿ **Version Robust**  
  Works consistently across Python 3.8+ with no dependencies.




## 2. ๐Ÿš€ Quick Start

### 2.1 Basic Usage Example

```python
from wizedispatcher import dispatch

# Fallback
def greet(name: object) -> str:
    return f"Hello, {name}!"

# Keyword constraint
@dispatch.greet(name=str)
def _(name: str) -> str:
    return f"Hello, {name}, nice to meet you."

# Positional constraint
@dispatch.greet(str, int)
def _(name, age) -> str:
    return f"{name} is {age} years old"

print(greet("Alice"))   # Hello, Alice, nice to meet you.
print(greet("Bob", 30)) # Bob is 30 years old
```

## 3. ๐Ÿ“Š Weight-Based Evaluation

### 3.1 Matching and Scoring Overview

WizeDispatcher first **filters** overloads by type **compatibility** and then
**scores** the remaining candidates to pick the most specific one.

#### 3.1.1 Compatibility filter

For each parameter in dispatch order, the runtime value must match the
overloadโ€™s **effective hint**. Matching supports:

- `Union | PEP 604`, `Optional`, `Literal`, `Annotated`, `ClassVar`
- `Type[T]` / `type`, protocols (runtime), `TypedDict`-like classes
- Callables with parameter shapes, containers (`list/tuple/dict/set/...`)
- `TypeVar` / `ParamSpec` (constraints/bounds respected)

> **Overload defaults participate in matching:**  
> If an overload defines a default for a parameter and the caller omitted it,
> the **default value** is used as the value to match/score for that parameter.

#### 3.1.2 Scoring the compatible candidates

For each parameter, we compute:

```
score += specificity(value, hint)
score += (40 if hint is not Any/object/WILDCARD else 20)
```

Then we apply a small **penalty** if the overload uses `*args`:

```
score -= 2  # has VAR_POSITIONAL
```

Finally, the overload with the **highest total score** wins. If multiple
overloads tie, the one **registered first** remains selected (deterministic).
If no overload is compatible, the **original (fallback)** is called.

#### Specificity highlights (per-parameter)

Below is a compact view of the core heuristic used by
`_type_specificity_score(value, hint)`:

| Hint shape                           | Specificity (approx)                  |
|-------------------------------------|---------------------------------------|
| `Literal[...]`                      | **100**                               |
| `Annotated[T, ...]`                 | `1 + specificity(value, T)`           |
| `ClassVar[T]`                       | `specificity(value, T)`               |
| `Union[T1, T2, ...]`                | `max(specificity(...)) - len(Union)`  |
| `Type[T]` / `type[T]`               | `15 + specificity(value, T)`          |
| Bare `Type` / `type`                | `8`                                   |
| `Callable[[args...], ...]`          | `12 + ฮฃ specificity(arg_i)`           |
| `Mapping[K, V]` / `dict[K, V]`      | `20 + specificity(K) + specificity(V)`|
| `Sequence[T]` / iterables           | `16` (unparam) or `18 + spec(T)`      |
| Concrete container w/ params        | `20 + ฮฃ specificity(param_i)`         |
| Unparameterized `Tuple/List/Dict`   | `10`                                  |
| Concrete class `C`                  | `5 + max(0, 50 - mro_distance(value, C))` |
| `Any`, `object`, or `WILDCARD`      | `0`                                   |

> **Note:** The extra **+40 / +20** bonus per param encourages overloads that
> *declare* types (even loosely) over ones that leave things unconstrained.

### 3.2 Example (why one wins)

```python
# Fallback
def greet(name: object) -> str: ...

@dispatch.greet(name=str)          # declares a concrete type for 'name'
def _(name: str) -> str: ...

@dispatch.greet(Any)               # explicitly Any
def _(name) -> str: ...
```

A call `greet("Alice")`:

- `name=str` overload:
  - Specificity for `str` with value `"Alice"`: high (concrete class match)
  - +40 bonus for a concrete (non-Any) hint
- `name=Any` overload:
  - Specificity: 0
  - +20 bonus (declared but Any)

โ†’ The `name=str` overloadโ€™s total is higher, so it wins.

### 3.3 Caching

Selections are cached by the **tuple of runtime parameter types** (in dispatch
order) for fast repeat calls.


## 4. ๐Ÿ“ Type Resolution Precedence

### 4.1 Precedence Rules Overview

WizeDispatcher determines the **effective type** for each parameter using a
clear, three-tier precedence. This governs what is matched and scored.

1) **Decorator overrides function annotations**  
   - `@dispatch.func(a=int)` means: for parameter `a`, **use `int`** even if
     the overload function annotates something else (e.g., `a: str`).  
   - Positional decorator args map by parameter order:
     `@dispatch.func(int, str)` โ†’ first param `int`, second `str`.

2) **If the decorator omits a param, use the overload function annotation**  
   - Example: overload is `def _(a: str, b: bytes) -> ...` and decorator
     is `@dispatch.func(a=int)`. Effective types โ†’ `a=int` (override),
     `b=bytes` (from function).

3) **If both decorator and overload omit a param, fall back to the default**  
   - The **default (original) function** annotations fill any remaining gaps.
   - If the default is also missing an annotation, that param becomes a
     **wildcard** (matches anything) and scores accordingly.

#### 3.1.4 TL;DR Summary
**Decorator > Overload function annotations > Default function annotations > Wildcard**

---

### 4.2 Case 1 โ€” Bare decorator uses overload annotations โ€” Bare decorator: use **overload function annotations**

```python
from wizedispatcher import dispatch

# Default (fallback) function
def process(a: int, b: str, c: float) -> str:
    return f"default: a={a!r}, b={b!r}, c={c!r}"

# Bare decorator โ†’ takes annotations from the overload itself
@dispatch.process
def _(a: int, b: bytes, c: float) -> str:
    return f"overload1: b_is={type(b).__name__}"

print(process(1, b"hi", 2.0))  # โœ… matches overload (b: bytes)
print(process(1, "hi", 2.0))   # โžœ falls back (b is str, not bytes)
```

**Why:** No decorator args were provided, so the overloadโ€™s own annotations
(`b: bytes`) are the effective constraint for matching.

---

### 4.3 Case 2 โ€” Decorator overrides overload annotations โ€” Decorator **overrides** overload annotations

```python
from wizedispatcher import dispatch

def process(a: int, b: str, c: float) -> str:
    return "default"

# Decorator forces a=str, overriding the overload's (a: int)
@dispatch.process(a=str)
def _(a: int, b: bytes, c: float) -> str:
    return "overload2"

print(process("x", b"y", 1.0))  # โœ… matches overload (a must be str)
print(process(1, b"y", 1.0))    # โžœ fallback (a is int, but decorator requires str)
```

**Positional decorator example** (maps by parameter order):

```python
from wizedispatcher import dispatch

def process(a: int, b: str, c: float) -> str:
    return "default"

# Positional mapping โ†’ a=str, b=bytes, c=float
@dispatch.process(str, bytes, float)
def _(a, b, c) -> str:
    return "overload3"

print(process("x", b"y", 1.0))  # โœ… matches overload3
print(process("x", "y", 1.0))   # โžœ fallback (b is str, expected bytes)
```

**Why:** When decorator arguments exist, they **override** the overloadโ€™s
annotations for the covered parameters.

---

### 4.4 Case 3 โ€” Missing on both decorator and overload โ†’ use default โ€” Missing on both decorator and overload โ†’ **use default**

```python
from wizedispatcher import dispatch

# Default provides types for all params
def process(a: int, b: str, c: float) -> str:
    return "default"

# Decorator sets only 'a', overload omits annotation for 'b'
@dispatch.process(a=str)       # no info for 'b' here
def _(a: int, b, c: float) -> str:  # no type for 'b' here either
    return "overload4"

print(process("x", "hello", 1.0))  # โœ… matches overload4
#   effective types: a=str (decorator), b=str (from default), c=float (overload)

print(process("x", 123, 1.0))      # โžœ fallback
#   'b' is int โ€” default says 'b: str', so overload4 is incompatible
```

**Wildcard note:** If the default also lacks an annotation for a parameter,
that parameter becomes a **wildcard** (matches anything but is scored as such).
## 5. ๐Ÿงฉ Partial Type Specification

```python
# Default function defines all parameters
def process(a: int, b: str, c: float) -> str:
    return "default"

# Overload defines only 'a', inherits 'b' and 'c' types from default
@dispatch.process(a=str)
def _(a: str, b, c) -> str:
    return f"a is str, b is {type(b)}, c is {type(c)}"
```

## 6. ๐Ÿ›  Methods & Properties

```python
class Converter:
    @property
    def value(self) -> int:
        return self._value

    @value.setter
    def value(self, val: object) -> None:
        self._value = val  # fallback setter

    @dispatch.value(value=int)
    def _(self, value: int) -> None:
        self._value = value * 10

    @dispatch.value(value=str)
    def _(self, value: str) -> None:
        self._value = int(value)

c = Converter()
c.value = 3
print(c.value)  # 30
c.value = "7"
print(c.value)  # 7
```

## 7. ๐Ÿ“ฆ Installation

```bash
pip install wizedispatcher
```

## 8. ๐Ÿ“š Documentation

- **Wiki**: Complete documentation in `/wizedispatcher_wiki`
- **Examples**: Ready-to-run demos in `/demo`

## 9. ๐Ÿ“ License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file.


## ๐ŸŽฏ How Type Constraints Are Determined

When deciding which types to use for overload matching, **WizeDispatcher**
follows a strict precedence order. This allows you to be as explicit or as
implicit as you like when defining overloads.

#### 3.1.1 No decorator arguments

```python
@dispatch.func
def _(a: int, b: str) -> None:
    ...
```
If the decorator has **no arguments**, the type hints are taken **directly**
from the overload functionโ€™s own signature.

#### 3.1.2 Decorator with arguments

```python
@dispatch.func(a=str)
def _(a: int, b: str) -> None:
    ...
```
If the decorator **has arguments**, those override the type hints for the
specified parameters, **ignoring** the overload function's own hints for those
parameters.

#### 3.1.3 Missing arguments in both decorator and overload

```python
# Default (fallback) function defines all parameters
def func(a: int, b: str) -> None:
    ...

# Overload defines only 'a' in the decorator, leaves 'b' undefined
@dispatch.func(a=str)
def _(a, b) -> None:
    ...
```
If a parameter is **missing** from both the decorator arguments **and** the
overload functionโ€™s type hints, WizeDispatcher uses the type hint from the
**default (fallback) function**.

### Summary Table

| Source                              | Priority |
|-------------------------------------|----------|
| Decorator arguments                 | Highest  |
| Overload function's type hints      | Medium   |
| Default function's type hints       | Lowest   |

This precedence ensures that you can:
- Override only what you need without redefining all types.
- Inherit defaults from the fallback function.
- Use explicit decorator arguments when you want to fully control matching.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kairos-xx/wizedispatcher",
    "name": "wizedispatcher",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "dispatch, overload, typing, decorator",
    "author": "Joao Lopes",
    "author_email": "Joao Lopes <joaoslopes@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/7f/0e/2e610db5f72d5a3d05849a347dca6375cc2a7603285b24fc95ea0b10c65e/wizedispatcher-0.1.4.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n  <img src=\"https://github.com/kairos-xx/wizedispatcher/raw/main/resources/icon_raster.png\" alt=\"Tree Interval Logo\" width=\"150\"/>\n    <h1>WizeDispatcher</h1>\n  <p><em>A lightweight, version-robust Python runtime dispatch library with powerful overload registration and type-based selection</em></p>\n\n  <a href=\"https://replit.com/@kairos/wizedispatcher\">\n    <img src=\"https://github.com/kairos-xx/wizedispatcher/raw/main/resources/replit.png\" alt=\"Try it on Replit\" width=\"150\"/>\n  </a>\n\n</div>\n\n## 1. \u2728 Features\n\n- \ud83c\udfaf **Overload Registration via Decorators**  \n  Register multiple implementations for the same function, method, or property setter, with **keyword** or **positional** type constraints.\n\n- \ud83d\udcdd **Type Hint Overrides**  \n  Overloads can specify types in the decorator to **override** or **partially use** type hints from the function signature.\n\n- \u2699 **Partial Type Specification**  \n  Missing type constraints in an overload are automatically filled from the fallback/default implementation.\n\n- \ud83d\udcca **Weighted Specificity Scoring**  \n  Runtime match scoring system is heuristic-based and typing-aware (see Weight-Based Evaluation).\n\n- \ud83d\udee0 **Full Typing Support**  \n  `Union`, `Optional`, `Literal`, generic containers (`list[int]`, `tuple[int, ...]`), and callable detection.\n\n- \ud83d\udce6 **Method & Property Support**  \n  Works with instance methods, `@classmethod`, `@staticmethod`, and property setters.\n\n- \ud83d\ude80 **Fast Cached Dispatch**  \n  Caches previous matches to speed up repeated calls.\n\n- \ud83e\udde9 **Varargs & Kwargs Handling**  \n  Fully supports `*args` and `**kwargs` in overloads, resolving them according to parameter order.\n\n- \ud83d\udc0d **Version Robust**  \n  Works consistently across Python 3.8+ with no dependencies.\n\n\n\n\n## 2. \ud83d\ude80 Quick Start\n\n### 2.1 Basic Usage Example\n\n```python\nfrom wizedispatcher import dispatch\n\n# Fallback\ndef greet(name: object) -> str:\n    return f\"Hello, {name}!\"\n\n# Keyword constraint\n@dispatch.greet(name=str)\ndef _(name: str) -> str:\n    return f\"Hello, {name}, nice to meet you.\"\n\n# Positional constraint\n@dispatch.greet(str, int)\ndef _(name, age) -> str:\n    return f\"{name} is {age} years old\"\n\nprint(greet(\"Alice\"))   # Hello, Alice, nice to meet you.\nprint(greet(\"Bob\", 30)) # Bob is 30 years old\n```\n\n## 3. \ud83d\udcca Weight-Based Evaluation\n\n### 3.1 Matching and Scoring Overview\n\nWizeDispatcher first **filters** overloads by type **compatibility** and then\n**scores** the remaining candidates to pick the most specific one.\n\n#### 3.1.1 Compatibility filter\n\nFor each parameter in dispatch order, the runtime value must match the\noverload\u2019s **effective hint**. Matching supports:\n\n- `Union | PEP 604`, `Optional`, `Literal`, `Annotated`, `ClassVar`\n- `Type[T]` / `type`, protocols (runtime), `TypedDict`-like classes\n- Callables with parameter shapes, containers (`list/tuple/dict/set/...`)\n- `TypeVar` / `ParamSpec` (constraints/bounds respected)\n\n> **Overload defaults participate in matching:**  \n> If an overload defines a default for a parameter and the caller omitted it,\n> the **default value** is used as the value to match/score for that parameter.\n\n#### 3.1.2 Scoring the compatible candidates\n\nFor each parameter, we compute:\n\n```\nscore += specificity(value, hint)\nscore += (40 if hint is not Any/object/WILDCARD else 20)\n```\n\nThen we apply a small **penalty** if the overload uses `*args`:\n\n```\nscore -= 2  # has VAR_POSITIONAL\n```\n\nFinally, the overload with the **highest total score** wins. If multiple\noverloads tie, the one **registered first** remains selected (deterministic).\nIf no overload is compatible, the **original (fallback)** is called.\n\n#### Specificity highlights (per-parameter)\n\nBelow is a compact view of the core heuristic used by\n`_type_specificity_score(value, hint)`:\n\n| Hint shape                           | Specificity (approx)                  |\n|-------------------------------------|---------------------------------------|\n| `Literal[...]`                      | **100**                               |\n| `Annotated[T, ...]`                 | `1 + specificity(value, T)`           |\n| `ClassVar[T]`                       | `specificity(value, T)`               |\n| `Union[T1, T2, ...]`                | `max(specificity(...)) - len(Union)`  |\n| `Type[T]` / `type[T]`               | `15 + specificity(value, T)`          |\n| Bare `Type` / `type`                | `8`                                   |\n| `Callable[[args...], ...]`          | `12 + \u03a3 specificity(arg_i)`           |\n| `Mapping[K, V]` / `dict[K, V]`      | `20 + specificity(K) + specificity(V)`|\n| `Sequence[T]` / iterables           | `16` (unparam) or `18 + spec(T)`      |\n| Concrete container w/ params        | `20 + \u03a3 specificity(param_i)`         |\n| Unparameterized `Tuple/List/Dict`   | `10`                                  |\n| Concrete class `C`                  | `5 + max(0, 50 - mro_distance(value, C))` |\n| `Any`, `object`, or `WILDCARD`      | `0`                                   |\n\n> **Note:** The extra **+40 / +20** bonus per param encourages overloads that\n> *declare* types (even loosely) over ones that leave things unconstrained.\n\n### 3.2 Example (why one wins)\n\n```python\n# Fallback\ndef greet(name: object) -> str: ...\n\n@dispatch.greet(name=str)          # declares a concrete type for 'name'\ndef _(name: str) -> str: ...\n\n@dispatch.greet(Any)               # explicitly Any\ndef _(name) -> str: ...\n```\n\nA call `greet(\"Alice\")`:\n\n- `name=str` overload:\n  - Specificity for `str` with value `\"Alice\"`: high (concrete class match)\n  - +40 bonus for a concrete (non-Any) hint\n- `name=Any` overload:\n  - Specificity: 0\n  - +20 bonus (declared but Any)\n\n\u2192 The `name=str` overload\u2019s total is higher, so it wins.\n\n### 3.3 Caching\n\nSelections are cached by the **tuple of runtime parameter types** (in dispatch\norder) for fast repeat calls.\n\n\n## 4. \ud83d\udcd0 Type Resolution Precedence\n\n### 4.1 Precedence Rules Overview\n\nWizeDispatcher determines the **effective type** for each parameter using a\nclear, three-tier precedence. This governs what is matched and scored.\n\n1) **Decorator overrides function annotations**  \n   - `@dispatch.func(a=int)` means: for parameter `a`, **use `int`** even if\n     the overload function annotates something else (e.g., `a: str`).  \n   - Positional decorator args map by parameter order:\n     `@dispatch.func(int, str)` \u2192 first param `int`, second `str`.\n\n2) **If the decorator omits a param, use the overload function annotation**  \n   - Example: overload is `def _(a: str, b: bytes) -> ...` and decorator\n     is `@dispatch.func(a=int)`. Effective types \u2192 `a=int` (override),\n     `b=bytes` (from function).\n\n3) **If both decorator and overload omit a param, fall back to the default**  \n   - The **default (original) function** annotations fill any remaining gaps.\n   - If the default is also missing an annotation, that param becomes a\n     **wildcard** (matches anything) and scores accordingly.\n\n#### 3.1.4 TL;DR Summary\n**Decorator > Overload function annotations > Default function annotations > Wildcard**\n\n---\n\n### 4.2 Case 1 \u2014 Bare decorator uses overload annotations \u2014 Bare decorator: use **overload function annotations**\n\n```python\nfrom wizedispatcher import dispatch\n\n# Default (fallback) function\ndef process(a: int, b: str, c: float) -> str:\n    return f\"default: a={a!r}, b={b!r}, c={c!r}\"\n\n# Bare decorator \u2192 takes annotations from the overload itself\n@dispatch.process\ndef _(a: int, b: bytes, c: float) -> str:\n    return f\"overload1: b_is={type(b).__name__}\"\n\nprint(process(1, b\"hi\", 2.0))  # \u2705 matches overload (b: bytes)\nprint(process(1, \"hi\", 2.0))   # \u279c falls back (b is str, not bytes)\n```\n\n**Why:** No decorator args were provided, so the overload\u2019s own annotations\n(`b: bytes`) are the effective constraint for matching.\n\n---\n\n### 4.3 Case 2 \u2014 Decorator overrides overload annotations \u2014 Decorator **overrides** overload annotations\n\n```python\nfrom wizedispatcher import dispatch\n\ndef process(a: int, b: str, c: float) -> str:\n    return \"default\"\n\n# Decorator forces a=str, overriding the overload's (a: int)\n@dispatch.process(a=str)\ndef _(a: int, b: bytes, c: float) -> str:\n    return \"overload2\"\n\nprint(process(\"x\", b\"y\", 1.0))  # \u2705 matches overload (a must be str)\nprint(process(1, b\"y\", 1.0))    # \u279c fallback (a is int, but decorator requires str)\n```\n\n**Positional decorator example** (maps by parameter order):\n\n```python\nfrom wizedispatcher import dispatch\n\ndef process(a: int, b: str, c: float) -> str:\n    return \"default\"\n\n# Positional mapping \u2192 a=str, b=bytes, c=float\n@dispatch.process(str, bytes, float)\ndef _(a, b, c) -> str:\n    return \"overload3\"\n\nprint(process(\"x\", b\"y\", 1.0))  # \u2705 matches overload3\nprint(process(\"x\", \"y\", 1.0))   # \u279c fallback (b is str, expected bytes)\n```\n\n**Why:** When decorator arguments exist, they **override** the overload\u2019s\nannotations for the covered parameters.\n\n---\n\n### 4.4 Case 3 \u2014 Missing on both decorator and overload \u2192 use default \u2014 Missing on both decorator and overload \u2192 **use default**\n\n```python\nfrom wizedispatcher import dispatch\n\n# Default provides types for all params\ndef process(a: int, b: str, c: float) -> str:\n    return \"default\"\n\n# Decorator sets only 'a', overload omits annotation for 'b'\n@dispatch.process(a=str)       # no info for 'b' here\ndef _(a: int, b, c: float) -> str:  # no type for 'b' here either\n    return \"overload4\"\n\nprint(process(\"x\", \"hello\", 1.0))  # \u2705 matches overload4\n#   effective types: a=str (decorator), b=str (from default), c=float (overload)\n\nprint(process(\"x\", 123, 1.0))      # \u279c fallback\n#   'b' is int \u2014 default says 'b: str', so overload4 is incompatible\n```\n\n**Wildcard note:** If the default also lacks an annotation for a parameter,\nthat parameter becomes a **wildcard** (matches anything but is scored as such).\n## 5. \ud83e\udde9 Partial Type Specification\n\n```python\n# Default function defines all parameters\ndef process(a: int, b: str, c: float) -> str:\n    return \"default\"\n\n# Overload defines only 'a', inherits 'b' and 'c' types from default\n@dispatch.process(a=str)\ndef _(a: str, b, c) -> str:\n    return f\"a is str, b is {type(b)}, c is {type(c)}\"\n```\n\n## 6. \ud83d\udee0 Methods & Properties\n\n```python\nclass Converter:\n    @property\n    def value(self) -> int:\n        return self._value\n\n    @value.setter\n    def value(self, val: object) -> None:\n        self._value = val  # fallback setter\n\n    @dispatch.value(value=int)\n    def _(self, value: int) -> None:\n        self._value = value * 10\n\n    @dispatch.value(value=str)\n    def _(self, value: str) -> None:\n        self._value = int(value)\n\nc = Converter()\nc.value = 3\nprint(c.value)  # 30\nc.value = \"7\"\nprint(c.value)  # 7\n```\n\n## 7. \ud83d\udce6 Installation\n\n```bash\npip install wizedispatcher\n```\n\n## 8. \ud83d\udcda Documentation\n\n- **Wiki**: Complete documentation in `/wizedispatcher_wiki`\n- **Examples**: Ready-to-run demos in `/demo`\n\n## 9. \ud83d\udcdd License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file.\n\n\n## \ud83c\udfaf How Type Constraints Are Determined\n\nWhen deciding which types to use for overload matching, **WizeDispatcher**\nfollows a strict precedence order. This allows you to be as explicit or as\nimplicit as you like when defining overloads.\n\n#### 3.1.1 No decorator arguments\n\n```python\n@dispatch.func\ndef _(a: int, b: str) -> None:\n    ...\n```\nIf the decorator has **no arguments**, the type hints are taken **directly**\nfrom the overload function\u2019s own signature.\n\n#### 3.1.2 Decorator with arguments\n\n```python\n@dispatch.func(a=str)\ndef _(a: int, b: str) -> None:\n    ...\n```\nIf the decorator **has arguments**, those override the type hints for the\nspecified parameters, **ignoring** the overload function's own hints for those\nparameters.\n\n#### 3.1.3 Missing arguments in both decorator and overload\n\n```python\n# Default (fallback) function defines all parameters\ndef func(a: int, b: str) -> None:\n    ...\n\n# Overload defines only 'a' in the decorator, leaves 'b' undefined\n@dispatch.func(a=str)\ndef _(a, b) -> None:\n    ...\n```\nIf a parameter is **missing** from both the decorator arguments **and** the\noverload function\u2019s type hints, WizeDispatcher uses the type hint from the\n**default (fallback) function**.\n\n### Summary Table\n\n| Source                              | Priority |\n|-------------------------------------|----------|\n| Decorator arguments                 | Highest  |\n| Overload function's type hints      | Medium   |\n| Default function's type hints       | Lowest   |\n\nThis precedence ensures that you can:\n- Override only what you need without redefining all types.\n- Inherit defaults from the fallback function.\n- Use explicit decorator arguments when you want to fully control matching.\n\n",
    "bugtrack_url": null,
    "license": "MIT License\n        \n        Copyright (c) 2025\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.\n        ",
    "summary": "Runtime dispatch with decorator-based overload registration.",
    "version": "0.1.4",
    "project_urls": {
        "Documentation": "https://github.com/kairos-xx/wizedispatcher/wiki",
        "Homepage": "https://github.com/kairos-xx/wizedispatcher",
        "Issues": "https://github.com/kairos-xx/wizedispatcher/issues",
        "Repository": "https://github.com/kairos-xx/wizedispatcher.git"
    },
    "split_keywords": [
        "dispatch",
        " overload",
        " typing",
        " decorator"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "52ef59deec5b6e1a4578eb0c63dd61ed49855e1821215a7663af6e5b7848e43d",
                "md5": "1b3b10d6d19285993f0fd1add6397f7d",
                "sha256": "66017347cc10afa5c5566076b3a1a5021d71a1c87435d9f7e6b30e5fbe237afb"
            },
            "downloads": -1,
            "filename": "wizedispatcher-0.1.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1b3b10d6d19285993f0fd1add6397f7d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 19317,
            "upload_time": "2025-08-12T02:38:36",
            "upload_time_iso_8601": "2025-08-12T02:38:36.232771Z",
            "url": "https://files.pythonhosted.org/packages/52/ef/59deec5b6e1a4578eb0c63dd61ed49855e1821215a7663af6e5b7848e43d/wizedispatcher-0.1.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7f0e2e610db5f72d5a3d05849a347dca6375cc2a7603285b24fc95ea0b10c65e",
                "md5": "6569ed872828f091c429bbf6cd9431c2",
                "sha256": "3e52dd10902b3579689e24930babade257dada9c70cad2247da37139a11b094b"
            },
            "downloads": -1,
            "filename": "wizedispatcher-0.1.4.tar.gz",
            "has_sig": false,
            "md5_digest": "6569ed872828f091c429bbf6cd9431c2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 30656,
            "upload_time": "2025-08-12T02:38:37",
            "upload_time_iso_8601": "2025-08-12T02:38:37.115063Z",
            "url": "https://files.pythonhosted.org/packages/7f/0e/2e610db5f72d5a3d05849a347dca6375cc2a7603285b24fc95ea0b10c65e/wizedispatcher-0.1.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-12 02:38:37",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kairos-xx",
    "github_project": "wizedispatcher",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "pytest",
            "specs": [
                [
                    ">=",
                    "7.0.0"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": []
        },
        {
            "name": "black",
            "specs": []
        },
        {
            "name": "ruff",
            "specs": []
        },
        {
            "name": "pyright",
            "specs": []
        }
    ],
    "lcname": "wizedispatcher"
}
        
Elapsed time: 1.47731s