data-manipulation 0.45__tar.gz → 0.46__tar.gz

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.
Files changed (42) hide show
  1. {data_manipulation-0.45/data_manipulation.egg-info → data_manipulation-0.46}/PKG-INFO +1 -1
  2. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/_version.py +3 -3
  3. data_manipulation-0.46/data_manipulation/base.py +372 -0
  4. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/beautifulsoup_.py +33 -41
  5. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/boto3_.py +35 -42
  6. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/cryptography_.py +48 -42
  7. data_manipulation-0.46/data_manipulation/django_.py +140 -0
  8. data_manipulation-0.46/data_manipulation/geopandas_.py +44 -0
  9. data_manipulation-0.46/data_manipulation/kerberos_.py +51 -0
  10. data_manipulation-0.46/data_manipulation/mysql_connector_python_.py +98 -0
  11. data_manipulation-0.46/data_manipulation/openldap_.py +56 -0
  12. data_manipulation-0.46/data_manipulation/pandas_.py +732 -0
  13. data_manipulation-0.46/data_manipulation/psycopg2_.py +247 -0
  14. data_manipulation-0.46/data_manipulation/psycopg_.py +101 -0
  15. data_manipulation-0.46/data_manipulation/pyspark_.py +446 -0
  16. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/smtplib_.py +30 -16
  17. data_manipulation-0.46/data_manipulation/sqlalchemy_.py +122 -0
  18. {data_manipulation-0.45 → data_manipulation-0.46/data_manipulation.egg-info}/PKG-INFO +1 -1
  19. data_manipulation-0.45/data_manipulation/base.py +0 -475
  20. data_manipulation-0.45/data_manipulation/django_.py +0 -127
  21. data_manipulation-0.45/data_manipulation/geopandas_.py +0 -42
  22. data_manipulation-0.45/data_manipulation/kerberos_.py +0 -45
  23. data_manipulation-0.45/data_manipulation/mysql_connector_python_.py +0 -96
  24. data_manipulation-0.45/data_manipulation/openldap_.py +0 -26
  25. data_manipulation-0.45/data_manipulation/pandas_.py +0 -864
  26. data_manipulation-0.45/data_manipulation/psycopg2_.py +0 -111
  27. data_manipulation-0.45/data_manipulation/psycopg_.py +0 -116
  28. data_manipulation-0.45/data_manipulation/pyspark_.py +0 -414
  29. data_manipulation-0.45/data_manipulation/sqlalchemy_.py +0 -98
  30. {data_manipulation-0.45 → data_manipulation-0.46}/LICENSE +0 -0
  31. {data_manipulation-0.45 → data_manipulation-0.46}/MANIFEST.in +0 -0
  32. {data_manipulation-0.45 → data_manipulation-0.46}/README.md +0 -0
  33. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/__init__.py +0 -0
  34. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/flask_.py +0 -0
  35. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation/prometheus_.py +0 -0
  36. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation.egg-info/SOURCES.txt +0 -0
  37. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation.egg-info/dependency_links.txt +0 -0
  38. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation.egg-info/requires.txt +0 -0
  39. {data_manipulation-0.45 → data_manipulation-0.46}/data_manipulation.egg-info/top_level.txt +0 -0
  40. {data_manipulation-0.45 → data_manipulation-0.46}/setup.cfg +0 -0
  41. {data_manipulation-0.45 → data_manipulation-0.46}/setup.py +0 -0
  42. {data_manipulation-0.45 → data_manipulation-0.46}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: data_manipulation
3
- Version: 0.45
3
+ Version: 0.46
4
4
  Summary: Powerful data manipulation
5
5
  Home-page: https://github.com/shawnngtq/data-manipulation
6
6
  Author: Shawn Ng
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-09-08T09:24:53+0800",
11
+ "date": "2024-11-24T20:58:50+0800",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "60bea1e3117837fae0b5506910b8006d348b5b81",
15
- "version": "0.45"
14
+ "full-revisionid": "8d4f86d6f48df8cc57789006ba9a8b8ee47ab4c2",
15
+ "version": "0.46"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -0,0 +1,372 @@
1
+ import itertools
2
+ import os
3
+ import re
4
+ import subprocess
5
+ from typing import List
6
+
7
+ from loguru import logger
8
+
9
+
10
+ # DATA STRUCTURE
11
+ def clean_string(
12
+ string: str, remove_parenthesis: bool = False, remove_brackets: bool = False
13
+ ) -> str:
14
+ """Cleans and standardizes input string.
15
+
16
+ Args:
17
+ string (str): String to clean.
18
+ remove_parenthesis (bool, optional): Whether to remove content within parentheses. Defaults to False.
19
+ remove_brackets (bool, optional): Whether to remove content within square brackets. Defaults to False.
20
+
21
+ Returns:
22
+ str: Uppercase cleaned string with standardized spacing.
23
+
24
+ Examples:
25
+ >>> clean_string(" sHawn tesT ")
26
+ 'SHAWN TEST'
27
+ >>> clean_string("shawn ( te st )")
28
+ 'SHAWN ( TE ST )'
29
+ >>> clean_string("shawn ( te st )", remove_parenthesis=True)
30
+ 'SHAWN'
31
+ >>> clean_string("shawn [ te st ]", remove_brackets=True)
32
+ 'SHAWN'
33
+ """
34
+
35
+ if remove_parenthesis:
36
+ string = re.sub(r"\(.*\)", "", string)
37
+ if remove_brackets:
38
+ string = re.sub(r"\[.*\]", "", string)
39
+
40
+ string = string.strip().upper()
41
+ string = " ".join(string.split())
42
+ return string
43
+
44
+
45
+ def get_string_case_combination(str_: str) -> list:
46
+ """Generates all possible case combinations of a string.
47
+
48
+ Args:
49
+ str_ (str): Input string to generate combinations for.
50
+
51
+ Returns:
52
+ list: List of all possible case combinations.
53
+
54
+ Examples:
55
+ >>> get_string_case_combination("abc")
56
+ ['ABC', 'ABc', 'AbC', 'Abc', 'aBC', 'aBc', 'abC', 'abc']
57
+ """
58
+
59
+ return list(map("".join, itertools.product(*zip(str_.upper(), str_.lower()))))
60
+
61
+
62
+ def get_none_variation() -> list:
63
+ """Returns a list of common variations of None/null values.
64
+
65
+ Returns:
66
+ list: List containing None and various string representations of null values.
67
+
68
+ Examples:
69
+ >>> get_none_variation()
70
+ [None, 'NONE', 'NONe', 'NOnE', 'NOne', 'NoNE', 'NoNe', 'NonE', 'None', 'nONE', 'nONe', 'nOnE', 'nOne', 'noNE', 'noNe', 'nonE', 'none', 'NULL', 'NULl', 'NUlL', 'NUll', 'NuLL', 'NuLl', 'NulL', 'Null', 'nULL', 'nULl', 'nUlL', 'nUll', 'nuLL', 'nuLl', 'nulL', 'null', 'NA', 'Na', 'nA', 'na', 'N.A', 'N.a', 'N.A', 'N.a', 'n.A', 'n.a', 'n.A', 'n.a', 'N.A.', 'N.A.', 'N.a.', 'N.a.', 'N.A.', 'N.A.', 'N.a.', 'N.a.', 'n.A.', 'n.A.', 'n.a.', 'n.a.', 'n.A.', 'n.A.', 'n.a.', 'n.a.', 'NAN', 'NAn', 'NaN', 'Nan', 'nAN', 'nAn', 'naN', 'nan', 'NIL', 'NIl', 'NiL', 'Nil', 'nIL', 'nIl', 'niL', 'nil']
71
+ """
72
+ variations = (
73
+ [None]
74
+ + get_string_case_combination("none")
75
+ + get_string_case_combination("null")
76
+ + get_string_case_combination("na")
77
+ + get_string_case_combination("n.a")
78
+ + get_string_case_combination("n.a.")
79
+ + get_string_case_combination("nan")
80
+ + get_string_case_combination("nil")
81
+ )
82
+ return variations
83
+
84
+
85
+ def get_country_name_variation() -> dict:
86
+ """Returns a dictionary mapping country names to their codes.
87
+
88
+ Returns:
89
+ dict: Dictionary with country names as keys and country codes as values.
90
+ """
91
+ variations = {
92
+ "AFRICA": "BW",
93
+ "BOSNIA": "BA",
94
+ "CZECH REPUBLIC": "CZ",
95
+ "MACEDONIA": "MK",
96
+ "REPUBLIC OF CHINA": "CN",
97
+ "REPUBLIC OF KOREA": "KR",
98
+ "RUSSIAN FEDERATION": "RU",
99
+ "SLAVONIC": "SK",
100
+ "SLOVAK REPUBLIC": "SK",
101
+ "TURKEY": "TR",
102
+ "TURKIYE": "TR",
103
+ "UNITED STATES": "US",
104
+ }
105
+ return variations
106
+
107
+
108
+ def get_country_code_variation() -> dict:
109
+ """Returns a dictionary mapping country codes to their name variations.
110
+
111
+ Returns:
112
+ dict: Dictionary with country codes as keys and lists of country name variations as values.
113
+ """
114
+ variations = {
115
+ "BA": ["BOSNIA"],
116
+ "BW": ["AFRICA"],
117
+ "CN": ["REPUBLIC OF CHINA"],
118
+ "CZ": ["CZECH REPUBLIC"],
119
+ "KR": ["REPUBLIC OF KOREA"],
120
+ "MK": ["MACEDONIA"],
121
+ "RU": ["RUSSIAN FEDERATION"],
122
+ "SK": ["SLAVONIC", "SLOVAK REPUBLIC"],
123
+ "TR": ["TURKEY", "TURKIYE"],
124
+ "US": ["UNITED STATES"],
125
+ }
126
+ return variations
127
+
128
+
129
+ def list_tuple_without_none(list_tuple: list | tuple) -> list | tuple:
130
+ """Removes None variations from a list or tuple.
131
+
132
+ Args:
133
+ list_tuple (list | tuple): Input list or tuple to clean.
134
+
135
+ Returns:
136
+ list | tuple: List or tuple with None variations removed.
137
+
138
+ Raises:
139
+ TypeError: If input is not a list or tuple.
140
+
141
+ Examples:
142
+ >>> list_tuple_without_none(["a", "none"])
143
+ ['a']
144
+ >>> list_tuple_without_none(("a", "none"))
145
+ ('a',)
146
+ """
147
+ none_variations = get_none_variation()
148
+ if isinstance(list_tuple, list):
149
+ lt = [item for item in list_tuple if item and item not in none_variations]
150
+ elif isinstance(list_tuple, tuple):
151
+ lt = tuple(item for item in list_tuple if item and item not in none_variations)
152
+ else:
153
+ raise TypeError("Wrong datatype(s)")
154
+ return lt
155
+
156
+
157
+ def string_boolean_to_int(boolean_str_rep: str) -> int:
158
+ """Converts string boolean representations to integers.
159
+
160
+ Deprecated: Will be removed in Python 3.12+
161
+
162
+ Args:
163
+ boolean_str_rep (str): String representation of boolean value.
164
+
165
+ Returns:
166
+ int: 1 for true values, 0 for false values.
167
+
168
+ Examples:
169
+ >>> string_boolean_to_int("true")
170
+ 1
171
+ >>> string_boolean_to_int("True")
172
+ 1
173
+ """
174
+ from distutils.util import strtobool
175
+
176
+ int_ = strtobool(string_str_to_str(boolean_str_rep))
177
+ return int_
178
+
179
+
180
+ def string_dlt_to_dlt(dlt_str_rep: str) -> dict | list | tuple:
181
+ """Converts string representation of data structures to actual Python objects.
182
+
183
+ Args:
184
+ dlt_str_rep (str): String representation of dictionary/list/tuple.
185
+
186
+ Returns:
187
+ dict | list | tuple: Converted Python data structure.
188
+
189
+ Examples:
190
+ >>> string_dlt_to_dlt("[1, 2, 3]")
191
+ [1, 2, 3]
192
+ >>> string_dlt_to_dlt("{'a': 1, 'b': 2}")
193
+ {'a': 1, 'b': 2}
194
+ >>> string_dlt_to_dlt("('1', '2', '3')")
195
+ ('1', '2', '3')
196
+ """
197
+ from ast import literal_eval
198
+
199
+ dlt = literal_eval(dlt_str_rep)
200
+ return dlt
201
+
202
+
203
+ def string_str_to_str(string_str_rep: str) -> str:
204
+ """Converts string representation to a clean string by removing quotes.
205
+
206
+ Args:
207
+ string_str_rep (str): String representation to clean.
208
+
209
+ Returns:
210
+ str: Cleaned string with outer quotes removed.
211
+
212
+ Examples:
213
+ >>> string_str_to_str("'test'")
214
+ 'test'
215
+ >>> string_str_to_str('"test"')
216
+ 'test'
217
+ """
218
+ str_ = string_str_rep.strip("'\"")
219
+ return str_
220
+
221
+
222
+ def delete_list_indices(list_: list, indices: list) -> None:
223
+ """Deletes multiple indices from a list in-place.
224
+
225
+ Args:
226
+ list_ (list): Original list to modify.
227
+ indices (list): List of indices to delete.
228
+
229
+ Examples:
230
+ >>> values = [0, 1, 2, 3, 4]
231
+ >>> delete_list_indices(values, [1, 3])
232
+ >>> values
233
+ [0, 2, 4]
234
+ """
235
+ for index in sorted(indices, reverse=True):
236
+ del list_[index]
237
+
238
+
239
+ # FILESYSTEM
240
+ def get_path_files(path: str, keywords: list) -> list:
241
+ """Returns sorted list of files from given path that contain specified keywords.
242
+
243
+ Args:
244
+ path (str): Directory path to search.
245
+ keywords (list): List of keywords to match in filenames.
246
+
247
+ Returns:
248
+ list: Sorted list of matching filenames.
249
+
250
+ Examples:
251
+ >>> get_path_files("test_base_folder", ["py"])
252
+ ['test1.py', 'test2.py', 'test3.py', 'test4.py', 'test5.py']
253
+ """
254
+
255
+ list_ = []
256
+ for file in sorted(os.listdir(path)):
257
+ if any(word in file for word in keywords):
258
+ list_.append(file)
259
+ return list_
260
+
261
+
262
+ def remove_path_file(path: str, keyword: str, n: int = 2) -> None:
263
+ """Removes all but the n newest files matching the keyword from the specified path.
264
+
265
+ Args:
266
+ path (str): Directory path.
267
+ keyword (str): Keyword to match in filenames.
268
+ n (int, optional): Number of newest files to keep. Defaults to 2.
269
+
270
+ Examples:
271
+ >>> remove_path_file("test_base_folder", ".py")
272
+ """
273
+
274
+ to_delete = get_path_files(path=path, keywords=[keyword])[:-n]
275
+ for file in to_delete:
276
+ os.remove(f"{path}/{file}")
277
+ logger.info(f"{path}/{file} deleted ...")
278
+
279
+
280
+ def list_to_file(filepath: str, list_: list, newline: bool = True) -> None:
281
+ """Writes list contents to a file.
282
+
283
+ Args:
284
+ filepath (str): Path to output file.
285
+ list_ (list): List of values to write.
286
+ newline (bool, optional): Whether to add newline after each item. Defaults to True.
287
+
288
+ Examples:
289
+ >>> list_to_file("test.txt", [1, 2, 3])
290
+ """
291
+ f = open(filepath, "w")
292
+ for line in list_:
293
+ f.write(str(line))
294
+ if newline:
295
+ f.write("\n")
296
+ f.close()
297
+
298
+
299
+ # URLLIB
300
+ def create_encode_url(url: str, query_params: dict = {}) -> str:
301
+ """Creates an encoded URL with query parameters.
302
+
303
+ Args:
304
+ url (str): Base URL.
305
+ query_params (dict, optional): Dictionary of URL query parameters. Defaults to {}.
306
+
307
+ Returns:
308
+ str: Encoded URL with query parameters.
309
+ """
310
+ from urllib.parse import urlencode
311
+
312
+ return f"{url}{urlencode(query_params)}"
313
+
314
+
315
+ # SYSTEM
316
+ def parse_ps_aux(ps_aux_commands: str) -> List[list]:
317
+ """Parses Linux ps aux command output into a list of records.
318
+
319
+ Args:
320
+ ps_aux_commands (str): Linux ps aux command string.
321
+
322
+ Returns:
323
+ List[list]: List of lists, where each inner list represents a process record.
324
+
325
+ Examples:
326
+ >>> # parse_ps_aux("ps aux | egrep -i '%cpu|anaconda3' | head")
327
+ """
328
+ output = subprocess.run(
329
+ ps_aux_commands,
330
+ capture_output=True,
331
+ text=True,
332
+ shell=True,
333
+ executable="/bin/bash",
334
+ )
335
+ lines = output.stdout.split("\n")
336
+ n_columns = len(lines[0].split()) - 1
337
+ rows = [line.split(None, n_columns) for line in lines if line]
338
+ return rows
339
+
340
+
341
+ if __name__ == "__main__":
342
+ import doctest
343
+
344
+ subprocess.run(
345
+ "mkdir -p test_base_folder",
346
+ capture_output=True,
347
+ shell=True,
348
+ text=True,
349
+ executable="/bin/bash",
350
+ )
351
+ subprocess.run(
352
+ "touch test_base_folder/test{1..5}.py",
353
+ capture_output=True,
354
+ shell=True,
355
+ text=True,
356
+ executable="/bin/bash",
357
+ )
358
+ doctest.testmod()
359
+ subprocess.run(
360
+ "rm -rf test_base_folder",
361
+ capture_output=True,
362
+ shell=True,
363
+ text=True,
364
+ executable="/bin/bash",
365
+ )
366
+ subprocess.run(
367
+ "rm test.txt",
368
+ capture_output=True,
369
+ shell=True,
370
+ text=True,
371
+ executable="/bin/bash",
372
+ )
@@ -5,24 +5,21 @@ from loguru import logger
5
5
 
6
6
 
7
7
  def preprocess(html: str) -> Optional[str]:
8
- """
9
- Remove whitespaces and newline characters. Reference: https://stackoverflow.com/questions/23241641/how-to-ignore-empty-lines-while-using-next-sibling-in-beautifulsoup4-in-python
10
-
11
- Parameters
12
- ----------
13
- html : str
14
- html to be cleared
15
-
16
- Examples
17
- --------
18
- >>> a = "<html> <p> Something </p> </html> "
19
- >>> preprocess(a)
20
- '<html><p>Something</p></html>'
21
-
22
- Returns
23
- -------
24
- Optional[str]
25
- cleaned html
8
+ """Removes whitespaces and newline characters from HTML string.
9
+
10
+ Args:
11
+ html (str): HTML string to be cleaned.
12
+
13
+ Returns:
14
+ Optional[str]: Cleaned HTML string with normalized whitespace.
15
+
16
+ Examples:
17
+ >>> a = "<html> <p> Something </p> </html> "
18
+ >>> preprocess(a)
19
+ '<html><p>Something</p></html>'
20
+
21
+ Note:
22
+ Reference: https://stackoverflow.com/questions/23241641
26
23
  """
27
24
 
28
25
  # remove leading and trailing whitespaces
@@ -37,29 +34,24 @@ def preprocess(html: str) -> Optional[str]:
37
34
  return html
38
35
 
39
36
 
40
- def build_soup(url: str, features: str = "lxml", to_preprocess: str = True):
41
- """
42
- Return Beautifulsoup object from given url
43
-
44
- Parameters
45
- ----------
46
- url : str
47
- URL
48
- features : str, optional
49
- parser to use
50
- to_preprocess : str, optional
51
- to preprocess?
52
-
53
- Examples
54
- --------
55
- >>> a = build_soup("https://google.com")
56
- >>> type(a)
57
- <class 'bs4.BeautifulSoup'>
58
-
59
- Returns
60
- -------
61
- Optional[BeautifulSoup]
62
- BeautifulSoup parsed by lxml
37
+ def build_soup(url: str, features: str = "lxml", to_preprocess: bool = True):
38
+ """Creates a BeautifulSoup object from a given URL.
39
+
40
+ Args:
41
+ url (str): URL to fetch and parse.
42
+ features (str, optional): Parser to use. Defaults to "lxml".
43
+ to_preprocess (bool, optional): Whether to preprocess the HTML. Defaults to True.
44
+
45
+ Returns:
46
+ Optional[BeautifulSoup]: Parsed BeautifulSoup object, or None if request fails.
47
+
48
+ Examples:
49
+ >>> a = build_soup("https://google.com")
50
+ >>> type(a)
51
+ <class 'bs4.BeautifulSoup'>
52
+
53
+ Note:
54
+ Requires requests and beautifulsoup4 packages.
63
55
  """
64
56
  import requests
65
57
  from bs4 import BeautifulSoup
@@ -12,34 +12,22 @@ def send_aws_ses_email(
12
12
  ses_client,
13
13
  attachment: str = None,
14
14
  ):
15
- """
16
- Send AWS SES email
17
-
18
- Parameters
19
- ----------
20
- sender : str
21
- sender email
22
- recipient : list
23
- list of recipient emails
24
- subject : str
25
- email subject
26
- body_text : str
27
- email body
28
- body_type : str
29
- email body type
30
- ses_client : _type_
31
- aws ses client
32
- attachment : str, optional
33
- attachment path, by default None
34
-
35
- Returns
36
- -------
37
- dict
38
- aws ses client email response or none
39
-
40
- Reference
41
- ---------
42
- - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ses/client/send_raw_email.html
15
+ """Sends an email using AWS SES service.
16
+
17
+ Args:
18
+ sender (str): Sender's email address.
19
+ recipient (list): List of recipient email addresses.
20
+ subject (str): Email subject line.
21
+ body_text (str): Email body content.
22
+ body_type (str): MIME type of email body (e.g., 'plain', 'html').
23
+ ses_client: AWS SES client instance.
24
+ attachment (str, optional): Path to file to attach. Defaults to None.
25
+
26
+ Returns:
27
+ dict: AWS SES response dictionary if successful, None if failed.
28
+
29
+ Note:
30
+ Reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ses/client/send_raw_email.html
43
31
  """
44
32
  from email.mime.application import MIMEApplication
45
33
  from email.mime.multipart import MIMEMultipart
@@ -87,20 +75,25 @@ def list_s3_bucket_files(
87
75
  bucket: str,
88
76
  to_dateframe: bool = False,
89
77
  ):
90
- """
91
- List s3 bucket files
92
-
93
- Parameters
94
- ----------
95
- bucket : str
96
- bucket name
97
- to_dateframe : bool, optional
98
- to convert to pandas dataframe, by default False
99
-
100
- Returns
101
- -------
102
- list | pandas.DataFrame
103
- default list, pandas.DataFrame if requested
78
+ """Lists all files in an S3 bucket.
79
+
80
+ Args:
81
+ bucket (str): Name of the S3 bucket.
82
+ to_dateframe (bool, optional): Whether to return results as pandas DataFrame. Defaults to False.
83
+
84
+ Returns:
85
+ Union[list, pd.DataFrame]: List of file keys or DataFrame containing file keys.
86
+ If to_dateframe is True, returns DataFrame with 'key' column.
87
+ If to_dateframe is False, returns list of file keys.
88
+
89
+ Examples:
90
+ >>> files = list_s3_bucket_files('my-bucket')
91
+ >>> type(files)
92
+ <class 'list'>
93
+
94
+ >>> df = list_s3_bucket_files('my-bucket', to_dateframe=True)
95
+ >>> type(df)
96
+ <class 'pandas.core.frame.DataFrame'>
104
97
  """
105
98
 
106
99
  import boto3
@@ -5,20 +5,22 @@ from loguru import logger
5
5
 
6
6
 
7
7
  def generate_fernet_key(output_directory: str, output_filename: str) -> bytes:
8
- """
9
- Generate cryptography fernet key
10
-
11
- Parameters
12
- ----------
13
- output_directory : str
14
- Linux directory
15
- output_filename : str
16
- Linux filename
17
-
18
- Returns
19
- -------
20
- bytes
21
- Fernet key in bytes
8
+ """Generates and saves a Fernet encryption key.
9
+
10
+ Args:
11
+ output_directory (str): Directory path where the key file will be saved.
12
+ output_filename (str): Name of the key file to be created.
13
+
14
+ Returns:
15
+ bytes: Generated Fernet key in bytes format.
16
+
17
+ Raises:
18
+ Exception: If key generation or file writing fails.
19
+
20
+ Examples:
21
+ >>> key = generate_fernet_key('/path/to/keys', 'encryption.key')
22
+ >>> isinstance(key, bytes)
23
+ True
22
24
  """
23
25
 
24
26
  key = None
@@ -36,20 +38,22 @@ def generate_fernet_key(output_directory: str, output_filename: str) -> bytes:
36
38
 
37
39
 
38
40
  def encrypt_fernet_file(keypath: str, filepath: str) -> str:
39
- """
40
- Encrypt file
41
-
42
- Parameters
43
- ----------
44
- keypath : str
45
- keypath
46
- filepath : str
47
- File path
48
-
49
- Returns
50
- -------
51
- str
52
- Encrypted data
41
+ """Encrypts a file using Fernet symmetric encryption.
42
+
43
+ Args:
44
+ keypath (str): Path to the Fernet key file.
45
+ filepath (str): Path to the file to be encrypted.
46
+
47
+ Returns:
48
+ str: Encrypted data.
49
+
50
+ Raises:
51
+ TypeError: If keypath or filepath are not strings.
52
+
53
+ Examples:
54
+ >>> encrypted = encrypt_fernet_file('key.txt', 'data.txt')
55
+ >>> isinstance(encrypted, str)
56
+ True
53
57
  """
54
58
  if isinstance(keypath, str) and isinstance(filepath, str):
55
59
  fernet = Fernet(open(keypath, "rb").read())
@@ -61,20 +65,22 @@ def encrypt_fernet_file(keypath: str, filepath: str) -> str:
61
65
 
62
66
 
63
67
  def decrypt_fernet_data(keypath: str, filepath: str) -> str:
64
- """
65
- Decrypt file
66
-
67
- Parameters
68
- ----------
69
- keypath : str
70
- keypath
71
- filepath : str
72
- File path
73
-
74
- Returns
75
- -------
76
- str
77
- Decrypted data
68
+ """Decrypts a file using Fernet symmetric encryption.
69
+
70
+ Args:
71
+ keypath (str): Path to the Fernet key file.
72
+ filepath (str): Path to the encrypted file.
73
+
74
+ Returns:
75
+ str: Decrypted data.
76
+
77
+ Raises:
78
+ TypeError: If keypath or filepath are not strings.
79
+
80
+ Examples:
81
+ >>> decrypted = decrypt_fernet_data('key.txt', 'encrypted_data.txt')
82
+ >>> isinstance(decrypted, str)
83
+ True
78
84
  """
79
85
  if isinstance(keypath, str) and isinstance(filepath, str):
80
86
  fernet = Fernet(open(keypath, "rb").read())