Skip to content

Commit

Permalink
fix: DependsAttrBinder.bind property evaluating on binding
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikakto committed Feb 4, 2023
1 parent 29dd23d commit eaaaa01
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Use `DependsAttr` to `Depends` from current instance attributes. All examples us
- class methods
- static methods
- instance methods
- `property` returning `callable`
- `property` (must return `callable` that will be used as dependency)

Your class must inherit from `DependsAttrBinder` and attributes must be `DependsAttr`. `DependsAttrBinder` automatically patch all methods with `DependsAttr` by instance attributes.

Expand Down
2 changes: 1 addition & 1 deletion fastapi_depends_ext/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def depends_attr_bind(depends: DependsAttr, _base_class: type, instance) -> Depe

method_definition = getattr(_base_class, depends.method_name)
if isinstance(method_definition, property):
depends_copy.dependency = functools.partial(method_definition.fget, instance)
depends_copy.dependency = method_definition.fget(instance)
else:
dependency = depends_attr_get_method(depends, _base_class, instance)
depends_copy.dependency = self.bind(dependency)
Expand Down
65 changes: 63 additions & 2 deletions tests/depends/depends_attr_binder/test_bind.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ def method(self, depends_attr: Any = depends):
assert isinstance(depends_attr.default, DependsAttr)
assert depends_attr.default is not depends
assert depends_attr.default.is_bound
assert depends_attr.default.dependency is not real_dependency
assert depends_attr.default.dependency() is real_dependency
assert depends_attr.default.dependency is real_dependency


def test_bind__method_has_depends_class__method_change(mocker):
Expand Down Expand Up @@ -177,6 +176,68 @@ def method(self, depends_attr: Any = depends):
assert depends_attr.default.dependency is Dependency


def test_bind__method_has_depends_callable__method_change(mocker):
depends = DependsAttr("dependency")

class Dependency:
def __call__(self):
return 1

class TestClass(DependsAttrBinder):
dependency = Dependency()

def method(self, depends_attr: Any = depends):
pass

with mocker.patch.object(DependsAttrBinder, "__init__", unittest.mock.MagicMock(return_value=None)):
instance = TestClass()
instance.bind(instance.method)

assert instance.method.__self__ is instance
assert instance.method.__func__ is not TestClass.method
assert instance.method.__func__.__code__ is TestClass.method.__code__

signature = get_typed_signature(instance.method)
depends_attr = signature.parameters["depends_attr"]
assert isinstance(depends_attr.default, DependsAttr)
assert depends_attr.default is not depends
assert depends_attr.default.is_bound
assert depends_attr.default.dependency is TestClass.dependency


def test_bind__method_has_depends_instance_defined_variable__method_change(mocker):
depends = DependsAttr("dependency")

class Dependency:
def __call__(self):
return 1

class TestClass(DependsAttrBinder):
dependency: Dependency

def __init__(self, *args, **kwargs):
self.dependency = Dependency()
super(TestClass, self).__init__(*args, **kwargs)

def method(self, depends_attr: Any = depends):
pass

with mocker.patch.object(DependsAttrBinder, "__init__", unittest.mock.MagicMock(return_value=None)):
instance = TestClass()
instance.bind(instance.method)

assert instance.method.__self__ is instance
assert instance.method.__func__ is not TestClass.method
assert instance.method.__func__.__code__ is TestClass.method.__code__

signature = get_typed_signature(instance.method)
depends_attr = signature.parameters["depends_attr"]
assert isinstance(depends_attr.default, DependsAttr)
assert depends_attr.default is not depends
assert depends_attr.default.is_bound
assert depends_attr.default.dependency is instance.dependency


def test_bind__method_has_depends_method_chained__method_changed_all(mocker):
depends = [DependsAttr("dependency"), DependsAttr("method_1")]

Expand Down

0 comments on commit eaaaa01

Please sign in to comment.