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).
main
Olivier Mangin 11 years ago
parent d758df2ac9
commit 136b8f83dc

@ -1,10 +1,9 @@
import os import os
import collections import collections
from .p3 import configparser from .p3 import configparser, _read_config
from . import content
from .content import system_path, check_file from .content import check_file, _open
# constant stuff (DFT = DEFAULT) # constant stuff (DFT = DEFAULT)
@ -64,17 +63,15 @@ class Config(object):
_config = self _config = self
def load(self, path=DFT_CONFIG_PATH): 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." raise IOError(("The configuration file {} does not exist."
" Did you run 'pubs init' ?").format(path)) " Did you run 'pubs init' ?").format(path))
with open(content.system_path(path), 'r') as f: with _open(path, 'r') as f:
read = self._cfg.readfp(f) _read_config(self._cfg, f)
# if len(read) == 0:
# raise IOError("Syntax error in {} config file. Aborting.".format(path))
return self return self
def save(self, path=DFT_CONFIG_PATH): 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) self._cfg.write(f)
def __setattr__(self, name, value): def __setattr__(self, name, value):

@ -43,6 +43,10 @@ def system_path(path):
return os.path.abspath(os.path.expanduser(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): def check_file(path, fail=True):
syspath = system_path(path) syspath = system_path(path)
return (_check_system_path_exists(syspath, fail=fail) return (_check_system_path_exists(syspath, fail=fail)
@ -57,14 +61,14 @@ def check_directory(path, fail=True):
def read_file(filepath): def read_file(filepath):
check_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() content = f.read()
return content return content
def write_file(filepath, data): def write_file(filepath, data):
check_directory(os.path.dirname(filepath)) 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) f.write(data)

@ -1,25 +1,29 @@
import io
import sys import sys
if sys.version_info[0] == 2: if sys.version_info[0] == 2:
import ConfigParser as configparser import ConfigParser as configparser
_read_config = configparser.SafeConfigParser.readfp
input = raw_input input = raw_input
ustr = unicode ustr = unicode
uchr = unichr uchr = unichr
from urlparse import urlparse from urlparse import urlparse
from urllib2 import urlopen from urllib2 import urlopen
from httplib import HTTPConnection from httplib import HTTPConnection
file = None
_fake_stdio = io.BytesIO # Only for tests to capture std{out,err}
else: else:
import configparser import configparser
_read_config = configparser.SafeConfigParser.read_file
ustr = str ustr = str
uchr = chr uchr = chr
file = None
from urllib.parse import urlparse from urllib.parse import urlparse
from urllib.request import urlopen from urllib.request import urlopen
from http.client import HTTPConnection from http.client import HTTPConnection
_fake_stdio = io.StringIO # Only for tests to capture std{out,err}
configparser = configparser configparser = configparser
input = input input = input
file = file
def isbasestr(obj): def isbasestr(obj):

@ -2,6 +2,7 @@ import copy
from dateutil.parser import parse as datetime_parse from dateutil.parser import parse as datetime_parse
from . import bibstruct from . import bibstruct
from .p3 import ustr
DEFAULT_META = {'docfile': None, 'tags': set()} DEFAULT_META = {'docfile': None, 'tags': set()}
@ -11,7 +12,7 @@ def _clean_metadata(metadata):
meta = copy.deepcopy(DEFAULT_META) meta = copy.deepcopy(DEFAULT_META)
meta.update(metadata or {}) # handles None metadata meta.update(metadata or {}) # handles None metadata
meta['tags'] = set(meta.get('tags', [])) # tags should be a set 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']) meta['added'] = datetime_parse(meta['added'])
return meta return meta

@ -4,7 +4,6 @@ import sys
from .beets_ui import _encoding, input_ from .beets_ui import _encoding, input_
from .content import editor_input from .content import editor_input
from .p3 import ustr
from . import color from . import color
# package-shared ui that can be accessed using : # 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 is not in the terminal's encoding's character set, just silently
replaces it. replaces it.
""" """
txt = [s.encode(self.encoding, 'replace') print(' '.join(strings).encode(self.encoding, 'replace'))
if isinstance(s, ustr) else s
for s in strings]
print(' '.join(txt))
def input_choice(self, options, option_chars, default=None, question=''): def input_choice(self, options, option_chars, default=None, question=''):
"""Ask the user to chose between a set of options. The iser is asked """Ask the user to chose between a set of options. The iser is asked

@ -2,6 +2,7 @@
from setuptools import setup, find_packages from setuptools import setup, find_packages
setup(name='pubs', setup(name='pubs',
version='4', version='4',
author='Fabien Benureau, Olivier Mangin, Jonathan Grizou', author='Fabien Benureau, Olivier Mangin, Jonathan Grizou',
@ -10,5 +11,5 @@ setup(name='pubs',
description='research papers manager', description='research papers manager',
requires=['pyyaml', 'bibtexparser', 'dateutil'], requires=['pyyaml', 'bibtexparser', 'dateutil'],
packages=find_packages(), packages=find_packages(),
scripts=['pubs/pubs'] scripts=['pubs/pubs'],
) )

@ -10,14 +10,13 @@ import fake_filesystem
import fake_filesystem_shutil import fake_filesystem_shutil
import fake_filesystem_glob import fake_filesystem_glob
from pubs.p3 import input from pubs.p3 import input, _fake_stdio
from pubs import content, filebroker from pubs import content, filebroker
# code for fake fs # code for fake fs
real_os = os real_os = os
real_open = open real_open = open
real_file = file
real_shutil = shutil real_shutil = shutil
real_glob = glob real_glob = glob
real_io = io real_io = io
@ -41,7 +40,7 @@ ENCODING = 'utf8'
class UnicodeStringIOWrapper(object): 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'] override = ['read', 'readline', 'readlines', 'write', 'writelines']
@ -55,6 +54,10 @@ class UnicodeStringIOWrapper(object):
else: else:
return self._strio.__getattribute__(name) return self._strio.__getattribute__(name)
def __iter__(self):
for l in self.readlines():
yield l
def read(self, *args): def read(self, *args):
return self._strio.read(*args).decode(ENCODING) return self._strio.read(*args).decode(ENCODING)
@ -78,13 +81,24 @@ class UnicodeStringIOWrapper(object):
return self._strio.__exit__(*args) 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): class FakeIO(object):
def __init__(self, fake_open): def __init__(self, fake_open):
self.fake_open = fake_open self.fake_open = fake_open
def open(self, *args, **kwargs): 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) fakefs_stringio = self.fake_open.Call(*args, **kwargs)
return UnicodeStringIOWrapper(fakefs_stringio) return UnicodeStringIOWrapper(fakefs_stringio)
@ -100,8 +114,6 @@ def create_fake_fs(module_list):
fake_fs.CreateDirectory(fake_os.path.expanduser('~')) fake_fs.CreateDirectory(fake_os.path.expanduser('~'))
__builtins__.update({'open': fake_open, 'file': fake_open})
sys.modules['os'] = fake_os sys.modules['os'] = fake_os
sys.modules['shutil'] = fake_shutil sys.modules['shutil'] = fake_shutil
sys.modules['glob'] = fake_glob sys.modules['glob'] = fake_glob
@ -111,7 +123,7 @@ def create_fake_fs(module_list):
md.os = fake_os md.os = fake_os
md.shutil = fake_shutil md.shutil = fake_shutil
md.open = fake_open md.open = fake_open
md.file = fake_open md.file = None
md.io = fake_io md.io = fake_io
return {'fs': fake_fs, return {'fs': fake_fs,
@ -125,10 +137,8 @@ def create_fake_fs(module_list):
def unset_fake_fs(module_list): def unset_fake_fs(module_list):
try: try:
__builtins__.open = real_open __builtins__.open = real_open
__builtins__.file = real_file
except AttributeError: except AttributeError:
__builtins__['open'] = real_open __builtins__['open'] = real_open
__builtins__['file'] = real_file
sys.modules['os'] = real_os sys.modules['os'] = real_os
sys.modules['shutil'] = real_shutil sys.modules['shutil'] = real_shutil
@ -139,7 +149,6 @@ def unset_fake_fs(module_list):
md.os = real_os md.os = real_os
md.shutil = real_shutil md.shutil = real_shutil
md.open = real_open md.open = real_open
md.file = real_file
md.io = real_io md.io = real_io
@ -163,8 +172,8 @@ def copy_dir(fs, real_dir, fake_dir = None):
def redirect(f): def redirect(f):
def newf(*args, **kwargs): def newf(*args, **kwargs):
old_stderr, old_stdout = sys.stderr, sys.stdout old_stderr, old_stdout = sys.stderr, sys.stdout
stdout = io.BytesIO() stdout = _fake_stdio()
stderr = io.BytesIO() stderr = _fake_stdio()
sys.stdout, sys.stderr = stdout, stderr sys.stdout, sys.stderr = stdout, stderr
try: try:
return f(*args, **kwargs), stdout, stderr return f(*args, **kwargs), stdout, stderr
@ -190,7 +199,7 @@ class FakeInput():
Then : Then :
input() returns 'yes' input() returns 'yes'
input() returns 'no' input() returns 'no'
input() raise IndexError input() raises IndexError
""" """
def __init__(self, inputs, module_list=tuple()): def __init__(self, inputs, module_list=tuple()):

@ -34,7 +34,6 @@ class TestEnDecode(unittest.TestCase):
data = decoder.encode_metadata(dummy_metadata) data = decoder.encode_metadata(dummy_metadata)
self.assertIsInstance(data, ustr) self.assertIsInstance(data, ustr)
def test_endecode_bibtex(self): def test_endecode_bibtex(self):
decoder = endecoder.EnDecoder() decoder = endecoder.EnDecoder()
entry = decoder.decode_bibdata(bibtex_raw0) entry = decoder.decode_bibdata(bibtex_raw0)

@ -29,11 +29,11 @@ class TestFileBroker(fake_env.TestFakeFs):
fake_env.copy_dir(self.fs, os.path.join(os.path.dirname(__file__), 'testrepo'), 'testrepo') fake_env.copy_dir(self.fs, os.path.join(os.path.dirname(__file__), 'testrepo'), 'testrepo')
fb = filebroker.FileBroker('testrepo', create = True) fb = filebroker.FileBroker('testrepo', create = True)
with open('testrepo/bib/Page99.bib', 'r') as f: bib_content = content.read_file('testrepo/bib/Page99.bib')
self.assertEqual(fb.pull_bibfile('Page99'), f.read()) self.assertEqual(fb.pull_bibfile('Page99'), bib_content)
with open('testrepo/meta/Page99.yaml', 'r') as f: meta_content = content.read_file('testrepo/meta/Page99.yaml')
self.assertEqual(fb.pull_metafile('Page99'), f.read()) self.assertEqual(fb.pull_metafile('Page99'), meta_content)
def test_errors(self): def test_errors(self):

@ -66,12 +66,12 @@ class CommandTestCase(unittest.TestCase):
In the latter case, the command is : In the latter case, the command is :
1. a string reprensenting the command to execute 1. a string reprensenting the command to execute
2. the user inputs to feed to the command during execution 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 = [] outs = []
for cmd in cmds: for cmd in cmds:
if hasattr(cmd, '__iter__'): if not isinstance(cmd, p3.ustr):
if len(cmd) == 2: if len(cmd) == 2:
input = fake_env.FakeInput(cmd[1], [content, uis, beets_ui, p3]) input = fake_env.FakeInput(cmd[1], [content, uis, beets_ui, p3])
input.as_global() input.as_global()
@ -293,6 +293,7 @@ class TestUsecase(DataCommandTestCase):
print(self.fs['os'].listdir(docdir)) print(self.fs['os'].listdir(docdir))
self.assertNotIn('turing-mind-1950.pdf', self.fs['os'].listdir(docdir)) self.assertNotIn('turing-mind-1950.pdf', self.fs['os'].listdir(docdir))
def test_tag_list(self): def test_tag_list(self):
correct = [b'Initializing pubs in /paper_first\n', correct = [b'Initializing pubs in /paper_first\n',
b'', b'',

Loading…
Cancel
Save