ccfx 0.4.0__py3-none-any.whl → 0.6.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
@@ -27,8 +27,12 @@ from osgeo import gdal, ogr, osr
27
27
  import py7zr
28
28
  import subprocess
29
29
  import multiprocessing
30
-
31
-
30
+ from mutagen.mp3 import MP3
31
+ from mutagen.id3 import ID3, TPE1, TALB, TIT2, TRCK, TDRC, TCON, APIC, COMM, USLT, TPE2, TCOM, TPE3, TPE4, TCOP, TENC, TSRC, TBPM
32
+ from concurrent.futures import ThreadPoolExecutor
33
+ import math
34
+ import requests
35
+ from tqdm import tqdm
32
36
 
33
37
  # functions
34
38
  def listFiles(path: str, ext: str = None) -> list:
@@ -63,6 +67,138 @@ def getExtension(filePath:str) -> str:
63
67
  return os.path.splitext(filePath)[1].lstrip('.')
64
68
 
65
69
 
70
+ def getMp3Metadata(fn, imagePath=None):
71
+ '''
72
+ This function takes a path to mp3 and returns a dictionary with
73
+ the following keys:
74
+ - artist, album, title, track number, year, genre
75
+ '''
76
+ metadata = {}
77
+
78
+ try:
79
+ audio = MP3(fn, ID3=ID3)
80
+
81
+ if 'TPE1' in audio.tags: metadata['artist'] = str(audio.tags['TPE1'])
82
+ else: metadata['artist'] = "Unknown Artist"
83
+
84
+ if 'TALB' in audio.tags: metadata['album'] = str(audio.tags['TALB'])
85
+ else: metadata['album'] = "Unknown Album"
86
+
87
+ if 'TIT2' in audio.tags: metadata['title'] = str(audio.tags['TIT2'])
88
+ else: metadata['title'] = os.path.basename(fn).replace('.mp3', '')
89
+
90
+ if 'TRCK' in audio.tags: metadata['track_number'] = str(audio.tags['TRCK'])
91
+ else: metadata['track_number'] = "0"
92
+
93
+ if 'TDRC' in audio.tags: metadata['year'] = str(audio.tags['TDRC'])
94
+ else: metadata['year'] = "Unknown Year"
95
+
96
+ if 'TCON' in audio.tags: metadata['genre'] = str(audio.tags['TCON'])
97
+ else: metadata['genre'] = "Unknown Genre"
98
+
99
+ if imagePath is not None:
100
+ foundImage = False
101
+ if audio.tags:
102
+ for tagKey in audio.tags.keys():
103
+ if tagKey.startswith("APIC:"):
104
+ with open(imagePath, 'wb') as img_file:
105
+ img_file.write(audio.tags[tagKey].data)
106
+ foundImage = True
107
+ break
108
+ if not foundImage:
109
+ print("No image found in metadata.")
110
+
111
+ except Exception as e:
112
+ print(f"Error extracting metadata from {fn}: {e}")
113
+ # Set default values if extraction fails
114
+ metadata = {
115
+ 'artist': "Unknown Artist",
116
+ 'album': "Unknown Album",
117
+ 'title': os.path.basename(fn).replace('.mp3', ''),
118
+ 'track_number': "0",
119
+ 'year': "Unknown Year",
120
+ 'genre': "Unknown Genre"
121
+ }
122
+
123
+ return metadata
124
+
125
+ def guessMimeType(imagePath):
126
+ ext = os.path.splitext(imagePath.lower())[1]
127
+ if ext in ['.jpg', '.jpeg']:
128
+ return 'image/jpeg'
129
+ elif ext == '.png':
130
+ return 'image/png'
131
+ return 'image/png'
132
+
133
+ def setMp3Metadata(fn, metadata, imagePath=None):
134
+ '''
135
+ This function takes a path to an mp3 and a metadata dictionary,
136
+ then writes that metadata to the file's ID3 tags.
137
+
138
+ The metadata dictionary should have these keys:
139
+ - artist, album, title, track_number, year, genre
140
+
141
+ Additionally, an optional imagePath parameter can be provided to
142
+ attach album artwork from a PNG or JPEG file.
143
+
144
+ Alternatively, you can include an 'imagePath' key in the metadata
145
+ dictionary instead of using the separate parameter.
146
+ '''
147
+ try:
148
+ # Try to load existing ID3 tags or create new ones if they don't exist
149
+ try:
150
+ audio = ID3(fn)
151
+ except:
152
+ audio = ID3()
153
+
154
+ # Set artist
155
+ if 'artist' in metadata and metadata['artist']: audio['TPE1'] = TPE1(encoding=3, text=metadata['artist'])
156
+ if 'album' in metadata and metadata['album']: audio['TALB'] = TALB(encoding=3, text=metadata['album'])
157
+ if 'title' in metadata and metadata['title']: audio['TIT2'] = TIT2(encoding=3, text=metadata['title'])
158
+ if 'track_number' in metadata and metadata['track_number']: audio['TRCK'] = TRCK(encoding=3, text=metadata['track_number'])
159
+ if 'year' in metadata and metadata['year']: audio['TDRC'] = TDRC(encoding=3, text=metadata['year'])
160
+ if 'genre' in metadata and metadata['genre']: audio['TCON'] = TCON(encoding=3, text=metadata['genre'])
161
+ if 'comment' in metadata and metadata['comment']: audio['COMM'] = COMM(encoding=3, text=metadata['comment'])
162
+ if 'lyrics' in metadata and metadata['lyrics']: audio['USLT'] = USLT(encoding=3, text=metadata['lyrics'])
163
+ if 'publisher' in metadata and metadata['publisher']: audio['TPUB'] = TPE2(encoding=3, text=metadata['publisher'])
164
+ if 'composer' in metadata and metadata['composer']: audio['TCOM'] = TCOM(encoding=3, text=metadata['composer'])
165
+ if 'conductor' in metadata and metadata['conductor']: audio['TPE3'] = TPE3(encoding=3, text=metadata['conductor'])
166
+ if 'performer' in metadata and metadata['performer']: audio['TPE4'] = TPE4(encoding=3, text=metadata['performer'])
167
+ if 'copyright' in metadata and metadata['copyright']: audio['TCOP'] = TCOP(encoding=3, text=metadata['copyright'])
168
+ if 'encoded_by' in metadata and metadata['encoded_by']: audio['TENC'] = TENC(encoding=3, text=metadata['encoded_by'])
169
+ if 'encoder' in metadata and metadata['encoder']: audio['TENC'] = TENC(encoding=3, text=metadata['encoder'])
170
+ if 'isrc' in metadata and metadata['isrc']: audio['TSRC'] = TSRC(encoding=3, text=metadata['isrc'])
171
+ if 'bpm' in metadata and metadata['bpm']: audio['TBPM'] = TBPM(encoding=3, text=metadata['bpm'])
172
+ # Check if image path is in metadata dictionary and not provided as parameter
173
+ if imagePath is None and 'imagePath' in metadata:
174
+ imagePath = metadata['imagePath']
175
+
176
+ # Attach image if provided
177
+ if imagePath and os.path.exists(imagePath):
178
+ with open(imagePath, 'rb') as img_file:
179
+ img_data = img_file.read()
180
+
181
+ # Determine image MIME type
182
+ mime = guessMimeType(imagePath)
183
+
184
+ # Create APIC frame for album artwork
185
+ audio['APIC'] = APIC(
186
+ encoding=3, # UTF-8 encoding
187
+ mime=mime, # MIME type of the image
188
+ type=3, # 3 means 'Cover (front)'
189
+ desc='Cover', # Description
190
+ data=img_data # The image data
191
+ )
192
+
193
+ # Save changes to the file
194
+ audio.save(fn)
195
+ return True
196
+
197
+ except Exception as e:
198
+ print(f"Error writing metadata to {fn}: {e}")
199
+ return False
200
+
201
+
66
202
  def deleteFile(filePath:str, v:bool = False) -> bool:
67
203
  '''
68
204
  Delete a file
@@ -114,6 +250,82 @@ def deletePath(path:str, v:bool = False) -> bool:
114
250
  deleted = False
115
251
 
116
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=7, 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
+
117
329
  def mergeRasterTiles(tileList:list, outFile:str) -> str:
118
330
  '''
119
331
  Merge raster tiles into one raster file
@@ -439,8 +651,11 @@ def moveDirectoryFiles(srcDir: str, destDir: str, v: bool = False) -> bool:
439
651
  src_file = os.path.join(root, file)
440
652
  dest_file = os.path.join(dest_root, file)
441
653
  if v:
442
- print(f"\t> Moving file \n\t - {src_file}\n\t - to {dest_file}")
443
- shutil.move(src_file, dest_file)
654
+ print(f"\t> Moving file \n\t - {src_file}\n\t to {dest_file}")
655
+ try:
656
+ shutil.move(src_file, dest_file)
657
+ except Exception as e:
658
+ print(f"! Error moving file: {e}")
444
659
 
445
660
  return True
446
661
 
@@ -1314,4 +1529,25 @@ def getMSE(data:pandas.DataFrame, observed:str = None, simulated:str = None, res
1314
1529
 
1315
1530
  return stats['MSE']
1316
1531
 
1532
+ def getTimeseriesStats(data:pandas.DataFrame, observed:str = None, simulated:str = None, resample:str = None ) -> dict:
1533
+ '''
1534
+ this function is a wrapper for calculateTimeseriesStats specifically to return all stats
1535
+
1536
+ data: pandas.DataFrame
1537
+ DataFrame containing the timeseries data
1538
+ observed: str
1539
+ name of the observed column
1540
+ simulated: str
1541
+ name of the simulated column
1542
+ resample: str
1543
+ if specified, the data will be resampled to the specified frequency
1544
+ available options: 'H' (hourly), 'D' (daily), 'M' (monthly), 'Y' (yearly)
1545
+
1546
+ return: dict
1547
+ dictionary containing all stats
1548
+ '''
1549
+ stats = calculateTimeseriesStats(data, observed, simulated, resample)
1550
+
1551
+ return stats
1552
+
1317
1553
  ignoreWarnings()
@@ -1,146 +1,150 @@
1
- Metadata-Version: 2.1
2
- Name: ccfx
3
- Version: 0.4.0
4
- Summary: This package implifies regular coommon actions for quick prototyping in a user friendly way
5
- Author-email: Celray James CHAWANDA <celray@chawanda.com>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/celray/ccfx
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.10
12
- Description-Content-Type: text/markdown
13
- License-File: LICENSE
14
- Requires-Dist: netCDF4
15
- Requires-Dist: gdal
16
- Requires-Dist: numpy
17
- Requires-Dist: shapely
18
- Requires-Dist: geopandas
19
- Requires-Dist: pandas
20
- Requires-Dist: xlsxwriter
21
- Requires-Dist: pyodbc
22
- Requires-Dist: sqlalchemy
23
- Requires-Dist: python-docx
24
- Requires-Dist: py7zr
25
-
26
- # ccfx
27
-
28
- `ccfx` is a comprehensive Python package designed to streamline file and data management, geospatial analysis, and NetCDF file processing for quick prototyping. The library provides versatile tools for file handling, raster and vector manipulation, database connectivity, and data export for geospatial and scientific computing projects.
29
-
30
- ## Features
31
-
32
- 1. **File Management**:
33
- - List, delete, move, and count files within directories.
34
- - Monitor file count over time in a specific directory.
35
- - Save, load, and manage Python variables via pickle serialization.
36
-
37
- 2. **Geospatial Data Processing**:
38
- - Read, write, and manage raster and vector geospatial data.
39
- - Clip rasters by bounding boxes and extract raster values at specified coordinates.
40
- - Create grids of polygons based on shapefile boundaries with user-defined resolutions.
41
- - Convert coordinates between coordinate reference systems (CRS).
42
- - Write NumPy arrays to GeoTIFF files with projection and geotransform settings.
43
-
44
- 3. **NetCDF File Handling**:
45
- - List available variables and dimensions in NetCDF files.
46
- - Export NetCDF variables to GeoTIFF format.
47
- - Calculate sum and average maps from NetCDF data across multiple files.
48
-
49
- 4. **Database Connectivity**:
50
- - Access and interact with databases using ODBC and SQLAlchemy for flexible database management.
51
- - Connect to both SQL Server and SQLite databases.
52
-
53
- 5. **Progress Tracking and System Info**:
54
- - Display dynamic progress bars for long-running operations.
55
- - Check the system’s platform information.
56
- - Enable or disable warnings programmatically.
57
-
58
- 6. **Excel and Word File Handling**:
59
- - Create and modify Excel files using xlsxwriter.
60
- - Generate Word documents with advanced formatting options using python-docx.
61
-
62
- ## Installation
63
-
64
- Install `ccfx` via pip:
65
- ```bash
66
- pip install ccfx
67
- ```
68
-
69
- ## Dependencies
70
-
71
- `ccfx` relies on the following libraries:
72
-
73
- - **netCDF4**: For working with NetCDF files.
74
- - **gdal**: Required for geospatial raster data manipulation.
75
- - **numpy**: For array processing and numerical operations.
76
- - **pandas**: For data manipulation and analysis.
77
- - **shapely**: Provides geometric operations for spatial data.
78
- - **geopandas**: Extends pandas to handle geospatial data.
79
- - **xlsxwriter**: For creating and writing Excel files.
80
- - **pyodbc**: Enables connectivity to databases through ODBC.
81
- - **sqlalchemy**: Provides SQL toolkit and ORM features for database access.
82
- - **python-docx**: Enables creation and manipulation of Word documents.
83
-
84
- These dependencies will be installed automatically when `ccfx` is installed.
85
-
86
- ## API Reference
87
-
88
- ### `listFiles(path: str, ext: str = None) -> list`
89
- Lists all files in a directory with a specified extension.
90
-
91
- - **Parameters**:
92
- - `path` (str): The directory to search.
93
- - `ext` (str, optional): File extension to filter by, e.g., `'txt'`, `'.txt'`, `'*txt'`, or `'*.txt'`.
94
-
95
- - **Returns**:
96
- - `list`: A list of file paths matching the criteria.
97
-
98
- ### `deleteFile(filePath: str, v: bool = False) -> bool`
99
- Deletes a specified file with optional verbose output.
100
-
101
- - **Parameters**:
102
- - `filePath` (str): Path to the file to be deleted.
103
- - `v` (bool, optional): If `True`, prints a confirmation message. Defaults to `False`.
104
-
105
- - **Returns**:
106
- - `bool`: `True` if deletion was successful; `False` otherwise.
107
-
108
- ### `createGrid(shapefile_path: str, resolution: float, useDegree: bool = True) -> tuple`
109
- Generates a grid of polygons from a shapefile at a given resolution.
110
-
111
- - **Parameters**:
112
- - `shapefile_path` (str): Path to the shapefile.
113
- - `resolution` (float): Resolution of the grid.
114
- - `useDegree` (bool, optional): If `True`, coordinates are in degrees. Defaults to `True`.
115
-
116
- - **Returns**:
117
- - `tuple`: Contains grid coordinates and metadata.
118
-
119
- ### `clipRasterByExtent(inFile: str, outFile: str, bounds: tuple) -> str`
120
- Clips a raster to specified bounding box coordinates.
121
-
122
- - **Parameters**:
123
- - `inFile` (str): Path to the input raster file.
124
- - `outFile` (str): Path to the output clipped raster file.
125
- - `bounds` (tuple): Bounding box as `(minx, miny, maxx, maxy)`.
126
-
127
- - **Returns**:
128
- - `str`: Path to the clipped raster file.
129
-
130
- ### `netcdfVariablesList(ncFile: str) -> list`
131
- Lists all variables in a NetCDF file.
132
-
133
- - **Parameters**:
134
- - `ncFile` (str): Path to the NetCDF file.
135
-
136
- - **Returns**:
137
- - `list`: A list of variable names in the file.
138
-
139
- ### ... And More ...
140
-
141
- ## Contributing
142
-
143
- Contributions are welcome! Please fork the repository, make your changes, and submit a pull request.
144
-
145
- ## License
146
- This project is licensed under the MIT License.
1
+ Metadata-Version: 2.4
2
+ Name: ccfx
3
+ Version: 0.6.0
4
+ Summary: This package simplifies regular common actions for quick prototyping in a user friendly way
5
+ Author-email: Celray James CHAWANDA <celray@chawanda.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/celray/ccfx
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: netCDF4
15
+ Requires-Dist: gdal
16
+ Requires-Dist: numpy
17
+ Requires-Dist: shapely
18
+ Requires-Dist: geopandas
19
+ Requires-Dist: pandas
20
+ Requires-Dist: xlsxwriter
21
+ Requires-Dist: pyodbc
22
+ Requires-Dist: sqlalchemy
23
+ Requires-Dist: python-docx
24
+ Requires-Dist: py7zr
25
+ Requires-Dist: mutagen
26
+ Requires-Dist: requests
27
+ Requires-Dist: tqdm
28
+ Dynamic: license-file
29
+
30
+ # ccfx
31
+
32
+ `ccfx` is a comprehensive Python package designed to streamline file and data management, geospatial analysis, and NetCDF file processing for quick prototyping. The library provides versatile tools for file handling, raster and vector manipulation, database connectivity, and data export for geospatial and scientific computing projects.
33
+
34
+ ## Features
35
+
36
+ 1. **File Management**:
37
+ - List, delete, move, and count files within directories.
38
+ - Monitor file count over time in a specific directory.
39
+ - Save, load, and manage Python variables via pickle serialization.
40
+
41
+ 2. **Geospatial Data Processing**:
42
+ - Read, write, and manage raster and vector geospatial data.
43
+ - Clip rasters by bounding boxes and extract raster values at specified coordinates.
44
+ - Create grids of polygons based on shapefile boundaries with user-defined resolutions.
45
+ - Convert coordinates between coordinate reference systems (CRS).
46
+ - Write NumPy arrays to GeoTIFF files with projection and geotransform settings.
47
+
48
+ 3. **NetCDF File Handling**:
49
+ - List available variables and dimensions in NetCDF files.
50
+ - Export NetCDF variables to GeoTIFF format.
51
+ - Calculate sum and average maps from NetCDF data across multiple files.
52
+
53
+ 4. **Database Connectivity**:
54
+ - Access and interact with databases using ODBC and SQLAlchemy for flexible database management.
55
+ - Connect to both SQL Server and SQLite databases.
56
+
57
+ 5. **Progress Tracking and System Info**:
58
+ - Display dynamic progress bars for long-running operations.
59
+ - Check the system’s platform information.
60
+ - Enable or disable warnings programmatically.
61
+
62
+ 6. **Excel and Word File Handling**:
63
+ - Create and modify Excel files using xlsxwriter.
64
+ - Generate Word documents with advanced formatting options using python-docx.
65
+
66
+ ## Installation
67
+
68
+ Install `ccfx` via pip:
69
+ ```bash
70
+ pip install ccfx
71
+ ```
72
+
73
+ ## Dependencies
74
+
75
+ `ccfx` relies on the following libraries:
76
+
77
+ - **netCDF4**: For working with NetCDF files.
78
+ - **gdal**: Required for geospatial raster data manipulation.
79
+ - **numpy**: For array processing and numerical operations.
80
+ - **pandas**: For data manipulation and analysis.
81
+ - **shapely**: Provides geometric operations for spatial data.
82
+ - **geopandas**: Extends pandas to handle geospatial data.
83
+ - **xlsxwriter**: For creating and writing Excel files.
84
+ - **pyodbc**: Enables connectivity to databases through ODBC.
85
+ - **sqlalchemy**: Provides SQL toolkit and ORM features for database access.
86
+ - **python-docx**: Enables creation and manipulation of Word documents.
87
+
88
+ These dependencies will be installed automatically when `ccfx` is installed.
89
+
90
+ ## API Reference
91
+
92
+ ### `listFiles(path: str, ext: str = None) -> list`
93
+ Lists all files in a directory with a specified extension.
94
+
95
+ - **Parameters**:
96
+ - `path` (str): The directory to search.
97
+ - `ext` (str, optional): File extension to filter by, e.g., `'txt'`, `'.txt'`, `'*txt'`, or `'*.txt'`.
98
+
99
+ - **Returns**:
100
+ - `list`: A list of file paths matching the criteria.
101
+
102
+ ### `deleteFile(filePath: str, v: bool = False) -> bool`
103
+ Deletes a specified file with optional verbose output.
104
+
105
+ - **Parameters**:
106
+ - `filePath` (str): Path to the file to be deleted.
107
+ - `v` (bool, optional): If `True`, prints a confirmation message. Defaults to `False`.
108
+
109
+ - **Returns**:
110
+ - `bool`: `True` if deletion was successful; `False` otherwise.
111
+
112
+ ### `createGrid(shapefile_path: str, resolution: float, useDegree: bool = True) -> tuple`
113
+ Generates a grid of polygons from a shapefile at a given resolution.
114
+
115
+ - **Parameters**:
116
+ - `shapefile_path` (str): Path to the shapefile.
117
+ - `resolution` (float): Resolution of the grid.
118
+ - `useDegree` (bool, optional): If `True`, coordinates are in degrees. Defaults to `True`.
119
+
120
+ - **Returns**:
121
+ - `tuple`: Contains grid coordinates and metadata.
122
+
123
+ ### `clipRasterByExtent(inFile: str, outFile: str, bounds: tuple) -> str`
124
+ Clips a raster to specified bounding box coordinates.
125
+
126
+ - **Parameters**:
127
+ - `inFile` (str): Path to the input raster file.
128
+ - `outFile` (str): Path to the output clipped raster file.
129
+ - `bounds` (tuple): Bounding box as `(minx, miny, maxx, maxy)`.
130
+
131
+ - **Returns**:
132
+ - `str`: Path to the clipped raster file.
133
+
134
+ ### `netcdfVariablesList(ncFile: str) -> list`
135
+ Lists all variables in a NetCDF file.
136
+
137
+ - **Parameters**:
138
+ - `ncFile` (str): Path to the NetCDF file.
139
+
140
+ - **Returns**:
141
+ - `list`: A list of variable names in the file.
142
+
143
+ ### ... And More ...
144
+
145
+ ## Contributing
146
+
147
+ Contributions are welcome! Please fork the repository, make your changes, and submit a pull request.
148
+
149
+ ## License
150
+ This project is licensed under the MIT License.
@@ -0,0 +1,11 @@
1
+ ccfx/__init__.py,sha256=VmBeF3oj6JTJ_793d4i8PvhyF8_FxaxA1L_FmHWqitc,142
2
+ ccfx/ccfx.py,sha256=05Xcv_RtPoQLVJdsdG2GO7ra_8ANTRf05dhTFHIA9RM,54836
3
+ ccfx/excel.py,sha256=cQ4TQW49XqbMB3sSS0IOhO3-WArIolEBIrvOvhFyPtI,4757
4
+ ccfx/mssqlConnection.py,sha256=TwyZXhHHI7zy6BSfH1pszuHVJ5cmndRC5dVxvEtSTks,7904
5
+ ccfx/sqliteConnection.py,sha256=jEJ94D5ySt84N7AeDpa27Rclt1NaKhkX6nYzidwApIg,11104
6
+ ccfx/word.py,sha256=AGa64jX5Zl5qotZh5L0QmrsjTnktIBhmj_ByRKZ88vw,3061
7
+ ccfx-0.6.0.dist-info/licenses/LICENSE,sha256=2-M3fBUS3FmrSIrqd3cZDmxXxojWVJtZY-SHSRE6RxM,1098
8
+ ccfx-0.6.0.dist-info/METADATA,sha256=OmS1T49N5s5qhS4B17LntNzA2qHxZV1BnELdB0n5PQM,5425
9
+ ccfx-0.6.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
10
+ ccfx-0.6.0.dist-info/top_level.txt,sha256=_cSvSA1WX2K8TgoV3iBJUdUZZqMKJbOPLNnKLYSLHaw,5
11
+ ccfx-0.6.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,11 +0,0 @@
1
- ccfx/__init__.py,sha256=VmBeF3oj6JTJ_793d4i8PvhyF8_FxaxA1L_FmHWqitc,142
2
- ccfx/ccfx.py,sha256=TcGb46QY57295iRfRnMwdm_fjjQ1Z-VDDlzveahRoEw,44547
3
- ccfx/excel.py,sha256=cQ4TQW49XqbMB3sSS0IOhO3-WArIolEBIrvOvhFyPtI,4757
4
- ccfx/mssqlConnection.py,sha256=TwyZXhHHI7zy6BSfH1pszuHVJ5cmndRC5dVxvEtSTks,7904
5
- ccfx/sqliteConnection.py,sha256=jEJ94D5ySt84N7AeDpa27Rclt1NaKhkX6nYzidwApIg,11104
6
- ccfx/word.py,sha256=AGa64jX5Zl5qotZh5L0QmrsjTnktIBhmj_ByRKZ88vw,3061
7
- ccfx-0.4.0.dist-info/LICENSE,sha256=2-M3fBUS3FmrSIrqd3cZDmxXxojWVJtZY-SHSRE6RxM,1098
8
- ccfx-0.4.0.dist-info/METADATA,sha256=3llLy7xyGpG1tpvmB9LZc4csbq-R41UoGMlR95ajT-s,5482
9
- ccfx-0.4.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
10
- ccfx-0.4.0.dist-info/top_level.txt,sha256=_cSvSA1WX2K8TgoV3iBJUdUZZqMKJbOPLNnKLYSLHaw,5
11
- ccfx-0.4.0.dist-info/RECORD,,