From 3f128c0e6ce6d91b2a3f4fdc34f4109bf179d6a1 Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Tue, 11 Apr 2017 12:04:52 +0500 Subject: [PATCH 1/7] Use functools.partial standart lib requirement --- pudb/debugger.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index 92979ac..5e570f1 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -7,6 +7,7 @@ import bdb import gc import os import sys +from functools import partial from types import TracebackType from pudb.settings import load_config, save_config @@ -19,18 +20,6 @@ if PY3: else: _next = "next" -try: - from functools import partial -except ImportError: - def partial(func, *args, **keywords): - def newfunc(*fargs, **fkeywords): - newkeywords = keywords.copy() - newkeywords.update(fkeywords) - return func(*(args + fargs), **newkeywords) - newfunc.func = func - newfunc.args = args - newfunc.keywords = keywords - return newfunc HELP_TEXT = """\ Welcome to PuDB, the Python Urwid debugger. From 97093483bf5a264f6a1e6b5486174c5553dc339e Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Tue, 11 Apr 2017 12:42:48 +0500 Subject: [PATCH 2/7] Use py2/3 built-it function next() for iteration step --- pudb/debugger.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index 5e570f1..e90e78d 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -10,16 +10,13 @@ import sys from functools import partial from types import TracebackType +from pudb.lowlevel import detect_encoding from pudb.settings import load_config, save_config +from pudb.py3compat import PY3, raw_input + CONFIG = load_config() save_config(CONFIG) -from pudb.py3compat import PY3, raw_input -if PY3: - _next = "__next__" -else: - _next = "next" - HELP_TEXT = """\ Welcome to PuDB, the Python Urwid debugger. @@ -575,8 +572,7 @@ class FileSourceCodeProvider(SourceCodeProvider): from linecache import getlines lines = getlines(self.file_name) - from pudb.lowlevel import detect_encoding - source_enc, _ = detect_encoding(getattr(iter(lines), _next)) + source_enc, _ = detect_encoding(partial(next, iter(lines))) decoded_lines = [] for l in lines: @@ -621,9 +617,7 @@ class DirectSourceCodeProvider(SourceCodeProvider): from pudb.source_view import format_source lines = self.code.split("\n") - - from pudb.lowlevel import detect_encoding - source_enc, _ = detect_encoding(getattr(iter(lines), _next)) + source_enc, _ = detect_encoding(partial(next, iter(lines))) decoded_lines = [] for i, l in enumerate(lines): From 3019e8829f27a5d8a6502fbf6bc09b00eaa93b83 Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Tue, 11 Apr 2017 12:48:39 +0500 Subject: [PATCH 3/7] Simplify lowlevel.detect_encoding for pudb use --- pudb/debugger.py | 4 ++-- pudb/lowlevel.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index e90e78d..171fe8f 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -572,7 +572,7 @@ class FileSourceCodeProvider(SourceCodeProvider): from linecache import getlines lines = getlines(self.file_name) - source_enc, _ = detect_encoding(partial(next, iter(lines))) + source_enc, _ = detect_encoding(lines) decoded_lines = [] for l in lines: @@ -617,7 +617,7 @@ class DirectSourceCodeProvider(SourceCodeProvider): from pudb.source_view import format_source lines = self.code.split("\n") - source_enc, _ = detect_encoding(partial(next, iter(lines))) + source_enc, _ = detect_encoding(lines) decoded_lines = [] for i, l in enumerate(lines): diff --git a/pudb/lowlevel.py b/pudb/lowlevel.py index 415b0cc..3de9331 100644 --- a/pudb/lowlevel.py +++ b/pudb/lowlevel.py @@ -86,7 +86,7 @@ def lookup_module(filename): # {{{ file encoding detection -# stolen from Python 3.1's tokenize.py, by Ka-Ping Yee +# the main idea stolen from Python 3.1's tokenize.py, by Ka-Ping Yee import re cookie_re = re.compile("^\s*#.*coding[:=]\s*([-\w.]+)") @@ -95,13 +95,13 @@ if PY3: BOM_UTF8 = BOM_UTF8.decode() -def detect_encoding(readline): +def detect_encoding(lines): """ The detect_encoding() function is used to detect the encoding that should - be used to decode a Python source file. It requires one argment, readline, - in the same way as the tokenize() generator. + be used to decode a Python source file. It requires one argment, lines, + iterable lines stream. - It will call readline a maximum of twice, and return the encoding used + It will read a maximum of two lines, and return the encoding used (as a string) and a list of any lines (left as bytes) it has read in. @@ -113,11 +113,11 @@ def detect_encoding(readline): If no encoding is specified, then the default of 'utf-8' will be returned. """ bom_found = False - encoding = None + line_iterator = iter(lines) def read_or_stop(): try: - return readline() + return next(line_iterator) except StopIteration: return '' From 7bf9ed38c006080631120ac0e39e42933c887dcd Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Tue, 11 Apr 2017 13:07:49 +0500 Subject: [PATCH 4/7] Clean-up a little the source lines decoding part --- pudb/debugger.py | 30 ++++-------------------------- pudb/lowlevel.py | 9 +++++++++ 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index 171fe8f..ec37ea6 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -10,7 +10,7 @@ import sys from functools import partial from types import TracebackType -from pudb.lowlevel import detect_encoding +from pudb.lowlevel import decode_lines from pudb.settings import load_config, save_config from pudb.py3compat import PY3, raw_input @@ -571,17 +571,7 @@ class FileSourceCodeProvider(SourceCodeProvider): try: from linecache import getlines lines = getlines(self.file_name) - - source_enc, _ = detect_encoding(lines) - - decoded_lines = [] - for l in lines: - if hasattr(l, "decode"): - decoded_lines.append(l.decode(source_enc)) - else: - decoded_lines.append(l) - - return format_source(debugger_ui, decoded_lines, set(breakpoints)) + return format_source(debugger_ui, list(decode_lines(lines)), set(breakpoints)) except: from pudb.lowlevel import format_exception debugger_ui.message("Could not load source file '%s':\n\n%s" % ( @@ -616,20 +606,8 @@ class DirectSourceCodeProvider(SourceCodeProvider): def get_lines(self, debugger_ui): from pudb.source_view import format_source - lines = self.code.split("\n") - source_enc, _ = detect_encoding(lines) - - decoded_lines = [] - for i, l in enumerate(lines): - if hasattr(l, "decode"): - l = l.decode(source_enc) - - if i+1 < len(lines): - l += "\n" - - decoded_lines.append(l) - - return format_source(debugger_ui, decoded_lines, set()) + lines = self.code.splitlines(True) + return format_source(debugger_ui, list(decode_lines(lines)), set()) # }}} diff --git a/pudb/lowlevel.py b/pudb/lowlevel.py index 3de9331..0f10004 100644 --- a/pudb/lowlevel.py +++ b/pudb/lowlevel.py @@ -166,6 +166,15 @@ def detect_encoding(lines): return 'utf-8', [first, second] + +def decode_lines(lines): + source_enc, _ = detect_encoding(lines) + + for line in lines: + if hasattr(line, "decode"): + yield line.decode(source_enc) + else: + yield line # }}} From 7033334e22f3fe31349675acc3c082fca39eb213 Mon Sep 17 00:00:00 2001 From: discort Date: Tue, 11 Apr 2017 21:29:20 +0300 Subject: [PATCH 5/7] added base tests for source code providers --- test/test_source_code_providers.py | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 test/test_source_code_providers.py diff --git a/test/test_source_code_providers.py b/test/test_source_code_providers.py new file mode 100644 index 0000000..b503fb8 --- /dev/null +++ b/test/test_source_code_providers.py @@ -0,0 +1,36 @@ +import pytest # noqa: F401 + +from pudb.debugger import NullSourceCodeProvider, FileSourceCodeProvider, DirectSourceCodeProvider +from pudb.source_view import SourceLine + + +class TestNullSourceCodeProvider: + def test_get_lines(self, mocker): + provider = NullSourceCodeProvider() + result = provider.get_lines(mocker.Mock()) + assert len(result) == 10 + assert isinstance(result[0], SourceLine) + + +class TestFileSourceCodeProvider: + def test_string_file_name(self, mocker): + mock_debugger = mocker.Mock() + mock_debugger.canonic = mocker.Mock(return_value='') + provider = FileSourceCodeProvider(mock_debugger, 'test file name') + result = provider.get_lines(mocker.MagicMock()) + assert len(result) == 1 + assert isinstance(result[0], SourceLine) + + def test_get_lines(self, mocker): + provider = FileSourceCodeProvider(mocker.Mock(), 'test file name') + result = provider.get_lines(mocker.MagicMock()) + assert len(result) == 1 + assert isinstance(result[0], SourceLine) + + +class TestDirectSourceCodeProvider: + def test_get_lines(self, mocker): + provider = DirectSourceCodeProvider(mocker.Mock(), 'test code') + result = provider.get_lines(mocker.Mock()) + assert len(result) == 1 + assert isinstance(result[0], SourceLine) From c47726b0b0809f5d179300ae3e6a5cb2c0edb90e Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Wed, 12 Apr 2017 01:28:26 +0500 Subject: [PATCH 6/7] Added lines decoding tests --- test/test_lowlevel.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 test/test_lowlevel.py diff --git a/test/test_lowlevel.py b/test/test_lowlevel.py new file mode 100644 index 0000000..b7c2f3d --- /dev/null +++ b/test/test_lowlevel.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +from pudb.lowlevel import detect_encoding, decode_lines +from pudb.py3compat import PY3 + + +def test_detect_encoding_nocookie(): + lines = ['Test Проверка'] + encoding, _ = detect_encoding(lines) + assert encoding == 'utf-8' + + +def test_detect_encoding_cookie(): + lines = [ + '# coding=utf-8', + 'Test', + 'Проверка' + ] + encoding, _ = detect_encoding(lines) + assert encoding == 'utf-8' + + +def test_decode_lines(): + lines = [ + '# coding=utf-8', + 'Test', + 'Проверка', + ] + if PY3: + assert lines == list(decode_lines(lines)) + else: + assert [l.decode('utf-8') for l in lines] == list(decode_lines(lines)) From 33644753b3342fa027259d91280adbbd7bf1bfc7 Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Sun, 16 Apr 2017 00:02:29 +0500 Subject: [PATCH 7/7] Put multiline contidion in one line --- pudb/debugger.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index ec37ea6..af9e447 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -541,10 +541,7 @@ class FileSourceCodeProvider(SourceCodeProvider): self.file_name = debugger.canonic(file_name) def __eq__(self, other): - return ( - type(self) == type(other) - and - self.file_name == other.file_name) + return type(self) == type(other) and self.file_name == other.file_name def identifier(self): return self.file_name