Skip to main content

Temporal Code - Time-native programming where function behavior evolves over time

Project description

Temporal Code

Time-Native Programming for Python

PyPI version Python License: MIT


Temporal Code introduces a programming paradigm where function behavior evolves over time. Instead of deploying new code and flipping a switch, you define multiple variants of a function and let a strategy decide which one runs — gradually shifting traffic, running canary tests, A/B comparisons, or switching at a scheduled time.

Zero external dependencies. Pure Python 3.10+.

Features

  • @evolving decorator — Make any function time-aware with a single line
  • Variant registration — Add new implementations via @func.variant("v2")
  • 4 built-in rollout strategies:
    • GradualStrategy — Linear traffic shift over N days
    • CanaryStrategy — Small % traffic with auto-promote/rollback
    • ABTestStrategy — Even split with comparison reporting
    • ScheduledStrategy — Hard switch at a specific timestamp
  • Automatic fallback — If the new variant throws, falls back to v1
  • Performance tracking — Latency, success rate, call count per variant
  • EvolutionTracker — Persistent JSON Lines log of all evolution events
  • CLI tool (tc) — Inspect evolution history from the terminal

Installation

pip install temporal-code

Quick Start

from temporal_code import evolving

@evolving(start="2026-06-01", duration_days=14)
def rank_results(items):
    """v1: Simple sort."""
    return sorted(items)

@rank_results.variant("v2")
def rank_results_v2(items):
    """v2: ML-powered ranking (gradually takes over in 14 days)."""
    return ml_sort(items)

# Just call it — the strategy picks the variant automatically
results = rank_results(["banana", "apple", "cherry"])

During the 14-day window starting June 1st, traffic gradually shifts from v1 to v2. If v2 raises an exception, v1 handles the request as a fallback.

Strategies

GradualStrategy

Linearly shifts traffic from the old variant to the new one over a configurable duration.

from temporal_code import evolving, GradualStrategy

@evolving(strategy=GradualStrategy(start="2026-06-01", duration_days=7))
def my_func(x):
    return old_logic(x)

@my_func.variant("v2")
def my_func_v2(x):
    return new_logic(x)
Day v1 traffic v2 traffic
0 100% 0%
3 ~57% ~43%
7 0% 100%

CanaryStrategy

Routes a small fixed percentage of traffic to the new variant. Automatically promotes after N successful calls, or rolls back if the success rate drops below a threshold.

from temporal_code import evolving, CanaryStrategy

strategy = CanaryStrategy(
    canary_weight=0.1,         # 10% traffic to new variant
    promote_after=100,         # Decide after 100 calls
    rollback_threshold=0.95,   # Roll back if success < 95%
)

@evolving(strategy=strategy)
def process_payment(amount):
    return legacy_processor(amount)

@process_payment.variant("v2")
def process_payment_v2(amount):
    return new_processor(amount)

# After 100 calls to v2:
# - If success_rate >= 95%: auto-promote v2 to 100%
# - If success_rate < 95%: auto-rollback to v1

ABTestStrategy

Splits traffic evenly (or with custom weights) and collects comparison metrics. Does not auto-promote — you decide based on the report.

from temporal_code import evolving, ABTestStrategy

ab = ABTestStrategy(split=[0.5, 0.5])

@evolving(strategy=ab, name="greeting")
def greet(user):
    return f"Dear {user}, welcome."

@greet.variant("casual")
def greet_casual(user):
    return f"Hey {user}!"

# Run for a while, then check results:
report = ab.report(greet.variants)
# {'variants': [...], 'recommendation': "Recommend 'casual': 100.0% success, 0ms avg"}

ScheduledStrategy

Hard switch at a specific point in time. Before the timestamp, v1 runs; after it, v2 runs.

from temporal_code import scheduled

@scheduled(switch_at="2026-07-01")
def get_pricing(product):
    return {"model": "flat", "price": 99}

@get_pricing.variant("v2")
def get_pricing_v2(product):
    return {"model": "tiered", "base": 49, "premium": 149}

For multi-phase schedules, use the @temporal decorator:

from temporal_code import temporal

@temporal(schedule=[
    ("2026-06-01", "v1"),
    ("2026-07-01", "v2"),
    ("2026-09-01", "v3"),
])
def pricing(item):
    return item.base_price  # v1

EvolutionTracker

Track all evolution events (calls, promotions, rollbacks) to a persistent JSON Lines file:

from pathlib import Path
from temporal_code import EvolutionTracker
from temporal_code.decorators import set_tracker

# Enable persistent tracking
tracker = EvolutionTracker(Path("./evolution_logs"))
set_tracker(tracker)

# All @evolving functions now log to ./evolution_logs/evolution.jsonl
# Query history:
history = tracker.get_history(func_name="rank_results", event_type="call", limit=50)
summary = tracker.summary("rank_results")

Each log entry is a JSON object:

{"event": "call", "function": "rank_results", "variant": "v2", "success": true, "latency_ms": 1.23, "timestamp": "2026-06-05T10:30:00+00:00"}

API Reference

Symbol Type Description
@evolving Decorator Make a function evolve over time
@temporal Decorator Multi-phase scheduled switching
@scheduled Decorator Simple two-phase switch at a timestamp
Variant Class A versioned implementation of a function
VariantResult Dataclass Result of a single variant execution
EvolutionTracker Class Persistent evolution event logger
GradualStrategy Class Linear traffic shift over N days
CanaryStrategy Class Canary deployment with auto-promote/rollback
ABTestStrategy Class A/B split test with reporting
ScheduledStrategy Class Time-based variant switching

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

temporal_code-0.1.0.tar.gz (16.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

temporal_code-0.1.0-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file temporal_code-0.1.0.tar.gz.

File metadata

  • Download URL: temporal_code-0.1.0.tar.gz
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for temporal_code-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a698e90763681c8b3effcbfe8c5f6d3ad27dc853f79d236edb5414b76fc5cdf4
MD5 1f7a24a5398a2339ef914854f42655d1
BLAKE2b-256 bd6649125e814d1b3270145d6105c73b7788d5568b1f162ddd955f2e8df1c5b3

See more details on using hashes here.

File details

Details for the file temporal_code-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: temporal_code-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for temporal_code-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 66374f3251764f6c881caaac874e90b99ed000d49c6da0e849cbdf7d4a30253e
MD5 505b40116a6d5f04d8e9b72e11c98f1c
BLAKE2b-256 66e56bbfa6645f6f77088442663075a1e7f34ad85450948f88fe8c91619f0baf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page