Skip to content

Commit 81aa081

Browse files
Enhance documentation and improve file organization functionality
- Updated index.rst to include a table of contents and improved badge information. - Refined about.py with additional metadata and keywords. - Modified cli.py to use the new organize_files_in_directory function. - Expanded main.py to include a more detailed folder structure for organizing files. - Added changelog.rst to document version history. - Created contributing.rst to outline contribution guidelines. - Established installation.rst for installation instructions. - Developed usage.rst to provide usage examples and options for the CLI tool.
1 parent f515bad commit 81aa081

9 files changed

Lines changed: 228 additions & 98 deletions

File tree

docs/changelog.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Changelog
2+
=========
3+
4+
v1.0.7 (2025-05-22)
5+
-------------------
6+
7+
- First `Production` release
8+
- Organize files via `movens -p <path>`
9+
- Version flag `-v` added

docs/contributing.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Contributing
2+
============
3+
4+
We welcome contributions from the community!
5+
6+
Steps:
7+
8+
1. Fork the repository
9+
2. Create a new branch: `git checkout -b feature-name`
10+
3. Commit your changes with clear messages
11+
4. Submit a pull request
12+
13+
Before submitting, ensure:
14+
15+
- Code is formatted (use `black` or `ruff` if used)
16+
- Functionality is tested
17+
18+
To install dev dependencies:
19+
20+
.. code-block:: bash
21+
22+
pip install -r requirements.txt

docs/index.rst

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1-
21
.. rst-class:: hide-header
32

43
Welcome to Movens documentation!
5-
=====================================
4+
=================================
5+
6+
.. image:: http://pepy.tech/badge/filemover
7+
:alt: Download badge
8+
:target: https://pepy.tech/project/filemover
9+
10+
Movens is a smart CLI tool that helps you organize files in a given directory.
11+
12+
.. toctree::
13+
:maxdepth: 2
14+
:caption: Contents:
615

7-
![Download badge](http://pepy.tech/badge/filemover)
16+
installation
17+
usage
18+
contributing
19+
changelog

docs/installation.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Installation
2+
============
3+
4+
Install Movens from PyPI:
5+
6+
.. code-block:: bash
7+
8+
pip install movens
9+
10+
Once installed, you can use the `movens` command directly in your terminal.
11+
12+
To check the version:
13+
14+
.. code-block:: bash
15+
16+
movens --version

docs/usage.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Usage Guide
2+
===========
3+
4+
The basic usage of **Movens**:
5+
6+
.. code-block:: bash
7+
8+
movens -p /path/to/your/folder
9+
10+
This command will scan the specified directory and organize the files based on predefined rules (e.g., by file type or extension).
11+
12+
Options
13+
-------
14+
15+
- `-p`, `--path`: **(Required)** Path to the directory you want to organize.
16+
- `-v`, `--version`: Print the current version and exit.
17+
18+
Example
19+
-------
20+
21+
.. code-block:: bash
22+
23+
movens --path ~/Downloads

movens/about.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1+
12
__title__ = 'Movens'
23
__package_name__ = 'movens'
34
__version__ = '1.0.7'
45
__description__ = "CLI tool to arrange files smartly"
56
__email__ = "deepak008@live.com"
6-
__author__ = 'PyContributors'
7-
__github__ = 'https://github.com/Py-Contributors/movens'
7+
__author__ = 'codeperfectplus'
8+
__github__ = 'https://github.com/codeperfectplus/movens'
89
__pypi__ = 'https://pypi.org/project/movens'
910
__license__ = 'MIT License'
11+
__keywords__ = 'movens, file organizer, file manager, file sorting, file arrangement, file categorization, file classification, file organization tool, command line tool, CLI tool'
12+
__development_status__ = '5 - Production/Stable'
13+
__programming_language__ = 'Python :: 3'
14+
__license__ = 'OSI Approved :: MIT License'
15+
__operating_system__ = 'Operating System :: OS Independent'
16+
__intended_audience__ = 'Intended Audience :: End Users/Desktop'
17+
__intended_audience_developers__ = 'Intended Audience :: Developers'
18+
__python_requires__ = '>=3.1'

movens/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
22
sys.path.append('.')
3-
from movens.main import start
3+
from movens.main import organize_files_in_directory
44
from movens.about import __version__
55

66
import argparse
@@ -13,7 +13,7 @@
1313

1414

1515
def main():
16-
start(args.path)
16+
organize_files_in_directory(args.path)
1717

1818

1919
if __name__ == "__main__":

movens/main.py

Lines changed: 103 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,115 @@
1-
from shutil import move
21
import os
2+
from pathlib import Path
3+
from shutil import move
34

4-
folder_ex = {
5-
'Programming Files': set(['ipynb', 'py', 'java', 'cs', 'js', 'vsix', 'jar', 'cc', 'ccc', 'html', 'xml', 'kt', 'c', 'css']),
6-
'Compressed': set(['zip', 'rar', 'arj', 'gz', 'sit', 'sitx', 'sea', 'ace', 'bz2', '7z']),
7-
'Applications': set(['exe', 'msi', 'deb', 'rpm']),
8-
'Pictures': set(['jpeg', 'jpg', 'png', 'gif', 'tiff', 'raw', 'webp', 'jfif', 'ico', 'psd', 'svg', 'ai']),
9-
'Videos': set(['mp4', 'webm', 'mkv', 'MPG', 'MP2', 'MPEG', 'MPE', 'MPV', 'OGG', 'M4P', 'M4V', 'WMV', 'MOV', 'QT', 'FLV', 'SWF', 'AVCHD', 'avi', 'mpg', 'mpe', 'mpeg', 'asf', 'wmv', 'mov', 'qt', 'rm']),
10-
'Documents': set(['txt', 'pdf', 'doc', 'xlsx', 'pdf', 'ppt', 'pps', 'docx', 'pptx']),
11-
'Music': set(['mp3', 'wav', 'wma', 'mpa', 'ram', 'ra', 'aac', 'aif', 'm4a', 'tsa']),
12-
'Torrents': set(['torrent']),
13-
'Other': set([])
5+
# Define categories with subfolders and file extensions
6+
FOLDER_STRUCTURE = {
7+
# Programming
8+
'Programming/Python': {'py', 'ipynb', 'pyd', 'pyc'},
9+
'Programming/JavaScript': {'js', 'ts', 'tsx'},
10+
'Programming/Java': {'java', 'jar'},
11+
'Programming/C_CPP': {'c', 'cpp', 'cc', 'h', 'hpp'},
12+
'Programming/CSharp': {'cs'},
13+
'Programming/Web': {'html', 'css', 'xml', 'php'},
14+
'Programming/Kotlin': {'kt'},
15+
'Programming/VS Extensions': {'vsix'},
16+
'Programming/Others': {'r', 'go', 'rs', 'dart', 'swift', 'lua', 'sh', 'bat'},
17+
18+
# Compressed files
19+
'Compressed': {'zip', 'rar', 'arj', 'gz', 'bz2', '7z', 'xz', 'tar', 'iso'},
20+
21+
# Applications / Executables
22+
'Applications/Windows': {'exe', 'msi'},
23+
'Applications/Linux': {'deb', 'rpm', 'AppImage'},
24+
'Applications/Android': {'apk'},
25+
26+
# Images
27+
'Pictures/RAW': {'raw', 'arw', 'cr2', 'nef', 'orf', 'rw2', 'dng', 'raf', 'pef', 'srw', 'x3f', 'cr3'},
28+
'Pictures/Photos': {'jpeg', 'jpg', 'png', 'gif', 'tiff', 'webp', 'bmp', 'ico', 'heic', 'jfif'},
29+
'Pictures/3D': {'3ds', 'blend', 'fbx', 'obj', 'stl', 'dae', 'ply'},
30+
'Pictures/Vector': {'svg', 'ai'},
31+
32+
# Videos
33+
'Videos/Standard': {'mp4', 'webm', 'mkv', 'mov', 'avi', 'flv', 'wmv'},
34+
'Videos/Legacy': {'qt', 'rm', 'vob', 'mpg', 'mpeg', 'm4v', '3gp', 'mts'},
35+
'Videos/Streaming': {'ts'},
36+
37+
38+
# Audio / Music
39+
'Music': {'mp3', 'aac', 'wma', 'm4a', 'flac', 'ogg', 'opus', 'wav', 'aiff', 'ape', 'mid', 'midi', 'ra'},
40+
41+
# Torrents
42+
'Torrents': {'torrent'},
43+
44+
# Documents
45+
'Documents/PDF': {'pdf'},
46+
'Documents/Word': {'doc', 'docx'},
47+
'Documents/Excel': {'xls', 'xlsx', 'csv'},
48+
'Documents/PowerPoint': {'ppt', 'pptx', 'pps'},
49+
'Documents/Text': {'txt', 'md', 'rtf', 'log'},
50+
'Documents/Notebooks': {'ipynb'},
51+
'Documents/LaTeX': {'tex', 'bib'},
52+
'Documents/Code Snippets': {'json', 'yaml', 'yml', 'toml', 'ini'},
53+
'Documents/Others': {'odt', 'odp', 'ods', 'epub'},
54+
55+
# Fallback
56+
'Other': set()
1457
}
1558

1659

17-
def create_folder(folder_name: str):
18-
'''
19-
Creates the folder
20-
21-
Args:
22-
folder_name (str): folder to be created
23-
'''
60+
def create_folder(path: Path) -> None:
61+
"""Create a folder if it doesn't exist."""
2462
try:
25-
os.mkdir(folder_name)
26-
print('{} Created ✔'.format(folder_name))
27-
except OSError:
28-
print('{} Already Exists'.format(folder_name))
29-
30-
31-
def move_files(folder_path:str, file_folder_map: dict):
32-
'''
33-
Move files to respective folder
34-
35-
Args:
36-
ext_file_map (dict) : File to Folder map
37-
'''
38-
for folder, files in file_folder_map.items():
39-
os.makedirs(os.path.join(folder_path, folder), exist_ok=True)
40-
for file in files:
41-
old_file_path = os.path.join(folder_path, file)
42-
new_file_path = os.path.join(folder_path, folder)
43-
move(old_file_path, new_file_path)
44-
63+
path.mkdir(parents=True, exist_ok=True)
64+
print(f"[✔] Folder ready: {path}")
65+
except Exception as e:
66+
print(f"[✖] Failed to create {path}: {e}")
4567

46-
def get_folder(ext):
47-
'''
48-
Returns the Folder that corresponds to the given extension.
4968

50-
Args:
51-
ext (String): The extension of the file.
52-
53-
Returns:
54-
String: The name of the Folder that holds the ext.
55-
'''
56-
for f, ex in folder_ex.items():
57-
if ext in ex:
58-
return f
69+
def classify_extension(extension: str) -> str:
70+
"""Return the folder path based on file extension."""
71+
for folder, extensions in FOLDER_STRUCTURE.items():
72+
if extension.lower() in extensions:
73+
return folder
5974
return 'Other'
6075

6176

62-
# TODO need to change function name
63-
def start(folder_path: str):
64-
'''
65-
Organize files on the current directory, each to the corresponding folder.
77+
def organize_files_in_directory(folder_path: str) -> None:
78+
"""
79+
Organize files in the given folder into subfolders based on their extensions.
6680
67-
folder_path: The path of the folder to be organized.
68-
'''
69-
70-
file_folder_map = dict()
71-
for filename in os.listdir(folder_path):
72-
# ignore filemover.py, hidden files or a directory
73-
if filename == os.path.basename(__file__) or filename[0] == '.' or '.' not in filename:
74-
continue
75-
76-
file_extension = os.path.basename(filename).split('.')[-1]
77-
folder = get_folder(file_extension)
78-
79-
# ignore files present in the folders
80-
if os.path.isfile(os.path.join(folder, filename)):
81-
continue
82-
83-
# insert file to file_folder_map
84-
if folder not in file_folder_map:
85-
file_folder_map[folder] = []
86-
file_folder_map[folder].append(filename)
87-
88-
# create required folders
89-
for folder in file_folder_map.keys():
90-
create_folder(folder)
91-
92-
# move files to folder
93-
move_files(folder_path, file_folder_map)
94-
81+
Args:
82+
folder_path (str): Path of the folder to organize.
83+
"""
84+
folder = Path(folder_path)
85+
if not folder.exists():
86+
print(f"[!] Provided path does not exist: {folder_path}")
87+
return
88+
89+
files_to_move = {}
90+
91+
for item in folder.iterdir():
92+
if item.is_file() and not item.name.startswith('.') and '.' in item.name:
93+
if item.name == Path(__file__).name:
94+
continue # Avoid moving the script itself
95+
extension = item.suffix[1:] # Remove the dot
96+
destination_folder = classify_extension(extension)
97+
files_to_move.setdefault(destination_folder, []).append(item)
98+
99+
for category in files_to_move:
100+
full_folder_path = folder / category
101+
create_folder(full_folder_path)
102+
for file in files_to_move[category]:
103+
try:
104+
move(str(file), str(full_folder_path / file.name))
105+
print(f" ↳ Moved: {file.name}{full_folder_path}")
106+
except Exception as e:
107+
print(f"[✖] Could not move {file.name}: {e}")
108+
109+
110+
if __name__ == '__main__':
111+
import sys
112+
if len(sys.argv) > 1:
113+
organize_files_in_directory(sys.argv[1])
114+
else:
115+
organize_files_in_directory(os.getcwd())

setup.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
11
import setuptools
2-
from movens.about import *
2+
from movens.about import (
3+
__package_name__,
4+
__version__,
5+
__description__,
6+
__email__,
7+
__author__,
8+
__github__,
9+
__pypi__,
10+
__license__,
11+
__keywords__,
12+
__development_status__,
13+
__programming_language__,
14+
__license__,
15+
__operating_system__,
16+
__intended_audience__,
17+
__intended_audience_developers__,
18+
__python_requires__,
19+
)
320

421
with open("README.md", "r") as fh:
522
long_description = fh.read()
623

24+
725
setuptools.setup(
826
name=__package_name__,
927
version=__version__,
@@ -13,17 +31,17 @@
1331
long_description=long_description,
1432
long_description_content_type="text/markdown",
1533
url=__github__,
16-
keywords="filemover, movefiles, organizefiles, organizefiles, filemovergui, filemover-gui",
34+
keywords=__keywords__,
1735
packages=setuptools.find_packages(),
1836
classifiers=[
19-
"Development Status :: 3 - Alpha",
20-
"Programming Language :: Python :: 3",
21-
"License :: OSI Approved :: MIT License",
22-
"Operating System :: OS Independent",
23-
"Intended Audience :: End Users/Desktop",
24-
"Intended Audience :: Developers",
37+
f"Development Status :: {__development_status__}",
38+
f"Programming Language :: {__programming_language__}",
39+
f"License :: {__license__}",
40+
f"Operating System :: {__operating_system__}",
41+
f"Intended Audience :: {__intended_audience__}",
42+
f"Intended Audience :: {__intended_audience_developers__}",
2543
],
26-
python_requires=">=3.1",
44+
python_requires=__python_requires__,
2745
entry_points={
2846
"console_scripts": ["movens = movens.cli:main"],
2947
},

0 commit comments

Comments
 (0)