Metadata-Version: 2.3
Name: bilocate
Version: 0.1.0
Summary: Transparent shadow testing for legacy refactors.
Keywords: mimic,mock,testing,asynchronous,synchronous
Author: Wannes Vantorre
Author-email: Wannes Vantorre <vantorrewannes@gmail.com>
License: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.14
Project-URL: Homepage, https://codeberg.org/ProductionCode/bilocate
Project-URL: Repository, https://codeberg.org/ProductionCode/bilocate
Project-URL: Issues, https://codeberg.org/ProductionCode/bilocate/issues
Description-Content-Type: text/markdown

# bilocate 🪞

**Transparent shadow testing for legacy refactors.**

Refactoring critical, legacy "spaghetti" code is terrifying. Standard shadow testing requires standing up API gateways, duplicating traffic via Kafka, or importing heavy JSON-diffing engines just to run V2 alongside V1. `bilocate` solves this at the Python function boundary.

You write your new logic, wrap the old function, and let the runtime natively background and compare the execution.

```bash
uv add bilocate
```

## The Difference

| Concept                | Standard Shadow Testing                  | `bilocate`                            |
| :--------------------- | :--------------------------------------- | :---------------------------------- |
| **Infrastructure**     | API Gateways, message duplication queues | None. Pure Python decorators.       |
| **Diffing Engine**     | Complex JSON serialization / `DeepDiff`  | Native `__eq__` evaluation.         |
| **Latency Impact**     | Network hop duplication                  | Zero. Async naturally backgrounds.  |
| **Telemetry & Alerts** | Custom SDKs (Datadog/Sentry)             | Standard library `warnings` module. |

## Usage

You need exactly one primitive: `@mimic`.

```python
import bilocate
import warnings

# Your shiny, untested V2 logic
def clean_v2_logic(payload):
    return new_pydantic_math(payload)

# 1. Wrap the legacy function.
# The system transparently routes the inputs to V2 in the background.
@bilocate.mimic(clean_v2_logic)
def spaghetti_v1_logic(payload):
    return legacy_dict_math(payload)


# 2. Call the function normally.
# The user gets the V1 response instantly.
result = spaghetti_v1_logic({"user_id": 123})

# CHECKPOINT:
# If clean_v2_logic returns a different value, or if V2 crashes while V1 succeeds,
# bilocate emits a native RuntimeWarning. The user's execution is completely unaffected.
```

## Core Mechanics

- **Native Telemetry:** `bilocate` requires absolutely zero configuration. It doesn't ask for a logger or a statsd client. When a mismatch occurs, it emits a standard `RuntimeWarning`. You can route this to Sentry, Datadog, or your console natively using Python's built-in `logging.captureWarnings(True)`.
- **Flawless Error Diffing:** `bilocate` treats exceptions as values. If V1 returns `None` but V2 raises a `KeyError`, `bilocate` cleanly intercepts the crash, compares the terminal states, and reports the discrepancy without blowing up the user's stack.
- **Native Async Backgrounding:** If your functions are `async`, `bilocate` automatically wraps V2 in a fire-and-forget `asyncio.create_task()`. V1 returns instantly, and V2 processes seamlessly in the background event loop with zero added latency.
- **Zero-Dependency Comparisons:** No heavy JSON serializers or deep-diffing libraries. `bilocate` delegates diffing purely to Python's native `__eq__` contract. If you need to compare a legacy `dict` to a V2 object, just define `__eq__` on your object.
