Completed
Push — dev-4.1-unstable ( e0128e...426fcf )
by Felipe A.
01:03
created

getdebug()   A

Complexity

Conditions 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
#!/usr/bin/env python
2
# -*- coding: UTF-8 -*-
3
4
import os
5
import os.path
6
import sys
7
import itertools
8
9
import warnings
10
import functools
11
12
FS_ENCODING = sys.getfilesystemencoding()
13
PY_LEGACY = sys.version_info < (3, )
14
ENV_PATH = []  # populated later
15
TRUE_VALUES = frozenset(('true', 'yes', '1', 'enable', 'enabled', True, 1))
16
17
try:
18
    from scandir import scandir, walk
19
except ImportError:
20
    if not hasattr(os, 'scandir'):
21
        raise
22
    scandir = os.scandir
23
    walk = os.walk
24
25
26
def isexec(path):
27
    '''
28
    Check if given path points to an executable file.
29
30
    :param path: file path
31
    :type path: str
32
    :return: True if executable, False otherwise
33
    :rtype: bool
34
    '''
35
    return os.path.isfile(path) and os.access(path, os.X_OK)
36
37
38
def which(name,
39
          env_path=ENV_PATH,
40
          is_executable_fnc=isexec,
41
          path_join_fnc=os.path.join):
42
    '''
43
    Get command absolute path.
44
45
    :param name: name of executable command
46
    :type name: str
47
    :param env_path: OS environment executable paths, defaults to autodetected
48
    :type env_path: list of str
49
    :param is_executable_fnc: callable will be used to detect if path is
50
                              executable, defaults to `isexec`
51
    :type is_executable_fnc: Callable
52
    :param path_join_fnc: callable will be used to join path components
53
    :type path_join_fnc: Callable
54
    :return: absolute path
55
    :rtype: str or None
56
    '''
57
    for path in env_path:
58
        exe_file = path_join_fnc(path, name)
59
        if is_executable_fnc(exe_file):
60
            return exe_file
61
    return None
62
63
64
def fsdecode(path, os_name=os.name, fs_encoding=FS_ENCODING, errors=None):
65
    '''
66
    Decode given path.
67
68
    :param path: path will be decoded if using bytes
69
    :type path: bytes or str
70
    :param os_name: operative system name, defaults to os.name
71
    :type os_name: str
72
    :param fs_encoding: current filesystem encoding, defaults to autodetected
73
    :type fs_encoding: str
74
    :return: decoded path
75
    :rtype: str
76
    '''
77
    if not isinstance(path, bytes):
78
        return path
79
    if not errors:
80
        use_strict = PY_LEGACY or os_name == 'nt'
81
        errors = 'strict' if use_strict else 'surrogateescape'
82
    return path.decode(fs_encoding, errors=errors)
83
84
85
def fsencode(path, os_name=os.name, fs_encoding=FS_ENCODING, errors=None):
86
    '''
87
    Encode given path.
88
89
    :param path: path will be encoded if not using bytes
90
    :type path: bytes or str
91
    :param os_name: operative system name, defaults to os.name
92
    :type os_name: str
93
    :param fs_encoding: current filesystem encoding, defaults to autodetected
94
    :type fs_encoding: str
95
    :return: encoded path
96
    :rtype: bytes
97
    '''
98
    if isinstance(path, bytes):
99
        return path
100
    if not errors:
101
        use_strict = PY_LEGACY or os_name == 'nt'
102
        errors = 'strict' if use_strict else 'surrogateescape'
103
    return path.encode(fs_encoding, errors=errors)
104
105
106
def getcwd(fs_encoding=FS_ENCODING, cwd_fnc=os.getcwd):
107
    '''
108
    Get current work directory's absolute path.
109
    Like os.getcwd but garanteed to return an unicode-str object.
110
111
    :param fs_encoding: filesystem encoding, defaults to autodetected
112
    :type fs_encoding: str
113
    :param cwd_fnc: callable used to get the path, defaults to os.getcwd
114
    :type cwd_fnc: Callable
115
    :return: path
116
    :rtype: str
117
    '''
118
    path = cwd_fnc()
119
    if isinstance(path, bytes):
120
        path = fsdecode(path, fs_encoding=fs_encoding)
121
    return os.path.abspath(path)
122
123
124
def getdebug(environ=os.environ, true_values=TRUE_VALUES):
125
    '''
126
    Get if app is expected to be ran in debug mode looking at environment
127
    variables.
128
129
    :param environ: environment dict-like object
130
    :type environ: collections.abc.Mapping
131
    :returns: True if debug contains a true-like string, False otherwise
132
    :rtype: bool
133
    '''
134
    return environ.get('DEBUG', '').lower() in true_values
135
136
137
def deprecated(func_or_text, environ=os.environ):
138
    '''
139
    Decorator used to mark functions as deprecated. It will result in a
140
    warning being emmitted hen the function is called.
141
142
    :param func: function or method
143
    :type func: callable
144
    '''
145
    def inner(func):
146
        message = (
147
            'Deprecated function {}.'.format(func.__name__)
148
            if callable(func_or_text) else
149
            func_or_text
150
            )
151
152
        @functools.wraps(func)
153
        def new_func(*args, **kwargs):
154
            with warnings.catch_warnings():
155
                if getdebug(environ):
156
                    warnings.simplefilter('always', DeprecationWarning)
157
                warnings.warn(message, category=DeprecationWarning,
158
                              stacklevel=3)
159
            return func(*args, **kwargs)
160
        return new_func
161
    return inner(func_or_text) if callable(func_or_text) else inner
162
163
164
ENV_PATH[:] = (
165
  fsdecode(path.strip('"'))
166
  for path in os.environ['PATH'].split(os.pathsep)
167
  )
168
169
if PY_LEGACY:
170
    FileNotFoundError = type('FileNotFoundError', (OSError,), {})
171
    range = xrange  # noqa
172
    filter = itertools.ifilter
173
    basestring = basestring
174
    unicode = unicode
175
else:
176
    FileNotFoundError = FileNotFoundError
177
    range = range
178
    filter = filter
179
    basestring = str
180
    unicode = str
181