organize - The file management automation tool

Overview

organize logo

tests Documentation Status License PyPI Version


organize - The file management automation tool
Full documentation at Read the docs

About

Your desktop is a mess? You cannot find anything in your downloads and documents? Sorting and renaming all these files by hand is too tedious? Time to automate it once and benefit from it forever.

organize is a command line, open-source alternative to apps like Hazel (macOS) or File Juggler (Windows).

Getting started

Installation

Python 3.6+ is needed. Install it via your package manager or from python.org.

Installation is done via pip. Note that the package name is organize-tool:

pip3 install -U organize-tool

If you want the text extraction capabilities, install with textract like this:

pip3 install -U "organize-tool[textract]"

This command can also be used to update to the newest version. Now you can run organize --help to check if the installation was successful.

Creating your first rule

In your shell, run organize config to edit the configuration:

rules:
    - folders: ~/Downloads
      subfolders: true
      filters:
          - extension: pdf
      actions:
          - echo: "Found PDF!"

If you have problems editing the configuration you can run organize config --open-folder to reveal the configuration folder in your file manager. You can then edit the config.yaml in your favourite editor.

Alternatively you can run organize config --path to see the full path to your config.yaml)

Save your config file and run organize run.

You will see a list of all .pdf files you have in your downloads folder (+ subfolders). For now we only show the text Found PDF! for each file, but this will change soon... (If it shows Nothing to do you simply don't have any pdfs in your downloads folder).

Run organize config again and add a copy-action to your rule:

actions:
    - echo: "Found PDF!"
    - move: ~/Documents/PDFs/

Now run organize sim to see what would happen without touching your files. You will see that your pdf-files would be moved over to your Documents/PDFs folder.

Congratulations, you just automated your first task. You can now run organize run whenever you like and all your pdfs are a bit more organized. It's that easy.

There is so much more. You want to rename / copy files, run custom shell- or python scripts, match filenames with regular expressions or use placeholder variables? organize has you covered. Have a look at the advanced usage example below!

Example rules

Here are some examples of simple organization and cleanup rules. Modify to your needs!

Move all invoices, orders or purchase documents into your documents folder:

rules:
    # sort my invoices and receipts
    - folders: ~/Downloads
      subfolders: true
      filters:
          - extension: pdf
          - filename:
                contains:
                    - Invoice
                    - Order
                    - Purchase
                case_sensitive: false
      actions:
          - move: ~/Documents/Shopping/

Move incomplete downloads older than 30 days into the trash:

rules:
    # move incomplete downloads older > 30 days into the trash
    - folders: ~/Downloads
      filters:
          - extension:
                - download
                - crdownload
                - part
          - lastmodified:
                days: 30
                mode: older
      actions:
          - trash

Delete empty files from downloads and desktop:

rules:
    # delete empty files from downloads and desktop
    - folders:
          - ~/Downloads
          - ~/Desktop
      filters:
          - filesize: 0
      actions:
          - trash

Move screenshots into a "Screenshots" folder on your desktop:

rules:
    # move screenshots into "Screenshots" folder
    - folders: ~/Desktop
      filters:
          - filename:
                startswith: "Screen Shot"
      actions:
          - move: ~/Desktop/Screenshots/

Organize your font downloads:

rules:
    # organize your font files but keep the folder structure:
    #   "~/Downloads/favourites/helvetica/helvetica-bold.ttf"
    #     is moved to
    #   "~/Documents/FONTS/favourites/helvetica/helvetica-bold.ttf"
    - folders: ~/Downloads/**/*.ttf
      actions:
          - Move: "~/Documents/FONTS/{relative_path}"

You'll find many more examples in the full documentation.

Advanced usage

This example shows some advanced features like placeholder variables, pluggable actions, recursion through subfolders and glob syntax:

rules:
    - folders: ~/Documents/**/*
      filters:
          - extension:
                - pdf
                - docx
          - created
      actions:
          - move: "~/Documents/{extension.upper}/{created.year}{created.month:02}/"
          - shell: 'open "{path}"'

Given we have two files in our ~/Documents folder (or any of its subfolders) named script.docx from january 2018 and demo.pdf from december 2016 this will happen:

  • script.docx will be moved to ~/Documents/DOCX/2018-01/script.docx
  • demo.pdf will be moved to ~/Documents/PDF/2016-12/demo.pdf
  • The files will be opened (open command in macOS) from their new location.
  • Note the format syntax for {created.month} to make sure the month is prepended with a zero.

Command line interface

The file management automation tool.

Usage:
    organize sim [--config-file=]
    organize run [--config-file=]
    organize config [--open-folder | --path | --debug] [--config-file=]
    organize list
    organize --help
    organize --version

Arguments:
    sim             Simulate a run. Does not touch your files.
    run             Organizes your files according to your rules.
    config          Open the configuration file in $EDITOR.
    list            List available filters and actions.
    --version       Show program version and exit.
    -h, --help      Show this screen and exit.

Options:
    -o, --open-folder  Open the folder containing the configuration files.
    -p, --path         Show the path to the configuration file.
    -d, --debug        Debug your configuration file.

Full documentation: https://organize.readthedocs.io
Comments
  • Version 2.x filecontent not working anymore

    Version 2.x filecontent not working anymore

    The filecontent regex is not compatible. Error is happening with pdf files. All rules previously working containing the "filecontent" command result in error. Tested with Version 2.09 and 2.1.

    - (filecontent) ERROR! 'NoneType' object has no attribute 'groupdict'
    

    Examples not working anymore:

        filters:
          - regex: '(?P<year>20\d{2})-[01]\d-[0-3]\d.*\.pdf'  
          - filecontent:
            - '(HUK-COBURG)|(ADAC)|(Meine HUK24)|(Sozialversicherung)'
          - filecontent:
            - '(?P<strasse>Brückl)'
    
       filters:
          - regex: '(?P<year>20\d{2})-[01]\d-[0-3]\d.*\.pdf'
          - filecontent:
            - '(Versorgung)|(Abwasser)|(Schmutzwasser)|(Abfall)'
          - filecontent:
            - 'Brückl'
    

    Even examples taken straight from documentation do not work anymore

        filters:
          - filecontent:
            - '(?P<inhalt>.*)'
    
    bug awaiting feedback 
    opened by Marty56 28
  • How to run the program

    How to run the program

    Hi,

    I am a newbie in all things technical. I have installed the package doing pip3 install -U organize-tool. How do I run it? I have written "organize" on the Terminal, but this does not work. Thanks in advance!

    opened by AtomicNess123 16
  • Error after update to V 2.0

    Error after update to V 2.0

    I have changed my rule file according migration documentation. Getting the following error:

    /usr/local/bin/python3 -m  organize sim --config-file='/Users/martinklimke/Library/Mobile Documents/com~apple~CloudDocs/Documents/Organize/Rules/config.yaml'
    (base) [email protected] ~ % /usr/local/bin/python3 -m  organize sim --config-file='/Users/martinklimke/Library/Mobile Documents/com~apple~CloudDocs/Documents/Organize/Rules/config.yaml'
    Deprecated: The --config-file option can now be omitted. See organize --help.
    organize 2.0.0
    Config: "/Users/martinklimke/Library/Mobile 
    Documents/com~apple~CloudDocs/Documents/Organize/Rules/config.yaml"
    ╭───────────────────── Traceback (most recent call last) ──────────────────────╮
    │                                                                              │
    │ /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-package │
    │ s/organize/cli.py:86 in run_local                                            │
    │                                                                              │
    │    83 │   │   config_dir, config_name = split(config_path)                   │
    │    84 │   │   config = open_fs(config_dir).readtext(config_name)             │
    │    85 │   │   os.chdir(working_dir)                                          │
    │ ❱  86 │   │   core.run(rules=config, simulate=simulate)                      │
    │    87 │   except NeedsMigrationError as e:                                   │
    │    88 │   │   console.error(e, title="Config needs migration")               │
    │    89 │   │   console.warn(                                                  │
    │ /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-package │
    │ s/organize/core.py:294 in run                                                │
    │                                                                              │
    │   291 │                                                                      │
    │   292 │   rules = config.cleanup(rules)                                      │
    │   293 │                                                                      │
    │ ❱ 294 │   migrate_v1(rules)                                                  │
    │   295 │                                                                      │
    │   296 │   if validate:                                                       │
    │   297 │   │   config.validate(rules)                                         │
    │                                                                              │
    │ /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-package │
    │ s/organize/migration.py:26 in migrate_v1                                     │
    │                                                                              │
    │   23 │   │   if "folders" in rule:                                           │
    │   24 │   │   │   raise NeedsMigrationError("`folders` are now `locations`")  │
    │   25 │   │   for fil in rule.get("filters", []):                             │
    │ ❱ 26 │   │   │   name, _ = entry_name_args(fil)                              │
    │   27 │   │   │   if name == "filename":                                      │
    │   28 │   │   │   │   raise NeedsMigrationError("`filename` is now `name`")   │
    │   29 │   │   │   if name == "filesize":                                      │
    ╰──────────────────────────────────────────────────────────────────────────────╯
    TypeError: cannot unpack non-iterable NoneType object
    
    opened by Marty56 15
  • macOS tags

    macOS tags

    I love this project and use it quite a lot.

    I would be great if organize could also support tagging under MacOS. Library for setting tags seems to be available https://pypi.org/project/macos-tags/

    feature request 
    opened by Marty56 15
  • {created} filter is not populated  version 2.0.x

    {created} filter is not populated version 2.0.x

    Hi Great work on the 2.x stuff..

    With the Created filter set and modified config for 2.x it seems that the created variable is not being populated

    config:

      - name: "Match Images"
        locations: "~/Downloads"
        filters:
          - extension:
              - png
              - jpg
              - jpeg
              - gif
              - tiff
              - eps
          - created
        actions:
          - echo: "Found Image File CREATED: {created} {created.strftime('%Y-%m-%d')}"
          - move: "~/Nextcloud/Pictures/2020 - 2029/{created.year}/{created.month}/Daily/{created.day}/"
    

    Output is as follows on SIM

    ⚙ Match Images ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    /home/marty/Downloads
      Picture 2022-02-09 10-05-19.png
        - (echo) ERROR! 'None' has no attribute 'strftime'
    

    Debug info:

    │                                                                                                  │
    │ /home/marty/.local/lib/python3.10/site-packages/organize/cli.py:87 in run_local                  │
    │                                                                                                  │
    │    84 │   │   config_dir, config_name = split(config_path)                                       │
    │    85 │   │   config = open_fs(config_dir).readtext(config_name)                                 │
    │    86 │   │   os.chdir(working_dir)                                                              │
    │ ❱  87 │   │   core.run(rules=config, simulate=simulate)                                          │
    │    88 │   except NeedsMigrationError as e:                                                       │
    │    89 │   │   console.error(e, title="Config needs migration")                                   │
    │    90 │   │   console.warn(                                                                      │
    │ /home/marty/.local/lib/python3.10/site-packages/organize/core.py:328 in run                      │
    │                                                                                                  │
    │   325 │   console.summary(count)                                                                 │
    │   326 │                                                                                          │
    │   327 │   if count["fail"]:                                                                      │
    │ ❱ 328 │   │   raise RuntimeWarning("Some actions failed.")                                       │
    │   329  
    
    awaiting feedback 
    opened by snuffop 14
  • Filter

    Filter "created" does not output date and time

    Hello all, In my config I try to rename the files with the filter "created" and move them to a certain folder.

    Unfortunately, no values are output in the variables used.

    VID-{created.year}{created.month}{created.day}.{created.hour}-{created.minutes}.{extension.lower}

    VID-.-.<built-in method lower of str object at 0xb65aad00>

    The file name should then look like this: Example: VID-20220210-06-20.mp4

    here my config:

      - locations:
          - *downloads
        filters:
          - extension:
              - mp4
              - avi
              - mpeg
              - mpg
              - mov
              - mkv
              - flv
              - m4v
              - 3gp
              - wmv
          - name:
              case_sensitive: false
          - created
        actions:
          - move: '/srv/mergerfs/Pool/Videos/VID-{created.year}{created.month}{created.day}.{created.hour}-{created.minutes}.{extension.lower}'  
        subfolders: false
    
    opened by wintuxx 12
  • Migration to 2.0 - InvalidCharsInPath: contains invalid characters

    Migration to 2.0 - InvalidCharsInPath: contains invalid characters

    I am trying to move from 1.0 to 2.0 on my Windows 10 laptop. However, I cannot simulate or run any rules.

    The error message reads : InvalidCharsInPath: path 'C:\Users\%USERPFOILE%\AppData\Local\organize\organize\config.yaml' contains invalid characters

    Errors are occurring at :

    Python\Python310\lib\site-packages\organize\cli.py:86 in │ │ run_local

    86 │ │ config = open_fs(config_dir).readtext(config_name)

    \Python\Python310\lib\site-packages\fs\base.py:691 in ││ readtext │

    691 │ │ │ self.open( │ │ 692 │ │ │ │ path, mode="rt", encoding=encoding, errors=errors, newline=newline │ │ 693 │ │ │ ) │ │ 694 │ │ ) as read_file:

    Python\Python310\lib\site-packages\fs\osfs.py:640 in open

    │ > 640 │ │ _path = self.validatepath(path)

    Python\Python310\lib\site-packages\fs\osfs.py:687 in │ │ validatepath │ │ > 687 │ │ return super(OSFS, self).validatepath(path)

    │ > 1577 │ │ │ │ raise errors.InvalidCharsInPath(path)

    How can I resolve this ? I'm I missing some dependencies ?

    bug awaiting feedback 
    opened by ktreharrison 11
  • Rule ignoring «contains: screenshot»

    Rule ignoring «contains: screenshot»

    This rule ignores any screenshot files in the pertinent folder. Maybe somebody can see where the error is? I need the rule to target any file whose filename contains screenshot.

      - name: "move screenshots to temp folder"
        locations: '~/OneDrive/Pictures/Camera Roll/'
        subfolders: false
        enabled: true
        filters:
          - extension:
            - png
            - jpg
            - jpeg
          - name:
              contains: screenshot
              case_sensitive: false
        actions:
          - move:
              dest: "~/Pictures/album/TEMP/"
              on_conflict: rename_new
              rename_template: "{name}_{counter}{extension}"
    
    bug awaiting feedback 
    opened by iburunat 11
  • Shortcuts not registering?

    Shortcuts not registering?

    This is an odd one because it seems to be inconsistent. I'm pointing the application to my desktop and asking it to move new .lnk files (shortcuts) somewhere else in my home directory... While it has worked before it often ignores certain shortcuts as if they don't even exist.

    Edit It managed to recognize the "ImageMagick Display" applications shortcut when updating it but I see no discernible difference between "it" and other shortcuts that sit on my desktop.

    opened by daephx 10
  • Duplicate filter can offer unpredictable results in folders with multiples copies of a single file

    Duplicate filter can offer unpredictable results in folders with multiples copies of a single file

    I have used organize to sort and rename files. After several runs, I created a few duplicates. As I tried to remove the dupes with the built-in filter, the simulations worried me a bit. I created a simplified example to demonstrate this behavior.

    Initial configuration

    You have a folder with several copies of the same file. There is an original file and several copies of the same file with numbers appended at the end. For this example, I created a testfile.txt under testdupes folder. Content of the file is "Hello World!". Then I copied the file 5 times using the Finder (on Mac).

    Organize rule

    This is the organize rule I used to match the duplicate files:

    - folders: ~/testdupes/**/*
        filters:
          - duplicate
        actions:
          - echo: "{path} is a duplicate of {duplicate}"
    

    Initial test

     ~ % vi testdupes/tesfile.txt
    (Files copied on Finder)
     ~ % cd testdupes 
    testdupes % ls -la
    total 48
    drwxr-xr-x   8 user  staff   256 27 ene 11:11 .
    drwxr-xr-x+ 53 user  staff  1696 27 ene 11:10 ..
    -rw-r--r--   1 user  staff    13 27 ene 11:10 tesfile_copy_1.txt
    -rw-r--r--   1 user  staff    13 27 ene 11:10 tesfile_copy_2.txt
    -rw-r--r--   1 user  staff    13 27 ene 11:10 tesfile_copy_3.txt
    -rw-r--r--   1 user  staff    13 27 ene 11:10 tesfile_copy_4.txt
    -rw-r--r--@  1 user  staff    13 27 ene 11:10 tesfile_copy_5.txt
    -rw-r--r--   1 user  staff    13 27 ene 11:10 tesfile_orig.txt
    

    Then I run the organize sim command:

    testdupes % organize sim            
    False
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIMULATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Folder /Users/user/testdupes:
      File tesfile_copy_2.txt:
        - [Echo] /Users/user/testdupes/tesfile_copy_2.txt is a duplicate of /Users/user/testdupes/tesfile_copy_1.txt
      File tesfile_copy_3.txt:
        - [Echo] /Users/user/testdupes/tesfile_copy_3.txt is a duplicate of /Users/user/testdupes/tesfile_copy_2.txt
      File tesfile_copy_4.txt:
        - [Echo] /Users/user/testdupes/tesfile_copy_4.txt is a duplicate of /Users/user/testdupes/tesfile_copy_3.txt
      File tesfile_copy_5.txt:
        - [Echo] /Users/user/testdupes/tesfile_copy_5.txt is a duplicate of /Users/user/testdupes/tesfile_copy_4.txt
      File tesfile_orig.txt:
        - [Echo] /Users/cesargarciasaez/testdupes/tesfile_orig.txt is a duplicate of /Users/cesargarciasaez/testdupes/tesfile_copy_5.txt
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIMULATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    Issues detected

    • Organize only looks for the first duplicate. If you have several duplicates of each other, they won't be detected as dupes of the original.
    • The order of the sort appear to be on last modified, not on creation date. This can create issues if you ask Organize to delete the duplicates. Instead of ending up with the original file, that file could be deleted and you could end up with one of the copies (but it is not easy to determine the ending name/number).
    • In this particular example, if I deleted instead of echoing the name, I would have keep just: tesfile_copy_1.txt
    • Note: I assume you will always retain one of the copies, but I am not sure this could not lead to a circular deletion of all duplicates, including the original file too.

    Additional tests

    To verify that last modified date is the default sort order, I rename all files but the original one.

    testdupes % mv tesfile_copy_1.txt 'testfile_orig 1.txt'
    testdupes % mv tesfile_copy_2.txt 'testfile_orig 2.txt'
    testdupes % mv tesfile_copy_3.txt 'testfile_orig 3.txt'
    testdupes % mv tesfile_copy_4.txt 'testfile_orig 4.txt'
    testdupes % mv tesfile_copy_5.txt 'testfile_orig 5.txt'
    

    Then running organize sim again, would leave testfile_orig.txt untouched.

    testdupes % organize sim                               
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIMULATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Folder /Users/user/testdupes:
      File testfile_orig 1.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 1.txt is a duplicate of /Users/user/testdupes/tesfile_orig.txt
      File testfile_orig 2.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 2.txt is a duplicate of /Users/user/testdupes/testfile_orig 1.txt
      File testfile_orig 3.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 3.txt is a duplicate of /Users/user/testdupes/testfile_orig 2.txt
      File testfile_orig 4.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 4.txt is a duplicate of /Users/user/testdupes/testfile_orig 3.txt
      File testfile_orig 5.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 5.txt is a duplicate of /Users/user/testdupes/testfile_orig 4.txt
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIMULATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    This test might suggest that last modified file is not tested for duplication. Is this expected behavior?

    Additional run, renaming the original file. This would leave us again with testfile_orig 1.txt as the only remaining copy.

    testdupes% mv tesfile_orig.txt testfile_true_orig.txt
    testdupes % organize sim                              
    False
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIMULATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Folder /Users/user/testdupes:
      File testfile_orig 2.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 2.txt is a duplicate of /Users/user/testdupes/testfile_orig 1.txt
      File testfile_orig 3.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 3.txt is a duplicate of /Users/user/testdupes/testfile_orig 2.txt
      File testfile_orig 4.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 4.txt is a duplicate of /Users/user/testdupes/testfile_orig 3.txt
      File testfile_orig 5.txt:
        - [Echo] /Users/user/testdupes/testfile_orig 5.txt is a duplicate of /Users/user/testdupes/testfile_orig 4.txt
      File testfile_true_orig.txt:
        - [Echo] /Users/user/testdupes/testfile_true_orig.txt is a duplicate of /Users/user/testdupes/testfile_orig 5.txt
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIMULATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    Final notes

    I am aware that I can use the regex filter (and maybe even the filename filter) to deal with duplicates with similar names, but I am not quite sure that the duplicate filter won't cause any data loss without any extra attention in folders with several copies of the same file.

    opened by elsatch 9
  • "macostags" causes error on M1 Mac

    The "macostags" causes the following error on M1 Mac

    Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/cli.py", line 77, in main execute_rules(config.rules, simulate=args["sim"]) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/config.py", line 161, in rules rule_actions = list(self.instantiate_actions(rule_item)) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/config.py", line 139, in instantiate_actions action_class = self._get_action_class_by_name(name) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/config.py", line 87, in _get_action_class_by_name return self.action_by_name[self.sanitize_key(name)] KeyError: 'macostags' 2021-04-27 20:18:11,822 - organize - ERROR - 'macostags' Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/cli.py", line 77, in main execute_rules(config.rules, simulate=args["sim"]) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/config.py", line 161, in rules rule_actions = list(self.instantiate_actions(rule_item)) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/config.py", line 139, in instantiate_actions action_class = self._get_action_class_by_name(name) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/organize/config.py", line 87, in _get_action_class_by_name return self.action_by_name[self.sanitize_key(name)] KeyError: 'macostags'

    opened by Marty56 9
  • Add option to preserve mtime on move action

    Add option to preserve mtime on move action

    Is your feature request related to a problem? Please describe. When I move files, I want the file creation and modified time to be preserved. Currently there is no option to do that.

    Describe the solution you'd like I want to be able to specify that a move action should preserve the modified time on files

    Describe alternatives you've considered There are none

    Additional context The code is already in place to preserve the mtime on file move, but it is off by default and there is no way to enable it via config.yaml. (See organize/actions/move.py)

    # this is taken from my PR
    def move_file_optimized(
        src_fs,
        src_path,
        dst_fs,
        dst_path,
        preserve_time=False,
        cleanup_dst_on_error=True,
    ):
        # type: (...) -> None
        """Move a file from one filesystem to another.
        Arguments:
            src_fs (FS or str): Source filesystem (instance or URL).
            src_path (str): Path to a file on ``src_fs``.
            dst_fs (FS or str): Destination filesystem (instance or URL).
            dst_path (str): Path to a file on ``dst_fs``.
            preserve_time (bool): If `True`, try to preserve mtime of the
                resources (defaults to `False`).
            cleanup_dst_on_error (bool): If `True`, tries to delete the file copied to
                ``dst_fs`` if deleting the file from ``src_fs`` fails (defaults to `True`).
    
    feature request 
    opened by FlorianMittag 0
  • Error with rename

    Error with rename

    Describe the bug Trying to run the script in sim mode.

    PS C:\Users\Paul\Downloads> organize sim
    organize 2.4.0
    Config: "C:\Users\Paul\AppData\Local\organize\config.yaml"
    Working dir: ""
    ╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\organize\core.py:181 in  │
    │ replace_with_instances                                                                           │
    │                                                                                                  │
    │   178 │   │   _actions = []                                                                      │
    │   179 │   │   for x in ensure_list(rule["actions"]):                                             │
    │   180 │   │   │   try:                                                                           │
    │ ❱ 181 │   │   │   │   _actions.append(instantiate_action(x))                                     │
    │   182 │   │   │   except Exception as e:                                                         │
    │   183 │   │   │   │   raise ValueError("Invalid action %s (%s)" % (x, e)) from e                 │
    │   184                                                                                            │
    │                                                                                                  │
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\organize\core.py:138 in  │
    │ instantiate_action                                                                               │
    │                                                                                                  │
    │   135 │   spec = ensure_dict(action_config)                                                      │
    │   136 │   name, value = next(iter(spec.items()))                                                 │
    │   137 │   args, kwargs = to_args(value)                                                          │
    │ ❱ 138 │   return ACTIONS[name](*args, **kwargs)                                                  │
    │   139                                                                                            │
    │   140                                                                                            │
    │   141 def syspath_or_exception(fs, path):                                                        │
    │                                                                                                  │
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\organize\actions\rename. │
    │ py:59 in __init__                                                                                │
    │                                                                                                  │
    │    56 │   │   │   │   "on_conflict must be one of %s" % ", ".join(CONFLICT_OPTIONS)              │
    │    57 │   │   │   )                                                                              │
    │    58 │   │                                                                                      │
    │ ❱  59 │   │   self.new_name = Template.from_string(name)                                         │
    │    60 │   │   self.conflict_mode = on_conflict                                                   │
    │    61 │   │   self.rename_template = Template.from_string(rename_template)                       │
    │    62                                                                                            │
    │                                                                                                  │
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\jinja2\environment.py:10 │
    │ 92 in from_string                                                                                │
    │                                                                                                  │
    │   1089 │   │   """                                                                               │
    │   1090 │   │   gs = self.make_globals(globals)                                                   │
    │   1091 │   │   cls = template_class or self.template_class                                       │
    │ ❱ 1092 │   │   return cls.from_code(self, self.compile(source), gs, None)                        │
    │   1093 │                                                                                         │
    │   1094 │   def make_globals(                                                                     │
    │   1095 │   │   self, d: t.Optional[t.Mapping[str, t.Any]]                                        │
    │                                                                                                  │
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\jinja2\environment.py:75 │
    │ 7 in compile                                                                                     │
    │                                                                                                  │
    │    754 │   │   │   │   filename = "<template>"                                                   │
    │    755 │   │   │   return self._compile(source, filename)                                        │
    │    756 │   │   except TemplateSyntaxError:                                                       │
    │ ❱  757 │   │   │   self.handle_exception(source=source_hint)                                     │
    │    758 │                                                                                         │
    │    759 │   def compile_expression(                                                               │
    │    760 │   │   self, source: str, undefined_to_none: bool = True                                 │
    │                                                                                                  │
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\jinja2\environment.py:92 │
    │ 5 in handle_exception                                                                            │
    │                                                                                                  │
    │    922 │   │   """                                                                               │
    │    923 │   │   from .debug import rewrite_traceback_stack                                        │
    │    924 │   │                                                                                     │
    │ ❱  925 │   │   raise rewrite_traceback_stack(source=source)                                      │
    │    926 │                                                                                         │
    │    927 │   def join_path(self, template: str, parent: str) -> str:                               │
    │    928 │   │   """Join a template with the parent.  By default all the lookups are               │
    │ <unknown>:1 in template                                                                          │
    ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
    TemplateSyntaxError: expected token 'end of print statement', got ':'
    
    The above exception was the direct cause of the following exception:
    
    ╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\organize\cli.py:151 in   │
    │ execute                                                                                          │
    │                                                                                                  │
    │   148 │                                                                                          │
    │   149 │   try:                                                                                   │
    │   150 │   │   console.info(config=config_path, working_dir=working_dir)                          │
    │ ❱ 151 │   │   core.run(                                                                          │
    │   152 │   │   │   rules=config_text,                                                             │
    │   153 │   │   │   simulate=simulate,                                                             │
    │   154 │   │   │   working_dir=working_dir,                                                       │
    │                                                                                                  │
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\organize\core.py:380 in  │
    │ run                                                                                              │
    │                                                                                                  │
    │   377 │   │   config.validate(rules)                                                             │
    │   378 │                                                                                          │
    │   379 │   # instantiate                                                                          │
    │ ❱ 380 │   warnings = replace_with_instances(rules, default_filesystem=working_dir)               │
    │   381 │   for msg in warnings:                                                                   │
    │   382 │   │   console.warn(msg)                                                                  │
    │   383                                                                                            │
    │                                                                                                  │
    │ C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\organize\core.py:183 in  │
    │ replace_with_instances                                                                           │
    │                                                                                                  │
    │   180 │   │   │   try:                                                                           │
    │   181 │   │   │   │   _actions.append(instantiate_action(x))                                     │
    │   182 │   │   │   except Exception as e:                                                         │
    │ ❱ 183 │   │   │   │   raise ValueError("Invalid action %s (%s)" % (x, e)) from e                 │
    │   184 │   │                                                                                      │
    │   185 │   │   rule["locations"] = _locations                                                     │
    │   186 │   │   rule["filters"] = _filters                                                         │
    ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
    ValueError: Invalid action {'rename': '{created.year}-{created.month:02}-{created.day:02}_{name}'} (expected token 'end
    of print statement', got ':')
    PS C:\Users\Paul\Downloads>
    

    Environment (please complete the following information):

    • OS: win11
    • Output of organize --version: organize, version 2.4.0
    # organize configuration file
    # https://organize.readthedocs.io
    
    rules:
      - name: "Delete installers"
        locations:
          - "~/Downloads"
        filters:
          - extension: exe
        actions:
          - trash
    rules:
      - name: "Move and rename images"
        locations:
          - "~/Downloads"
        filters:
          - extension:
            - jpg
            - jpeg
            - png
            - webp
        actions:
          - rename: "{created.year}-{created.month:02}-{created.day:02}_{name}"
          - move: "H:/local/images/"
    
    bug 
    opened by DeutscheGabanna 1
  • Bump types-pyyaml from 6.0.11 to 6.0.12.2

    Bump types-pyyaml from 6.0.11 to 6.0.12.2

    Bumps types-pyyaml from 6.0.11 to 6.0.12.2.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies python 
    opened by dependabot[bot] 0
  • Possibility to use vars instead of absolute paths when using certain location features

    Possibility to use vars instead of absolute paths when using certain location features

    Is your feature request related to a problem? Please describe. It doesn't seem to be possible to use variables along with certain options, like exclude_dirs.

    E.g. this works:

    folderpath: &mypath
      - "/run/media/myuser/samsung/"
    
    excl_dirs: &excldirs
      - "github"
      - "backups"
    
    rules:
      - name: "Finding audio"
        locations: *mypath
        subfolders: true
        filters:
            - extension
                - *aud
        actions:
            - echo: "File: {relative_path}"
    

    This doesn't (it keeps asking for a [str]):

    folderpath: &mypath
      - "/run/media/myuser/samsung/"
    
    excl_dirs: &excldirs
      - "github"
      - "backups"
    
    rules:
      - name: "Finding audio"
        locations:
          - path: *mypath
            exclude_dirs: *excldirs
        subfolders: true
        filters:
            - extension
                - *aud
        actions:
            - echo: "File: {relative_path}"
    

    In order for that to work, you have to provide an absolute path:

    rules:
      - name: "Finding audio"
        locations:
          - path: "/run/media/myuser/samsung/"
            exclude_dirs:
              - "github"
              - "backups"
        subfolders: true
        filters:
            - extension
                - *aud
        actions:
            - echo: "File: {relative_path}"
    

    Describe the solution you'd like Just the possibility to use variables instead of having to use absolute paths 😊

    Describe alternatives you've considered I'm just making do with the available options

    Additional context It could very well be that it is I that's doing something wrong.

    feature request 
    opened by telometto 1
  • Python filter: regex.mon triggers error 'dict' object has no attribute 'mon'

    Python filter: regex.mon triggers error 'dict' object has no attribute 'mon'

    Describe the bug I tried to write a python filter that takes a short month name and returns the corresponding month number. I took the python filter example from the docs that changes the last name into an email, and changed it as needed (see below)

    Issue

    The preceding regex filter creates a mon attribute. Python should be able to fetch that attribute as

    regex.mon
    

    but I get an error instead: (python) ERROR! 'dict' object has no attribute 'mon' When I change the code as follows:

    regex["mon"]
    

    the code works.

    • OS: macOS 12.6
    • Output of organize --version: organize, version 2.2.0
    • Python 3.10.8

    Your config file

      - name: "Monthly Hours"
        tags:
          - finances
        locations:
          - ~/Downloads
        filters:
          - extension: csv
          - regex: 'Monthly_Hours_(?P<year>\d\d\d\d)-(?P<mon>...)'
          - python: |
              print(regex)
              print(regex["year"])
              print(regex.mon)  # <- This syntax errors out
              months = {
                "Jan": "01",
                "Feb": "02",
                "Mar": "03",
                "Apr": "04",
                "May": "05",
                "Jun": "06",
                "Jul": "07",
                "Aug": "08",
                "Sep": "09",
                "Oct": "10",
                "Nov": "11",
                "Dec": "12",
              }
              return {"month": months[regex["mon"]]}
        actions:
          - move: "target_dir/Monthly_Hours_{regex.year}-{python.month}.csv"
    

    Output of organize sim:

      Monthly_Hours_2022-Jan-01-2022-Jan-31.csv
        - (python) {'year': '2022', 'mon': 'Jan'}
        - (python) 2022
        - (python) ERROR! 'dict' object has no attribute 'mon'
    
    bug 
    opened by christophberger 1
  • Bump mkdocs-include-markdown-plugin from 3.6.1 to 3.9.1

    Bump mkdocs-include-markdown-plugin from 3.6.1 to 3.9.1

    Bumps mkdocs-include-markdown-plugin from 3.6.1 to 3.9.1.

    Release notes

    Sourced from mkdocs-include-markdown-plugin's releases.

    v3.9.1

    Bug fixes:

    • Fixed event order on Mkdocs >= 1.4.0

    v3.9.0

    New features:

    • Included files are watched when using mkdocs serve. Only supported from Mkdocs v1.4.0 onwards.

    Deprecated:

    • The support for Python 3.6 has been oficially deprecated and the plugin will not be installable on that version from the next v4.0.0 release.

    v3.8.1

    Bug fixes:

    • Fixed two errors relative to includer indentation for both directives.

    v3.8.0

    New features:

    v3.7.1

    Bug fixes:

    • HTML-escape file paths in comments generated by include-markdown directive to prevent broken content when including some edge cases.

    v3.7.0

    New features:

    • Added new argument encoding for both directives.
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies python 
    opened by dependabot[bot] 0
Releases(v2.4.0)
This program can help you to move and rename many files at once

This program can help you to rename and save many files in a folder in seconds, but don't give the same name to files, it can delete both files.

João Assalim 1 Oct 10, 2022
Search for files under the specified directory. Extract the file name and file path and import them as data.

Search for files under the specified directory. Extract the file name and file path and import them as data. Based on that, search for the file, select it and open it.

G-jon FujiYama 2 Jan 10, 2022
Python library for reading and writing tabular data via streams.

tabulator-py A library for reading and writing tabular data (csv/xls/json/etc). [Important Notice] We have released Frictionless Framework. This frame

Frictionless Data 231 Dec 09, 2022
An easy-to-use library for emulating code in minidump files.

dumpulator Note: This is a work-in-progress prototype, please treat it as such. An easy-to-use library for emulating code in minidump files. Example T

Duncan Ogilvie 362 Dec 31, 2022
A tool for batch processing large fasta files and accompanying metadata table to upload to repositories via API

Fasta Uploader A tool for batch processing large fasta files and accompanying metadata table to repositories via API The python fasta_uploader.py scri

Centre for Infectious Disease and One Health 1 Dec 09, 2021
This project is a set of programs that I use to create a README.md file.

🤖 codex-readme 📜 codex-readme What is it? This project is a set of programs that I use to create a README.md file. How does it work? It reads progra

Tom Dörr 224 Jan 07, 2023
LightCSV - This CSV reader is implemented in just pure Python.

LightCSV Simple light CSV reader This CSV reader is implemented in just pure Python. It allows to specify a separator, a quote char and column titles

Jose Rodriguez 6 Mar 05, 2022
Lumar - Smart File Creator

Lumar is a free tool for creating and managing files. With Lumar you can quickly create any type of file, add a file content and file size. With Lumar you can also find out if Photoshop or other imag

Paul - FloatDesign 3 Dec 10, 2021
Singer is an open source standard for moving data between databases, web APIs, files, queues, and just about anything else you can think of.

Singer is an open source standard for moving data between databases, web APIs, files, queues, and just about anything else you can think of. Th

Singer 1.1k Jan 05, 2023
csv2ir is a script to convert ir .csv files to .ir files for the flipper.

csv2ir csv2ir is a script to convert ir .csv files to .ir files for the flipper. For a repo of .ir files, please see https://github.com/logickworkshop

Alex 38 Dec 31, 2022
dotsend is a web application which helps you to upload your large files and share file via link

dotsend is a web application which helps you to upload your large files and share file via link

Devocoe 0 Dec 03, 2022
Pti-file-format - Reverse engineering the Polyend Tracker instrument file format

pti-file-format Reverse engineering the Polyend Tracker instrument file format.

Jaap Roes 14 Dec 30, 2022
Object-oriented file system path manipulation

path (aka path pie, formerly path.py) implements path objects as first-class entities, allowing common operations on files to be invoked on those path

Jason R. Coombs 1k Dec 28, 2022
Python library and shell utilities to monitor filesystem events.

Watchdog Python API and shell utilities to monitor file system events. Works on 3.6+. If you want to use Python 2.6, you should stick with watchdog

Yesudeep Mangalapilly 5.6k Jan 04, 2023
A tiny Configuration File Parser for Python Projects

A tiny Configuration File Parser for Python Projects. Currently working on JSON Config Files only.

Tanmoy Sen Gupta 1 Feb 12, 2022
The best way to convert files on your computer, be it .pdf to .png, .pdf to .docx, .png to .ico, or anything you can imagine.

The best way to convert files on your computer, be it .pdf to .png, .pdf to .docx, .png to .ico, or anything you can imagine.

JareBear 2 Nov 20, 2021
Simple Python File Manager

This script lets you automatically relocate files based on their extensions. Very useful from the downloads folder !

Aimé Risson 22 Dec 27, 2022
A simple bulk file renamer, written in python.

Python File Editor A simple bulk file renamer, written in python. There are two functions, the bulk rename and the bulk file extention change. Bulk Fi

Sam Bloomfield 2 Dec 22, 2021
Simple, convenient and cross-platform file date changing library. 📝📅

Simple, convenient and cross-platform file date changing library.

kubinka0505 15 Dec 18, 2022
BOOTH宛先印刷用CSVから色々な便利なリストを作成してCSVで出力するプログラムです。

BOOTH注文リスト作成スクリプト このPythonスクリプトは、BOOTHの「宛名印刷用CSV」から、 未発送の注文 今月の注文 特定期間の注文 を抽出した上で、各注文を商品毎に一覧化したCSVとして出力するスクリプトです。 簡単な使い方 ダウンロード 通常は、Relaseから、booth_ord

hinananoha 1 Nov 28, 2021