Developer Debugging Guide Discussion

I think it would be useful if we could use this opportunity to put together some informal guidelines about how to easily debug your qiime2 plugins.

After talking to many others @wasade, it can be unintuitive figuring out how to go about debugging your first plugin.

From discussions with @ebolyen, I learned that importing the qiime2.sdk.plugin_manager.PluginManager object on the command line could help figure out how to load plugins in the Python interpreter.

From personal debugging, I found out that directly importing your plugin is the best way to catch silent errors. For example, if you had a plugin called q2-dummy that wasn't throwing any errors, but wasn't being displayed in the CLI, you could see the errors by running

>>> from q2_dummy.plugin_setup import Plugin

While this may seem obvious in hindsight, these sorts of tricks aren't obvious when getting started. But having these sorts of resources available could really help boost the development of new awesome plugins from more prospective developers! Other tips for debugging from you guys would be key for doing this.

1 Like

Thanks for starting this thread @mortonjt!

I’ll throw in a couple more very informal tips:

PluginManager and the Plugin objects are easy to explore interactively and are really just a collection of dicts, OrderedDicts, and the occasional namedtuple instances (if it looks like NounRecord that’s what it is).

Burried inside the Plugin objects are objects of type Method and Visualizer. These are what you are actually using when you import some method via qiime2.plugins.<your plugin>. They do some dirty magic (to rewrite the signature), but ultimately they are just objects with some references to your original code. They have a .signature property which will basically tell you what the framework thinks your action can do.

3 Likes

I found that adding my repo folder to my PYTHONPATH and trying to run python plugin_setup.py from the command line until it stopped giving me errors was a really simple way to check that I’d set everything up correctly.

Then, when I was ready to try actually running the plugin and have it do more than just “not break”, I went to my main directory and ran python setup.py install to add my plugin to qiime. Then, I could debug by just trying to run my plugin function(s) (e.g. qiime perc-norm percentile-normalize --help).

I realize these may be fairly simple things for more experienced developers, but hopefully this will be helpful to others just starting out!

2 Likes

hi, I would like to dig up this thread and ask which IDEs do you use and if / how do you use debugging features from those developing your plugins?

Now, I do exactly as @cduvallet described above - simply installing my plugin from the scratch and see if some errors occur by running a "whole" command. However, it would be cool to use the power of modern IDEs, e.g., PyCharm, where one can set a Stop button inside the code and track bugs in its particular parts.

Does anyone use this approach and can share some practices?

Hey @Oleg,

What I usually do is to create a small Python script which contains code to run the action you want to test and then create a PyCharm Python configuration for that script - you can then easily debug from there. For example, I would use this file (test_me.py) to debug the "map_positions" action:

from qiime2.plugins import protein_pca
from qiime2 import Artifact


def test_me():
    aln_seqs = Artifact.import_data(
        'FeatureData[AlignedProteinSequence]',
        'q2_protein_pca/tests/data/aligned-protein-sequences-1.fasta'
    )
    meta_result = protein_pca.methods.map_positions(
        aligned_sequences=aln_seqs
    )


if __name__ == "__main__":
    test_me()

together with the following run configuration:

You can then just set your breakpoints wherever you need in the code and you should be good to go (the same thing can also be achieved in VS Code).

Does that help?

Cheers,
Michal

5 Likes

Something else I thought I would share here, also as a note to self - in case you're interested (for whatever reason) in debugging the entire thing as if you were running it from the cli (rather than using Python API as in the example above) you could do something like this in VS Code (I have not managed to make this work in PyCharm - remote debugging is a bit limited there):

  1. Install debugpy in your environment.
  2. Create a Task configuration which will launch the process to be debugged (in tasks.json). For example:
    {
        "label": "Run action",
        "type": "process",
        "command": "${command:python.interpreterPath}",
        "args": [
            "-m", "debugpy", "--wait-for-client", "--listen", "5678", 
            "/Users/mziemski/miniconda3/envs/protein-pca/bin/qiime",
            "protein-pca",
            "map-positions",
            "--i-aligned-sequences",
            "${workspaceFolder}/sample_data/artifacts/thioredoxin-aln.qza",
            "--o-mapped-positions",
            "${workspaceFolder}/sample_data/test-output.qza"
        ],
        "group": "test",
    }
    
    Importantly, you need to pay attention to the line in args which points to the right qiime executable (it needs to be the one from your environment). This command can also be run from the terminal.
  3. Create a Run/Debug configuration (in launch.json) which will let you attach to the process started by the task above, for example:
    {
        "name": "Python: Remote Attach",
        "type": "python",
        "request": "attach",
        "connect": {
            "host": "localhost",
            "port": 5678
        },
        "justMyCode": true
    }
    
  4. Execute the task from point 2 first (it will start the remote debugging session and wait for an incoming connection) and start your debugging session from point 3 - it will now attach to the task process. Et voilà! You can now step through your code.

Note: the justMyCode param in point 3 let's you define whether you want to walk through your code specifically or also through the external libraries that are being called.

6 Likes