Metadata-Version: 2.4
Name: typecheck-runtime
Version: 0.1.0
Summary: Tiny runtime checker for typing annotations (dict[str,str], list[T], unions, literals) with an Option-like API.
Project-URL: Homepage, https://github.com/schizza/py-typecheck
Project-URL: Repository, https://github.com/schizza/py-typecheck
Project-URL: Issues, https://github.com/schizza/py-typecheck/issues
Author: Lukas Svoboda
License: MIT
License-File: LICENSE
Keywords: runtime,typecheck,typing,validation
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# typecheck-runtime 

Tiny runtime checker for typing annotations with an Option-like API.

`py-typecheck` solves a very specific problem:

**I have a value (object or Any) and I want to check if
the value refers to specific typing annotation.**

Does not parse data. Does not transforms data.
Just **checks structure and returns refered value** or 
`None` if validation failed.


## Installation

```bash
pip install typecheck-runtime

Python ≥ 3.10
```

---

## Core idea

Main function is `checked`

```python
from py_typecheck import checked
```

Acts like `Option[T]` or Rust-like `Some(T, None)`:
 - returns value if matches the type
 - returns `None` if validation failed

 No exceptions, no side-efects.

---

### Basic usage

```python
value: object = {"a": 1}

if (d := checked(value, dict[str, int])) is not None:
    print(d["a"] + 1)
```

**Important**
- always compare against `None` when using `checked`
- do not rely on truthiness (0, False, [] are valid values!)
- bool is treated as not matching int (so True wont pass as int)

---

## Supported typing constructs

`py-typecheck` supports common runtime-validable constructs from `typing`:

### Primitive types

```python
checked(1, int)          # 1
checked("x", int)        # None
checked(True, int)       # None
```
Note: bool is not considered an int in this library.


### Union (X | Y, typing.Union)

```python
checked(1, int | str)      # 1
checked("x", int | str)    # "x"
checked(1.5, int | str)    # None
```

### List / Set / FrozenSet

```python
checked([1, 2], list[int])           # [1, 2]
checked({1, 2}, set[int])            # {1, 2}
checked(frozenset({1}), frozenset[int])
```

Nested structures work as expected:
```python
checked([[1, 2], [3]], list[list[int]])
```

### Dict

```python
checked({"a": 1}, dict[str, int])
checked({"a": "x"}, dict[str, int])   # None
```

Supports unions and nesting:
```python
checked({"a": [1, 2]}, dict[str, list[int]])
```

### Tuple

Fixed-length:
```python
checked((1, "x"), tuple[int, str])
```

Variadic:
```python
checked((1, 2, 3), tuple[int, ...])
```

### Literal

```python
from typing import Literal

checked(True, Literal[True])    # True
checked(False, Literal[True])   # None
```

### Any
```python
from typing import Any

checked(object(), Any)   # always matches
```
---

## `is_type`

There is also a boolean helper:

```python
from py_typecheck import is_type

if is_type(value, dict[str, int]):
    ...
```

- It returns only True / False.
- For most code paths, checked is preferred, because it avoids
type confusion and double-checking mistakes.

---

### Design principles
- Explicit is better than clever
-	No exceptions for control flow
-	No implicit casting
-	No data mutation
-	No dependency on dataclasses or models
-	One function, one responsibility

This is not a validator framework.
This is a runtime structural check with a safe return value.

### Non-goals

`py-typecheck` intentionally does not:
-	coerce types ("1" → 1)
-	fill defaults
-	validate constraints (ranges, regexes, etc.)
-	replace pydantic or attrs

If you want parsing + validation + coercion → use `Pydantic`.
If you want “is this already the right shape?” → **use this**.

---

## Comparison

|Tool|Purpose|
|-|-|
|isinstance|Runtime type only|
|typing|Static type checking|
|pydantic|Parsing + validation + coercion|
|py-typecheck|Runtime structural check only|

---

## Development status
-	Fully typed (basedpyright strict)
-	Tested against Python 3.10 – 3.13
-	CI + lint + coverage
-	Small surface area, easy to audit

---

License
MIT

