ccfx 0.5.0__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ccfx/ccfx.py CHANGED
@@ -29,7 +29,10 @@ import subprocess
29
29
  import multiprocessing
30
30
  from mutagen.mp3 import MP3
31
31
  from mutagen.id3 import ID3, TPE1, TALB, TIT2, TRCK, TDRC, TCON, APIC, COMM, USLT, TPE2, TCOM, TPE3, TPE4, TCOP, TENC, TSRC, TBPM
32
-
32
+ from concurrent.futures import ThreadPoolExecutor
33
+ import math
34
+ import requests
35
+ from tqdm import tqdm
33
36
 
34
37
  # functions
35
38
  def listFiles(path: str, ext: str = None) -> list:
@@ -247,6 +250,82 @@ def deletePath(path:str, v:bool = False) -> bool:
247
250
  deleted = False
248
251
 
249
252
 
253
+ def downloadChunk(url, start, end, path):
254
+ headers = {'Range': f'bytes={start}-{end}'}
255
+ response = requests.get(url, headers=headers, stream=True)
256
+ with open(path, 'wb') as f:
257
+ for chunk in response.iter_content(chunk_size=8192):
258
+ if chunk:
259
+ f.write(chunk)
260
+
261
+ def downloadFile(url, save_path, exists_action='resume', num_connections=5, v=True):
262
+ if v:
263
+ print(f"\ndownloading {url}")
264
+ fname = getFileBaseName(url, extension=True)
265
+ save_dir = os.path.dirname(save_path)
266
+ save_fname = "{0}/{1}".format(save_dir, fname)
267
+
268
+ if not os.path.isdir(save_dir):
269
+ os.makedirs(save_dir)
270
+
271
+ # Handle existing file
272
+ if os.path.exists(save_fname):
273
+ if exists_action == 'skip':
274
+ if v:
275
+ print(f"File exists, skipping: {save_fname}")
276
+ return
277
+ elif exists_action == 'overwrite':
278
+ os.remove(save_fname)
279
+ # 'resume' is handled below
280
+
281
+ # Get file size
282
+ response = requests.head(url)
283
+ file_size = int(response.headers.get('content-length', 0))
284
+
285
+ # Resume download if file exists and exists_action is 'resume'
286
+ initial_pos = 0
287
+ if exists_action == 'resume' and os.path.exists(save_fname):
288
+ initial_pos = os.path.getsize(save_fname)
289
+ if initial_pos >= file_size:
290
+ if v:
291
+ print(f"File already completed: {save_fname}")
292
+ return
293
+
294
+ # Calculate chunk sizes
295
+ chunk_size = math.ceil((file_size - initial_pos) / num_connections)
296
+ chunks = []
297
+ for i in range(num_connections):
298
+ start = initial_pos + (i * chunk_size)
299
+ end = min(start + chunk_size - 1, file_size - 1)
300
+ chunks.append((start, end))
301
+
302
+ # Download chunks in parallel
303
+ temp_files = [f"{save_fname}.part{i}" for i in range(num_connections)]
304
+ with ThreadPoolExecutor(max_workers=num_connections) as executor:
305
+ futures = []
306
+ for i, (start, end) in enumerate(chunks):
307
+ futures.append(
308
+ executor.submit(downloadChunk, url, start, end, temp_files[i])
309
+ )
310
+
311
+ # Wait for all downloads to complete with progress bar
312
+ with tqdm(total=file_size-initial_pos, initial=initial_pos, unit='B',
313
+ unit_scale=True, desc=fname) as pbar:
314
+ completed = initial_pos
315
+ while completed < file_size:
316
+ current = sum(os.path.getsize(f) for f in temp_files if os.path.exists(f))
317
+ pbar.update(current - completed)
318
+ completed = current
319
+
320
+ # Merge chunks
321
+ with open(save_fname, 'ab' if initial_pos > 0 else 'wb') as outfile:
322
+ for temp_file in temp_files:
323
+ if os.path.exists(temp_file):
324
+ with open(temp_file, 'rb') as infile:
325
+ outfile.write(infile.read())
326
+ os.remove(temp_file)
327
+
328
+
250
329
  def mergeRasterTiles(tileList:list, outFile:str) -> str:
251
330
  '''
252
331
  Merge raster tiles into one raster file
@@ -1114,6 +1193,29 @@ def listAllFiles(folder, extension="*"):
1114
1193
  return list_of_files
1115
1194
 
1116
1195
 
1196
+ def clipFeatures(inputFeaturePath:str, boundaryFeature:str, outputFeature:str, keepOnlyTypes = None, v = False) -> geopandas.GeoDataFrame:
1197
+ '''
1198
+ keepOnlyTypes = ['MultiPolygon', 'Polygon', 'Point', etc]
1199
+
1200
+ '''
1201
+ mask_gdf = geopandas.read_file(boundaryFeature)
1202
+ input_gdf = geopandas.read_file(inputFeaturePath)
1203
+
1204
+ outDir = os.path.dirname(outputFeature)
1205
+ createPath(f"{outDir}/")
1206
+ out_gdf = input_gdf.clip(mask_gdf.to_crs(input_gdf.crs))
1207
+
1208
+ if not keepOnlyTypes is None:
1209
+ out_gdf = out_gdf[out_gdf.geometry.apply(lambda x : x.type in keepOnlyTypes)]
1210
+
1211
+ out_gdf.to_file(outputFeature)
1212
+
1213
+ if v:
1214
+ print("\t - clipped feature to " + outputFeature)
1215
+ return out_gdf
1216
+
1217
+
1218
+
1117
1219
  def createPointGeometry(coords: list, proj: str = "EPSG:4326") -> geopandas.GeoDataFrame:
1118
1220
  '''
1119
1221
  Convert list of coordinate tuples to GeoDataFrame
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ccfx
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: This package simplifies regular common actions for quick prototyping in a user friendly way
5
5
  Author-email: Celray James CHAWANDA <celray@chawanda.com>
6
6
  License: MIT
@@ -23,6 +23,8 @@ Requires-Dist: sqlalchemy
23
23
  Requires-Dist: python-docx
24
24
  Requires-Dist: py7zr
25
25
  Requires-Dist: mutagen
26
+ Requires-Dist: requests
27
+ Requires-Dist: tqdm
26
28
  Dynamic: license-file
27
29
 
28
30
  # ccfx
@@ -1,11 +1,11 @@
1
1
  ccfx/__init__.py,sha256=VmBeF3oj6JTJ_793d4i8PvhyF8_FxaxA1L_FmHWqitc,142
2
- ccfx/ccfx.py,sha256=A61uV0bKlusLAcLlgNVhKaMQ4KutWxB7hzEQnitJpus,51808
2
+ ccfx/ccfx.py,sha256=4BD22BQovfkcAFZRkoHaA1quvXlDBFc1GiH_Fffz6Q8,55571
3
3
  ccfx/excel.py,sha256=cQ4TQW49XqbMB3sSS0IOhO3-WArIolEBIrvOvhFyPtI,4757
4
4
  ccfx/mssqlConnection.py,sha256=TwyZXhHHI7zy6BSfH1pszuHVJ5cmndRC5dVxvEtSTks,7904
5
5
  ccfx/sqliteConnection.py,sha256=jEJ94D5ySt84N7AeDpa27Rclt1NaKhkX6nYzidwApIg,11104
6
6
  ccfx/word.py,sha256=AGa64jX5Zl5qotZh5L0QmrsjTnktIBhmj_ByRKZ88vw,3061
7
- ccfx-0.5.0.dist-info/licenses/LICENSE,sha256=2-M3fBUS3FmrSIrqd3cZDmxXxojWVJtZY-SHSRE6RxM,1098
8
- ccfx-0.5.0.dist-info/METADATA,sha256=6tpyj3FwWBdkm8BCvU26J9rZFsP_mCIoZUxTb71GYRA,5381
9
- ccfx-0.5.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
10
- ccfx-0.5.0.dist-info/top_level.txt,sha256=_cSvSA1WX2K8TgoV3iBJUdUZZqMKJbOPLNnKLYSLHaw,5
11
- ccfx-0.5.0.dist-info/RECORD,,
7
+ ccfx-0.7.0.dist-info/licenses/LICENSE,sha256=2-M3fBUS3FmrSIrqd3cZDmxXxojWVJtZY-SHSRE6RxM,1098
8
+ ccfx-0.7.0.dist-info/METADATA,sha256=_rPWPy0bHKGdUv5y2Ovt_XGpIbRv7Xa33oJJDfWDv-o,5425
9
+ ccfx-0.7.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
10
+ ccfx-0.7.0.dist-info/top_level.txt,sha256=_cSvSA1WX2K8TgoV3iBJUdUZZqMKJbOPLNnKLYSLHaw,5
11
+ ccfx-0.7.0.dist-info/RECORD,,
File without changes