Sublime Forum

Dynamic build target

#1

I created a "Python: Copy Path For Pytest" command, which, depending on the current cursor position, returns something like "mypackage.tests.test_module::TestClass.test_method" and copies it to the clipboard. I then switch to my terminal and pass that string as an argument for pytest, e.g.

$ python3 -m pytest mypackage.tests.test_module::TestClass.test_method

This way I can run a specific (single) Python test.

Now, I would like to do something similar by using the build system instead. This way I can avoid switching back & forth from the Linux shell. Basically what I need is to tell the build system to interpret a custom $variable. Something like:

{
    "cmd": ["python3", "-m", "pytest", "$pytest_obj_path"],
    "selector": "source.python",
}

Any idea on what’s the best way to accomplish this?

Thanks in advance

0 Likes

#2

You can use a custom build target to

  1. Get that pytest representation from the clipboard and construct that custom cmd.
  2. Calls the exec command with the custom cmd.
1 Like

#3

An example of the technique is the following:

1 Like

#4

Thanks a lot Terence. I have modified your script a bit:

import sublime
from Default.exec import ExecCommand


def pytest_path(view):
    """
    Given the current cursor position, return a string like:
    tests/test_autoimport.py::TestCLI::test_importable_third_party
    """
    return "foo"  # omitted


class SmartExecCommand(ExecCommand):
    """Same as original 'exec' cmd, but in addition supports the translation
    of custom variables
    """

    def run(self, **kwargs):
        view = sublime.active_window().active_view()
        if "${pytest_path}" in str(kwargs):
            kwargs = sublime.expand_variables(
                kwargs, {"pytest_path": pytest_path(view)}
            )
        super().run(**kwargs)  # call original `exec` command

And this is the Pytest This.sublime-build file:

{
    "selector": "source.python",
    "target": "smart_exec",
    "shell_cmd": "python3 -m pytest -v -s \\${pytest_path}",
    "working_dir": "${folder}",
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
    "env": {"PYTHONIOENCODING": "utf-8",
            "PYTHONUNBUFFERED": "1",
            "PYTHONWARNINGS": "always"},
}
0 Likes

#5

The advice I was given in a similar scenario was to use WindowCommand rather than subclassing Default.Exec.

class MyCommand(sublime_plugin.WindowCommand):
    def run(self, **kwargs):
        
        # modify kwargs as required

        self.window.run_command("exec", kwargs)
0 Likes