Module xinject.proxy
Used to have a normal looking object that can be imported directly into other modules and used.
It will in reality, always lookup currently active version of a Dependency and use that each time it's asked anything.
This makes it 'act' like the current version of some dependency, code and just use it like a normal object.
See one of these for more details:
- Active Dependency Proxy - pydoc
- [Active Dependency Proxy - github] (https://github.com/xyngular/py-xinject#active-dependecy-proxy#documentation)
Expand source code
"""
Used to have a normal looking object that can be imported directly into other modules and used.
It will in reality, always lookup currently active version of a Dependency and use that each
time it's asked anything.
This makes it 'act' like the current version of some dependency,
code and just use it like a normal object.
See one of these for more details:
- [Active Dependency Proxy - pydoc](./#active-dependency-proxy)
- [Active Dependency Proxy - github]
(https://github.com/xyngular/py-xinject#active-dependecy-proxy#documentation)
"""
from typing import TypeVar, Type, Generic, Callable, Any
from .dependency import Dependency
D = TypeVar('D')
class CurrentDependencyProxy(Generic[D]):
"""
Used to simplify accessing the current dependency class via proxy object,
so you can use the object like a normal global-object, but every time you access a
normal (non-private) attribute/method it will grab you the one from the currenly active
dependency.
>>> class MyClass(Dependency):
... def my_method(self):
... pass
Typically, to access attributes of a particular dependency subclass you would have to do this:
>>> MyClass.grab().my_method()
With ProxyActive you can do this instead:
>>> my_class = CurrentDependencyProxy.wrap(MyClass)
>>> my_class.my_method()
This will always call the active/current dependency without having to use the boilerplate
`.dependency()` method on the dependency class/type.
>>> # You can use the `proxy` convenience
>>> # method to also accomplish this:
>>> my_class = MyClass.proxy()
It's sometimes useful to put at the top-level of a module the proxy-version of the dependency
so it can be directly imported into other modules, and used directly like a normal object.
>>> # We are in some other Module;
>>> # import the 'my_class' we defined above.
>>> from my_class_module import my_class
>>>
>>> my_class.my_method()
"""
@classmethod
def wrap(cls, dependency_type: Type[D]) -> D:
""" Just like init'ing a new object with `dependency_type`....
Except this will preserve
the type-hinting, and tell things that care about the type (like an IDE) that
what's returned from here should act like an instance of the `dependency_type` passed
into this method.
A simpler/alternate way to wrap a Dependency with a `CurrentDependencyProxy` is via the
`xinject.dependency.Dependency.proxy` convenience method.
"""
# noinspection PyTypeChecker
return cls(dependency_type=dependency_type)
def __init__(
self, dependency_type: Type[D],
grabber: Callable[[D], Any] = None,
repr_info: str = None
):
"""
See `CurrentDependencyProxy` for and overview. Init method doc below.
## Init Method
When you create a CurrentDependencyProxy, you pass in the `dependency_type` you want
it to proxy.
Will act like the current/active object of Dependency type `dependency_type`.
you can optionally provide a grabber function, that will be called with the current
dependency passed to it. You can then grab something from that dependency and return it.
If you pass in a grabber function, this ProxyActive will act like a proxy of whatever
is returned from the grabber method.
Args:
dependency_type: Type of dependency to proxy.
grabber: Optional callable, if you wish to grab a specific attribute off the dependency
and act like a proxy for that, you can pass in a method here to do so.
Whatever is returned from the grabber is what is used to as the object to 'proxy'.
repr_info: Will provide this additional info if self gets `repr()` called on it
(ie: if used/shown in debugger, etc).
Example: Currently used to show the attribute-name/info being proxied when you use
`xinject.dependency.Dependency.proxy_attribute`.
"""
# Would give unusual error later on, lets just check right now!
if not issubclass(dependency_type, Dependency):
raise Exception(
f"Must pass a xinject.Dependency subtype to xinject.ProxyActive.wrap, "
f"I was given a ({dependency_type}) instead."
)
self._dependency_type = dependency_type
self._grabber = grabber
self._repr_info = repr_info
pass
def _get_active(self):
# Get current/active instance of dependency type
value = self._dependency_type.grab()
if self._grabber:
return self._grabber(value)
return value
def __getattribute__(self, name):
# Anything the starts with a `_` is something that we want to get/set on self,
# and not on the current config object.
if name.startswith('_'):
return super().__getattribute__(name)
return getattr(self._get_active(), name)
def __setattr__(self, key, value):
if key.startswith('_'):
# Anything the starts with a `_` is something that we want to get/set on self,
# and not on the current config object.
return super().__setattr__(key, value)
# Otherwise, we set it on the current/active dependency object.
return setattr(self._get_active(), key, value)
def __repr__(self):
info = ''
if repr_info := self._repr_info:
info = f'({repr_info})'
return f'CurrentDependencyProxy{info}<{self._get_active().__repr__()}>'
def __str__(self):
return self._get_active().__str__()
def __getitem__(self, key):
return self._get_active().__getitem__(key)
def __setitem__(self, key, value):
return self._get_active().__setitem__(key, value)
Classes
class CurrentDependencyProxy (dependency_type: Type[~D], grabber: Callable[[~D], Any] = None, repr_info: str = None)
-
Used to simplify accessing the current dependency class via proxy object, so you can use the object like a normal global-object, but every time you access a normal (non-private) attribute/method it will grab you the one from the currenly active dependency.
>>> class MyClass(Dependency): ... def my_method(self): ... pass
Typically, to access attributes of a particular dependency subclass you would have to do this:
>>> MyClass.grab().my_method()
With ProxyActive you can do this instead:
>>> my_class = CurrentDependencyProxy.wrap(MyClass) >>> my_class.my_method()
This will always call the active/current dependency without having to use the boilerplate
.dependency()
method on the dependency class/type.>>> # You can use the <code>proxy</code> convenience >>> # method to also accomplish this: >>> my_class = MyClass.proxy()
It's sometimes useful to put at the top-level of a module the proxy-version of the dependency so it can be directly imported into other modules, and used directly like a normal object.
>>> # We are in some other Module; >>> # import the 'my_class' we defined above. >>> from my_class_module import my_class >>> >>> my_class.my_method()
See
CurrentDependencyProxy
for and overview. Init method doc below.Init Method
When you create a CurrentDependencyProxy, you pass in the
dependency_type
you want it to proxy.Will act like the current/active object of Dependency type
dependency_type
. you can optionally provide a grabber function, that will be called with the current dependency passed to it. You can then grab something from that dependency and return it. If you pass in a grabber function, this ProxyActive will act like a proxy of whatever is returned from the grabber method.Args
dependency_type
- Type of dependency to proxy.
grabber
- Optional callable, if you wish to grab a specific attribute off the dependency and act like a proxy for that, you can pass in a method here to do so. Whatever is returned from the grabber is what is used to as the object to 'proxy'.
repr_info
- Will provide this additional info if self gets
repr()
called on it (ie: if used/shown in debugger, etc). Example: Currently used to show the attribute-name/info being proxied when you useDependency.proxy_attribute()
.
Expand source code
class CurrentDependencyProxy(Generic[D]): """ Used to simplify accessing the current dependency class via proxy object, so you can use the object like a normal global-object, but every time you access a normal (non-private) attribute/method it will grab you the one from the currenly active dependency. >>> class MyClass(Dependency): ... def my_method(self): ... pass Typically, to access attributes of a particular dependency subclass you would have to do this: >>> MyClass.grab().my_method() With ProxyActive you can do this instead: >>> my_class = CurrentDependencyProxy.wrap(MyClass) >>> my_class.my_method() This will always call the active/current dependency without having to use the boilerplate `.dependency()` method on the dependency class/type. >>> # You can use the `proxy` convenience >>> # method to also accomplish this: >>> my_class = MyClass.proxy() It's sometimes useful to put at the top-level of a module the proxy-version of the dependency so it can be directly imported into other modules, and used directly like a normal object. >>> # We are in some other Module; >>> # import the 'my_class' we defined above. >>> from my_class_module import my_class >>> >>> my_class.my_method() """ @classmethod def wrap(cls, dependency_type: Type[D]) -> D: """ Just like init'ing a new object with `dependency_type`.... Except this will preserve the type-hinting, and tell things that care about the type (like an IDE) that what's returned from here should act like an instance of the `dependency_type` passed into this method. A simpler/alternate way to wrap a Dependency with a `CurrentDependencyProxy` is via the `xinject.dependency.Dependency.proxy` convenience method. """ # noinspection PyTypeChecker return cls(dependency_type=dependency_type) def __init__( self, dependency_type: Type[D], grabber: Callable[[D], Any] = None, repr_info: str = None ): """ See `CurrentDependencyProxy` for and overview. Init method doc below. ## Init Method When you create a CurrentDependencyProxy, you pass in the `dependency_type` you want it to proxy. Will act like the current/active object of Dependency type `dependency_type`. you can optionally provide a grabber function, that will be called with the current dependency passed to it. You can then grab something from that dependency and return it. If you pass in a grabber function, this ProxyActive will act like a proxy of whatever is returned from the grabber method. Args: dependency_type: Type of dependency to proxy. grabber: Optional callable, if you wish to grab a specific attribute off the dependency and act like a proxy for that, you can pass in a method here to do so. Whatever is returned from the grabber is what is used to as the object to 'proxy'. repr_info: Will provide this additional info if self gets `repr()` called on it (ie: if used/shown in debugger, etc). Example: Currently used to show the attribute-name/info being proxied when you use `xinject.dependency.Dependency.proxy_attribute`. """ # Would give unusual error later on, lets just check right now! if not issubclass(dependency_type, Dependency): raise Exception( f"Must pass a xinject.Dependency subtype to xinject.ProxyActive.wrap, " f"I was given a ({dependency_type}) instead." ) self._dependency_type = dependency_type self._grabber = grabber self._repr_info = repr_info pass def _get_active(self): # Get current/active instance of dependency type value = self._dependency_type.grab() if self._grabber: return self._grabber(value) return value def __getattribute__(self, name): # Anything the starts with a `_` is something that we want to get/set on self, # and not on the current config object. if name.startswith('_'): return super().__getattribute__(name) return getattr(self._get_active(), name) def __setattr__(self, key, value): if key.startswith('_'): # Anything the starts with a `_` is something that we want to get/set on self, # and not on the current config object. return super().__setattr__(key, value) # Otherwise, we set it on the current/active dependency object. return setattr(self._get_active(), key, value) def __repr__(self): info = '' if repr_info := self._repr_info: info = f'({repr_info})' return f'CurrentDependencyProxy{info}<{self._get_active().__repr__()}>' def __str__(self): return self._get_active().__str__() def __getitem__(self, key): return self._get_active().__getitem__(key) def __setitem__(self, key, value): return self._get_active().__setitem__(key, value)
Ancestors
- typing.Generic
Static methods
def wrap(dependency_type: Type[~D]) ‑> ~D
-
Just like init'ing a new object with
dependency_type
.... Except this will preserve the type-hinting, and tell things that care about the type (like an IDE) that what's returned from here should act like an instance of thedependency_type
passed into this method.A simpler/alternate way to wrap a Dependency with a
CurrentDependencyProxy
is via theDependency.proxy()
convenience method.Expand source code
@classmethod def wrap(cls, dependency_type: Type[D]) -> D: """ Just like init'ing a new object with `dependency_type`.... Except this will preserve the type-hinting, and tell things that care about the type (like an IDE) that what's returned from here should act like an instance of the `dependency_type` passed into this method. A simpler/alternate way to wrap a Dependency with a `CurrentDependencyProxy` is via the `xinject.dependency.Dependency.proxy` convenience method. """ # noinspection PyTypeChecker return cls(dependency_type=dependency_type)