Python Plugin Developer Tools

yes, thanks!
One remark: once the button is in checked state, selecting another item in treeview works, the selected item in treeview is highlighted in UI.

But if you switch to inspector tab and select another item from inspector, the button is not checked anymore…
I think it would be better if the state stay persistent, let the user decide to check/uncheck it.

Also, I got an error when I’ve selected an action:

AttributeError
Python 3.8.1: /usr/bin/python3
Mon Nov  1 10:20:35 2021

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred.

 /home/grum/.local/share/krita/pykrita/PluginDevTools/PluginDevToolsDocker.py in itemSelectionChanged(self=<PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsInspector object>, new=<PyQt5.QtCore.QItemSelection object>, old=<PyQt5.QtCore.QItemSelection object>)
 1378             indexes = new.indexes()
 1379             if indexes:
 1380                 self.loadItemInfo( indexes[0].data(101) )
 1381 
 1382         def loadItemInfo(self, obj):
self = <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsInspector object>
self.loadItemInfo = <bound method PluginDevToolsDocker.PluginDevTool...inDevToolsDocker.PluginDevToolsInspector object>>
indexes = [<PyQt5.QtCore.QModelIndex object>, <PyQt5.QtCore.QModelIndex object>, <PyQt5.QtCore.QModelIndex object>, <PyQt5.QtCore.QModelIndex object>, <PyQt5.QtCore.QModelIndex object>]
].data undefined

 /home/grum/.local/share/krita/pykrita/PluginDevTools/PluginDevToolsDocker.py in loadItemInfo(self=<PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsInspector object>, obj=<PyQt5.QtWidgets.QAction object>)
 1387 
 1388             if self.showCurrentWidgetHighlight:
 1389                 self.caller.t['selector'].setCurrentSelector(self.currentWidget, False)
 1390 
 1391             self.tableModel.clear()
self = <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsInspector object>
self.caller = <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker object>
self.caller.t = {'actions': <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsActions object>, 'console': <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsConsole object>, 'icons': <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsIcons object>, 'inspector': <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsInspector object>, 'kritaapi': <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsKritaAPI object>, 'selector': <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsSelector object>, 'welcome': <PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsWelcome object>}
].setCurrentSelector undefined
self.currentWidget = <PyQt5.QtWidgets.QAction object>

 /home/grum/.local/share/krita/pykrita/PluginDevTools/PluginDevToolsDocker.py in setCurrentSelector(self=<PluginDevTools.PluginDevToolsDocker.PluginDevToolsDocker.PluginDevToolsSelector object>, obj=<PyQt5.QtWidgets.QAction object>, localCall=False)
 1028                     obj.update()
 1029 
 1030                 rect = obj.geometry()
 1031 
 1032                 if obj.metaObject().superClass().className() == 'QLayout' or obj.metaObject().superClass().className() == 'QBoxLayout':
rect undefined
obj = <PyQt5.QtWidgets.QAction object>
obj.geometry undefined
AttributeError: 'QAction' object has no attribute 'geometry'
    __cause__ = None
    __class__ = <class 'AttributeError'>
    __context__ = None
    __delattr__ = <method-wrapper '__delattr__' of AttributeError object>
    __dict__ = {}
    __dir__ = <built-in method __dir__ of AttributeError object>
    __doc__ = 'Attribute not found.'
    __eq__ = <method-wrapper '__eq__' of AttributeError object>
    __format__ = <built-in method __format__ of AttributeError object>
    __ge__ = <method-wrapper '__ge__' of AttributeError object>
    __getattribute__ = <method-wrapper '__getattribute__' of AttributeError object>
    __gt__ = <method-wrapper '__gt__' of AttributeError object>
    __hash__ = <method-wrapper '__hash__' of AttributeError object>
    __init__ = <method-wrapper '__init__' of AttributeError object>
    __init_subclass__ = <built-in method __init_subclass__ of type object>
    __le__ = <method-wrapper '__le__' of AttributeError object>
    __lt__ = <method-wrapper '__lt__' of AttributeError object>
    __ne__ = <method-wrapper '__ne__' of AttributeError object>
    __new__ = <built-in method __new__ of type object>
    __reduce__ = <built-in method __reduce__ of AttributeError object>
    __reduce_ex__ = <built-in method __reduce_ex__ of AttributeError object>
    __repr__ = <method-wrapper '__repr__' of AttributeError object>
    __setattr__ = <method-wrapper '__setattr__' of AttributeError object>
    __setstate__ = <built-in method __setstate__ of AttributeError object>
    __sizeof__ = <built-in method __sizeof__ of AttributeError object>
    __str__ = <method-wrapper '__str__' of AttributeError object>
    __subclasshook__ = <built-in method __subclasshook__ of type object>
    __suppress_context__ = False
    __traceback__ = <traceback object>
    args = ("'QAction' object has no attribute 'geometry'",)
    with_traceback = <built-in method with_traceback of AttributeError object>

The above is a description of an error in a Python program.  Here is
the original traceback:

Traceback (most recent call last):
  File "/home/grum/.local/share/krita/pykrita/PluginDevTools/PluginDevToolsDocker.py", line 1380, in itemSelectionChanged
    self.loadItemInfo( indexes[0].data(101) )
  File "/home/grum/.local/share/krita/pykrita/PluginDevTools/PluginDevToolsDocker.py", line 1389, in loadItemInfo
    self.caller.t['selector'].setCurrentSelector(self.currentWidget, False)
  File "/home/grum/.local/share/krita/pykrita/PluginDevTools/PluginDevToolsDocker.py", line 1030, in setCurrentSelector
    rect = obj.geometry()
AttributeError: 'QAction' object has no attribute 'geometry'

But it seems it’s not reproducible in all case: I’m not able to reproduce it and don’t really remember what I did to get this :sweat_smile:
Now, it seems as soon as I select a QAction in inspector, the error message is displayed

Grum999

Looking forward to test things out by the weekend! Thank you for the update!

I added a thing where it will exclude anything that has geometry from showing. Maybe in the future I can add for QActions that it shows the associated widgets with that QAction.

I also added the thing where it retains the show selector when you switch back to inspector.

It’s been a while since I added some features here, so in is a new feature called “Event/Signal Viewer”

Event/Signal Viewer
- Ability to monitor signals and events and inject code into them. Just select the object in question in Inspector and press the "Event and Signal Viewer/Debugger" button. (Beta)

It still needs a lot of work and polish, code is also kind of a mess since I rushed it a bit. But it should work for the most part and should help a lot with figuring out and working with signals and events.

Hope it will come in useful.

6 Likes

Thank you for keeping up the good work.

Thanks for this plugin! It is by far the most useful thing for python scripting development.

I have been wanting to make a plugin for krita for a couple years and made no real progress. Thanks to this I have a working prototype of it now.

Glad it could help :slight_smile:

Just wanted to say thank you for this, I’ve been tinkering with making blender plugins to fit my needs for a while and for whatever reason never came to the realization that Krita had similar API support until recently which I believe will make me a permanent Krita user as the possibilities seem endless. Your tool should be at the start of any plugin dev tutorial lol thank you again!

1 Like

I’ve been a bit busy with work so I wasn’t able to add all the stuff I wanted to, but since I saw someone add a pull request I wanted to added one more quick feature.

Simple Plugin Generator - A simple generator that creates a starter for your own plugin

A lot of people don’t know where to start and get confused on where to put what or how to add shortcuts. This starter does just that, it also adds autocomplete as well and generates basic starter templates. It also creates a symlink so you can keep your workspace outside(so you can test different krita versions by just symlinking to a central source) and presets up git if git is installed

Edit: I also added more tips to the code generator for PyQT5 mappings in case an item does not have a name and how to hook up to it. While the method is slower it shouldn’t be a problem when cached and should make it easier for people to hook onto widgets with no name (END EDIT)

As for the pull request, it was added by zerobikappa. Adding the ability to detach the docker as a separate dialog. Special thanks goes out to them for contributing!

@deltisheffort - Glad it could help :slight_smile:

8 Likes

This plugin is a GEM! IMHO should be included with Krita!

(I asked in a different topic, but maybe would be better here for future users).

Any guideance about how to set up the autocomplete?

As mentioned in the first post, the Krita API tab, there is a button to generate it.

How to use it is in this post:

You can also go to Tools->Scripts->Create your own plugin and it will generate a template for you

2 Likes

Thank you. And sorry, I first generated it but I thought it was meant to make the API tab to work inside the plugin docker (didn’t see the little button to generate it later).

Is great, the autocomplete works perfect.

Even though, not sure if I’m having a bug (?) when creating a template extension:
When I choose the folder %APPDATA%\Roaming\krita\pykrita\ (unchecking symlink), it creates a folder with the name of the extension, like %APPDATA%\Roaming\krita\pykrita\my_new_extension with everything inside that folder. After creating it, and without restarting, I can see in the plugin importer that the new extension is enabled, but after reloading Krita, the extension is gone and doesn’t appear there anymore.

(Is ok, to make it work I just have to move all its content. I’m saying it simply because not sure if this was meant to be that way (at least on my side, plugins don’t seem to be recognized if the .desktop is not in the first level of the pykrita folder)) (not sure if maybe is a setting from Krita or what. TBH I would preffer Krita could recognize when the plugins are inside their folders, for better organization).

Thanks again for that extension, makes developing plugins literally 1000 times better.

1 Like

I can’t tell you why, but for what I know Krita needs this *.desktop-files, maybe or probably to “make them known to Krita”, but that is guessed. As far as I remember, I have not seen an extension/plugin without its *.desktop-file.

Michelist

1 Like

Sorry about that, seems like when I made the symlink as the default, I broke the non-symlink way. I added a fix and it should work fine now

2 Likes

No problem. Thanks to you for solving it that fast!

Even though, now it gives an error when unchecking the Use Symlink:
pykrita\PluginDevTools\PluginGenerator.py", line 205, in toggleSymlink self.centralWidget.projectPathHeaderLabel.setText('Project Path:') AttributeError: 'QWidget' object has no attribute 'projectPathHeaderLabel'

But I just made a pull request solving it (it was that the QLabel was named label_7 instead of projectPathHeaderLabel)

1 Like

Oops, that’s what I get for being too lazy to set up 2FA and copy and pasting rather than syncing the repo. Sorry about that…

I merged the pull request, thanks

Don’t worry, I guessed you simply forgot to commit the .ui. I’m happy because solving it made me understand better the interfaces generated with Qt designer and how they work with Krita. :smiley: (Is also very handy that you added templates for it).

And after setting some repositories, now I understand how useful is the Symlink option. Is very handy that you added that option.

I know I repeat myself, but this plugin is amazing, should be integrated with Krita IMHO. Thank you so much for the awesome work.

Is there any way to get a debug log when working on a extension?

(Im on Windows). I tried executing Krita with the cmd, but it shows no logs/prints

@Michelist Thank you for the help Michelist :four_leaf_clover:. The Log Viewer seems helpful, but sadly it seems not to show extensions’ print(). But stills helpful, since I think I can trigger some krita actions from my extension and get them in the Log Viewer (and at least I think I could know if the code is executed, I guess).

PS: Sorry, I thought I asked this question in my “newbie asking questions” thread, I wrote in the wrong tab

I don’t use it and so my answer may not be sufficient, respective the Log Viewer-Docker in Krita is not powerful enough for your needs. You will find this docker in Krita via ‘‘Settings’’ >> ‘‘Configure Krita’’ >> ‘‘Dockers’’, in the Log-Viewer you can/have to enable the parts that should be logged, that settings dialog is found via the button in the lower right corner of that docker.

Furthermore, you can get logs via the methods described in the Krita manual under Getting Krita logs.

Michelist

1 Like

I created a new plugin from the SimpleDockerGUIQML template. Without editing anything, the Docker wasn’t showing anything in Krita.

After some research I found that replacing the commented code with setWidget() worked, and now shows correctly the .ui from the template (also my own .ui)

(Not saying the template is wrong or anything, because I’m still learning and I have no clue why it doesn’t work, but I just want to report it since I was very confused with the blank docker)

1 Like