Metadata-Version: 2.4
Name: vcti-predicate
Version: 1.0.7
Summary: VCollab Predicate - condition evaluation engine with extensible operators and modifiers
Author: Visual Collaboration Technologies Inc.
Requires-Python: <3.15,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: lint
Requires-Dist: ruff; extra == "lint"
Dynamic: license-file

# Predicate Evaluator

## Purpose

VCollab applications frequently need to evaluate conditions — "is this
value greater than X?", "does this string contain Y?", "does this list
include Z?" These checks appear in filtering, validation, workflow
conditionals, and routing logic.

The `vcti-predicate` package provides two entry points — `check()` and
`evaluate()` — that resolve the right comparison logic based on the
operand types, apply type-appropriate normalization, and support
extensible operators with group-level and operator-specific options.

This package has **zero external dependencies**.

---

## Installation

```bash
pip install vcti-predicate
```

### In `requirements.txt`

```
vcti-predicate>=1.0.7
```

### In `pyproject.toml` dependencies

```toml
dependencies = [
    "vcti-predicate>=1.0.7",
]
```

---

## Quick Start

```python
from vcti.predicate import check

# ── Binary: check(lhs, symbol, rhs) ──

# String (case-insensitive by default)
check("Hello", "==", "hello")         # True
check("filename.pdf", "$=", "pdf")    # True
check("filename", "?=", "name")       # True

# Integer (exact)
check(5, ">", 3)     # True
check(5, "==", 5)    # True

# Float (with tolerance)
check(1.0, "==", 1.001, tolerance=0.01)   # True

# Case-sensitive via modifier or suffix
check("Hello", "==", "hello", case_sensitive=True)  # False
check("Hello", "^=cs", "Hello")                     # True

# Collection operations
check(2, "@=", [1, 2, 3])                  # True
check(["a", "b"], "all", ["a", "b", "c"])  # True

# Regex matching with options
check("test123", "~=", r"\d+")                          # True
check("line1\nline2", "~=", r"^line2", multiline=True)  # True

# Negation
check("hello", "!^=", "xyz")    # True (does not start with)
check("hello", "!~=", r"\d+")   # True (no digits)
check(4, "!@=", [1, 2, 3])     # True (not in list)

# Range (rhs is a tuple of bounds)
check(5, "between", (1, 10))       # True
check(0, "!between", (1, 10))      # True

# ── Unary: check(value, symbol) ──

check("", "is_empty")           # True
check(None, "exists")           # False
check("/tmp/f.txt", "is_file")  # True (if file exists)
check("/tmp", "is_dir")         # True (if directory exists)
```

---

## Entry Points

| Function | Argument order | Use case |
|----------|---------------|----------|
| `check(lhs, op, rhs?)` | Value-first | Primary user-facing function — binary and unary |
| `evaluate(op, lhs, rhs?)` | Symbol-first | For rule engines and programmatic use |

Both use the same resolution, normalization, and dispatch engine.

---

## Symbol Summary

### Comparison

| Symbol | Alias | Description |
|--------|-------|-------------|
| `==` | `eq` | Equal |
| `!=` | `ne` | Not equal |
| `<` `<=` `>` `>=` | `lt` `le` `gt` `ge` | Ordering |

### String

| Symbol | Alias | Negation | Description |
|--------|-------|----------|-------------|
| `^=` | `startswith` | `!^=` | Starts with |
| `$=` | `endswith` | `!$=` | Ends with |
| `?=` | `contains` | `!?=` | Contains |
| `@=` | `in` | `!@=` | In collection/string |

### Regex

| Symbol | Alias | Negation | Description |
|--------|-------|----------|-------------|
| `~=` | `matches` | `!~=` | Regex search |

### Unary

| Symbol | Description |
|--------|-------------|
| `is_empty` / `exists` / `is_numeric` | Value checks |
| `is_file` / `is_dir` / `path_exists` | Filesystem checks |

### Range

| Symbol | Description |
|--------|-------------|
| `between` / `!between` | Value within bounds (rhs is a tuple) |

### Modifier Suffixes

Append `cs` or `ic` to string symbols for case control:
`^=cs`, `$=ic`, `?=cs`, `@=ic`, `~=cs`

For the complete symbol reference, see the
[Symbol Reference](docs/symbols.md).

---

## Modifiers

Pass modifiers as keyword arguments to control behavior:

```python
check("Hello", "==", "hello", case_sensitive=True)   # False
check(1.0, "==", 1.001, tolerance=0.01)              # True
check(5, "between", (1, 10), inclusive=False)         # True
check("text", "~=", r"^line", multiline=True)        # regex option
```

| Modifier | Groups | Default | Effect |
|----------|--------|---------|--------|
| `case_sensitive` | string, collection, regex | `False` | Case-sensitive comparison |
| `tolerance` | float | `0.0` | Maximum difference for equality |
| `inclusive` | range | `True` | Include bounds in range check |

---

## Documentation

- [Usage Patterns](docs/patterns.md) — Real-world recipes and integration patterns
- [Design](docs/design.md) — Concepts, architecture decisions, and trade-offs
- [Source Guide](docs/source-guide.md) — Execution flow traces for developers
- [Extension Guide](docs/extending.md) — How to add operators, groups, and symbols
- [Symbol Reference](docs/symbols.md) — Complete symbol tables
- [API Reference](docs/api.md) — Autodoc for all modules
