Refactored the "Hello" Python script and added excessive documentation
ClosedPublic

Authored by victorw on Aug 3 2017, 8:27 PM.

Details

Reviewers
rempt
woltherav
Group Reviewers
Krita
Summary

The "Hello" Python script looked like a good minimal example, so I refactored it a bit in the hopes that it can be used as a reference for more advanced scripts!

I also documented it excessively for the same reason, using Python docstrings and supported reStructuredText syntax. Unfortunately getting Sphinx to generate API docs for scripts using embedded modules is a bit involving, so I haven't been able to test the output yet.

This is intended as a proposal, and some changes I've made are subjective. My hope is that you can pick out the parts you like and weave that into the code standard. Some things, like documentation, can also be enforced via tests if we want to!

Diff Detail

Repository
R37 Krita
Lint
Lint Skipped
Unit
Unit Tests Skipped
victorw created this revision.Aug 3 2017, 8:27 PM
woltherav accepted this revision.EditedAug 3 2017, 8:41 PM

Seems sensible to me. I had been wondering how we should be commenting the python scripts.

Edit:
This is reST syntax for those wondering: https://thomas-cokelaer.info/tutorials/sphinx/rest_syntax.html

This revision is now accepted and ready to land.Aug 3 2017, 8:41 PM
victorw added inline comments.Aug 3 2017, 9:59 PM
plugins/extensions/pykrita/plugin/plugins/hello/hello.py
1

This is a module docstring and can be accessed via hello.hello.__doc__

I also noticed that the script lacks a license. If we enforce that for regular header and source files, it should probably be enforced for bundled Python scripts too...

2

For smaller scripts, this is unlikely to cause issues. Though it's bad practice and I recommend avoiding it on principle; code styles and patterns have a tendency to propagate, so maintaining good habits can prevent the propagation of bad ones, and it helps educate new programmers!

As it might not be immediately obvious why this is bad, here's a quick explanation:

This is roughly equivalent to "using namespace ..." in C++, only with Python the consequences can be worse.

  • You may end up shadowing previous imports, and Python being Python you may find yourself calling the wrong function without obvious breakage.
  • It makes the code less readable as it becomes difficult to figure out where a function, class or variable is defined
  • It prevents analysers like PyFlakes from detecting certain problems with your script

Note: There are cases where it might be the right thing to do, but these are rare. For example, if you want to repackage and selectively alter an external module without knowing exactly what it contains.

12

This is a function docstring, and is available via hello.__doc__

Or if you're using the full package.module.function format: hello.hello.hello.__doc__

15

This change is a bit subjective: There are multiple ways to format strings in Python. This one is a bit verbose. There's also a C-style fmt version, which would look something like this:

"Hello! This is Krita version %s" % (Application.version(),)

I find that one to be a bit more readable, but it's not as powerful. In this case it might be the better one to use, so I'll probably switch to it. Python 3.6 also has a new literal string interpolation which is pretty neat. But it that would require bumping the minimum Python version to 3.6, so it's not quite feasible yet: https://www.python.org/dev/peps/pep-0498/

Note: There is no performance gain here. In fact, the .format() syntax is likely slower, although it shouldn't matter in practice.

19

This is a class docstring, and is available via HelloExtension.__doc__

As with other class variables, you can also access it via an instance of the class, e.g. self.__doc__

29

I think Sphinx should be able to locate QWidget as it's imported as such at the top. If it does, then the generated docs will format the keyword and link to the class documentation.

58

Is this comment correct? This is what the code appears to do, though I'm not sure if this is how you're supposed to set the menu name.

62

The _ prefix on member variables in Python is a standard convention for "protected" variables; Python doesn't really enforce this though, so it's mostly a way to indicate that the variable is not part of the public API. Supposedly _ prefixed variables are protected from wildcard imports like from mymodule import *, which I didn't know!

__ prefix is a standard convention for "private" variables, and this will actually mangle the variable so it's harder to access from outside the class, though it's not enforced beyond that.

See latter half of https://www.python.org/dev/peps/pep-0008/#descriptive-naming-styles for more info.

rempt added a comment.Feb 28 2018, 1:54 PM

This was accepted -- so please push it?

victorw closed this revision.Mar 1 2018, 6:23 PM

This has already been pushed in 80af6093bad5847fe3681e4715f7ab8b683b2a6a (2017-08-04)

I don't know why it didn't link to Phabricator.