mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-22 14:41:39 +00:00
Refactoring: Path API compatibility with pathlib
Refactored dupeGuru to make hscommon.path's API a bit close to pathlib's API. It's not 100% compatible yet, but it's much better than before. This is more of a hscommon refactoring than a dupeguru one, but since duepGuru is the main user of Path, it was the driver behind the refactoring. This refactoring also see the introduction of @pathify, which ensure Path arguments. Previously, we were often unsure of whether the caller of a function was passing a Path or a str. This problem is now solved and this allows us to remove hscommon.io, an ill-conceived attempt to solve that same ambiguity problem. Fixes #235.
This commit is contained in:
@@ -61,44 +61,44 @@ class TestCase_move_copy:
|
||||
def pytest_funcarg__do_setup(self, request):
|
||||
tmpdir = request.getfuncargvalue('tmpdir')
|
||||
self.path = Path(str(tmpdir))
|
||||
io.open(self.path + 'foo', 'w').close()
|
||||
io.open(self.path + 'bar', 'w').close()
|
||||
io.mkdir(self.path + 'dir')
|
||||
self.path['foo'].open('w').close()
|
||||
self.path['bar'].open('w').close()
|
||||
self.path['dir'].mkdir()
|
||||
|
||||
def test_move_no_conflict(self, do_setup):
|
||||
smart_move(self.path + 'foo', self.path + 'baz')
|
||||
assert io.exists(self.path + 'baz')
|
||||
assert not io.exists(self.path + 'foo')
|
||||
assert self.path['baz'].exists()
|
||||
assert not self.path['foo'].exists()
|
||||
|
||||
def test_copy_no_conflict(self, do_setup): # No need to duplicate the rest of the tests... Let's just test on move
|
||||
smart_copy(self.path + 'foo', self.path + 'baz')
|
||||
assert io.exists(self.path + 'baz')
|
||||
assert io.exists(self.path + 'foo')
|
||||
assert self.path['baz'].exists()
|
||||
assert self.path['foo'].exists()
|
||||
|
||||
def test_move_no_conflict_dest_is_dir(self, do_setup):
|
||||
smart_move(self.path + 'foo', self.path + 'dir')
|
||||
assert io.exists(self.path + ('dir', 'foo'))
|
||||
assert not io.exists(self.path + 'foo')
|
||||
assert self.path['dir']['foo'].exists()
|
||||
assert not self.path['foo'].exists()
|
||||
|
||||
def test_move_conflict(self, do_setup):
|
||||
smart_move(self.path + 'foo', self.path + 'bar')
|
||||
assert io.exists(self.path + '[000] bar')
|
||||
assert not io.exists(self.path + 'foo')
|
||||
assert self.path['[000] bar'].exists()
|
||||
assert not self.path['foo'].exists()
|
||||
|
||||
def test_move_conflict_dest_is_dir(self, do_setup):
|
||||
smart_move(self.path + 'foo', self.path + 'dir')
|
||||
smart_move(self.path + 'bar', self.path + 'foo')
|
||||
smart_move(self.path + 'foo', self.path + 'dir')
|
||||
assert io.exists(self.path + ('dir', 'foo'))
|
||||
assert io.exists(self.path + ('dir', '[000] foo'))
|
||||
assert not io.exists(self.path + 'foo')
|
||||
assert not io.exists(self.path + 'bar')
|
||||
smart_move(self.path['foo'], self.path['dir'])
|
||||
smart_move(self.path['bar'], self.path['foo'])
|
||||
smart_move(self.path['foo'], self.path['dir'])
|
||||
assert self.path['dir']['foo'].exists()
|
||||
assert self.path['dir']['[000] foo'].exists()
|
||||
assert not self.path['foo'].exists()
|
||||
assert not self.path['bar'].exists()
|
||||
|
||||
def test_copy_folder(self, tmpdir):
|
||||
# smart_copy also works on folders
|
||||
path = Path(str(tmpdir))
|
||||
io.mkdir(path + 'foo')
|
||||
io.mkdir(path + 'bar')
|
||||
smart_copy(path + 'foo', path + 'bar') # no crash
|
||||
assert io.exists(path + '[000] bar')
|
||||
path['foo'].mkdir()
|
||||
path['bar'].mkdir()
|
||||
smart_copy(path['foo'], path['bar']) # no crash
|
||||
assert path['[000] bar'].exists()
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
from datetime import date
|
||||
import sqlite3 as sqlite
|
||||
|
||||
from .. import io
|
||||
from ..testutil import eq_, assert_almost_equal
|
||||
from ..currency import Currency, RatesDB, CAD, EUR, USD
|
||||
|
||||
@@ -64,7 +63,7 @@ def test_db_with_connection():
|
||||
|
||||
def test_corrupt_db(tmpdir):
|
||||
dbpath = str(tmpdir.join('foo.db'))
|
||||
fh = io.open(dbpath, 'w')
|
||||
fh = open(dbpath, 'w')
|
||||
fh.write('corrupted')
|
||||
fh.close()
|
||||
db = RatesDB(dbpath) # no crash. deletes the old file and start a new db
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
# http://www.hardcoded.net/licenses/bsd_license
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from pytest import raises, mark
|
||||
|
||||
from ..path import *
|
||||
from ..path import Path, pathify
|
||||
from ..testutil import eq_
|
||||
|
||||
def pytest_funcarg__force_ossep(request):
|
||||
@@ -44,7 +45,7 @@ def test_init_with_tuple_and_list(force_ossep):
|
||||
def test_init_with_invalid_value(force_ossep):
|
||||
try:
|
||||
path = Path(42)
|
||||
self.fail()
|
||||
assert False
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
@@ -63,6 +64,16 @@ def test_slicing(force_ossep):
|
||||
eq_('foo/bar',subpath)
|
||||
assert isinstance(subpath,Path)
|
||||
|
||||
def test_parent(force_ossep):
|
||||
path = Path('foo/bar/bleh')
|
||||
subpath = path.parent()
|
||||
eq_('foo/bar', subpath)
|
||||
assert isinstance(subpath, Path)
|
||||
|
||||
def test_filename(force_ossep):
|
||||
path = Path('foo/bar/bleh.ext')
|
||||
eq_(path.name, 'bleh.ext')
|
||||
|
||||
def test_deal_with_empty_components(force_ossep):
|
||||
"""Keep ONLY a leading space, which means we want a leading slash.
|
||||
"""
|
||||
@@ -99,7 +110,7 @@ def test_add(force_ossep):
|
||||
#Invalid concatenation
|
||||
try:
|
||||
Path(('foo','bar')) + 1
|
||||
self.fail()
|
||||
assert False
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
@@ -180,6 +191,16 @@ def test_Path_of_a_Path_returns_self(force_ossep):
|
||||
p = Path('foo/bar')
|
||||
assert Path(p) is p
|
||||
|
||||
def test_getitem_str(force_ossep):
|
||||
# path['something'] returns the child path corresponding to the name
|
||||
p = Path('/foo/bar')
|
||||
eq_(p['baz'], Path('/foo/bar/baz'))
|
||||
|
||||
def test_getitem_path(force_ossep):
|
||||
# path[Path('something')] returns the child path corresponding to the name (or subpath)
|
||||
p = Path('/foo/bar')
|
||||
eq_(p[Path('baz/bleh')], Path('/foo/bar/baz/bleh'))
|
||||
|
||||
@mark.xfail(reason="pytest's capture mechanism is flaky, I have to investigate")
|
||||
def test_log_unicode_errors(force_ossep, monkeypatch, capsys):
|
||||
# When an there's a UnicodeDecodeError on path creation, log it so it can be possible
|
||||
@@ -206,4 +227,25 @@ def test_remove_drive_letter(monkeypatch):
|
||||
p = Path('C:\\')
|
||||
eq_(p.remove_drive_letter(), Path(''))
|
||||
p = Path('z:\\foo')
|
||||
eq_(p.remove_drive_letter(), Path('foo'))
|
||||
eq_(p.remove_drive_letter(), Path('foo'))
|
||||
|
||||
def test_pathify():
|
||||
@pathify
|
||||
def foo(a: Path, b, c:Path):
|
||||
return a, b, c
|
||||
|
||||
a, b, c = foo('foo', 0, c=Path('bar'))
|
||||
assert isinstance(a, Path)
|
||||
assert a == Path('foo')
|
||||
assert b == 0
|
||||
assert isinstance(c, Path)
|
||||
assert c == Path('bar')
|
||||
|
||||
def test_pathify_preserve_none():
|
||||
# @pathify preserves None value and doesn't try to return a Path
|
||||
@pathify
|
||||
def foo(a: Path):
|
||||
return a
|
||||
|
||||
a = foo(None)
|
||||
assert a is None
|
||||
|
||||
@@ -11,7 +11,6 @@ from io import StringIO
|
||||
from pytest import raises
|
||||
|
||||
from ..testutil import eq_
|
||||
from .. import io
|
||||
from ..path import Path
|
||||
from ..util import *
|
||||
|
||||
@@ -210,39 +209,49 @@ class TestCase_modified_after:
|
||||
monkeyplus.patch_osstat('first', st_mtime=42)
|
||||
assert modified_after('first', 'does_not_exist') # no crash
|
||||
|
||||
def test_first_file_is_none(self, monkeyplus):
|
||||
# when the first file is None, we return False
|
||||
monkeyplus.patch_osstat('second', st_mtime=42)
|
||||
assert not modified_after(None, 'second') # no crash
|
||||
|
||||
def test_second_file_is_none(self, monkeyplus):
|
||||
# when the second file is None, we return True
|
||||
monkeyplus.patch_osstat('first', st_mtime=42)
|
||||
assert modified_after('first', None) # no crash
|
||||
|
||||
|
||||
class TestCase_delete_if_empty:
|
||||
def test_is_empty(self, tmpdir):
|
||||
testpath = Path(str(tmpdir))
|
||||
assert delete_if_empty(testpath)
|
||||
assert not io.exists(testpath)
|
||||
assert not testpath.exists()
|
||||
|
||||
def test_not_empty(self, tmpdir):
|
||||
testpath = Path(str(tmpdir))
|
||||
io.mkdir(testpath + 'foo')
|
||||
testpath['foo'].mkdir()
|
||||
assert not delete_if_empty(testpath)
|
||||
assert io.exists(testpath)
|
||||
assert testpath.exists()
|
||||
|
||||
def test_with_files_to_delete(self, tmpdir):
|
||||
testpath = Path(str(tmpdir))
|
||||
io.open(testpath + 'foo', 'w')
|
||||
io.open(testpath + 'bar', 'w')
|
||||
testpath['foo'].open('w')
|
||||
testpath['bar'].open('w')
|
||||
assert delete_if_empty(testpath, ['foo', 'bar'])
|
||||
assert not io.exists(testpath)
|
||||
assert not testpath.exists()
|
||||
|
||||
def test_directory_in_files_to_delete(self, tmpdir):
|
||||
testpath = Path(str(tmpdir))
|
||||
io.mkdir(testpath + 'foo')
|
||||
testpath['foo'].mkdir()
|
||||
assert not delete_if_empty(testpath, ['foo'])
|
||||
assert io.exists(testpath)
|
||||
assert testpath.exists()
|
||||
|
||||
def test_delete_files_to_delete_only_if_dir_is_empty(self, tmpdir):
|
||||
testpath = Path(str(tmpdir))
|
||||
io.open(testpath + 'foo', 'w')
|
||||
io.open(testpath + 'bar', 'w')
|
||||
testpath['foo'].open('w')
|
||||
testpath['bar'].open('w')
|
||||
assert not delete_if_empty(testpath, ['foo'])
|
||||
assert io.exists(testpath)
|
||||
assert io.exists(testpath + 'foo')
|
||||
assert testpath.exists()
|
||||
assert testpath['foo'].exists()
|
||||
|
||||
def test_doesnt_exist(self):
|
||||
# When the 'path' doesn't exist, just do nothing.
|
||||
@@ -251,7 +260,7 @@ class TestCase_delete_if_empty:
|
||||
def test_is_file(self, tmpdir):
|
||||
# When 'path' is a file, do nothing.
|
||||
p = Path(str(tmpdir)) + 'filename'
|
||||
io.open(p, 'w').close()
|
||||
p.open('w').close()
|
||||
delete_if_empty(p) # no crash
|
||||
|
||||
def test_ioerror(self, tmpdir, monkeypatch):
|
||||
@@ -259,7 +268,7 @@ class TestCase_delete_if_empty:
|
||||
def do_raise(*args, **kw):
|
||||
raise OSError()
|
||||
|
||||
monkeypatch.setattr(io, 'rmdir', do_raise)
|
||||
monkeypatch.setattr(Path, 'rmdir', do_raise)
|
||||
delete_if_empty(Path(str(tmpdir))) # no crash
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user