Frequently Asked Questions¶
Open a new issue if you have a question not answered in the FAQ, Guides, or API docs.
Working with Proxies¶
What is resolving my proxy?¶
Certain data structures can unintenionally resolve a proxy.
This is because the Proxy
type forwards all special methods to the target object.
For example, data structures which use the hash of an object, such as set()
or dict()
, will cause a proxy to resolve because proxy.__hash__()
is forwarded to the target object's __hash__()
.
Tip
The cache_defaults=True
and target
flags can be used inside the Proxy
constructor to cache the __hash__
value of the target which will make the proxy hashable without needing to be resolved first.
This only applies to hashable target objects.
Similarly, passing populate_target=True
to Store.proxy()
will automatically set these flags on the returned proxy.
There are a few mechanisms for determining when a proxy is getting resolved while debugging.
- Use
is_resolved()
. - Use a fake factory which raises an error to halt the program and get a traceback at the point the proxy was resolved.
- Proxies created via a
Store
will produceDEBUG
level logs when a proxy is created and resolved. EnablingDEBUG
level logging can help determine when or how often a proxy is getting resolved. Look for thePUT
andGET
messages indicating a target object was put in the store when creating the proxy and when the target object is retrieved when the proxy is resolved, respectively.
How do I serialize a proxy?¶
A Proxy
can be serialized using most common serializers.
Importantly, only the factory of the proxy will be serialized, not the target object. This means that the factory must be serializable (lambda functions, for example, are not serializable with pickle), and the serialized size of the proxy is a function of the factory and not the target object. This typically means that proxies can be very efficiently serialized. For example, here the target object is a large 10,000 character string but the serialized proxy is less than 200 bytes.
Runtime Type Checking¶
How do I check the type of a proxy?¶
To check if an object is a proxy, use isinstance(obj, Proxy)
.
This will not resolve the proxy.
Checking the type of a proxy's target object requires more care because isinstance(proxy, MyType)
will resolve the proxy.
This can be avoided by doing a direct type comparisons (e.g., type(proxy) == MyType)
) but this will mean that type comparisons with subclasses will not work.
If the target object is known when creating a proxy, the cache_defaults
and target
parameters can be used to cache the type of the target so that isinstance
checks do not need to resolve the proxy.
- Passing
target=value
will create a proxy that is already resolved. Deleting the wrapped target object will "unresolve" the proxy. isinstance
can be used safely because the__class__
value of the target was cached inside the proxy instance.
Why does isinstance()
behave differently with proxies?¶
Generally, isinstance()
works the same with proxies as with other types.
However, there are some edge cases where behavior is different.
This is most common with special generic alias types such as typing.Mapping
or typing.Sequence
.
Consider the following example, where a Proxy
with a dict
target object is an instance of dict
but not typing.Mapping
.
Here, the isinstance()
check fails with the aliased type typing.Mapping
but succeeds with the ABC collections.abc.Mapping
.
If you encounter a similar issue, try replacing the deprecated typing
aliases with the types defined in collections.abc
.
An alternative solution is to extract()
the proxy before type checking.
This will incur the cost of resolving the proxy, if it was not already resolved, but isinstance()
checks will often resolve a proxy anyways.
See the related discussion on checking the type of a proxy.
The isinstance(my_dict, Proxy)
check is not necessary in this specific example as we know my_dict
is a Proxy
instance.
However, this pattern is useful in the general case where you may have a type T
or a Proxy[T]
.
Static Type Checking¶
How do I annotate a proxy type?¶
The Proxy
is a generic type on its target object, and mypy will infer the correct type of the target from the provided factory function.
For example, the extract()
function is annotated as follows.
In the event a proxy's type is ambiguous, an annotation can be provided directly.
For example, this is the case with Store.proxy_from_key()
because the type system cannot infer the target type from a key which is a tuple of metadata.
Can mypy infer attributes of a proxied type?¶
In general, no.
Attributes and methods of an object of type T
, accessed indirectly via a Proxy[T]
, are ambiguous to mypy and will typically resolve to Any
.
However, ProxyStore provides a mypy plugin that, when enabled, will help mypy resolve types related to proxies correctly. Check out the mypy plugin to learn more.
ProxyStore Endpoints¶
Why are my endpoints not working?¶
Check out the Endpoints Debugging Guide.