diff --git a/.gitignore b/.gitignore index 07f27968cd053c5715b5d40567c4c8fb5220792b..b60872318a0ab777ab30fd0b763eaa30e49c96c5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ setuptools-*gz setuptools-*egg traceback*txt .DS_Store +.cache/ +.coverage diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 54dc1b6b755a605e4956d5681d06960742e18e18..9ba9bf068aa9d9c08aeb7f0f037772258abe4269 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,6 +2,7 @@ Python 2.7: script: - py_version=2.7 - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh + - export REQUIREMENTS_TXT=requirements.dev.txt - ". ./build-and-test-py-project.sh" tags: - python2.7 @@ -13,6 +14,7 @@ Python 3.5: script: - py_version=3.5 - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh + - export REQUIREMENTS_TXT=requirements.dev.txt - ". ./build-and-test-py-project.sh" tags: - python3.5 @@ -24,6 +26,7 @@ Python 3.6: script: - py_version=3.6 - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh + - export REQUIREMENTS_TXT=requirements.dev.txt - ". ./build-and-test-py-project.sh" tags: - python3.6 @@ -35,6 +38,7 @@ Python 2.6: script: - py_version=2.6 - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh + - export REQUIREMENTS_TXT=requirements.dev.txt - ". ./build-and-test-py-project.sh" tags: - python2.6 diff --git a/pudb/py3compat.py b/pudb/py3compat.py index 9c6b466c195a5d916fb8804f23a3f0a80dc05743..d390bbd78e2cf9dcd140c21ee091b5022c7797db 100644 --- a/pudb/py3compat.py +++ b/pudb/py3compat.py @@ -18,3 +18,11 @@ else: string_types = (basestring,) # noqa: F821 text_type = unicode # noqa: F821 execfile = execfile + + +try: + import builtins + from configparser import ConfigParser +except ImportError: + import __builtin__ as builtins # noqa: F401 + from ConfigParser import ConfigParser # noqa: F401 diff --git a/pudb/settings.py b/pudb/settings.py index a5f9019ffc558872559e3c9bce2ccacb63c9a10e..81c4d5b3e0ca52a4ba5e7dbfa6445a48a586f262 100644 --- a/pudb/settings.py +++ b/pudb/settings.py @@ -3,11 +3,8 @@ from __future__ import absolute_import, division, print_function import os import sys -from pudb.py3compat import PY3 -if PY3: - from configparser import ConfigParser -else: - from ConfigParser import ConfigParser +from pudb.py3compat import ConfigParser +from pudb.lowlevel import lookup_module, get_breakpoint_invalid_reason # minor LGPL violation: stolen from python-xdg @@ -15,21 +12,24 @@ _home = os.environ.get('HOME', None) xdg_data_home = os.environ.get('XDG_DATA_HOME', os.path.join(_home, '.local', 'share') if _home else None) -xdg_config_home = os.environ.get('XDG_CONFIG_HOME', - os.path.join(_home, '.config') if _home else None) -xdg_config_dirs = [xdg_config_home] if xdg_config_home else [] + \ - os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg').split(':') +XDG_CONFIG_HOME = os.environ.get('XDG_CONFIG_HOME', + os.path.join(_home, '.config') if _home else None) + +if XDG_CONFIG_HOME: + XDG_CONFIG_DIRS = [XDG_CONFIG_HOME] +else: + XDG_CONFIG_DIRS = os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg').split(':') def get_save_config_path(*resource): - if xdg_config_home is None: + if XDG_CONFIG_HOME is None: return None if not resource: resource = [XDG_CONF_RESOURCE] resource = os.path.join(*resource) assert not resource.startswith('/') - path = os.path.join(xdg_config_home, resource) + path = os.path.join(XDG_CONFIG_HOME, resource) if not os.path.isdir(path): os.makedirs(path, 448) # 0o700 return path @@ -54,7 +54,7 @@ def load_config(): try: cparser.read([ join(cdir, XDG_CONF_RESOURCE, CONF_FILE_NAME) - for cdir in xdg_config_dirs if isdir(cdir)]) + for cdir in XDG_CONFIG_DIRS if isdir(cdir)]) if cparser.has_section(CONF_SECTION): conf_dict.update(dict(cparser.items(CONF_SECTION))) @@ -429,9 +429,7 @@ def parse_breakpoints(lines): if colon > 0: filename = arg[:colon].strip() - from pudb.lowlevel import lookup_module f = lookup_module(filename) - if not f: continue else: @@ -445,7 +443,6 @@ def parse_breakpoints(lines): else: continue - from pudb.lowlevel import get_breakpoint_invalid_reason if get_breakpoint_invalid_reason(filename, lineno) is None: breakpoints.append((filename, lineno, False, cond, funcname)) @@ -462,13 +459,17 @@ def get_breakpoints_file_name(): def load_breakpoints(): + """ + Loads and check saved breakpoints out from files + Returns: list of tuples + """ from os.path import join, isdir - file_names = [ - join(cdir, XDG_CONF_RESOURCE, name) - for cdir in xdg_config_dirs if isdir(cdir) - for name in [SAVED_BREAKPOINTS_FILE_NAME, BREAKPOINTS_FILE_NAME] - ] + file_names = [] + for cdir in XDG_CONFIG_DIRS: + if isdir(cdir): + for name in [SAVED_BREAKPOINTS_FILE_NAME, BREAKPOINTS_FILE_NAME]: + file_names.append(join(cdir, XDG_CONF_RESOURCE, name)) lines = [] for fname in file_names: @@ -485,12 +486,12 @@ def load_breakpoints(): def save_breakpoints(bp_list): """ - :arg bp_list: a list of tuples `(file_name, line)` + :arg bp_list: a list of `bdb.Breakpoint` objects """ - save_path = get_breakpoints_file_name() if not save_path: return + histfile = open(get_breakpoints_file_name(), 'w') bp_list = set([(bp.file, bp.line, bp.cond) for bp in bp_list]) for bp in bp_list: diff --git a/requirements.dev.txt b/requirements.dev.txt new file mode 100644 index 0000000000000000000000000000000000000000..b23697351c83ef3d6765080adea8a27c497a61db --- /dev/null +++ b/requirements.dev.txt @@ -0,0 +1,9 @@ +coverage==4.3.4 +pbr==2.0.0 +py==1.4.33 +Pygments==2.2.0 +pytest==3.0.7 +pytest-cov==2.4.0 +pytest-mock==1.6.0 +six==1.10.0 +urwid==1.3.1 diff --git a/test/test_settings.py b/test/test_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..d8ed647d8e0f8e405bd75bf2f566bd1c27eee022 --- /dev/null +++ b/test/test_settings.py @@ -0,0 +1,34 @@ +import collections + +import pytest # noqa: F401 + +from pudb.py3compat import builtins +from pudb.settings import load_breakpoints, save_breakpoints + + +def test_load_breakpoints(mocker): + fake_data = ['b /home/user/test.py:41'], ['b /home/user/test.py:50'] + mock_open = mocker.mock_open() + mock_open.return_value.readlines.side_effect = fake_data + mocker.patch.object(builtins, 'open', mock_open) + mocker.patch('pudb.settings.lookup_module', + mocker.Mock(return_value='/home/user/test.py')) + mocker.patch('pudb.settings.get_breakpoint_invalid_reason', + mocker.Mock(return_value=None)) + result = load_breakpoints() + expected = [('/home/user/test.py', 41, False, None, None), + ('/home/user/test.py', 50, False, None, None)] + assert result == expected + + +def test_save_breakpoints(mocker): + MockBP = collections.namedtuple('MockBreakpoint', 'file line cond') + mock_breakpoints = [MockBP('/home/user/test.py', 41, None), + MockBP('/home/user/test.py', 50, None)] + mocker.patch('pudb.settings.get_breakpoints_file_name', + mocker.Mock(return_value='saved-breakpoints')) + mock_open = mocker.mock_open() + mocker.patch.object(builtins, 'open', mock_open) + + save_breakpoints(mock_breakpoints) + mock_open.assert_called_with('saved-breakpoints', 'w')