Completed
Push — master ( ed35bb...dcee7e )
by Bjorn
07:54
created

dkfileutils.which()   F

Complexity

Conditions 19

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 19
dl 0
loc 50
rs 2.7503

1 Method

Rating   Name   Duplication   Size   Complexity  
B dkfileutils.match() 0 14 6

How to fix   Complexity   

Complexity

Complex classes like dkfileutils.which() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
"""Print where on the path an executable is located.
3
"""
4
from __future__ import print_function
5
import sys
6
import os
7
from stat import ST_MODE, S_IXUSR, S_IXGRP, S_IXOTH
8
9
10
def get_executable(name):
11
    return list(which(name))[0]
12
13
14
def get_path_directories():
15
    pth = os.environ['PATH']
16
    if sys.platform == 'win32' and os.environ.get("BASH"):
17
        # winbash has a bug..
18
        if pth[1] == ';':  # pragma: nocover
19
            pth = pth.replace(';', ':', 1)
20
    return pth.split(os.pathsep)
21
22
23
def is_executable(fname):
24
    return os.stat(fname)[ST_MODE] & (S_IXUSR | S_IXGRP | S_IXOTH)
25
26
27
def which(filename, interactive=False, verbose=False):
28
    exe = os.environ.get('PATHEXT', ['.cmd', '.bat', '.exe', '.com'])
29
30
    name, ext = os.path.splitext(filename)
31
    if ext and (ext in exe):  # pragma: nocover
32
        exe = []
33
34
    def match(filenames):
35
        res = set()
36
        for fname in filenames:
37
            if fname == filename:  # pragma: nocover
38
                res.add(fname)
39
                continue
40
41
            fn_name, fn_ext = os.path.splitext(fname)
42
            if name == fn_name:
43
                for suffix in exe:
44
                    if name + fn_ext == fname:
45
                        res.add(fname)
46
47
        return sorted(res)
48
49
    returnset = set()
50
    found = False
51
    for pth in get_path_directories():
52
        if not pth.strip():  # pragma: nocover
53
            continue
54
55
        if verbose:  # pragma: nocover
56
            print('checking pth..')
57
58
        try:
59
            fnames = os.listdir(pth)
60
        except:  # pragma: nocover
61
            continue
62
63
        matched = match(fnames)
64
65
        if matched:
66
            for m in matched:
67
                found_file = os.path.normcase(os.path.normpath(os.path.join(pth, m)))
68
                if found_file not in returnset:
69
                    if is_executable(found_file):
70
                        yield found_file
71
                    returnset.add(found_file)
72
            found = True
73
74
    if not found and interactive:  # pragma: nocover
75
        print("Couldn't find %r anywhere on the path.." % filename)
76
        sys.exit(1)
77
78
79
if __name__ == "__main__":  # pragma: nocover
80
    for _fname in which(sys.argv[1], interactive=True, verbose='-v' in sys.argv):
81
        print(_fname)
82
    sys.exit(0)
83