18 from typing
import Generator, Optional, Union
19 from pathlib
import Path
20 from zipfile
import ZipFile
33 Exception raised if file extension is unkown or invalid
39 def guessMimeType(filePath: Union[Path, str]) -> str:
41 Tries to guess mime type of the file
45 filePath : Union[Path, str]
46 file whose mime type will be guessed
50 str -> guessed mime type, or "application/octet-stream" if
51 it was not possible to guess
54 mimeTypesResult = mimetypes.guess_type(filePath)
56 mimeType = mimeTypesResult[0]
58 return "application/octet-stream"
63 def isGzip(path: Path) -> bool:
65 Checks if the file is compressed with gz
67 Might not be 100% reliable, it checks the first 2 bytes
68 of the file for the gz-compressed file header (0x1F and 0x8B)
69 and checks for .gz file extension
74 the file to be checked
78 bool -> True if file is gz compressed, False otherwise
87 if not path.is_file():
90 with open(path,
'rb')
as file:
91 return file.read(2) == b
'\x1f\x8b' and path.name.endswith(
".gz")
94 def isArchive(path: Path) -> bool:
96 Checks if the file is an archive
105 bool -> True if it is an archive, False otherwise
108 return zipfile.is_zipfile(path)
or tarfile.is_tarfile(path)
111 def gzipDecompress(source: Path, destination: Path) ->
None:
113 Decompresses a gz-compressed file
118 file to be decompressed
120 location to which the decompressed file will be stored
124 ValueError -> if the file is not a gz-compressed file
127 if not isGzip(source):
128 raise ValueError(
">> [Coretex] Not a .gz file")
130 with gzip.open(source,
"r")
as gzipFile, open(destination,
"wb")
as destinationFile:
131 shutil.copyfileobj(gzipFile, destinationFile)
134 def archive(source: Path, destination: Path) ->
None:
136 Archives and compresses the provided file or directory
142 file to be archived and compressed
144 location to which the zip file will be stored
147 with ZipFile(destination,
"w", zipfile.ZIP_DEFLATED)
as destinationFile:
149 destinationFile.write(source, source.name)
151 for path
in source.rglob(
"*"):
152 if not path.is_file():
155 destinationFile.write(path, path.relative_to(source))
158 def walk(path: Path) -> Generator[Path,
None,
None]:
160 os.walk implementation for pathlib.Path
165 starting point of the walk function, must be a directory
169 Generator[Path, None, None] -> generator which contains all
170 subdirectories and subfiles
173 for p
in path.iterdir():
180 def recursiveUnzip(entryPoint: Path, destination: Optional[Path] =
None, remove: bool =
False) ->
None:
182 Recursively unarchives the file
188 destination : Optional[Path]
189 destination of unarchived files
191 delete archive after unarchive is done
195 ValueError -> if the path is not an archive
198 logging.getLogger(
"coretexpylib").debug(f
">> [Coretex] recursiveUnzip: source = {str(entryPoint)}, destination = {str(destination)}")
200 if destination
is None:
201 destination = entryPoint.parent / entryPoint.stem
204 if isGzip(entryPoint):
205 gzipDecompress(entryPoint, destination)
210 if not isArchive(destination):
215 recursiveUnzip(destination, destination.parent / destination.stem, remove =
True)
218 if not isArchive(entryPoint):
219 raise ValueError(
">> [Coretex] Not an archive")
221 if zipfile.is_zipfile(entryPoint):
222 with ZipFile(entryPoint,
"r")
as zipFile:
223 zipFile.extractall(destination)
225 if tarfile.is_tarfile(entryPoint):
226 with tarfile.open(entryPoint,
"r")
as tarFile:
227 tarFile.extractall(destination)
232 for path
in walk(destination):
233 if isArchive(path)
or isGzip(path):
234 recursiveUnzip(path, remove =
True)