From 72b6cdc3885ca3e1be662b24826ea7d2fdcc5967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Paix=C3=A3o=20Resende?= Date: Wed, 25 Mar 2020 11:42:48 -0300 Subject: [PATCH 1/3] fix unit tests --- tests/test_classifier.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_classifier.py b/tests/test_classifier.py index 16a5ccd..8a6ec8d 100755 --- a/tests/test_classifier.py +++ b/tests/test_classifier.py @@ -25,6 +25,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 +37,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,7 +50,7 @@ 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: From 3a400c3ea4c2fb9478c6aa70ca43762c3156cdeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Paix=C3=A3o=20Resende?= Date: Wed, 25 Mar 2020 14:58:34 -0300 Subject: [PATCH 2/3] adds --ignore-newer-than --- classifier/classifier.py | 45 +++++++++++++++++++++++++++++----------- tests/test_classifier.py | 29 +++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/classifier/classifier.py b/classifier/classifier.py index bd22471..44ec369 100755 --- a/classifier/classifier.py +++ b/classifier/classifier.py @@ -12,11 +12,12 @@ """ import argparse -import arrow import os import subprocess import sys +from datetime import timedelta +import arrow VERSION = 'Classifier 2.0' DIRCONFFILE = '.classifier.conf' @@ -34,7 +35,7 @@ def main(): - Classifier() + Classifier(sys.argv[1:]).run() class Classifier: @@ -47,7 +48,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 +63,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 +90,14 @@ 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=int, + help="Ignore files newer than provided duration in minutes (i.e. 1m, 1h, 30s, 1w, 5d)") + + 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 +112,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 +124,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 +202,20 @@ def _format_arg(self, arg): arg = self._format_text_arg(arg) return arg + def _is_file_too_recent(self, from_file): + if self.args.ignore_newer_than is None: + return False + + ignore_newer_than = int(self.args.ignore_newer_than) + + file_creation_time = arrow.get(os.path.getctime(from_file)) + + diff: timedelta = arrow.utcnow() - file_creation_time + + minutes = diff.total_seconds() / 60 + + return ignore_newer_than > minutes + def run(self): if self.args.version: # Show version information and quit @@ -203,7 +225,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: @@ -287,4 +309,3 @@ def run(self): print("Done!\n") return True - diff --git a/tests/test_classifier.py b/tests/test_classifier.py index 8a6ec8d..d46e33f 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_中文'] __tmp_dirs = [u'test_dir', u'test_dir_中文'] def setUp(self): @@ -56,6 +58,31 @@ def test_classify_bydate(self): 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=10' + ]) + + self.classifier.run() + + for file in self.__tmp_files: + self.assertTrue(os.path.exists(self.__location.join(file))) + + def test_ignore_newer_than_should_ignore_new_files(self): + self.classifier = clf.Classifier([ + '--ignore-newer-than=10' + ]) + + for file_ in self.__tmp_files: + date = datetime.datetime.now() - datetime.timedelta(minutes=11) + mod_time = time.mktime(date.timetuple()) + os.utime(file_, (mod_time, mod_time)) + + self.classifier.run() + + for file in self.__tmp_files: + self.assertFalse(os.path.exists(self.__location.join(file))) + if __name__ == '__main__': unittest.main() From 6818038956c472c040ddad8be9b8bbdf7ddf6c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Paix=C3=A3o=20Resende?= Date: Thu, 26 Mar 2020 02:41:10 -0300 Subject: [PATCH 3/3] adds better input format for --ignore-newer-than, fix tests --- classifier/classifier.py | 31 ++++++++++++++++++++++--------- setup.py | 27 ++++++++++++++------------- tests/test_classifier.py | 27 ++++++++++++++++++--------- 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/classifier/classifier.py b/classifier/classifier.py index 44ec369..4f61180 100755 --- a/classifier/classifier.py +++ b/classifier/classifier.py @@ -15,6 +15,7 @@ import os import subprocess import sys +from pytimeparse import parse as timeparse from datetime import timedelta import arrow @@ -90,8 +91,11 @@ def __init__(self, args=None): self.parser.add_argument("-df", "--dateformat", type=str, help="set the date format using YYYY, MM or DD") - self.parser.add_argument("-n", "--ignore-newer-than", type=int, - help="Ignore files newer than provided duration in minutes (i.e. 1m, 1h, 30s, 1w, 5d)") + 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' @@ -203,18 +207,19 @@ def _format_arg(self, arg): return arg def _is_file_too_recent(self, from_file): - if self.args.ignore_newer_than is None: + if self._ignore_newer_than is None: return False - ignore_newer_than = int(self.args.ignore_newer_than) - - file_creation_time = arrow.get(os.path.getctime(from_file)) + file_modification_time = arrow.get(os.path.getmtime(from_file)) - diff: timedelta = arrow.utcnow() - file_creation_time + time_since_modification: timedelta = arrow.utcnow() - file_modification_time - minutes = diff.total_seconds() / 60 + return self._ignore_newer_than > time_since_modification - return ignore_newer_than > minutes + 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: @@ -277,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) 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 d46e33f..36b4505 100755 --- a/tests/test_classifier.py +++ b/tests/test_classifier.py @@ -15,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.mp3', u'test_file_中文'] + __tmp_files = [u'test_file.mp3', u'test_file_中文.rar'] __tmp_dirs = [u'test_dir', u'test_dir_中文'] def setUp(self): @@ -60,28 +60,37 @@ def test_classify_bydate(self): def test_ignore_newer_than_should_ignore_new_files(self): self.classifier = clf.Classifier([ - '--ignore-newer-than=10' + '--ignore-newer-than=10m' ]) - self.classifier.run() + self.assertTrue(self.classifier.run()) for file in self.__tmp_files: - self.assertTrue(os.path.exists(self.__location.join(file))) + file_path = os.path.join(self.__location, file) + self.assertTrue(os.path.exists(file_path)) - def test_ignore_newer_than_should_ignore_new_files(self): + def test_ignore_newer_than_should_not_ignore_old_files(self): self.classifier = clf.Classifier([ - '--ignore-newer-than=10' + '--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(file_, (mod_time, mod_time)) + os.utime(os.path.join(self.__location, file_), (mod_time, mod_time)) - self.classifier.run() + self.assertTrue(self.classifier.run()) for file in self.__tmp_files: - self.assertFalse(os.path.exists(self.__location.join(file))) + 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__':