Sublime Forum

Dynamic build target


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



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


An example of the technique is the following:

1 Like


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:
    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"},


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)