Repository navigation
Expand file tree
/
Copy pathutil.py
More file actions
164 lines (125 loc) · 4.54 KB
/
Copy pathutil.py
File metadata and controls
164 lines (125 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE in the project root
# for license information.
import inspect
import os
import sys
def evaluate(code, path=__file__, mode="eval"):
# Setting file path here to avoid breaking here if users have set
# "break on exception raised" setting. This code can potentially run
# in user process and is indistinguishable if the path is not set.
# We use the path internally to skip exception inside the debugger.
expr = compile(code, path, "eval")
return eval(expr, {}, sys.modules)
class Observable(object):
"""An object with change notifications."""
observers = () # used when attributes are set before __init__ is invoked
def __init__(self):
self.observers = []
def __setattr__(self, name, value):
try:
return super().__setattr__(name, value)
finally:
for ob in self.observers:
ob(self, name)
class Env(dict):
"""A dict for environment variables."""
@staticmethod
def snapshot():
"""Returns a snapshot of the current environment."""
return Env(os.environ)
def copy(self, updated_from=None):
result = Env(self)
if updated_from is not None:
result.update(updated_from)
return result
def prepend_to(self, key, entry):
"""Prepends a new entry to a PATH-style environment variable, creating
it if it doesn't exist already.
"""
try:
tail = os.path.pathsep + self[key]
except KeyError:
tail = ""
self[key] = entry + tail
def force_str(s, encoding, errors="strict"):
"""Converts s to str, using the provided encoding. If s is already str,
it is returned as is.
"""
return s.decode(encoding, errors) if isinstance(s, bytes) else str(s)
def force_bytes(s, encoding, errors="strict"):
"""Converts s to bytes, using the provided encoding. If s is already bytes,
it is returned as is.
If errors="strict" and s is bytes, its encoding is verified by decoding it;
UnicodeError is raised if it cannot be decoded.
"""
if isinstance(s, str):
return s.encode(encoding, errors)
else:
s = bytes(s)
if errors == "strict":
# Return value ignored - invoked solely for verification.
s.decode(encoding, errors)
return s
def force_ascii(s, errors="strict"):
"""Same as force_bytes(s, "ascii", errors)"""
return force_bytes(s, "ascii", errors)
def force_utf8(s, errors="strict"):
"""Same as force_bytes(s, "utf8", errors)"""
return force_bytes(s, "utf8", errors)
def nameof(obj, quote=False):
"""Returns the most descriptive name of a Python module, class, or function,
as a Unicode string
If quote=True, name is quoted with repr().
Best-effort, but guaranteed to not fail - always returns something.
"""
try:
name = obj.__qualname__
except Exception:
try:
name = obj.__name__
except Exception:
# Fall back to raw repr(), and skip quoting.
try:
name = repr(obj)
except Exception:
return "<unknown>"
else:
quote = False
if quote:
try:
name = repr(name)
except Exception:
pass
return force_str(name, "utf-8", "replace")
def srcnameof(obj):
"""Returns the most descriptive name of a Python module, class, or function,
including source information (filename and linenumber), if available.
Best-effort, but guaranteed to not fail - always returns something.
"""
name = nameof(obj, quote=True)
# Get the source information if possible.
try:
src_file = inspect.getsourcefile(obj)
except Exception:
pass
else:
name += f" (file {src_file!r}"
try:
_, src_lineno = inspect.getsourcelines(obj)
except Exception:
pass
else:
name += f", line {src_lineno}"
name += ")"
return name
def hide_debugpy_internals():
"""Returns True if the caller should hide something from debugpy."""
return "DEBUGPY_TRACE_DEBUGPY" not in os.environ
def hide_thread_from_debugger(thread):
"""Disables tracing for the given thread if DEBUGPY_TRACE_DEBUGPY is not set.
DEBUGPY_TRACE_DEBUGPY is used to debug debugpy with debugpy
"""
if hide_debugpy_internals():
thread.pydev_do_not_trace = True
thread.is_pydev_daemon_thread = True