_reflection.py 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. from __future__ import annotations
  2. import inspect
  3. from typing import Any, Callable
  4. def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool:
  5. """Returns whether or not the given function has a specific parameter"""
  6. sig = inspect.signature(func)
  7. return arg_name in sig.parameters
  8. def assert_signatures_in_sync(
  9. source_func: Callable[..., Any],
  10. check_func: Callable[..., Any],
  11. *,
  12. exclude_params: set[str] = set(),
  13. description: str = "",
  14. ) -> None:
  15. """Ensure that the signature of the second function matches the first."""
  16. check_sig = inspect.signature(check_func)
  17. source_sig = inspect.signature(source_func)
  18. errors: list[str] = []
  19. for name, source_param in source_sig.parameters.items():
  20. if name in exclude_params:
  21. continue
  22. custom_param = check_sig.parameters.get(name)
  23. if not custom_param:
  24. errors.append(f"the `{name}` param is missing")
  25. continue
  26. if custom_param.annotation != source_param.annotation:
  27. errors.append(
  28. f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}"
  29. )
  30. continue
  31. if errors:
  32. raise AssertionError(
  33. f"{len(errors)} errors encountered when comparing signatures{description}:\n\n" + "\n\n".join(errors)
  34. )