github.com/tilt-dev/wat@v0.0.2-0.20180626175338-9349b638e250/cli/wat/plugin_pytest.go (about)

     1  package wat
     2  
     3  import (
     4  	"context"
     5  	"os/exec"
     6  
     7  	"fmt"
     8  	"regexp"
     9  )
    10  
    11  var rePrefix = regexp.MustCompile("(^|/)test_(.*)\\.py")
    12  var rePostfix = regexp.MustCompile("(.*)_test\\.py")
    13  var testRegexps = []*regexp.Regexp{rePrefix, rePostfix}
    14  
    15  type PluginPytest struct{}
    16  
    17  func (PluginPytest) name() string { return "python+pytest populate" }
    18  
    19  func (PluginPytest) run(ctx context.Context, root string) ([]WatCommand, error) {
    20  	// 1. is pytest relevant?
    21  	if !projUsesPytest(ctx, root) {
    22  		return nil, nil
    23  	}
    24  
    25  	// 2. where are the test files?
    26  	files, err := findTestFiles(ctx, root)
    27  	if err != nil {
    28  		return nil, fmt.Errorf("findTestFiles: %v", err)
    29  	}
    30  
    31  	// 3. which tests --> which files?
    32  	watCmds := []WatCommand{}
    33  	for _, f := range files {
    34  		filePattern := testFileToPattern(root, f.name)
    35  		watCmds = append(watCmds, WatCommand{
    36  			Command:     fmt.Sprintf("pytest %s", f.name),
    37  			FilePattern: filePattern,
    38  		})
    39  	}
    40  
    41  	return watCmds, nil
    42  }
    43  
    44  // Here's the naive implementation. Other possibilities:
    45  // a. are there py files?
    46  // b. is some other framework configured here that takes precedence?
    47  // c. pytest-related files in .gitignore, requirements.txt, setup.py?
    48  // d. config files
    49  // + path/pytest.ini
    50  // + path/setup.cfg  (must also contain [tool:pytest] section to match)
    51  // + path/tox.ini    (must also contain [pytest] section to match)
    52  // + pytest.ini
    53  func projUsesPytest(ctx context.Context, root string) bool {
    54  	// is there a pytest executable?
    55  	cmd := exec.CommandContext(ctx, "python", "-c", "import pytest")
    56  	err := cmd.Run()
    57  	if err != nil {
    58  		return false
    59  	}
    60  
    61  	return true
    62  }
    63  
    64  // This is the naive function that just finds test_*.py files, returns their
    65  // invocations (NOT caring about associated code)
    66  func findTestFiles(ctx context.Context, root string) ([]fileInfo, error) {
    67  	allFiles, err := walkDir(root)
    68  	if err != nil {
    69  		return nil, fmt.Errorf("walkDir: %v", err)
    70  	}
    71  	return filterFilesMatchAny(allFiles, testRegexps), nil
    72  }
    73  
    74  func testFileToPattern(root, test string) string {
    75  	// Fallthrough: associate with all .py files
    76  	return "**/*.py"
    77  }
    78  
    79  func baseFile(test string) string {
    80  	if substrs := rePrefix.FindStringSubmatch(test); len(substrs) > 1 {
    81  		fmt.Println(substrs)
    82  		return fmt.Sprintf("%s.py", substrs[1])
    83  	}
    84  	if substrs := rePostfix.FindStringSubmatch(test); len(substrs) > 1 {
    85  		fmt.Println(substrs)
    86  		return fmt.Sprintf("%s.py", substrs[1])
    87  	}
    88  	return ""
    89  }
    90  
    91  var _ plugin = PluginPytest{}