diff --git a/classifier/classifier.py b/classifier/classifier.py index bd22471..4f61180 100755 --- a/classifier/classifier.py +++ b/classifier/classifier.py @@ -12,11 +12,13 @@ """ import argparse -import arrow import os import subprocess import sys +from pytimeparse import parse as timeparse +from datetime import timedelta +import arrow VERSION = 'Classifier 2.0' DIRCONFFILE = '.classifier.conf' @@ -34,7 +36,7 @@ def main(): - Classifier() + Classifier(sys.argv[1:]).run() class Classifier: @@ -47,7 +49,7 @@ class Classifier: Documents - https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions """ - def __init__(self): + def __init__(self, args=None): self.description = "Organize files in your directory instantly,by classifying them into different folders" self.parser = argparse.ArgumentParser(description=self.description) @@ -62,13 +64,13 @@ def __init__(self): self.parser.add_argument("-rst", "--reset", action='store_true', help="Reset the default Config file") - + """ self.parser.add_argument("-r", "--recursive", action='store_true', help="Recursively search your source directory. " + "WARNING: Ensure you use the correct path as this " + "WILL move all files from your selected types.") - """ + """ self.parser.add_argument("-st", "--specific-types", type=str, nargs='+', help="Move all file extensions, given in the args list, " + @@ -89,12 +91,17 @@ def __init__(self): self.parser.add_argument("-df", "--dateformat", type=str, help="set the date format using YYYY, MM or DD") - self.args = self.parser.parse_args() + self.parser.add_argument("-n", "--ignore-newer-than", type=str, + help="Ignore files created or modified in less than provided time " + "(i.e. 5m, 32m, 2h32m, 3d2h32m, 1h, 1d, 2w)") + + self._ignore_newer_than = None + + self.args = self.parser.parse_args(args) self.dateformat = 'YYYY-MM-DD' self.formats = {} self.dirconf = None self.checkconfig() - self.run() def create_default_config(self): with open(CONFIG, "w") as conffile: @@ -109,7 +116,7 @@ def create_default_config(self): "DEBPackages: deb\n" + "Programs: exe, msi\n" + "RPMPackages: rpm") - print("CONFIG file created at: "+CONFIG) + print("CONFIG file created at: " + CONFIG) def checkconfig(self): """ create a default config if not available """ @@ -121,14 +128,19 @@ def checkconfig(self): with open(CONFIG, 'r') as file: for items in file: spl = items.replace('\n', '').split(':') - key = spl[0].replace(" ","") - val = spl[1].replace(" ","") + key = spl[0].replace(" ", "") + val = spl[1].replace(" ", "") self.formats[key] = val return def moveto(self, filename, from_folder, to_folder): from_file = os.path.join(from_folder, filename) + + if self._is_file_too_recent(from_file): + return + to_file = os.path.join(to_folder, filename) + # to move only files, not folders if not to_file == from_file: print('moved: ' + str(to_file)) @@ -194,6 +206,21 @@ def _format_arg(self, arg): arg = self._format_text_arg(arg) return arg + def _is_file_too_recent(self, from_file): + if self._ignore_newer_than is None: + return False + + file_modification_time = arrow.get(os.path.getmtime(from_file)) + + time_since_modification: timedelta = arrow.utcnow() - file_modification_time + + return self._ignore_newer_than > time_since_modification + + def _parse_ignore_newer_than(self): + if not self.args.ignore_newer_than: + return + self._ignore_newer_than = timedelta(seconds=timeparse(self.args.ignore_newer_than)) + def run(self): if self.args.version: # Show version information and quit @@ -203,7 +230,7 @@ def run(self): if self.args.types: # Show file format information then quit for key, value in self.formats.items(): - print(key + ': '+ value) + print(key + ': ' + value) return False if self.args.edittypes: @@ -255,6 +282,14 @@ def run(self): 'Dateformat -df must be given alongwith date -dt option') sys.exit() + if self.args.ignore_newer_than: + try: + self._parse_ignore_newer_than() + except TypeError: + print("Invalid value for ignore-newer-than: " + self.args.ignore_newer_than) + print("Example of valid values: 5m, 32m, 2h32m, 3d2h32m, 1h, 1d, 2w") + return False + if self.args.date: if self.args.dateformat: self.classify_by_date(self.args.dateformat, output, directory) @@ -287,4 +322,3 @@ def run(self): print("Done!\n") return True - diff --git a/setup.py b/setup.py index 58d88f3..21c7fdd 100644 --- a/setup.py +++ b/setup.py @@ -1,20 +1,21 @@ from setuptools import setup setup( - name="classifier", - version="2.0", - description="Classify the files in your Downloads folder into suitable destinations.", - url="http://github.com/bhrigu123/classifier", - author="Bhrigu Srivastava", - author_email="captain.bhrigu@gmail.com", - license='MIT', - packages=["classifier"], - entry_points=""" + name="classifier", + version="2.0", + description="Classify the files in your Downloads folder into suitable destinations.", + url="http://github.com/bhrigu123/classifier", + author="Bhrigu Srivastava", + author_email="captain.bhrigu@gmail.com", + license='MIT', + packages=["classifier"], + entry_points=""" [console_scripts] classifier = classifier.classifier:main """, - install_requires=[ - 'arrow' - ], - zip_safe=False + install_requires=[ + 'arrow', + 'pytimeparse' + ], + zip_safe=False ) diff --git a/tests/test_classifier.py b/tests/test_classifier.py index 16a5ccd..36b4505 100755 --- a/tests/test_classifier.py +++ b/tests/test_classifier.py @@ -4,6 +4,8 @@ import os import shutil import unittest +import time +import datetime import classifier.classifier as clf @@ -13,7 +15,7 @@ class ClassifierTest(unittest.TestCase): __location = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__), '.unittest')) - __tmp_files = [u'test_file', u'test_file_中文'] + __tmp_files = [u'test_file.mp3', u'test_file_中文.rar'] __tmp_dirs = [u'test_dir', u'test_dir_中文'] def setUp(self): @@ -25,6 +27,9 @@ def setUp(self): for dir_ in self.__tmp_dirs: if not os.path.exists(dir_): os.mkdir(dir_) + + self.classifier = clf.Classifier() + super(ClassifierTest, self).setUp() def tearDown(self): @@ -34,7 +39,7 @@ def tearDown(self): def test_moveto(self): target_dir = os.path.abspath(os.path.join(self.__location, 'moveto')) for file_ in self.__tmp_files: - clf.self.moveto(file_, self.__location, target_dir) + self.classifier.moveto(file_, self.__location, target_dir) for file_ in self.__tmp_files: final_file_path = os.path.join(target_dir, file_) @@ -47,12 +52,46 @@ def test_classify_bydate(self): target_dir = arrow.get(os.path.getctime(file_)).format(date_format) final_file_path = os.path.join(target_dir, file_) target_files.append(final_file_path) - clf.self.classify_by_date(date_format, self.__location) + self.classifier.classify_by_date(date_format, self.__location, self.__location) for file_ in target_files: self.assertTrue(os.path.exists(file_)) for dir_ in self.__tmp_dirs: self.assertTrue(os.path.exists(dir_)) + def test_ignore_newer_than_should_ignore_new_files(self): + self.classifier = clf.Classifier([ + '--ignore-newer-than=10m' + ]) + + self.assertTrue(self.classifier.run()) + + for file in self.__tmp_files: + file_path = os.path.join(self.__location, file) + self.assertTrue(os.path.exists(file_path)) + + def test_ignore_newer_than_should_not_ignore_old_files(self): + self.classifier = clf.Classifier([ + '--ignore-newer-than=10m' + ]) + + for file_ in self.__tmp_files: + date = datetime.datetime.now() - datetime.timedelta(minutes=11) + mod_time = time.mktime(date.timetuple()) + os.utime(os.path.join(self.__location, file_), (mod_time, mod_time)) + + self.assertTrue(self.classifier.run()) + + for file in self.__tmp_files: + fp = os.path.join(self.__location, file) + self.assertFalse(os.path.exists(fp)) + + def test_ignore_newer_than_with_wrong_input(self): + self.classifier = clf.Classifier([ + '--ignore-newer-than=wrong_input' + ]) + + self.assertFalse(self.classifier.run()) + if __name__ == '__main__': unittest.main()