diff --git a/README b/README index a180d79b..e08933bc 100644 --- a/README +++ b/README @@ -26,7 +26,6 @@ General dependencies - Python 3.1 (http://www.python.org) - Send2Trash3k (http://hg.hardcoded.net/send2trash) -- hsutil3k (http://hg.hardcoded.net/hsutil) - hsaudiotag3k 1.1.0 (for ME) (http://hg.hardcoded.net/hsaudiotag) - jobprogress (http://hg.hardcoded.net/jobprogress) - Markdown, to generate help files. (http://pypi.python.org/pypi/Markdown) diff --git a/cocoa/me/dg_cocoa.py b/cocoa/me/dg_cocoa.py index 4c7e0868..78ea0778 100644 --- a/cocoa/me/dg_cocoa.py +++ b/cocoa/me/dg_cocoa.py @@ -15,7 +15,7 @@ import core_me.app_cocoa, core_me.data, core_me.fs, core_me.scanner import hsaudiotag.aiff, hsaudiotag.flac, hsaudiotag.genres, hsaudiotag.id3v1,\ hsaudiotag.id3v2, hsaudiotag.mp4, hsaudiotag.mpeg, hsaudiotag.ogg, hsaudiotag.wma from hsaudiotag import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma -import hsutil.conflict +import hscommon.conflict import core.engine, core.fs, core.app import xml.etree.ElementPath import gzip diff --git a/cocoa/pe/dg_cocoa.py b/cocoa/pe/dg_cocoa.py index 6dd5e684..9166b2fc 100644 --- a/cocoa/pe/dg_cocoa.py +++ b/cocoa/pe/dg_cocoa.py @@ -8,7 +8,7 @@ from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel from core_pe import app_cocoa as app_pe_cocoa # Fix py2app imports which chokes on relative imports and other stuff -import hsutil.conflict +import hscommon.conflict import core.engine, core.fs, core.app import core_pe.block, core_pe.cache, core_pe.matchbase, core_pe.data, core_pe._block_osx import xml.etree.ElementPath diff --git a/cocoa/se/dg_cocoa.py b/cocoa/se/dg_cocoa.py index 32635ee5..3cc59c91 100644 --- a/cocoa/se/dg_cocoa.py +++ b/cocoa/se/dg_cocoa.py @@ -11,7 +11,7 @@ from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel from core_se.app_cocoa import DupeGuru # Fix py2app imports with chokes on relative imports and other stuff -import hsutil.conflict +import hscommon.conflict import core.engine, core.fs, core.app import core_se.fs, core_se.data import xml.etree.ElementPath diff --git a/core/app.py b/core/app.py index 3da9c31c..58636941 100644 --- a/core/app.py +++ b/core/app.py @@ -17,9 +17,8 @@ from hscommon import io from hscommon.reg import RegistrableApplication from hscommon.notify import Broadcaster from hscommon.path import Path -from hsutil import files -from hsutil.misc import flatten, first -from hsutil.str import escape +from hscommon.conflict import smart_move, smart_copy +from hscommon.util import delete_if_empty, first, escape from . import directories, results, scanner, export, fs @@ -156,14 +155,14 @@ class DupeGuru(RegistrableApplication, Broadcaster): def apply_filter(self, filter): self.results.apply_filter(None) if self.options['escape_filter_regexp']: - filter = escape(filter, '()[]\\.|+?^') + filter = escape(filter, set('()[]\\.|+?^')) filter = escape(filter, '*', '.') self.results.apply_filter(filter) self.notify('results_changed') def clean_empty_dirs(self, path): if self.options['clean_empty_dirs']: - while files.delete_if_empty(path, ['.DS_Store']): + while delete_if_empty(path, ['.DS_Store']): path = path[:-1] def copy_or_move(self, dupe, copy, destination, dest_type): @@ -185,9 +184,9 @@ class DupeGuru(RegistrableApplication, Broadcaster): io.makedirs(dest_path) # Raises an EnvironmentError if there's a problem if copy: - files.copy(source_path, dest_path) + smart_copy(source_path, dest_path) else: - files.move(source_path, dest_path) + smart_move(source_path, dest_path) self.clean_empty_dirs(source_path[:-1]) def copy_or_move_marked(self, copy, destination, recreate_path): diff --git a/core/app_cocoa_inter.py b/core/app_cocoa_inter.py index 1793cd74..f9142587 100644 --- a/core/app_cocoa_inter.py +++ b/core/app_cocoa_inter.py @@ -20,7 +20,7 @@ from .gui.stats_label import StatsLabel # Fix py2app's problems on relative imports from core import app, app_cocoa, data, directories, engine, export, ignore, results, fs, scanner -from hsutil import conflict +from hscommon import conflict class PyDupeGuruBase(PyFairware): #---Directories diff --git a/core/data.py b/core/data.py index 6eb1c1ef..1a447e7f 100644 --- a/core/data.py +++ b/core/data.py @@ -6,7 +6,7 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/bsd_license -from hsutil.str import format_time, FT_DECIMAL, format_size +from hscommon.util import format_time_decimal, format_size import time @@ -15,7 +15,7 @@ def format_path(p): def format_timestamp(t, delta): if delta: - return format_time(t, FT_DECIMAL) + return format_time_decimal(t) else: if t > 0: return time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(t)) diff --git a/core/directories.py b/core/directories.py index 697b863c..d1a67a76 100644 --- a/core/directories.py +++ b/core/directories.py @@ -10,7 +10,7 @@ from xml.etree import ElementTree as ET from hscommon import io from hscommon.path import Path -from hsutil.files import FileOrPath +from hscommon.util import FileOrPath from . import fs diff --git a/core/engine.py b/core/engine.py index f0861362..14dead52 100644 --- a/core/engine.py +++ b/core/engine.py @@ -14,8 +14,7 @@ import string from collections import defaultdict, namedtuple from unicodedata import normalize -from hsutil.misc import flatten -from hsutil.str import multi_replace +from hscommon.util import flatten, multi_replace from jobprogress import job (WEIGHT_WORDS, diff --git a/core/fs.py b/core/fs.py index 5457d6ab..27bc91d2 100644 --- a/core/fs.py +++ b/core/fs.py @@ -15,8 +15,7 @@ import hashlib import logging from hscommon import io -from hsutil.misc import nonone, flatten -from hsutil.str import get_file_ext +from hscommon.util import nonone, flatten, get_file_ext class FSError(Exception): cls_message = "An error has occured on '{name}' in '{parent}'" diff --git a/core/ignore.py b/core/ignore.py index b1e80c35..2b298a06 100644 --- a/core/ignore.py +++ b/core/ignore.py @@ -8,9 +8,9 @@ from xml.etree import ElementTree as ET -from hsutil.files import FileOrPath +from hscommon.util import FileOrPath -class IgnoreList(object): +class IgnoreList: """An ignore list implementation that is iterable, filterable and exportable to XML. Call Ignore to add an ignore list entry, and AreIgnore to check if 2 items are in the list. diff --git a/core/results.py b/core/results.py index 9b3ced67..a54e1802 100644 --- a/core/results.py +++ b/core/results.py @@ -13,9 +13,7 @@ from xml.etree import ElementTree as ET from . import engine from jobprogress.job import nulljob from hscommon.markable import Markable -from hsutil.misc import flatten, nonone -from hsutil.str import format_size -from hsutil.files import FileOrPath +from hscommon.util import flatten, nonone, FileOrPath, format_size class Results(Markable): #---Override diff --git a/core/scanner.py b/core/scanner.py index b0127849..af353c8b 100644 --- a/core/scanner.py +++ b/core/scanner.py @@ -11,8 +11,7 @@ import re from jobprogress import job from hscommon import io -from hsutil.misc import dedupe -from hsutil.str import get_file_ext, rem_file_ext +from hscommon.util import dedupe, rem_file_ext, get_file_ext from . import engine from .ignore import IgnoreList diff --git a/core/tests/app_test.py b/core/tests/app_test.py index dcd16eb0..5f42251e 100644 --- a/core/tests/app_test.py +++ b/core/tests/app_test.py @@ -13,9 +13,9 @@ import logging from pytest import mark from hscommon import io from hscommon.path import Path -from hsutil.decorators import log_calls -import hsutil.files -from hscommon.testutil import CallLogger, eq_ +import hscommon.conflict +import hscommon.util +from hscommon.testutil import CallLogger, eq_, log_calls from jobprogress.job import nulljob, Job, JobCancelled from . import data @@ -46,27 +46,27 @@ def add_fake_files_to_directories(directories, files): class TestCaseDupeGuru: def test_apply_filter_calls_results_apply_filter(self, monkeypatch): - app = DupeGuru() - monkeypatch.setattr(app.results, 'apply_filter', log_calls(app.results.apply_filter)) - app.apply_filter('foo') - eq_(2, len(app.results.apply_filter.calls)) - call = app.results.apply_filter.calls[0] + dgapp = DupeGuru() + monkeypatch.setattr(dgapp.results, 'apply_filter', log_calls(dgapp.results.apply_filter)) + dgapp.apply_filter('foo') + eq_(2, len(dgapp.results.apply_filter.calls)) + call = dgapp.results.apply_filter.calls[0] assert call['filter_str'] is None - call = app.results.apply_filter.calls[1] + call = dgapp.results.apply_filter.calls[1] eq_('foo', call['filter_str']) def test_apply_filter_escapes_regexp(self, monkeypatch): - app = DupeGuru() - monkeypatch.setattr(app.results, 'apply_filter', log_calls(app.results.apply_filter)) - app.apply_filter('()[]\\.|+?^abc') - call = app.results.apply_filter.calls[1] + dgapp = DupeGuru() + monkeypatch.setattr(dgapp.results, 'apply_filter', log_calls(dgapp.results.apply_filter)) + dgapp.apply_filter('()[]\\.|+?^abc') + call = dgapp.results.apply_filter.calls[1] eq_('\\(\\)\\[\\]\\\\\\.\\|\\+\\?\\^abc', call['filter_str']) - app.apply_filter('(*)') # In "simple mode", we want the * to behave as a wilcard - call = app.results.apply_filter.calls[3] + dgapp.apply_filter('(*)') # In "simple mode", we want the * to behave as a wilcard + call = dgapp.results.apply_filter.calls[3] eq_('\(.*\)', call['filter_str']) - app.options['escape_filter_regexp'] = False - app.apply_filter('(abc)') - call = app.results.apply_filter.calls[5] + dgapp.options['escape_filter_regexp'] = False + dgapp.apply_filter('(abc)') + call = dgapp.results.apply_filter.calls[5] eq_('(abc)', call['filter_str']) def test_copy_or_move(self, tmpdir, monkeypatch): @@ -75,14 +75,16 @@ class TestCaseDupeGuru: # every change I want to make. The blowup was caused by a missing import. p = Path(str(tmpdir)) io.open(p + 'foo', 'w').close() - monkeypatch.setattr(hsutil.files, 'copy', log_calls(lambda source_path, dest_path: None)) + monkeypatch.setattr(hscommon.conflict, 'smart_copy', log_calls(lambda source_path, dest_path: None)) + # XXX This monkeypatch is temporary. will be fixed in a better monkeypatcher. + monkeypatch.setattr(app, 'smart_copy', hscommon.conflict.smart_copy) monkeypatch.setattr(os, 'makedirs', lambda path: None) # We don't want the test to create that fake directory - app = DupeGuru() - app.directories.add_path(p) - [f] = app.directories.get_files() - app.copy_or_move(f, True, 'some_destination', 0) - eq_(1, len(hsutil.files.copy.calls)) - call = hsutil.files.copy.calls[0] + dgapp = DupeGuru() + dgapp.directories.add_path(p) + [f] = dgapp.directories.get_files() + dgapp.copy_or_move(f, True, 'some_destination', 0) + eq_(1, len(hscommon.conflict.smart_copy.calls)) + call = hscommon.conflict.smart_copy.calls[0] eq_('some_destination', call['dest_path']) eq_(f.path, call['source_path']) @@ -132,17 +134,19 @@ class TestCaseDupeGuru: class TestCaseDupeGuru_clean_empty_dirs: def pytest_funcarg__do_setup(self, request): monkeypatch = request.getfuncargvalue('monkeypatch') - monkeypatch.setattr(hsutil.files, 'delete_if_empty', log_calls(lambda path, files_to_delete=[]: None)) + monkeypatch.setattr(hscommon.util, 'delete_if_empty', log_calls(lambda path, files_to_delete=[]: None)) + # XXX This monkeypatch is temporary. will be fixed in a better monkeypatcher. + monkeypatch.setattr(app, 'delete_if_empty', hscommon.util.delete_if_empty) self.app = DupeGuru() def test_option_off(self, do_setup): self.app.clean_empty_dirs(Path('/foo/bar')) - eq_(0, len(hsutil.files.delete_if_empty.calls)) + eq_(0, len(hscommon.util.delete_if_empty.calls)) def test_option_on(self, do_setup): self.app.options['clean_empty_dirs'] = True self.app.clean_empty_dirs(Path('/foo/bar')) - calls = hsutil.files.delete_if_empty.calls + calls = hscommon.util.delete_if_empty.calls eq_(1, len(calls)) eq_(Path('/foo/bar'), calls[0]['path']) eq_(['.DS_Store'], calls[0]['files_to_delete']) @@ -153,10 +157,12 @@ class TestCaseDupeGuru_clean_empty_dirs: def mock_delete_if_empty(path, files_to_delete=[]): return len(path) > 1 - monkeypatch.setattr(hsutil.files, 'delete_if_empty', mock_delete_if_empty) + monkeypatch.setattr(hscommon.util, 'delete_if_empty', mock_delete_if_empty) + # XXX This monkeypatch is temporary. will be fixed in a better monkeypatcher. + monkeypatch.setattr(app, 'delete_if_empty', mock_delete_if_empty) self.app.options['clean_empty_dirs'] = True self.app.clean_empty_dirs(Path('not-empty/empty/empty')) - calls = hsutil.files.delete_if_empty.calls + calls = hscommon.util.delete_if_empty.calls eq_(3, len(calls)) eq_(Path('not-empty/empty/empty'), calls[0]['path']) eq_(Path('not-empty/empty'), calls[1]['path']) diff --git a/core/tests/data.py b/core/tests/data.py index c4c8cddf..a3a69c54 100644 --- a/core/tests/data.py +++ b/core/tests/data.py @@ -9,7 +9,7 @@ # data module for tests -from hsutil.str import format_size +from hscommon.util import format_size from ..data import format_path, cmp_value COLUMNS = [ diff --git a/core/tests/engine_test.py b/core/tests/engine_test.py index 61af1bbe..94bc817d 100644 --- a/core/tests/engine_test.py +++ b/core/tests/engine_test.py @@ -9,9 +9,8 @@ import sys from jobprogress import job -from hsutil.decorators import log_calls -from hsutil.misc import first -from hscommon.testutil import eq_ +from hscommon.util import first +from hscommon.testutil import eq_, log_calls from .. import engine from ..engine import * diff --git a/core/tests/results_test.py b/core/tests/results_test.py index c31e3697..df5b3219 100644 --- a/core/tests/results_test.py +++ b/core/tests/results_test.py @@ -14,7 +14,7 @@ from xml.etree import ElementTree as ET from hscommon.path import Path from hscommon.testutil import eq_ -from hsutil.misc import first +from hscommon.util import first from . import engine_test, data from .. import engine diff --git a/core_me/data.py b/core_me/data.py index 13f00f7f..16df32a0 100644 --- a/core_me/data.py +++ b/core_me/data.py @@ -6,7 +6,7 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/bsd_license -from hsutil.str import format_time, FT_MINUTES, format_size +from hscommon.util import format_time, format_size from core.data import (format_path, format_timestamp, format_words, format_perc, format_dupe_count, cmp_value) @@ -61,7 +61,7 @@ def GetDisplayInfo(dupe, group, delta): dupe.name, format_path(dupe.path), format_size(size, 2, 2, False), - format_time(duration, FT_MINUTES), + format_time(duration, with_hours=False), str(bitrate), str(samplerate), dupe.extension, diff --git a/core_me/fs.py b/core_me/fs.py index aaadc385..274ba10d 100644 --- a/core_me/fs.py +++ b/core_me/fs.py @@ -7,7 +7,7 @@ # http://www.hardcoded.net/licenses/bsd_license from hsaudiotag import auto -from hsutil.str import get_file_ext +from hscommon.util import get_file_ext from core import fs TAG_FIELDS = {'audiosize', 'duration', 'bitrate', 'samplerate', 'title', 'artist', diff --git a/core_pe/app_cocoa.py b/core_pe/app_cocoa.py index 23959e4e..723687ae 100644 --- a/core_pe/app_cocoa.py +++ b/core_pe/app_cocoa.py @@ -14,7 +14,7 @@ import re from appscript import app, k, CommandError, ApplicationNotFoundError from hscommon import io -from hsutil.str import get_file_ext, remove_invalid_xml +from hscommon.util import get_file_ext, remove_invalid_xml from hscommon.path import Path from hscommon.cocoa import as_fetch from hscommon.cocoa.objcmin import NSUserDefaults, NSURL diff --git a/core_pe/data.py b/core_pe/data.py index 81104330..09f1215c 100644 --- a/core_pe/data.py +++ b/core_pe/data.py @@ -6,7 +6,7 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/bsd_license -from hsutil.str import format_size +from hscommon.util import format_size from core.data import format_path, format_timestamp, format_perc, format_dupe_count, cmp_value def format_dimensions(dimensions): diff --git a/core_se/data.py b/core_se/data.py index e2f398c7..f1ffcb91 100644 --- a/core_se/data.py +++ b/core_se/data.py @@ -6,7 +6,7 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/bsd_license -from hsutil.str import format_size +from hscommon.util import format_size from core.data import (format_path, format_timestamp, format_words, format_perc, format_dupe_count, cmp_value) diff --git a/core_se/fs.py b/core_se/fs.py index 5f3635f2..234f8a82 100644 --- a/core_se/fs.py +++ b/core_se/fs.py @@ -10,7 +10,7 @@ import hashlib from hscommon import io -from hsutil.misc import nonone +from hscommon.util import nonone from core import fs diff --git a/core_se/tests/fs_test.py b/core_se/tests/fs_test.py index 64b9e832..bfeaac36 100644 --- a/core_se/tests/fs_test.py +++ b/core_se/tests/fs_test.py @@ -9,7 +9,7 @@ import hashlib -from hsutil.path import Path +from hscommon.path import Path from hscommon.testutil import eq_ from core.fs import File from core.tests.directories_test import create_fake_fs diff --git a/package.py b/package.py index af51028b..8515a2fc 100644 --- a/package.py +++ b/package.py @@ -86,7 +86,7 @@ def package_debian(edition): os.makedirs(destpath) os.makedirs(srcpath) shutil.copy('run.py', op.join(srcpath, 'run.py')) - packages = ['hscommon', 'core', ed('core_{0}'), 'qtlib', 'qt', 'hsutil', 'send2trash', 'jobprogress'] + packages = ['hscommon', 'core', ed('core_{0}'), 'qtlib', 'qt', 'send2trash', 'jobprogress'] if edition == 'me': packages.append('hsaudiotag') copy_packages(packages, srcpath) diff --git a/qt/base/main_window.py b/qt/base/main_window.py index a1dc6c27..c37cf5dd 100644 --- a/qt/base/main_window.py +++ b/qt/base/main_window.py @@ -13,7 +13,7 @@ from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QToolButton, QLabel QMessageBox, QInputDialog, QLineEdit, QDesktopServices, QFileDialog, QAction, QMenuBar, QToolBar, QWidget, QVBoxLayout, QAbstractItemView, QStatusBar) -from hsutil.misc import nonone +from hscommon.util import nonone from core.app import NoScannableFileError diff --git a/qt/pe/app.py b/qt/pe/app.py index c4ad5507..09efbb96 100644 --- a/qt/pe/app.py +++ b/qt/pe/app.py @@ -11,7 +11,7 @@ import logging from PyQt4.QtGui import QImage, QImageReader -from hsutil.str import get_file_ext +from hscommon.util import get_file_ext from core import fs from core_pe import data as data_pe diff --git a/qt/se/preferences_dialog.py b/qt/se/preferences_dialog.py index 61bea884..68342609 100644 --- a/qt/se/preferences_dialog.py +++ b/qt/se/preferences_dialog.py @@ -11,7 +11,7 @@ from PyQt4.QtCore import SIGNAL, Qt, QSize from PyQt4.QtGui import (QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QLabel, QComboBox, QSlider, QSizePolicy, QSpacerItem, QWidget, QCheckBox, QLineEdit, QDialogButtonBox, QApplication) -from hsutil.misc import tryint +from hscommon.util import tryint from core.scanner import ScanType