Type Hints#
Static type hints – together with a type checker like Mypy – are an excellent way to make your code more robust, self-documenting, and maintainable in the long run. And as of 20.2.0, structlog comes with type hints for all of its APIs.
Since structlog is highly configurable and tries to give a clean façade to its users, adding types without breaking compatibility – while remaining useful! – was a formidable task.
The main problem is that structlog.get_logger()
returns whatever you’ve configured the bound logger to be.
The only commonality are the binding methods like bind()
and we’ve extracted them into the structlog.typing.BindableLogger
Protocol
.
But using that as a return type is worse than useless, because you’d have to use typing.cast()
on every logger returned by structlog.get_logger()
, if you wanted to actually call any logging methods.
The second problem is that said bind()
and its cousins are inherited from a common base class (a big mistake in hindsight) and can’t know what concrete class subclasses them and therefore what type they are returning.
The chosen solution is adding structlog.stdlib.get_logger()
that just calls structlog.get_logger()
but has the correct type hints and adding structlog.stdlib.BoundLogger.bind
et al that also only delegate to the base class.
structlog.get_logger()
is typed as returning typing.Any
so you can use your own type annotation and stick to the old APIs, if that’s what you prefer:
import structlog
logger: structlog.stdlib.BoundLogger = structlog.get_logger()
logger.info("hi") # <- ok
logger.msg("hi") # <- Mypy: 'error: "BoundLogger" has no attribute "msg"'