Skip to content
This repository was archived by the owner on Feb 18, 2025. It is now read-only.

Commit adf830d

Browse files
author
harryjmoss
committed
Adding first working version to repository!
0 parents  commit adf830d

File tree

5 files changed

+170
-0
lines changed

5 files changed

+170
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
minEnv/
2+
nonCompliant*.txt

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Folder and file name checking tool
2+
This windows tool checks file and folder names against the following criteria:
3+
4+
## Folders
5+
Folders names must follow one of the two conventions below:
6+
7+
- Seven-digit ID number [underscore] four-digit date, e.g. `0002268_1865`
8+
- Seven-digit ID number [underscore] four-digit date [underscore] three-digit month [underscore] three-digit month, e.g. `0002268_1865_JAN_JUN`
9+
- Months should always be represented with three letters and matching is not case-sensitive
10+
11+
12+
## Files
13+
File names must be comprised of
14+
- parent folder [underscore] four-digit number beginning `0001`, e.g.
15+
- 0002091_1856_Jan_Jun/
16+
- 0002091_1856_Jan_Jun_0001.tif
17+
- 0002091_1856_Jan_Jun_0002.tif
18+
- 0002091_1856_Jan_Jun_0003.tif
19+
- ...
20+
21+
Matching is by default case-insensitive, but this functionality can be enabled at run-time.
22+
23+
## Running the tool
24+
The tool is supplied as an executable but can be run as a python script. The tool requires as an input a directory of directories, each containing files to be scanned. For instance, if the path
25+
`C:\Users\JoeBloggs\Desktop\Files` is given, all directories within this directory, and their contents, will be scanned. Alternatively, the executable can be placed in the directory and run with an option to use the current directory.
26+
27+
### Running the executable version
28+
- Open the file `nameSchemeCheck.exe`
29+
- Type `Y` and press `Enter` to run in case-sensitive filename checking mode, otherwise press `Enter`
30+
- To scan the current direcory, enter `Y`
31+
- The default behaviour is to scan a pre-configured directory
32+
- Enter `N` to scan a directory of your choice
33+
- Unrecognised inputs set the path to the default `\\P12B-NAS1\scandata2\HMD\RAW SCANS\Dave\FMP\Still to deliver to FMP`
34+
- The tool checks if the directory exists and falls back to the default path if this is not the case
35+
- Folder names and file names are scanned according to the conventions defined above
36+
- Any folder or file names not fulfilling these criteria have their full path written to a file
37+
- nonCompliantFolders.txt
38+
- nonCompliantFiles.txt
39+
- Files appear in the same directory as the executable
40+
41+
### Running the python script
42+
The python script was developed using python 3.7 and requires additional modules to run. To install these with `pip`, call
43+
```
44+
pip install -r requirements.txt
45+
```
46+
It is recommended to perform this step inside a virtual environment.
47+
48+
To run the python script, call:
49+
50+
```
51+
python nameSchemeCheck.py
52+
```
53+
54+
- All steps described for the executable version apply to the python version
55+
- Running the script allows the user to modify the default directory, hard-code case-matching options and provides a greater level of control over the program
56+
- To recompile the script as an executable, call
57+
```
58+
pyinstaller -F nameSchemeCheck.py
59+
```

nameSchemeCheck.exe

10.4 MB
Binary file not shown.

nameSchemeCheck.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import os, re
2+
from tqdm import tqdm
3+
__name__ = "__main__"
4+
5+
def scanFolders(inputDirectory):
6+
foldersFound=[]
7+
for folder in os.listdir(inputDirectory):
8+
if os.path.isdir(os.path.join(inputDirectory,folder)):
9+
foldersFound.append(folder)
10+
11+
# checks if you're pointing it to a folder with subfolders in:
12+
fullPaths=[]
13+
print("Checking for subfolders in top level directory:\n",flush=True)
14+
for folder in tqdm(foldersFound):
15+
fullpath=inputDirectory+'\\'+folder
16+
if os.path.isdir(fullpath):
17+
fullPaths.append(fullpath)
18+
19+
if fullPaths:
20+
# compile regexs outside of loops
21+
folderPatternOne=re.compile("(^\d{7}_\d{4}$)",re.MULTILINE)
22+
folderPatternTwo=re.compile("(^\d{7}_\d{4}_[a-zA-Z]{3}_[a-zA-Z]{3}$)",re.MULTILINE)
23+
24+
print("\nChecking folder name compliance:\n",flush=True)
25+
with open ('nonCompliantFolders.txt','a+') as badFolders:
26+
for folder in tqdm(foldersFound):
27+
matchOne=folderPatternOne.match(folder)
28+
matchTwo=folderPatternTwo.match(folder)
29+
if matchOne is None:
30+
if matchTwo is None:
31+
badFolders.write(folder+'\n')
32+
33+
return fullPaths
34+
else:
35+
print("No subfolders found within this directory!",flush=True)
36+
return 0
37+
38+
def scanFiles(pedantic,fullPaths):
39+
print("\nChecking filename compliance:\n",flush=True)
40+
with open('nonCompliantFiles.txt','a+') as badFileNames:
41+
for directoryPath in tqdm(fullPaths):
42+
filenames=os.listdir(directoryPath)
43+
filePattern=(os.path.basename(directoryPath))+r'(_\d{4}.tif)'
44+
if pedantic is True:
45+
regexPattern=re.compile(filePattern)
46+
else:
47+
regexPattern=re.compile(filePattern,re.IGNORECASE)
48+
for tifFile in filenames:
49+
match=regexPattern.match(tifFile)
50+
if match is None:
51+
outstring=directoryPath+'\\'+tifFile
52+
badFileNames.write(outstring+'\n')
53+
54+
def setup():
55+
pedantic=False
56+
mode=input("Type Y to run in case-sensitive filename checking mode, or enter to continue in case-insensitive mode:\n")
57+
if mode is "Y":
58+
pedantic=True
59+
else:
60+
pedantic=False
61+
if pedantic is True:
62+
print("Running in case-sensitive mode\n")
63+
else:
64+
print("Running in case-insensitive mode\n")
65+
66+
67+
inputDirectory=r"\\P12B-NAS1\scandata2\HMD\RAW SCANS\Dave\FMP\Still to deliver to FMP"
68+
inDir=input("Scan current folder? Y/N:\n")
69+
if (inDir=="Y" or inDir=="y" or inDir=="Yes" or inDir=="yes"):
70+
inputDirectoryUser=os.getcwd()
71+
elif (inDir=="N" or inDir=="n" or inDir=="No" or inDir=="no"):
72+
inputDirectoryUser=input("Enter full path of folder to scan:\n")
73+
if inputDirectoryUser=="":
74+
print("No path entered, using default filepath: {}\n".format(inputDirectory),flush=True)
75+
inputDirectoryUser=inputDirectory
76+
else:
77+
inputDirectoryUser=inputDirectory
78+
print("Input not recognised, using default filepath: {}\n".format(inputDirectory))
79+
print("Checking if directory exists...\n",flush=True)
80+
81+
82+
83+
if os.path.isdir(inputDirectoryUser):
84+
print("Input directory: {}\ exists!\n".format(inputDirectoryUser))
85+
inputDirectory = inputDirectoryUser
86+
else:
87+
print("File path not a valid directory, using default path {}\n".format(inputDirectory))
88+
89+
return pedantic,inputDirectory
90+
91+
def main():
92+
93+
isPedantic,inputDir=setup()
94+
filePaths=scanFolders(inputDir)
95+
scanFiles(isPedantic,filePaths)
96+
97+
98+
input("Complete! Press enter to exit")
99+
100+
101+
if __name__=="__main__":
102+
main()

requirements.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
altgraph==0.16.1
2+
future==0.17.1
3+
pefile==2019.4.18
4+
PyInstaller==3.5
5+
pywin32==224
6+
pywin32-ctypes==0.2.0
7+
tqdm==4.35.0

0 commit comments

Comments
 (0)