RemoteAttrib is a descriptor that allows object attributes to transparently map to remote operations such as API calls, RPC methods, or external services.
It lets you read, write, and delete attributes while automatically calling the appropriate remote logic — with optional caching.
Using @property for remote data quickly becomes painful:
- No argument forwarding
- No caching
- Large, repetitive code
- Hard to compose or reuse
RemoteAttrib solves this by turning remote calls into attributes.
- Attribute-style access (
obj.value) - Remote getter / setter / deleter
- Optional per-instance caching (TTL-based)
- Lambda-friendly API
- Strong typing (
Generic[T]) - Clean, declarative class definitions
class User:
def __init__(self, user_id: int):
self.id = user_id
name = RemoteAttrib[str](
getter=lambda s: api_get(s.id, "name"),
setter=lambda s, v: api_set(s.id, "name", v),
cache_timeout=5,
)u = User(42)
print(u.name) # Remote fetch
print(u.name) # Cached
u.name = "Alice" # Remote updatestatus = RemoteAttrib[str](
getter=lambda s: api_get(s.id, "status")
)print(user.status) # OK
user.status = "x" # AttributeErrortrigger = RemoteAttrib[None](
setter=lambda s, v: api_trigger(s.id, v)
)user.trigger = "refresh"
print(user.trigger) # AttributeErrorNo setter, no remote storage — just composition:
fullname = RemoteAttrib[str](
getter=lambda s: f"{s.first_name} {s.last_name}"
)This behaves like a compact, reusable @property.
Each instance has an internal cache:
instance._remote_attrib_cache-
Cache is per instance
-
Cache entry format:
{ "attr_name": (value, timestamp) } -
Automatically expires after
cache_timeout -
Automatically invalidated on:
__set____delete__
Need to pass parameters to remote calls?
email = RemoteAttrib[str](
getter=lambda s, field: api_get(s.id, field),
setter=lambda s, v, field: api_set(s.id, field, v),
getter_args=("email",),
setter_args=("email",),
)token = RemoteAttrib[str](
getter=lambda s: api_get(s.id, "token"),
deleter=lambda s: api_delete(s.id, "token"),
)del user.token # Remote delete + cache clearErrors are explicit and predictable:
| Operation | Error |
|---|---|
| No getter | AttributeError |
| No setter | AttributeError |
| No deleter | AttributeError |
No silent failures.
User.name # -> RemoteAttrib[str]Useful for:
- Introspection
- Documentation tools
- Framework integration
Because RemoteAttrib is generic:
name = RemoteAttrib[str](...)Type checkers infer:
user.name # strWorks correctly with:
- Pyright
- Pylance
- MyPy
Use RemoteAttrib when:
- Attributes map to remote systems
- Reads are expensive
- Writes have side effects
- Caching matters
- Clean APIs matter
Don’t use it when:
- Data is purely local
- No side effects exist
- Simpler access is sufficient
- Explicit over magical
- Descriptor-based (no metaclasses)
- Instance-safe caching
- No global state
- Library-friendly defaults
RemoteAttrib gives you:
@propertyergonomics- Remote power
- Caching
- Type safety
- Cleaner classes
All without boilerplate.