def _add_contract_to_setter(setter_fun, var_name, property_contract, property_name):
# 0. check that we can import contracts
try:
# noinspection PyUnresolvedReferences
from contracts import ContractNotRespected, contract
except ImportError as e:
raise Exception('Use of _add_contract_to_setter requires that PyContract library is installed. Check that you '
'can \'import contracts\'')
# -- check if a contract already exists on the function
if hasattr(setter_fun, '__contracts__'):
msg = 'overridden setter for attribute ' + property_name + ' implemented by function ' \
+ str(setter_fun.__qualname__) + ' has a contract while there is a contract already defined ' \
+ 'for this property in the __init__ constructor. This will lead to double-contract in the final ' \
+ 'setter, please remove the one on the overridden setter.'
warn(msg)
# -- add the generated contract
setter_fun_with_possible_contract = contract(setter_fun, **{var_name: property_contract})
# the only thing we can't do is to replace the function's parameter name dynamically in the error messages
# so we wrap the function again to catch the potential pycontracts error :(
# old:
# @functools.wraps(func) -> to make the wrapper function look like the wrapped function
# def wrapper(self, *args, **kwargs):
# new:
# we now use 'decorate' to have a wrapper that has the same signature, see below
def _contracts_parser_interceptor(func, self, *args, **kwargs):
try:
return func(self, *args, **kwargs)
except ContractNotRespected as er:
er.error = er.error.replace('\'val\'', '\'' + property_name + '\'')
raise er
# f = _contracts_parser_interceptor(f)
setter_fun_with_possible_contract = decorate(setter_fun_with_possible_contract, _contracts_parser_interceptor)
return setter_fun_with_possible_contract
评论列表
文章目录