Open s22chan opened 2 years ago
Good evening,
Could you provide full code example which cause en error with library you mention?
I would try to figure out how to fix it.
Best regards, Artem.
from dependencies import Injector
from lazy_object_proxy import Proxy
class Outer:
def __init__(self, inner):
self.inner = inner
class Inner:
def __init__(self):
print("inner")
class Root(Injector):
outer = Outer
inner = Inner
Ideally, Root.outer
would assign the inner proxy to outer, which will defer any resource allocation until the outer.inner
attribute is actually used;
but calling isinstance(inner, _IsScope)
calls
https://github.com/ionelmc/python-lazy-object-proxy/blob/03003b012feef472b4bb54b971a8f4782a41f93f/src/lazy_object_proxy/slots.py#L128
which instantiates at
https://github.com/ionelmc/python-lazy-object-proxy/blob/03003b012feef472b4bb54b971a8f4782a41f93f/src/lazy_object_proxy/slots.py#L106.
I understand that dependencies
can't be expected to support all these little hacks, so unless there's an easy solution, I'll look into other libraries/custom code to make virtual proxies. Thanks again!
Good morning,
I did some initial testing for lazy_object_proxy
library. Generally, I'm interested in support of such libraries.
What I have at that time:
>>> from dependencies import Injector
>>> from lazy_object_proxy import Proxy
>>> class Inner:
... def __init__(self, x):
... print('x', x)
...
>>> class Container(Injector):
... a = Proxy
... factory = Inner
... x = 1
...
Traceback (most recent call last):
...
_dependencies.exceptions.DependencyError: Proxy.__init__ have arbitrary argument list and keyword arguments
Due to implementation on C layer.
This could be solved in the future with shield
object #487
Speaking about early instantiation, I could confirm it :cry:
>>> from lazy_object_proxy import Proxy
>>> from dependencies import Injector
>>> class Inner:
... def __init__(self, x):
... print('x', x)
...
>>> class Container(Injector):
... a = Proxy
... factory = Inner
... x = 1
...
>>> Container.a
x 1
<Proxy at 0x7fbdfb7a5840 with factory <__main__.Inner object at 0x7fbdfb7ced10>>
In that case I see two approaches to workaround this problem.
First of all, you could try to wrap Injector itself into lazy proxy.
>>> class Container(Injector):
... inner = Inner
... x = 1
...
>>> Proxy(lambda: Container.inner)
<Proxy at 0x7fbdfb4b7f40 with factory <function <lambda> at 0x7fbdfb67e950>>
>>> str(Proxy(lambda: Container.inner))
x 1
'<__main__.Inner object at 0x7fbdfb7ced10>'
Or better rewrite your classes to avoid resource allocation inside constructor.
class Inner:
def __init__(self, socket):
...
@classmethod
def connect(cls, host, port):
socket = make_connection(host, port)
return cls(socket)
I would recommend this talk https://www.youtube.com/watch?v=FThx_Jk24Rc
What do you think?
sorry I realize I didn't complete the example:
class Root(Injector):
outer = Outer
@value
def inner():
return Proxy(Inner)
is how I would use it, so I would've liked the wiring of the proxy to be defined by the Injector. Not sure how I would use a Proxied injector in this case to supply the argument to Outer
Yeah I totally agree that the constructors should be lightweight, but I'm refactoring a rather large code-base and would like to be doing this baby steps at a time. Thanks for the video talk.
Indeed, Proxy(Injector())
could be used only to wrap main injector. This solution does not work with nested Injectors.
I just tried to reproduce example you provide:
from dependencies import Injector, value
from lazy_object_proxy import Proxy
class Inner:
def __init__(self, x):
print("inner")
self.x = x
def do(self):
return self.x
class Outer:
def __init__(self, inner):
print("outer")
self.inner = inner
def do(self):
return self.inner.do()
class Container(Injector):
outer = Outer
@value
def inner(x):
return Proxy(lambda: Inner(x))
x = 1
>>> o = Container.outer
outer
>>> o.do()
inner
1
Looks like it kinda works :thinking:
odd I'm not sure why I get a different result running your sample. I'll debug it later. Thanks again for the great support:
In [2]: o = Container.outer
inner
outer
Quick suggestion: try both ipython
and python -i
consoles. It could introduce additional magic.
I've tried both, it still outputs inner. I've also tried python 3.7..3.9. The only time I don't see this is if I rollback dependencies to 6.0.1 (from 7.1.7)
I'll update it if I can see what's going on later (I'm also using lazy-objects-proxy==1.7.1)
That's because I'm an idiot.
My system has python 3.10 by default, most recent dependencies release specified 3.9 as supported, so pip
decided to install 3.0.0
version as most compatible.
Sorry it takes me too long to get back to this issue.
I could confirm Proxy
object does eager initialization in the example I post previously.
>>> from dependencies import Injector, value
>>> from lazy_object_proxy import Proxy
>>> class Inner:
... def __init__(self, x):
... print("inner")
... self.x = x
... def do(self):
... return self.x
...
>>> class Outer:
... def __init__(self, inner):
... print("outer")
... self.inner = inner
... def do(self):
... return self.inner.do()
...
>>> class Container(Injector):
... outer = Outer
... @value
... def inner(x):
... return Proxy(lambda: Inner(x))
... x = 1
...
>>> o = Container.outer
inner
outer
>>> o.do()
1
>>>
dependencies==7.1.7
lazy-object-proxy==1.7.1
I found the way to workaround isinstance
check you mention it the very first message.
from dependencies import Injector, value
from lazy_object_proxy import Proxy as _Proxy
class Inner:
def __init__(self, x):
print("inner")
self.x = x
def do(self):
return self.x
class Outer:
def __init__(self, inner):
print("outer")
self.inner = inner
def do(self):
return self.inner.do()
class Proxy(_Proxy):
@property
def __class__(self):
return Proxy
class Container(Injector):
outer = Outer
@value
def inner(x):
return Proxy(lambda: Inner(x))
x = 1
>>> from t import Container
>>> o = Container.outer
outer
>>> o.do()
inner
1
>>>
I'll include this example into documentation later today, since it's not obvious how to solve it.
Thanks Artem, that's amazing!
I need to use some virtual proxies for some complex classes and https://github.com/ionelmc/python-lazy-object-proxy provides a no effort pluggable solution.
Unfortunately, https://github.com/proofit404/dependencies/blob/697f97c925419ad034efe7b416611f51fc80f97d/src/_dependencies/objects/classes.py#L36-L38 triggers the instantiation.
I was wondering if there's a way to get around this, or will I have to make custom proxies for each class?
Great library by the way, really appreciate how much effort you're putting into supporting it.