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)
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
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
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
Various converters to convert value sets from CSV to JSON, etc.

ValueSet Converters Tools for converting value sets in different formats. Such as converting extensional value sets in CSV format to JSON format able

Health Open Terminology Ecosystem 4 Sep 08, 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
Convert CSV files into a SQLite database

csvs-to-sqlite Convert CSV files into a SQLite database. Browse and publish that SQLite database with Datasette. Basic usage: csvs-to-sqlite myfile.cs

Simon Willison 731 Dec 27, 2022
A Python script to backup your favorite Discord gifs

About the project Discord recently felt like it would be a good idea to limit the favorites to 250, which made me lose most of my gifs... Luckily for

4 Aug 03, 2022
OnedataFS is a PyFilesystem interface to Onedata virtual file system

OnedataFS OnedataFS is a PyFilesystem interface to Onedata virtual file system. As a PyFilesystem concrete class, OnedataFS allows you to work with On

onedata 0 Jan 10, 2022
A simple file sharing tool written in python

Share it A simple file sharing tool written in python Installation If you are using Windows os you can directly Run .exe file -- download If you are

Sachit Yadav 7 Dec 16, 2022
Import Python modules from any file system path

pathimp Import Python modules from any file system path. Installation pip3 install pathimp Usage import pathimp

Danijar Hafner 2 Nov 29, 2021
A Certificate renaming tool made for IEEE CS SBC, SJCE.

PDF Batch Renamer Made for IEEE CS SBC, SJCE How to use? Before using the python script, ensure that pytesseract, pdf2image, opencv and other supporti

Ashwin Kumar U 2 Nov 14, 2021
pydicom - Read, modify and write DICOM files with python code

pydicom is a pure Python package for working with DICOM files. It lets you read, modify and write DICOM data in an easy "pythonic" way.

DICOM in Python 1.5k Jan 04, 2023
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
Here is some Python code that allows you to read in SVG files and approximate their paths using a Fourier series.

Here is some Python code that allows you to read in SVG files and approximate their paths using a Fourier series. The Fourier series can be animated and visualized, the function can be output as a tw

Alexander 12 Jan 01, 2023
CleverCSV is a Python package for handling messy CSV files.

CleverCSV is a Python package for handling messy CSV files. It provides a drop-in replacement for the builtin CSV module with improved dialect detection, and comes with a handy command line applicati

The Alan Turing Institute 1k Dec 19, 2022
Uncompress DEFLATE streams in pure Python

stream-inflate Uncompress DEFLATE streams in pure Python. Installation pip install stream-inflate Usage from stream_inflate import stream_inflate impo

Michal Charemza 7 Oct 13, 2022
Some-tasks - Files for some of the tasks for the group sessions

Files for some of the tasks for the group sessions Here you can find some of the

<a href=[email protected] Computer Networks"> 0 Aug 25, 2022
Python package to read and display segregated file names present in a directory based on type of the file

tpyfilestructure Python package to read and display segregated file names present in a directory based on type of the file. Installation You can insta

Tharun Kumar T 2 Nov 28, 2021
Listreqs is a simple requirements.txt generator. It's an alternative to pipreqs

⚡ Listreqs Listreqs is a simple requirements.txt generator. It's an alternative to pipreqs. Where in Pipreqs, it helps you to Generate requirements.tx

Soumyadip Sarkar 4 Oct 15, 2021
Measure file similarity in a many-to-many fashion

Mesi Mesi is a tool to measure the similarity in a many-to-many fashion of long-form documents like Python source code or technical writing. The outpu

GatorEducator 3 Feb 02, 2022