1import sys
2
3from typing import AnyStr
4from typing import List
5from typing import Optional
6from typing import Union
7
8import six.moves.urllib.parse as urllib_parse
9
10
11urlparse = urllib_parse
12
13
14try:  # Python 2
15    long = long
16    unicode = unicode
17    basestring = basestring
18except NameError:  # Python 3
19    long = int
20    unicode = str
21    basestring = str
22
23
24PY2 = sys.version_info[0] == 2
25PY34 = sys.version_info >= (3, 4)
26PY35 = sys.version_info >= (3, 5)
27PY36 = sys.version_info >= (3, 6)
28PY37 = sys.version_info >= (3, 7)
29
30WINDOWS = sys.platform == "win32"
31
32if PY2:
33    import pipes
34
35    shell_quote = pipes.quote
36else:
37    import shlex
38
39    shell_quote = shlex.quote
40
41if PY35:
42    from pathlib import Path  # noqa
43else:
44    from pathlib2 import Path  # noqa
45
46if not PY36:
47    from collections import OrderedDict  # noqa
48else:
49    OrderedDict = dict
50
51
52try:
53    FileNotFoundError
54except NameError:
55    FileNotFoundError = IOError  # noqa
56
57
58def decode(
59    string, encodings=None
60):  # type: (Union[AnyStr, unicode], Optional[str]) -> Union[str, bytes]
61    if not PY2 and not isinstance(string, bytes):
62        return string
63
64    if PY2 and isinstance(string, unicode):
65        return string
66
67    encodings = encodings or ["utf-8", "latin1", "ascii"]
68
69    for encoding in encodings:
70        try:
71            return string.decode(encoding)
72        except (UnicodeEncodeError, UnicodeDecodeError):
73            pass
74
75    return string.decode(encodings[0], errors="ignore")
76
77
78def encode(
79    string, encodings=None
80):  # type: (AnyStr, Optional[str]) -> Union[str, bytes]
81    if not PY2 and isinstance(string, bytes):
82        return string
83
84    if PY2 and isinstance(string, str):
85        return string
86
87    encodings = encodings or ["utf-8", "latin1", "ascii"]
88
89    for encoding in encodings:
90        try:
91            return string.encode(encoding)
92        except (UnicodeEncodeError, UnicodeDecodeError):
93            pass
94
95    return string.encode(encodings[0], errors="ignore")
96
97
98def to_str(string):  # type: (AnyStr) -> str
99    if isinstance(string, str) or not isinstance(string, (unicode, bytes)):
100        return string
101
102    if PY2:
103        method = "encode"
104    else:
105        method = "decode"
106
107    encodings = ["utf-8", "latin1", "ascii"]
108
109    for encoding in encodings:
110        try:
111            return getattr(string, method)(encoding)
112        except (UnicodeEncodeError, UnicodeDecodeError):
113            pass
114
115    return getattr(string, method)(encodings[0], errors="ignore")
116
117
118def list_to_shell_command(cmd):  # type: (List[str]) -> str
119    executable = cmd[0]
120
121    if " " in executable:
122        executable = '"{}"'.format(executable)
123        cmd[0] = executable
124
125    return " ".join(cmd)
126