Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added __pycache__/pyorganize.cpython-313.pyc
Binary file not shown.
3 changes: 3 additions & 0 deletions pyorganize.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Metadata-Version: 2.4
Name: pyorganize
Version: 0.1.0
9 changes: 9 additions & 0 deletions pyorganize.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
README.md
setup.py
pyorganize.egg-info/PKG-INFO
pyorganize.egg-info/SOURCES.txt
pyorganize.egg-info/dependency_links.txt
pyorganize.egg-info/entry_points.txt
pyorganize.egg-info/top_level.txt
tests/__init__.py
tests/test_pyorganize.py
1 change: 1 addition & 0 deletions pyorganize.egg-info/dependency_links.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 2 additions & 0 deletions pyorganize.egg-info/entry_points.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[console_scripts]
pyorganize = pyorganize.pyorganize:main
1 change: 1 addition & 0 deletions pyorganize.egg-info/top_level.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests
30 changes: 15 additions & 15 deletions pyorganize.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# [ ] Add support for other file types using a dictionary (Images, Videos, Docs, etc.)✅
# [ ] Implement command-line arguments (target folder, dry-run, etc.)✅
# [ ] Refactor into functions and use OOP for extensibility✅
# [ ] Add unit tests using PyTest
# [ ] Add unit tests using PyTest
# [ ] Add logging and error handling
# [ ] Set up GitHub repo and CI pipeline (GitHub Actions)
# [ ] Publish as a pip-installable CLI tool (local install)
Expand Down Expand Up @@ -94,6 +94,7 @@ def __init__(self, path, dry_run=False, verbose=False):
self.path = path
self.dry_run = dry_run
self.verbose = verbose
self.moved_count = 0 # initialize counter

def organize(self):
try:
Expand All @@ -103,7 +104,6 @@ def organize(self):
print("❌ Folder not found. Check your path.")
return

moved_any = False # Track if any file was moved or would be moved
for item in items:
full_path = os.path.join(self.path, item)

Expand All @@ -116,40 +116,40 @@ def organize(self):
if self.verbose:
print(f"[Verbose] Checking file: {item} (.{ext})")

matched = False
for folder, extensions in FILE_MAP.items():
if ext in extensions:
matched = True
destination_folder = os.path.join(self.path, folder)
os.makedirs(destination_folder, exist_ok=True)
dest_path = os.path.join(destination_folder, item)

base, extn = os.path.splitext(item)
counter = 1

while os.path.exists(dest_path):
# only rename when actually moving
while os.path.exists(dest_path) and not self.dry_run:
new_name = f"{base}_{counter}{extn}"
dest_path = os.path.join(destination_folder, new_name)
counter += 1

if self.dry_run:
# Always show dry-run actions, even if not verbose
print(f"[Dry Run] Would move: {item} → {folder}")
moved_any = True
else:
shutil.move(full_path, dest_path)
# Only show actual moves when verbose
if self.verbose:
print(f"Moved: {item} → {folder}")
moved_any = True

break # Stop after first match
if not matched and self.verbose:
print(f"[Verbose] No category for: {item}")
self.moved_count += 1 # increment counter
break # stop checking other categories

if not moved_any:
print("No files matched any category or needed to be moved.")
else:
# no category matched
if self.verbose:
print(f"[Verbose] No category for: {item}")

# print summary
if self.dry_run:
print(f"[Dry Run Complete] {self.moved_count} files would have been moved.")
else:
print(f"✅ {self.moved_count} files moved.")

# 🚀 Run as script
if __name__ == '__main__':
Expand Down
13 changes: 13 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from setuptools import setup, find_packages

setup(
name="pyorganize",
version="0.1.0",
packages=find_packages(),
install_requires=[],
entry_points={
"console_scripts": [
"pyorganize=pyorganize.pyorganize:main",
],
},
)
Empty file added tests/__init__.py
Empty file.
Binary file added tests/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file not shown.
41 changes: 41 additions & 0 deletions tests/test_pyorganize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import os
import pytest
import pyorganize

@pytest.fixture
def temp_dir(tmp_path):
# Create sample files and a subfolder
for name in ["a.pdf", "b.jpg", "c.txt", "d.exe"]:
(tmp_path / name).write_text("dummy")
(tmp_path / "subfolder").mkdir()
return tmp_path

def test_dry_run_does_not_move_files(temp_dir, capsys):
organizer = pyorganize.FileOrganizer(str(temp_dir), dry_run=True, verbose=False)
organizer.organize()
# Original files still exist
for fname in ["a.pdf", "b.jpg", "c.txt", "d.exe"]:
assert (temp_dir / fname).exists()
# Dry‑run summary printed
captured = capsys.readouterr()
assert "[Dry Run Complete]" in captured.out

def test_move_files(temp_dir):
organizer = pyorganize.FileOrganizer(str(temp_dir), dry_run=False, verbose=False)
organizer.organize()
assert (temp_dir / "PDF Files" / "a.pdf").exists()
assert (temp_dir / "Image Files" / "b.jpg").exists()
assert (temp_dir / "Text Files" / "c.txt").exists()
assert (temp_dir / "Software Files" / "d.exe").exists()

def test_verbose_output(temp_dir, capsys):
organizer = pyorganize.FileOrganizer(str(temp_dir), dry_run=False, verbose=True)
organizer.organize()
captured = capsys.readouterr()
assert "Moved: a.pdf → PDF Files" in captured.out
assert "Moved: b.jpg → Image Files" in captured.out

def test_ignores_directories(temp_dir):
organizer = pyorganize.FileOrganizer(str(temp_dir), dry_run=False, verbose=True)
organizer.organize()
assert (temp_dir / "subfolder").exists()