diff --git a/pysnooper/pysnooper.py b/pysnooper/pysnooper.py index cff1814..917fe00 100644 --- a/pysnooper/pysnooper.py +++ b/pysnooper/pysnooper.py @@ -1,9 +1,10 @@ # Copyright 2019 Ram Rachum. # This program is distributed under the MIT license. +from future import standard_library +standard_library.install_aliases() import sys import os -import pathlib import inspect import types import datetime as datetime_module @@ -20,26 +21,31 @@ from .tracer import Tracer def get_write_function(output): if output is None: def write(s): + s += '\n' + if isinstance(s, bytes): # Python 2 compatibility + s = s.decode('utf-8') stderr = sys.stderr stderr.write(s) - stderr.write('\n') elif isinstance(output, (pycompat.PathLike, str)): - output_path = pathlib.Path(output) def write(s): - with output_path.open('a') as output_file: + s += '\n' + if isinstance(s, bytes): # Python 2 compatibility + s = s.decode('utf-8') + with open(output_path, 'a') as output_file: output_file.write(s) - output_file.write('\n') else: assert isinstance(output, utils.WritableStream) def write(s): + s += '\n' + if isinstance(s, bytes): # Python 2 compatibility + s = s.decode('utf-8') output.write(s) - output.write('\n') return write -def snoop(output=None, *, variables=(), depth=1): +def snoop(output=None, variables=(), depth=1): write = get_write_function(output) @decorator.decorator def decorate(function, *args, **kwargs): diff --git a/pysnooper/tracer.py b/pysnooper/tracer.py index 497be6b..e693ee0 100644 --- a/pysnooper/tracer.py +++ b/pysnooper/tracer.py @@ -7,14 +7,15 @@ import re import collections import datetime as datetime_module -def get_shortish_repr(item) -> str: +import six + +def get_shortish_repr(item): r = repr(item) if len(r) > 100: r = '{r[:97]}...'.format(**locals()) return r -def get_local_reprs(frame: types.FrameType, *, - variables=()) -> dict: +def get_local_reprs(frame, variables=()): result = {} for key, value in frame.f_locals.items(): try: @@ -40,7 +41,7 @@ def get_local_reprs(frame: types.FrameType, *, source_cache_by_module_name = {} source_cache_by_file_name = {} -def get_source_from_frame(frame: types.FrameType) -> str: +def get_source_from_frame(frame): module_name = frame.f_globals.get('__name__') or '' if module_name: try: @@ -85,7 +86,8 @@ def get_source_from_frame(frame: types.FrameType) -> str: if match: encoding = match.group(1).decode('ascii') break - source = [str(sline, encoding, 'replace') for sline in source] + source = [six.text_type(sline, encoding, 'replace') for sline in + source] if module_name: source_cache_by_module_name[module_name] = source @@ -94,8 +96,7 @@ def get_source_from_frame(frame: types.FrameType) -> str: return source class Tracer: - def __init__(self, *, target_code_object: types.CodeType, write: callable, - variables=(), depth: int=1): + def __init__(self, target_code_object, write, variables=(), depth=1): self.target_code_object = target_code_object self.write = write self.variables = variables @@ -112,8 +113,7 @@ class Tracer: sys.settrace(self.original_trace_function) - def trace(self: 'Tracer', frame: types.FrameType, event: str, - arg): + def trace(self, frame, event, arg): ### Checking whether we should trace this line: ####################### # # diff --git a/requirements.txt b/requirements.txt index a1cabb9..b34828c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ decorator>=4.3.0 -future>=0.17.1 \ No newline at end of file +future>=0.17.1 +six>=1.12.0 \ No newline at end of file diff --git a/setup.py b/setup.py index af92292..0730306 100644 --- a/setup.py +++ b/setup.py @@ -3,8 +3,6 @@ import setuptools -with open('README.md', 'r') as readme_file: - long_description = readme_file.read() setuptools.setup( name='PySnooper', @@ -12,15 +10,12 @@ setuptools.setup( author='Ram Rachum', author_email='ram@rachum.com', description="A poor man's debugger for Python.", - long_description=long_description, + long_description=open('README.md', 'r').read(), long_description_content_type='text/markdown', url='https://github.com/cool-RR/PySnooper', packages=setuptools.find_packages(), - install_requires=('decorator>=4.3.0',), - tests_require=( - 'pytest>=4.4.1', - 'python_toolbox>=0.9.3', - ), + install_requires=open('requirements.txt', 'r').read().split('\n'), + tests_require=open('test_requirements.txt', 'r').read().split('\n'), classifiers=[ 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', diff --git a/tests/test_pysnooper.py b/tests/test_pysnooper.py index 810ce40..5de04aa 100644 --- a/tests/test_pysnooper.py +++ b/tests/test_pysnooper.py @@ -40,7 +40,7 @@ def test_string_io(): def test_variables(): - class Foo: + class Foo(object): def __init__(self): self.x = 2 diff --git a/tests/utils.py b/tests/utils.py index ce0e11a..638a098 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -11,7 +11,7 @@ import pysnooper.pycompat class _BaseEntry(pysnooper.pycompat.ABC): @abc.abstractmethod - def check(self, s: str) -> bool: + def check(self, s): pass class VariableEntry(_BaseEntry): @@ -19,7 +19,7 @@ class VariableEntry(_BaseEntry): r"""^(?P(?: {4})*)(?PNew|Modified|Starting) var:""" r"""\.{2,7} (?P[^ ]+) = (?P.+)$""" ) - def __init__(self, name=None, value=None, stage=None, *, + def __init__(self, name=None, value=None, stage=None, name_regex=None, value_regex=None): if name is not None: assert name_regex is None @@ -35,7 +35,7 @@ class VariableEntry(_BaseEntry): self.value_regex = (None if value_regex is None else re.compile(value_regex)) - def _check_name(self, name: str) -> bool: + def _check_name(self, name): if self.name is not None: return name == self.name elif self.name_regex is not None: @@ -43,7 +43,7 @@ class VariableEntry(_BaseEntry): else: return True - def _check_value(self, value: str) -> bool: + def _check_value(self, value): if self.value is not None: return value == self.value elif self.value_regex is not None: @@ -51,14 +51,14 @@ class VariableEntry(_BaseEntry): else: return True - def _check_stage(self, stage: str) -> bool: + def _check_stage(self, stage): stage = stage.lower() if self.stage is None: return stage in ('starting', 'new', 'modified') else: return stage == self.value - def check(self, s: str) -> bool: + def check(self, s): match = self.line_pattern.match(s) if not match: return False @@ -68,7 +68,7 @@ class VariableEntry(_BaseEntry): class _BaseEventEntry(_BaseEntry): - def __init__(self, source=None, *, source_regex=None): + def __init__(self, source=None, source_regex=None): if type(self) is _BaseEventEntry: raise TypeError if source is not None: @@ -87,7 +87,7 @@ class _BaseEventEntry(_BaseEntry): def event_name(self): return re.match('^[A-Z][a-z]*', type(self).__name__).group(0).lower() - def _check_source(self, source: str) -> bool: + def _check_source(self, source): if self.source is not None: return source == self.source elif self.source_regex is not None: @@ -95,7 +95,7 @@ class _BaseEventEntry(_BaseEntry): else: return True - def check(self, s: str) -> bool: + def check(self, s): match = self.line_pattern.match(s) if not match: return False