INADA Naoki email@example.com added the comment:
Also, it mirrors practices in the standard library (decimal.DecimalException and sqlite3.DatabaseError).
As Nathaniel said, "it's good idea in the particular circumstances of a particular module's implementation, but generally not." (I removed "very" because it is too noisy)
For example, socket.error was migrated into OSError. So not having base exception class for module is also "practices in the standard library".
For users, it provides a way to catch possible errors that are specific to a particular module.
For tutorial readers, caching errors specific to particular cause should be suggested, instead of particular module.
"How/When custom base exception class is useful" is very high level topic. It's too difficult for tutorial.
If tutorial reader start using base exception class without any real benefit, it will lead ugly code like this:
try: # some code here except ValueError as e: raise CustomValueError(e.args) except TypeError as e: raise CustomTypeError(e.args) except ...