Description
Have you read the Contributing Guidelines on issues?
- I have read the Contributing Guidelines on issues.
Description
In version 3, state handler functions need to have the arguments as described by StateHandlerFull
, StateHandlerNoAction
and so on. In function _set_function_state_handler
and _state_handler_dict
, there are checks on how many parameters there are in the function, e,g. by having len(inspect.signature(f).parameters) != 2
calls.
I would like to replace this by something like this
parameters = inspect.signature(handler).parameters
parameters_without_defaults = {k: v for k, v in parameters.items() if
v.default is v.empty}
...
if len(parameters_without_defaults) != 2:
...
This would generate more flexibility in defining state_handler functions. The TypeAliases would need be extended.
Motivation
The current implementation forbids the usage of extra parameters to be passed on to state handler functions. However, this might be a requirement when fixtures are used. E.g. in test_provider
in the test_01_fastapi_provider.py
, it might not be sufficient to use only the server as a fixture, but another one, where we pass the database object that we want to modify by the state handler. This requirement is definitely there for our use case.
This currently cannot be passed on to the state_handler_function as fixtures are not available in normal functions. It could be relieved by using functools.partial
. The test_provider_code
could then look like:
def test_provider(server: str, my_fixture) -> None:
partial_state_handler = partial(
provider_state_handler, my_extra_arg=my_fixture
)
verifier = (
Verifier("v3_http_provider")
.add_transport(url=server)
.add_source("examples/pacts/v3_http_consumer-v3_http_provider.json")
.state_handler(partial_state_handler, teardown=True)
)
verifier.verify()
def provider_state_handler(
state: str,
action: str,
_parameters: dict[str, Any] | None,
my_extra_arg: Any | None = None
) -> None:
if action == "setup":
mapping = {
"user doesn't exists": mock_user_doesnt_exist,
"user exists": mock_user_exists,
"the specified user doesn't exist": mock_post_request_to_create_user,
"user is present in DB": mock_delete_request_to_delete_user,
}
# TODO: there might be a cleaner and more general approach here
if my_extra_arg is None:
mapping[state]()
else:
mapping[state](my_extra_arg)
if action == "teardown":
mapping = {
"user doesn't exists": verify_user_doesnt_exist_mock,
"user exists": verify_user_exists_mock,
"the specified user doesn't exist": verify_mock_post_request_to_create_user,
"user is present in DB": verify_mock_delete_request_to_delete_user,
}
mapping[state]()
I am unsure if this feature has been requested by other users. For us, it is a blocker.
Have you tried building it?
I can definitely create a PR for this, if approved by the maintainers.
I need support on how to run the complete test suite though. I currently still get many
FileNotFoundError: [Errno 2] No such file or directory: './pact-python/tests/v3/compatibility_suite/definition/features/V1/http_consumer.feature'
errors when running hatch run test
. The definition
subfolder is completely empty.
Also I am unsure how to extend the TypeAliases, to include optional default arguments.
Self-service
- I'd be willing to contribute this feature to Pact Python myself.