Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions pysnooper/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ def write(s):
return write


def _path_eq_or_sub(c, p):
# ref: https://stackoverflow.com/q/3812849/12388699
# assert file == os.path.realpath(file), 'property of frame.f_code.co_filename'
p_slash = os.path.join(p, '')
return c.rstrip(os.sep) == p.rstrip(os.sep) or \
os.path.commonprefix([c, p_slash]).rstrip(os.sep) == p.rstrip(os.sep)


class FileWriter(object):
def __init__(self, path, overwrite):
self.path = pycompat.text_type(path)
Expand Down Expand Up @@ -191,6 +199,10 @@ class Tracer:
Show snoop lines for functions that your function calls::

@pysnooper.snoop(depth=2)

Only snoop lines that are in the specified source directories::

@pysnooper.snoop(src_dir='path/to/myproj')

Start all snoop lines with a prefix, to grep for them easily::

Expand Down Expand Up @@ -225,7 +237,7 @@ class Tracer:
def __init__(self, output=None, watch=(), watch_explode=(), depth=1,
prefix='', overwrite=False, thread_info=False, custom_repr=(),
max_variable_length=100, normalize=False, relative_time=False,
color=True):
color=True, source_paths=[], exclude_paths=[]):
self._write = get_write_function(output, overwrite)

self.watch = [
Expand Down Expand Up @@ -255,7 +267,6 @@ def __init__(self, output=None, watch=(), watch_explode=(), depth=1,
self.relative_time = relative_time
self.color = color and sys.platform in ('linux', 'linux2', 'cygwin',
'darwin')

if self.color:
self._FOREGROUND_BLUE = '\x1b[34m'
self._FOREGROUND_CYAN = '\x1b[36m'
Expand All @@ -281,6 +292,18 @@ def __init__(self, output=None, watch=(), watch_explode=(), depth=1,
self._STYLE_NORMAL = ''
self._STYLE_RESET_ALL = ''

def process_paths(paths):
ret = []
if isinstance(paths, str):
ret = [paths]
else:
assert isinstance(paths, list)
ret = paths
return list(map(os.path.realpath, ret))

self.source_paths = process_paths(source_paths)
self.exclude_paths = process_paths(exclude_paths)

def __call__(self, function_or_class):
if DISABLED:
return function_or_class
Expand Down Expand Up @@ -397,6 +420,17 @@ def trace(self, frame, event, arg):
# We should trace this line either if it's in the decorated function,
# or the user asked to go a few levels deeper and we're within that
# number of levels deeper.
if self.source_paths and not (
frame.f_code.co_filename[0] == '/' and # in case of '<frozen xxx>'
any(_path_eq_or_sub(frame.f_code.co_filename, p) for p in self.source_paths)
):
return None

if self.exclude_paths and (
frame.f_code.co_filename[0] == '/' and # in case of '<frozen xxx>'
any(_path_eq_or_sub(frame.f_code.co_filename, p) for p in self.exclude_paths)
):
return None

if not (frame.f_code in self.target_codes or frame in self.target_frames):
if self.depth == 1:
Expand Down