def test_python_args(tmp_path, mock_echo): create_filesystem( tmp_path, files=[ "empty", ("full", "0" * 2000), ("halffull", "0" * 1010), ("two_thirds.txt", "0" * 666), ], config=""" rules: - folders: files filters: - python: | return 2000 - filesize: '= {python}b' actions: - echo: '{path.name} {filesize.bytes}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls( [ call("full 2000"), ], any_order=True, )
def test_python_dict(tmp_path, mock_echo): create_filesystem( tmp_path, files=["foo-01.jpg", "foo-01.txt", "bar-02.txt", "baz-03.txt"], config=""" rules: - folders: files filters: - extension: txt - python: | return { "name": path.name[:3], "code": int(path.name.split('.')[0][-2:]) * 100, } actions: - echo: '{python.code} {python.name}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls( ( call("100 foo"), call("200 bar"), call("300 baz"), ), any_order=True, )
def test_exif_filter_single(tmp_path): """ Filter by camera """ copy_resources(tmp_path) create_filesystem( tmp_path, files=["nothing.jpg"], config=""" rules: - folders: files filters: - exif: image.model: Nikon D3200 actions: - move: 'files/{exif.image.model}/' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "nothing.jpg", "1.jpg", "NIKON D3200/2.jpg", "3.jpg", "4.jpg", "5.jpg", )
def test_basic(tmp_path, mock_echo): create_filesystem( tmp_path, files=[ "empty", ("full", "0" * 2000), ("halffull", "0" * 1010), ("two_thirds.txt", "0" * 666), ], config=""" rules: - folders: files filters: - filesize: '> 1kb, <= 1.0 KiB' actions: - echo: '{path.name} {filesize.bytes}' - folders: files filters: - filesize: - '> 0.5 kb' - '<1.0 KiB' actions: - echo: '2/3 {filesize.bytes}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls( [ call("halffull 1010"), call("2/3 666"), ], any_order=True, )
def test_exif_filter_tag_exists(tmp_path): """ Filter by GPS """ copy_resources(tmp_path) create_filesystem( tmp_path, files=["nothing.jpg"], config=""" rules: - folders: files filters: - exif: gps.gpsdate actions: - echo: "{exif.gps.gpsdate}" - move: 'files/has_gps/' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "nothing.jpg", "1.jpg", "2.jpg", "has_gps/3.jpg", "has_gps/4.jpg", "has_gps/5.jpg", )
def test_file_content(tmp_path): # inspired by https://github.com/tfeldmann/organize/issues/43 create_filesystem( tmp_path, files=[ ("Test1.txt", "Lorem MegaCorp Ltd. ipsum\nInvoice 12345\nMore text\nID: 98765"), ("Test2.txt", "Tests"), ("Test3.txt", "My Homework ...") ], config=r""" rules: - folders: files filters: - filecontent: 'MegaCorp Ltd.+^Invoice (?P<number>\w+)$.+^ID: 98765$' actions: - rename: "MegaCorp_Invoice_{filecontent.number}.txt" - folders: files filters: - filecontent: '.*Homework.*' actions: - rename: "Homework.txt" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "Homework.txt", "MegaCorp_Invoice_12345.txt", "Test2.txt")
def test_startswith_issue74(tmp_path): # test for issue https://github.com/tfeldmann/organize/issues/74 create_filesystem( tmp_path, files=[ "Cálculo_1.pdf", "Cálculo_2.pdf", "Calculo.pdf", ], config=r""" # Cálculo PDF rules: - folders: files filters: - extension: - pdf - filename: startswith: Cálculo actions: - move: "files/Cálculo Integral/Periodo #6/PDF's/" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "Cálculo Integral/Periodo #6/PDF's/Cálculo_1.pdf", "Cálculo Integral/Periodo #6/PDF's/Cálculo_2.pdf", "Calculo.pdf", )
def test_rename_issue51(tmp_path): # test for issue https://github.com/tfeldmann/organize/issues/51 create_filesystem( tmp_path, files=["19asd_WF_test2.pdf", "other.pdf", "18asd_WFX_test2.pdf",], config=r""" rules: - folders: files filters: - filename: startswith: "19" contains: - "_WF_" actions: - rename: "{path.stem}_unread{path.suffix}" - copy: dest: "files/copy/" overwrite: false counter_separator: "_" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "19asd_WF_test2_unread.pdf", "other.pdf", "copy/19asd_WF_test2_unread.pdf", "18asd_WFX_test2.pdf", )
def test_duplicate_smallfiles(tmp_path): create_filesystem( tmp_path, files=[ ("unique.txt", "I'm unique."), ("unique_too.txt", "I'm unique, too."), ("a.txt", CONTENT_SMALL), ("copy2.txt", CONTENT_SMALL), ("other/copy.txt", CONTENT_SMALL), ("other/copy.jpg", CONTENT_SMALL), ("large_unique.txt", CONTENT_LARGE), ("other/large.txt", CONTENT_LARGE), ], config=""" rules: - folders: files subfolders: true filters: - duplicate actions: - trash """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "unique.txt", "unique_too.txt", "a.txt", "large_unique.txt")
def test_globstr_exclude(tmp_path): create_filesystem( tmp_path, files=[ "Test.pdf", "Invoice.pdf", "Start.txt", "other/a.txt", "other/next/b.txt", "exclude/test.pdf", "exclude/sub/journal.md", "exclude/sub/journal.pdf", ], config=""" rules: - folders: - files/**/* - !files/exclude/* - '! files/*' actions: - shell: "rm {path}" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "Test.pdf", "Invoice.pdf", "Start.txt", "exclude/test.pdf", )
def test_dependent_rules(tmp_path): create_filesystem( tmp_path, files=["asd.txt", "newname 2.pdf", "newname.pdf", "test.pdf"], config=""" rules: - folders: files filters: - filename: test actions: - copy: files/newfolder/test.pdf - folders: files/newfolder/ filters: - filename: test actions: - rename: test-found.pdf """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "newname.pdf", "newname 2.pdf", "test.pdf", "asd.txt", "newfolder/test-found.pdf", )
def test_exif(tmp_path): """ Sort photos by camera """ copy_resources(tmp_path) create_filesystem( tmp_path, files=["nothing.jpg"], config=""" rules: - folders: files filters: - extension: jpg - exif actions: - move: 'files/{exif.image.model}/' - echo: "{exif}" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "nothing.jpg", "DMC-GX80/1.jpg", "NIKON D3200/2.jpg", "iPhone 6s/3.jpg", "iPhone 6s/4.jpg", "iPhone 5s/5.jpg", )
def test_exif_filter_multiple(tmp_path): """ Filter by camera """ copy_resources(tmp_path) create_filesystem( tmp_path, files=["nothing.jpg"], config=""" rules: - folders: files filters: - exif: image.make: Apple exif.lensmodel: "iPhone 6s back camera 4.15mm f/2.2" actions: - echo: "{exif.image}" - move: 'files/chosen/' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "nothing.jpg", "1.jpg", "2.jpg", "chosen/3.jpg", "chosen/4.jpg", "5.jpg", )
def test_normalization_glob(tmp_path): create_filesystem( tmp_path, files=[b"Ertra\xcc\x88gnisaufstellung.txt".decode("utf-8")], config=""" rules: - folders: ./**/{}.* actions: - rename: "found-glob.txt" """.format(b"Ertr\xc3\xa4gnisaufstellung".decode("utf-8")), ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "found-glob.txt")
def test_globstr(tmp_path): create_filesystem( tmp_path, files=["asd.txt", "newname 2.pdf", "newname.pdf", "test.pdf"], config=""" rules: - folders: 'file[s]/*.pdf' actions: - delete """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "asd.txt")
def test_filename_move(tmp_path): create_filesystem( tmp_path, files=["test.PY"], config=""" rules: - folders: files filters: - Extension actions: - rename: '{path.stem}{path.stem}.{extension.lower}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "testtest.py")
def test_size_zero(tmp_path, mock_echo): create_filesystem( tmp_path, files=["1", "2", "3"], config=""" rules: - folders: files filters: - filesize: 0 actions: - echo: '{path.name}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls((call("1"), call("2"), call("3")), any_order=True)
def test_python(tmp_path, mock_echo): create_filesystem( tmp_path, files=["student-01.jpg", "student-01.txt", "student-02.txt", "student-03.txt"], config=""" rules: - folders: files filters: - extension: txt - python: | return int(path.name.split('.')[0][-2:]) * 100 actions: - echo: '{python}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls( (call("100"), call("200"), call("300"),), any_order=True, )
def test_name_reverser(tmp_path): create_filesystem( tmp_path, files=["desrever.jpg", "emanelif.txt"], config=""" rules: - folders: files filters: - extension - python: | return { "reversed_name": path.stem[::-1], } actions: - rename: '{python.reversed_name}.{extension}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "reversed.jpg", "filename.txt")
def test_globstr_subfolder_serious(tmp_path): create_filesystem( tmp_path, files=[ "Test.pdf", "Invoice.pdf", "Other.pdf", "Start.txt", "x/foo/test.pdf", "x/sub/journal.md", "x/sub/journal.pdf", "wub/best.pdf", "sub/other/marks.pdf", "x/sub/testjournal.pdf", "sub/test.pdf", "wub/test.pdf", "dub/test.pdf", ], config=""" rules: - folders: - files/**/*ub/**/test*.pdf - !files/dub/* actions: - shell: "rm {path}" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "Test.pdf", "Invoice.pdf", "Other.pdf", "Start.txt", "x/foo/test.pdf", "x/sub/journal.md", "x/sub/journal.pdf", "wub/best.pdf", "sub/other/marks.pdf", "dub/test.pdf", )
def test_rename_files_date(tmp_path): # inspired by https://github.com/tfeldmann/organize/issues/43 create_filesystem( tmp_path, files=[ "File_abc_dat20190812_xyz.pdf", "File_xyz_bar19990101_a.pdf", "File_123456_foo20000101_xyz20190101.pdf", ], config=r""" rules: - folders: files filters: - regex: 'File_.*?(?P<y>\d{4})(?P<m>\d{2})(?P<d>\d{2}).*?.pdf' actions: - rename: "File_{regex.d}{regex.m}{regex.y}.pdf" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "File_12082019.pdf", "File_01011999.pdf", "File_01012000.pdf")
def test_odd_detector(tmp_path, mock_echo): create_filesystem( tmp_path, files=["student-01.txt", "student-02.txt", "student-03.txt", "student-04.txt"], config=""" rules: - folders: files filters: - python: | return int(path.stem.split('-')[1]) % 2 == 1 actions: - echo: 'Odd student numbers: {path.name}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls( ( call("Odd student numbers: student-01.txt"), call("Odd student numbers: student-03.txt"), ), any_order=True, )
def test_codepost_usecase(tmp_path): create_filesystem( tmp_path, files=[ "Devonte-Betts.txt", "Alaina-Cornish.txt", "Dimitri-Bean.txt", "Lowri-Frey.txt", "Someunknown-User.txt", ], config=r""" rules: - folders: files filters: - extension: txt - regex: (?P<firstname>\w+)-(?P<lastname>\w+)\..* - python: | emails = { "Betts": "*****@*****.**", "Cornish": "*****@*****.**", "Bean": "*****@*****.**", "Frey": "*****@*****.**", } if regex.lastname in emails: return {"mail": emails[regex.lastname]} actions: - rename: '{python.mail}.txt' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**", "Someunknown-User.txt", # no email found -> keep file )
def test_multiple_regex_placeholders(tmp_path, mock_echo): create_filesystem( tmp_path, files=["test-123.jpg", "other-456.pdf"], config=r""" rules: - folders: files filters: - regex: (?P<word>\w+)-(?P<number>\d+).* - regex: (?P<all>.+?)\.\w{3} - extension actions: - echo: '{regex.word} {regex.number} {regex.all} {extension}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls( ( call("test 123 test-123 jpg"), call("other 456 other-456 pdf"), ), any_order=True, )
def test_globstr(tmp_path): # inspired by https://github.com/tfeldmann/organize/issues/39 create_filesystem( tmp_path, files=[ "Test.pdf", "Invoice.pdf", "Other.pdf", "Start.txt", "journal.md", "sub/test.pdf", "sub/other/marks.pdf", ], config=""" rules: - folders: files/*.pdf actions: - shell: "rm {path}" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "Start.txt", "journal.md", "sub/test.pdf", "sub/other/marks.pdf")
def test_filename_move(tmp_path, mock_echo): create_filesystem( tmp_path, files=["test.jpg", "asd.JPG", "nomatch.jpg.zip", "camel.jPeG"], config=""" rules: - folders: files filters: - extension: - .jpg - jpeg actions: - echo: 'Found JPG file: {path.name}' """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) mock_echo.assert_has_calls( ( call("Found JPG file: test.jpg"), call("Found JPG file: asd.JPG"), call("Found JPG file: camel.jPeG"), ), any_order=True, )
def test_globstr_subfolder_setting(tmp_path): create_filesystem( tmp_path, files=[ "Test.pdf", "Invoice.pdf", "Other.pdf", "Start.txt", "sub/journal.md", "sub/test.pdf", "sub/other/marks.pdf", ], config=""" rules: - folders: files subfolders: true filters: - extension: pdf actions: - shell: "rm {path}" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir(tmp_path, "Start.txt", "sub/journal.md")
def test_folder_instructions(tmp_path): """ I would like to include path/folder-instructions into the filename because I have a lot of different files (and there are always new categories added) I don't want create rules for. For example my filename is '2019_Jobs_CategoryA_TagB_A-Media_content-name_V01_draft_eng.docx' which means: Move the file to the folder '2019/Jobs/CategoryA/TagB/Media/drafts/eng' whereby 'A-' is an additional instruction and should be removed from the filename afterwards ('2019_Jobs_CategoryA_TagB_content-name_V01_draft_eng.docx'). I have a rough idea to figure it out with python but I'm new to it (see below a sketch). Is there a possibility to use such variables, conditions etc. with organizer natively? If no, is it possible to do it with Python in Organizer at all? - Transform file-string into array - Search for 'A-...', 'V...' and 'content-name' and get index of values - remove value 'A-... and 'content-name' of array - build new filename string - remove value 'V...' and 'A-' of array - build folder-path string (convert _ to /) etc. """ # inspired by: https://github.com/tfeldmann/organize/issues/52 create_filesystem( tmp_path, files=[ "2019_Jobs_CategoryA_TagB_A-Media_content-name_V01_draft_eng.docx", "2019_Work_CategoryC_V-Test_A-Audio_V14_final.pdf", "other.pdf", ], config=r""" rules: - folders: files filters: - extension: - pdf - docx - filename: contains: "_" - python: | import os parts = [] instructions = dict() for part in path.stem.split("_"): if part.startswith("A-"): instructions["A"] = part[2:] elif part.startswith("V-"): instructions["V"] = part[2:] elif part.startswith("content-name"): instructions["content"] = part[12:] else: parts.append(part) return { "new_path": os.path.join(*parts), "instructions": instructions, } actions: - echo: "New path: {python.new_path}" - echo: "Instructions: {python.instructions}" - echo: "Value of A: {python.instructions.A}" - move: "files/{python.new_path}/{path.name}" """, ) main(["run", "--config-file=%s" % (tmp_path / "config.yaml")]) assertdir( tmp_path, "other.pdf", "2019/Jobs/CategoryA/TagB/V01/draft/eng/2019_Jobs_CategoryA_TagB_A-Media_content-name_V01_draft_eng.docx", "2019/Work/CategoryC/V14/final/2019_Work_CategoryC_V-Test_A-Audio_V14_final.pdf", "other.pdf", )