Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
nameko.utils 源代码
import inspect
import re
from copy import deepcopy
from pydoc import locate
from typing import Any
import six
from six.moves.urllib.parse import urlparse
[文档]
REDACTED = "********"
[文档]
def get_redacted_args ( entrypoint , * args , ** kwargs ):
"""
用于与标记为 ``sensitive_arguments`` 的入口点配合使用的实用函数,例如: :class:`nameko.rpc.Rpc` 和 :class:`nameko.events.EventHandler`。
:Parameters:
entrypoint : :class:`~nameko.extensions.Entrypoint`
被触发的入口点。
args : tuple
方法调用的位置参数。
kwargs : dict
方法调用的关键字参数。
入口点应该具有 ``sensitive_arguments`` 属性,其值是一个字符串或字符串元组,指定应该被隐去的参数或部分参数。如果要部分隐去某个参数,使用以下语法::
<argument-name>.<dict-key>[<list-index>]
:Returns:
返回一个字典,由 :func:`inspect.getcallargs` 返回,但敏感参数或部分参数已被隐去。
.. note::
如果其中一个 ``sensitive_arguments`` 与调用的 ``args`` 和 ``kwargs`` 不匹配或部分匹配,该函数不会引发异常。
这允许进行“模糊”模式匹配(例如,如果存在字段,则隐去该字段,否则不执行任何操作)。
为了避免因拼写错误而泄露敏感参数,建议单独测试每个具有 ``sensitive_arguments`` 的入口点的配置。例如:
.. code-block:: python
class Service(object):
@rpc(sensitive_arguments="foo.bar")
def method(self, foo):
pass
container = ServiceContainer(Service, {})
entrypoint = get_extension(container, Rpc, method_name="method")
# no redaction
foo = "arg"
expected_foo = {'foo': "arg"}
assert get_redacted_args(entrypoint, foo) == expected
# 'bar' key redacted
foo = {'bar': "secret value", 'baz': "normal value"}
expected = {'foo': {'bar': "********", 'baz': "normal value"}}
assert get_redacted_args(entrypoint, foo) == expected
.. seealso::
该实用程序的测试演示了其完整用法: :class:`test.test_utils.TestGetRedactedArgs` 。
"""
sensitive_arguments = entrypoint . sensitive_arguments
if isinstance ( sensitive_arguments , six . string_types ):
sensitive_arguments = ( sensitive_arguments ,)
method = getattr ( entrypoint . container . service_cls , entrypoint . method_name )
callargs = inspect . getcallargs ( method , None , * args , ** kwargs )
del callargs [ "self" ]
# make a deepcopy before redacting so that "partial" redacations aren't applied to a referenced object
# 在进行敏感参数隐去之前,先执行深拷贝,以确保“部分”隐去不会应用于被引用的对象。
callargs = deepcopy ( callargs )
def redact ( data , keys ):
key = keys [ 0 ]
if len ( keys ) == 1 :
try :
data [ key ] = REDACTED
except ( KeyError , IndexError , TypeError ):
pass
else :
if key in data :
redact ( data [ key ], keys [ 1 :])
for variable in sensitive_arguments :
keys = []
for dict_key , list_index in re . findall ( r "(\w+)|\[(\d+)\]" , variable ):
if dict_key :
keys . append ( dict_key )
elif list_index :
keys . append ( int ( list_index ))
if keys [ 0 ] in callargs :
redact ( callargs , keys )
return callargs
[文档]
def import_from_path ( path ) -> Any :
"""如果对象在 `path` 中存在,则导入并返回该对象。
如果未找到该对象,则引发 `ImportError`。
"""
if path is None :
return
obj = locate ( path )
if obj is None :
raise ImportError ( "` {} ` could not be imported" . format ( path ))
return obj
[文档]
def sanitize_url ( url ):
"""在 URLs 中隐藏密码。"""
parts = urlparse ( url )
if parts . password is None :
return url
host_info = parts . netloc . rsplit ( "@" , 1 )[ - 1 ]
parts = parts . _replace (
netloc = " {} : {} @ {} " . format ( parts . username , REDACTED , host_info )
)
return parts . geturl ()