-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add helpers.resolver for resolve objects by dotted notations names
- Loading branch information
Showing
7 changed files
with
141 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import inspect | ||
|
||
from zope.dottedname.resolve import resolve | ||
|
||
|
||
def resolver(*for_resolve): | ||
""" Resolve dotted names | ||
Usage: | ||
@resolver('klass1', 'klass2') | ||
def method(app, klass1, param, klass2): | ||
"klass1 and klass2 may be object or dotted notation path" | ||
assert not isinstance(klass1, str) | ||
assert not isinstance(klass2, str) | ||
assert isinstance(param, str) | ||
""" | ||
def decorator(func): | ||
spec = inspect.getargspec(func).args[1:] | ||
if set(for_resolve) - set(spec): | ||
raise ValueError('bad arguments') | ||
|
||
def wrapper(app, *args, **kwargs): | ||
module = getattr(app, '_module', None) | ||
|
||
args = list(args) | ||
|
||
for item in for_resolve: | ||
n = spec.index(item) | ||
if n >= len(args): | ||
continue | ||
|
||
if n is not None and isinstance(args[n], str): | ||
args[n] = resolve(args[n], module) | ||
|
||
for kw, value in kwargs.copy().items(): | ||
if kw in for_resolve and isinstance(value, str): | ||
kwargs[kw] = resolve(value, module) | ||
|
||
return func(app, *args, **kwargs) | ||
|
||
wrapper.__name__ = func.__name__ | ||
wrapper.__doc__ = func.__doc__ | ||
wrapper.__annotations__ = func.__annotations__ | ||
|
||
return wrapper | ||
|
||
return decorator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,13 @@ | ||
def includeme(app): | ||
app['test_include_info'] = ('includeme', app) | ||
assert app is not app._app | ||
assert app.start == app._app.start | ||
assert app.start.__func__ == app._app.start.__func__ | ||
|
||
|
||
def func(app): | ||
app['test_include_info'] = ('func', app) | ||
assert app is not app._app | ||
assert app.start == app._app.start | ||
assert app.start.__func__ == app._app.start.__func__ | ||
|
||
|
||
not_callable = 'not callable data' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from unittest.mock import Mock | ||
|
||
import pytest | ||
|
||
from aiotraversal.helpers import resolver | ||
|
||
|
||
def test_resolver(): | ||
class Obj: | ||
@resolver('obj1', 'obj2') | ||
def meth(self, obj1, ar, obj2=2, kw=3): | ||
return (self, obj1, ar, obj2, kw) | ||
|
||
obj = Obj() | ||
res = obj.meth('os.path.isdir', 'str', obj2='sys.exit') | ||
|
||
from os.path import isdir | ||
from sys import exit | ||
|
||
assert res[0] is obj | ||
assert res[1] is isdir | ||
assert res[2] == 'str' | ||
assert res[3] is exit | ||
assert res[4] == 3 | ||
|
||
res = obj.meth(isdir, 'str', obj2=exit) | ||
|
||
assert res[0] is obj | ||
assert res[1] is isdir | ||
assert res[2] == 'str' | ||
assert res[3] is exit | ||
assert res[4] == 3 | ||
|
||
|
||
def test_resolver__relative(): | ||
@resolver('obj') | ||
def func(app, obj): | ||
return (app, obj) | ||
|
||
res = func(Mock(name='app', _module='tests'), '.for_include.func') | ||
|
||
from .for_include import func as func_imported | ||
assert res[0]._module == 'tests' | ||
assert res[1] is func_imported | ||
|
||
|
||
def test_resolver__import_error(): | ||
@resolver('obj') | ||
def func(app, obj): | ||
return (app, obj) | ||
|
||
with pytest.raises(ImportError): | ||
func('app', 'not_found') | ||
|
||
|
||
def test_resolver__declare_error(): | ||
with pytest.raises(ValueError): | ||
@resolver('not_exist') | ||
def func(app, obj): | ||
return (app, obj) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters