Okay. So by further expanding @Ister's answer, according to comments, I concluded to do as follows:
- Model my modules as static classes as @esoterik suggested.
- Pick those UML diagrams which seem to be relevant.
- Expand diagrams with my own conventions to make them more descriptive. as @DocBrown pointed out.
- If in any case, UML turned out to be inexpressive, I can come up with my own notation. As @esoterik and @KaspervandenBerg explicitly suggested.
Although this seems to be pretty rare to happen as we don't have strict rules about how to utilize UML diagrams, so we are allowed to use them intuitively in order to tailor them according to our needs.
There is no "law" which forbids you to replace the names of objects by the names of modules involved.
The main confusing point was that UML actually uses an Object-Oriented design approach while python doesn't always conform to that, especially when standalone functions are used. But that shouldn't be a matter.
Also even if you don't follow OOP principles fully it's good to keep them mostly regardless if the language you use enable that or not. It's beneficiary in the long run (easier maintenance). And in every language, you can write OOP-like style.
As I googled around about how people use UML with python, I reached the fact that almost nobody designs a software before it is developed in python; at least not with UML! They use UML generators instead when the code is ready, which has its own drawbacks.
Python objects can be extended at runtime, and objects of any type can be assigned to any instance variable. Figuring out what classes an object can contain pointers to (composition) would require a full understanding of the runtime behavior of the program.