From 136b8f83dcb5dafc61967d91f3ad397f40fe9771 Mon Sep 17 00:00:00 2001 From: Olivier Mangin Date: Tue, 9 Sep 2014 12:48:54 +0200 Subject: [PATCH] Fix fake_env, fix configparser issues, uniform 'open'. - Update fake_env for compatibility with io. - Uniform open (through _my_open in content). - Fix read issue for config (although still using SafeConfigParser that is deprecated in py3). --- pubs/configs.py | 15 ++++++--------- pubs/content.py | 8 ++++++-- pubs/p3.py | 8 ++++++-- pubs/paper.py | 3 ++- pubs/uis.py | 6 +----- setup.py | 3 ++- tests/fake_env.py | 35 ++++++++++++++++++++++------------- tests/test_endecoder.py | 1 - tests/test_filebroker.py | 8 ++++---- tests/test_usecase.py | 5 +++-- 10 files changed, 52 insertions(+), 40 deletions(-) diff --git a/pubs/configs.py b/pubs/configs.py index bfb51dc..50e13de 100644 --- a/pubs/configs.py +++ b/pubs/configs.py @@ -1,10 +1,9 @@ import os import collections -from .p3 import configparser -from . import content +from .p3 import configparser, _read_config -from .content import system_path, check_file +from .content import check_file, _open # constant stuff (DFT = DEFAULT) @@ -64,17 +63,15 @@ class Config(object): _config = self def load(self, path=DFT_CONFIG_PATH): - if not content.check_file(path, fail=False): + if not check_file(path, fail=False): raise IOError(("The configuration file {} does not exist." " Did you run 'pubs init' ?").format(path)) - with open(content.system_path(path), 'r') as f: - read = self._cfg.readfp(f) - # if len(read) == 0: - # raise IOError("Syntax error in {} config file. Aborting.".format(path)) + with _open(path, 'r') as f: + _read_config(self._cfg, f) return self def save(self, path=DFT_CONFIG_PATH): - with open(content.system_path(path), 'w') as f: + with _open(path, 'w') as f: self._cfg.write(f) def __setattr__(self, name, value): diff --git a/pubs/content.py b/pubs/content.py index 18f8c50..9d015fc 100644 --- a/pubs/content.py +++ b/pubs/content.py @@ -43,6 +43,10 @@ def system_path(path): return os.path.abspath(os.path.expanduser(path)) +def _open(path, mode): + return io.open(system_path(path), mode, encoding=ENCODING) + + def check_file(path, fail=True): syspath = system_path(path) return (_check_system_path_exists(syspath, fail=fail) @@ -57,14 +61,14 @@ def check_directory(path, fail=True): def read_file(filepath): check_file(filepath) - with io.open(system_path(filepath), 'r', encoding=ENCODING) as f: + with _open(filepath, 'r') as f: content = f.read() return content def write_file(filepath, data): check_directory(os.path.dirname(filepath)) - with io.open(system_path(filepath), 'w', encoding=ENCODING) as f: + with _open(filepath, 'w') as f: f.write(data) diff --git a/pubs/p3.py b/pubs/p3.py index d8f1792..034260c 100644 --- a/pubs/p3.py +++ b/pubs/p3.py @@ -1,25 +1,29 @@ +import io import sys if sys.version_info[0] == 2: import ConfigParser as configparser + _read_config = configparser.SafeConfigParser.readfp input = raw_input ustr = unicode uchr = unichr from urlparse import urlparse from urllib2 import urlopen from httplib import HTTPConnection + file = None + _fake_stdio = io.BytesIO # Only for tests to capture std{out,err} else: import configparser + _read_config = configparser.SafeConfigParser.read_file ustr = str uchr = chr - file = None from urllib.parse import urlparse from urllib.request import urlopen from http.client import HTTPConnection + _fake_stdio = io.StringIO # Only for tests to capture std{out,err} configparser = configparser input = input -file = file def isbasestr(obj): diff --git a/pubs/paper.py b/pubs/paper.py index 7798366..5abc3be 100644 --- a/pubs/paper.py +++ b/pubs/paper.py @@ -2,6 +2,7 @@ import copy from dateutil.parser import parse as datetime_parse from . import bibstruct +from .p3 import ustr DEFAULT_META = {'docfile': None, 'tags': set()} @@ -11,7 +12,7 @@ def _clean_metadata(metadata): meta = copy.deepcopy(DEFAULT_META) meta.update(metadata or {}) # handles None metadata meta['tags'] = set(meta.get('tags', [])) # tags should be a set - if 'added' in meta and isinstance(meta['added'], basestring): + if 'added' in meta and isinstance(meta['added'], ustr): meta['added'] = datetime_parse(meta['added']) return meta diff --git a/pubs/uis.py b/pubs/uis.py index ce98b2a..7a965d2 100644 --- a/pubs/uis.py +++ b/pubs/uis.py @@ -4,7 +4,6 @@ import sys from .beets_ui import _encoding, input_ from .content import editor_input -from .p3 import ustr from . import color # package-shared ui that can be accessed using : @@ -39,10 +38,7 @@ class UI: is not in the terminal's encoding's character set, just silently replaces it. """ - txt = [s.encode(self.encoding, 'replace') - if isinstance(s, ustr) else s - for s in strings] - print(' '.join(txt)) + print(' '.join(strings).encode(self.encoding, 'replace')) def input_choice(self, options, option_chars, default=None, question=''): """Ask the user to chose between a set of options. The iser is asked diff --git a/setup.py b/setup.py index feaa100..06fbb91 100644 --- a/setup.py +++ b/setup.py @@ -2,6 +2,7 @@ from setuptools import setup, find_packages + setup(name='pubs', version='4', author='Fabien Benureau, Olivier Mangin, Jonathan Grizou', @@ -10,5 +11,5 @@ setup(name='pubs', description='research papers manager', requires=['pyyaml', 'bibtexparser', 'dateutil'], packages=find_packages(), - scripts=['pubs/pubs'] + scripts=['pubs/pubs'], ) diff --git a/tests/fake_env.py b/tests/fake_env.py index c6fa458..7719c94 100644 --- a/tests/fake_env.py +++ b/tests/fake_env.py @@ -10,14 +10,13 @@ import fake_filesystem import fake_filesystem_shutil import fake_filesystem_glob -from pubs.p3 import input +from pubs.p3 import input, _fake_stdio from pubs import content, filebroker # code for fake fs real_os = os real_open = open -real_file = file real_shutil = shutil real_glob = glob real_io = io @@ -41,7 +40,7 @@ ENCODING = 'utf8' class UnicodeStringIOWrapper(object): - """This is a hack because fake_filesystem does not provied mock of io. + """This is a hack because fake_filesystem does not provide mock of io. """ override = ['read', 'readline', 'readlines', 'write', 'writelines'] @@ -55,6 +54,10 @@ class UnicodeStringIOWrapper(object): else: return self._strio.__getattribute__(name) + def __iter__(self): + for l in self.readlines(): + yield l + def read(self, *args): return self._strio.read(*args).decode(ENCODING) @@ -78,13 +81,24 @@ class UnicodeStringIOWrapper(object): return self._strio.__exit__(*args) +def _force_binary_mode(mode): + if 'b' in mode: + raise ValueError('Open should not happen in binary mode.') + return mode + 'b' + + class FakeIO(object): def __init__(self, fake_open): self.fake_open = fake_open def open(self, *args, **kwargs): - # Forces python3 mode for FakeFileOpen + # Forces binary mode for FakeFileOpen + args = list(args) + if len(args) > 1: + args[1] = _force_binary_mode(args[1]) + else: + kwargs['mode'] = _force_binary_mode(kwargs.get('mode', 'r')) fakefs_stringio = self.fake_open.Call(*args, **kwargs) return UnicodeStringIOWrapper(fakefs_stringio) @@ -100,8 +114,6 @@ def create_fake_fs(module_list): fake_fs.CreateDirectory(fake_os.path.expanduser('~')) - __builtins__.update({'open': fake_open, 'file': fake_open}) - sys.modules['os'] = fake_os sys.modules['shutil'] = fake_shutil sys.modules['glob'] = fake_glob @@ -111,7 +123,7 @@ def create_fake_fs(module_list): md.os = fake_os md.shutil = fake_shutil md.open = fake_open - md.file = fake_open + md.file = None md.io = fake_io return {'fs': fake_fs, @@ -125,10 +137,8 @@ def create_fake_fs(module_list): def unset_fake_fs(module_list): try: __builtins__.open = real_open - __builtins__.file = real_file except AttributeError: __builtins__['open'] = real_open - __builtins__['file'] = real_file sys.modules['os'] = real_os sys.modules['shutil'] = real_shutil @@ -139,7 +149,6 @@ def unset_fake_fs(module_list): md.os = real_os md.shutil = real_shutil md.open = real_open - md.file = real_file md.io = real_io @@ -163,8 +172,8 @@ def copy_dir(fs, real_dir, fake_dir = None): def redirect(f): def newf(*args, **kwargs): old_stderr, old_stdout = sys.stderr, sys.stdout - stdout = io.BytesIO() - stderr = io.BytesIO() + stdout = _fake_stdio() + stderr = _fake_stdio() sys.stdout, sys.stderr = stdout, stderr try: return f(*args, **kwargs), stdout, stderr @@ -190,7 +199,7 @@ class FakeInput(): Then : input() returns 'yes' input() returns 'no' - input() raise IndexError + input() raises IndexError """ def __init__(self, inputs, module_list=tuple()): diff --git a/tests/test_endecoder.py b/tests/test_endecoder.py index 96e91b1..d5e51f1 100644 --- a/tests/test_endecoder.py +++ b/tests/test_endecoder.py @@ -34,7 +34,6 @@ class TestEnDecode(unittest.TestCase): data = decoder.encode_metadata(dummy_metadata) self.assertIsInstance(data, ustr) - def test_endecode_bibtex(self): decoder = endecoder.EnDecoder() entry = decoder.decode_bibdata(bibtex_raw0) diff --git a/tests/test_filebroker.py b/tests/test_filebroker.py index 53a1f23..67fa48e 100644 --- a/tests/test_filebroker.py +++ b/tests/test_filebroker.py @@ -29,11 +29,11 @@ class TestFileBroker(fake_env.TestFakeFs): fake_env.copy_dir(self.fs, os.path.join(os.path.dirname(__file__), 'testrepo'), 'testrepo') fb = filebroker.FileBroker('testrepo', create = True) - with open('testrepo/bib/Page99.bib', 'r') as f: - self.assertEqual(fb.pull_bibfile('Page99'), f.read()) + bib_content = content.read_file('testrepo/bib/Page99.bib') + self.assertEqual(fb.pull_bibfile('Page99'), bib_content) - with open('testrepo/meta/Page99.yaml', 'r') as f: - self.assertEqual(fb.pull_metafile('Page99'), f.read()) + meta_content = content.read_file('testrepo/meta/Page99.yaml') + self.assertEqual(fb.pull_metafile('Page99'), meta_content) def test_errors(self): diff --git a/tests/test_usecase.py b/tests/test_usecase.py index e6d7c42..47fbdb5 100644 --- a/tests/test_usecase.py +++ b/tests/test_usecase.py @@ -66,12 +66,12 @@ class CommandTestCase(unittest.TestCase): In the latter case, the command is : 1. a string reprensenting the command to execute 2. the user inputs to feed to the command during execution - 3. the output excpected, verified with assertEqual + 3. the output expected, verified with assertEqual """ outs = [] for cmd in cmds: - if hasattr(cmd, '__iter__'): + if not isinstance(cmd, p3.ustr): if len(cmd) == 2: input = fake_env.FakeInput(cmd[1], [content, uis, beets_ui, p3]) input.as_global() @@ -293,6 +293,7 @@ class TestUsecase(DataCommandTestCase): print(self.fs['os'].listdir(docdir)) self.assertNotIn('turing-mind-1950.pdf', self.fs['os'].listdir(docdir)) + def test_tag_list(self): correct = [b'Initializing pubs in /paper_first\n', b'',