Skip to content

Commit c0284b2

Browse files
authored
Merge pull request #3 from Supporterino/refactor/exception-handling
refactor: ♻️ Better exception handling and code readability
2 parents 349a56f + 5536906 commit c0284b2

File tree

6 files changed

+268
-134
lines changed

6 files changed

+268
-134
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.1] - 2024-06-25
9+
10+
### Changed
11+
12+
- Refactored the `main` function to improve code modularity and readability by extracting logical components into separate functions.
13+
14+
### Added
15+
16+
- Unit tests for core functions using `pytest`.
17+
18+
### Fixed
19+
20+
- Improved logging messages for better debugging and clarity during file operations.
21+
822
## [1.1.0] - 2024-06-25
923

1024
### Added

photo_organizer/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# Nothing to do atm
1+
# Nothing to do atm

photo_organizer/main.py

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import shutil
66
import datetime
77
import logging
8+
import filecmp
89

910

1011
def list_files(source, recursive=False, file_endings=None):
@@ -79,8 +80,26 @@ def ensure_directory_exists(folder_path):
7980
logging.debug(f"Directory already exists: {folder_path}")
8081

8182

82-
def main():
83-
# Set up the argument parser
83+
def configure_logging(verbose):
84+
"""
85+
Configure logging settings.
86+
87+
Parameters:
88+
verbose (bool): If True, enable verbose logging.
89+
"""
90+
logging.basicConfig(
91+
level=logging.DEBUG if verbose else logging.INFO,
92+
format="%(asctime)s - %(levelname)s - %(message)s",
93+
)
94+
95+
96+
def parse_arguments():
97+
"""
98+
Parse command line arguments.
99+
100+
Returns:
101+
Namespace: Parsed command line arguments.
102+
"""
84103
parser = argparse.ArgumentParser(
85104
description="Sort photos from source to target directory."
86105
)
@@ -115,29 +134,17 @@ def main():
115134
help="Do not place month folders inside a year folder",
116135
)
117136

118-
# Parse the arguments
119-
args = parser.parse_args()
137+
return parser.parse_args()
120138

121-
# Configure logging
122-
logging.basicConfig(
123-
level=logging.DEBUG if args.verbose else logging.INFO,
124-
format="%(asctime)s - %(levelname)s - %(message)s",
125-
)
126-
127-
logging.info("Starting file sorting process")
128139

129-
# Ensure the source directory exists
130-
if not os.path.exists(args.source):
131-
logging.error(f"Source directory '{args.source}' does not exist.")
132-
return
133-
134-
# Ensure the target directory exists
135-
ensure_directory_exists(args.target)
136-
137-
# List all files in the source directory
138-
files = list_files(args.source, args.recursive, args.endings)
140+
def organize_files(args, files):
141+
"""
142+
Organize files by moving or copying them to the target directory.
139143
140-
# Move or copy files to the target directory organized by year/month (and optionally day)
144+
Parameters:
145+
args (Namespace): Parsed command line arguments.
146+
files (list): List of file paths to organize.
147+
"""
141148
for file_path in files:
142149
year, month, day = get_creation_date(file_path)
143150
if args.no_year:
@@ -158,11 +165,51 @@ def main():
158165
ensure_directory_exists(target_folder)
159166
target_path = os.path.join(target_folder, os.path.basename(file_path))
160167

161-
if args.copy:
162-
# Copy the file
163-
shutil.copy2(file_path, target_path)
164-
logging.info(f"Copied '{file_path}' to '{target_path}'")
165-
else:
166-
# Move the file
167-
shutil.move(file_path, target_path)
168-
logging.info(f"Moved '{file_path}' to '{target_path}'")
168+
if os.path.exists(target_path):
169+
if filecmp.cmp(file_path, target_path, shallow=False):
170+
logging.warning(
171+
f"File '{target_path}' already exists and is identical. Skipping."
172+
)
173+
continue
174+
else:
175+
logging.error(
176+
f"File '{target_path}' already exists and is different. Aborting."
177+
)
178+
return
179+
180+
try:
181+
if args.copy:
182+
shutil.copy2(file_path, target_path)
183+
logging.info(f"Copied '{file_path}' to '{target_path}'")
184+
else:
185+
shutil.move(file_path, target_path)
186+
logging.info(f"Moved '{file_path}' to '{target_path}'")
187+
except Exception as e:
188+
logging.error(
189+
f"Failed to {'copy' if args.copy else 'move'} '{file_path}' to '{target_path}': {e}"
190+
)
191+
return
192+
193+
194+
def main():
195+
# Parse the arguments
196+
args = parse_arguments()
197+
198+
# Configure logging
199+
configure_logging(args.verbose)
200+
201+
logging.info("Starting file sorting process")
202+
203+
# Ensure the source directory exists
204+
if not os.path.exists(args.source):
205+
logging.error(f"Source directory '{args.source}' does not exist.")
206+
return
207+
208+
# Ensure the target directory exists
209+
ensure_directory_exists(args.target)
210+
211+
# List all files in the source directory
212+
files = list_files(args.source, args.recursive, args.endings)
213+
214+
# Organize files by moving or copying them to the target directory
215+
organize_files(args, files)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name='photo_organizer',
7-
version='1.1.0',
7+
version='1.1.1',
88
packages=find_packages(),
99
entry_points={
1010
'console_scripts': [

tests/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# Nothing to do atm
1+
# Nothing to do atm

0 commit comments

Comments
 (0)