lionagi 0.0.209__py3-none-any.whl → 0.0.211__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.
- lionagi/__init__.py +2 -4
- lionagi/api_service/base_endpoint.py +65 -0
- lionagi/api_service/base_rate_limiter.py +121 -0
- lionagi/api_service/base_service.py +146 -0
- lionagi/api_service/chat_completion.py +6 -0
- lionagi/api_service/embeddings.py +6 -0
- lionagi/api_service/payload_package.py +47 -0
- lionagi/api_service/status_tracker.py +29 -0
- lionagi/core/__init__.py +3 -3
- lionagi/core/branch.py +22 -3
- lionagi/core/session.py +14 -2
- lionagi/schema/__init__.py +5 -8
- lionagi/schema/base_schema.py +821 -0
- lionagi/structures/graph.py +1 -1
- lionagi/structures/relationship.py +1 -1
- lionagi/structures/structure.py +1 -1
- lionagi/tools/tool_manager.py +0 -163
- lionagi/tools/tool_util.py +2 -1
- lionagi/utils/__init__.py +5 -6
- lionagi/utils/api_util.py +6 -1
- lionagi/version.py +1 -1
- {lionagi-0.0.209.dist-info → lionagi-0.0.211.dist-info}/METADATA +3 -18
- lionagi-0.0.211.dist-info/RECORD +56 -0
- lionagi/agents/planner.py +0 -1
- lionagi/agents/prompter.py +0 -1
- lionagi/agents/scorer.py +0 -1
- lionagi/agents/summarizer.py +0 -1
- lionagi/agents/validator.py +0 -1
- lionagi/bridge/__init__.py +0 -22
- lionagi/bridge/langchain.py +0 -195
- lionagi/bridge/llama_index.py +0 -266
- lionagi/datastores/__init__.py +0 -1
- lionagi/datastores/chroma.py +0 -1
- lionagi/datastores/deeplake.py +0 -1
- lionagi/datastores/elasticsearch.py +0 -1
- lionagi/datastores/lantern.py +0 -1
- lionagi/datastores/pinecone.py +0 -1
- lionagi/datastores/postgres.py +0 -1
- lionagi/datastores/qdrant.py +0 -1
- lionagi/iservices/anthropic.py +0 -79
- lionagi/iservices/anyscale.py +0 -0
- lionagi/iservices/azure.py +0 -1
- lionagi/iservices/bedrock.py +0 -0
- lionagi/iservices/everlyai.py +0 -0
- lionagi/iservices/gemini.py +0 -0
- lionagi/iservices/gpt4all.py +0 -0
- lionagi/iservices/huggingface.py +0 -0
- lionagi/iservices/litellm.py +0 -33
- lionagi/iservices/localai.py +0 -0
- lionagi/iservices/openllm.py +0 -0
- lionagi/iservices/openrouter.py +0 -44
- lionagi/iservices/perplexity.py +0 -0
- lionagi/iservices/predibase.py +0 -0
- lionagi/iservices/rungpt.py +0 -0
- lionagi/iservices/vllm.py +0 -0
- lionagi/iservices/xinference.py +0 -0
- lionagi/loaders/__init__.py +0 -18
- lionagi/loaders/chunker.py +0 -166
- lionagi/loaders/load_util.py +0 -240
- lionagi/loaders/reader.py +0 -122
- lionagi/models/__init__.py +0 -0
- lionagi/models/base_model.py +0 -0
- lionagi/models/imodel.py +0 -53
- lionagi/parsers/__init__.py +0 -1
- lionagi/schema/async_queue.py +0 -158
- lionagi/schema/base_condition.py +0 -1
- lionagi/schema/base_node.py +0 -422
- lionagi/schema/base_tool.py +0 -44
- lionagi/schema/data_logger.py +0 -131
- lionagi/schema/data_node.py +0 -88
- lionagi/schema/status_tracker.py +0 -37
- lionagi/tests/test_utils/test_encrypt_util.py +0 -323
- lionagi/utils/encrypt_util.py +0 -283
- lionagi-0.0.209.dist-info/RECORD +0 -98
- /lionagi/{agents → api_service}/__init__.py +0 -0
- /lionagi/{iservices → services}/__init__.py +0 -0
- /lionagi/{iservices → services}/base_service.py +0 -0
- /lionagi/{iservices → services}/mistralai.py +0 -0
- /lionagi/{iservices → services}/mlx_service.py +0 -0
- /lionagi/{iservices → services}/oai.py +0 -0
- /lionagi/{iservices → services}/ollama.py +0 -0
- /lionagi/{iservices → services}/services.py +0 -0
- /lionagi/{iservices → services}/transformers.py +0 -0
- {lionagi-0.0.209.dist-info → lionagi-0.0.211.dist-info}/LICENSE +0 -0
- {lionagi-0.0.209.dist-info → lionagi-0.0.211.dist-info}/WHEEL +0 -0
- {lionagi-0.0.209.dist-info → lionagi-0.0.211.dist-info}/top_level.txt +0 -0
lionagi/schema/status_tracker.py
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
from dataclasses import dataclass
|
2
|
-
|
3
|
-
|
4
|
-
# credit to OpenAI for the following object
|
5
|
-
@dataclass
|
6
|
-
class StatusTracker:
|
7
|
-
"""
|
8
|
-
Class for keeping track of various task statuses.
|
9
|
-
|
10
|
-
This class serves as a simple way to monitor different types of task
|
11
|
-
outcomes and errors within a system. It uses dataclasses for easy
|
12
|
-
creation and management of state.
|
13
|
-
|
14
|
-
Attributes:
|
15
|
-
num_tasks_started:
|
16
|
-
The number of tasks that have been initiated.
|
17
|
-
num_tasks_in_progress:
|
18
|
-
The number of tasks currently being processed.
|
19
|
-
num_tasks_succeeded:
|
20
|
-
The number of tasks that have completed successfully.
|
21
|
-
num_tasks_failed:
|
22
|
-
The number of tasks that have failed.
|
23
|
-
num_rate_limit_errors:
|
24
|
-
The number of tasks that failed due to rate limiting.
|
25
|
-
num_api_errors:
|
26
|
-
The number of tasks that failed due to API errors.
|
27
|
-
num_other_errors:
|
28
|
-
The number of tasks that failed due to other errors.
|
29
|
-
"""
|
30
|
-
num_tasks_started: int = 0
|
31
|
-
num_tasks_in_progress: int = 0
|
32
|
-
num_tasks_succeeded: int = 0
|
33
|
-
num_tasks_failed: int = 0
|
34
|
-
num_rate_limit_errors: int = 0
|
35
|
-
num_api_errors: int = 0
|
36
|
-
num_other_errors: int = 0
|
37
|
-
|
@@ -1,323 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
import os
|
3
|
-
import tempfile
|
4
|
-
import zipfile
|
5
|
-
import hashlib
|
6
|
-
from cryptography.fernet import InvalidToken
|
7
|
-
from lionagi.utils.encrypt_util import EncrytionUtil
|
8
|
-
|
9
|
-
|
10
|
-
class TestPasswordStrengthChecker(unittest.TestCase):
|
11
|
-
|
12
|
-
def test_short_passwords(self):
|
13
|
-
self.assertFalse(EncrytionUtil.password_strength_checker("Short1"))
|
14
|
-
self.assertFalse(EncrytionUtil.password_strength_checker("A1"))
|
15
|
-
|
16
|
-
def test_passwords_without_digits(self):
|
17
|
-
self.assertFalse(EncrytionUtil.password_strength_checker("NoDigitsHere"))
|
18
|
-
self.assertFalse(EncrytionUtil.password_strength_checker("Onlyletters!"))
|
19
|
-
|
20
|
-
def test_passwords_without_uppercase(self):
|
21
|
-
self.assertFalse(EncrytionUtil.password_strength_checker("alllowercase1"))
|
22
|
-
self.assertFalse(EncrytionUtil.password_strength_checker("nouppercase1!"))
|
23
|
-
|
24
|
-
def test_strong_passwords(self):
|
25
|
-
self.assertTrue(EncrytionUtil.password_strength_checker("ValidPass1"))
|
26
|
-
self.assertTrue(EncrytionUtil.password_strength_checker("AnotherGood1"))
|
27
|
-
|
28
|
-
|
29
|
-
class TestGenerateEncryptionKey(unittest.TestCase):
|
30
|
-
|
31
|
-
def setUp(self):
|
32
|
-
# Strong password and predefined salt for testing
|
33
|
-
self.strong_password = "StrongPass1"
|
34
|
-
self.salt = b'0123456789abcdef'
|
35
|
-
|
36
|
-
def test_with_strong_password_and_provided_salt(self):
|
37
|
-
key = EncrytionUtil.generate_encryption_key(password=self.strong_password, salt=self.salt)
|
38
|
-
self.assertIsInstance(key, str)
|
39
|
-
|
40
|
-
def test_with_strong_password_and_no_salt(self):
|
41
|
-
key = EncrytionUtil.generate_encryption_key(password=self.strong_password)
|
42
|
-
self.assertIsInstance(key, str)
|
43
|
-
|
44
|
-
def test_with_weak_password(self):
|
45
|
-
with self.assertRaises(ValueError):
|
46
|
-
EncrytionUtil.generate_encryption_key(password="weak")
|
47
|
-
|
48
|
-
def test_with_no_password(self):
|
49
|
-
key = EncrytionUtil.generate_encryption_key()
|
50
|
-
self.assertIsInstance(key, str)
|
51
|
-
self.assertEqual(len(key), 44) # Typical length of a Fernet key
|
52
|
-
|
53
|
-
|
54
|
-
class TestEncrypt(unittest.TestCase):
|
55
|
-
|
56
|
-
def setUp(self):
|
57
|
-
self.valid_key = EncrytionUtil.generate_encryption_key("StrongPass1")
|
58
|
-
self.invalid_key = "invalidkey"
|
59
|
-
self.test_data = "This is a test string."
|
60
|
-
|
61
|
-
def test_valid_encryption(self):
|
62
|
-
encrypted_data = EncrytionUtil.encrypt(self.test_data, self.valid_key)
|
63
|
-
self.assertIsInstance(encrypted_data, str)
|
64
|
-
self.assertNotEqual(encrypted_data, self.test_data)
|
65
|
-
|
66
|
-
def test_with_invalid_key(self):
|
67
|
-
with self.assertRaises(Exception):
|
68
|
-
EncrytionUtil.encrypt(self.test_data, self.invalid_key)
|
69
|
-
|
70
|
-
def test_with_non_string_data(self):
|
71
|
-
with self.assertRaises(AttributeError): # or whichever error is appropriate
|
72
|
-
EncrytionUtil.encrypt(12345, self.valid_key)
|
73
|
-
|
74
|
-
def test_with_empty_string(self):
|
75
|
-
encrypted_data = EncrytionUtil.encrypt("", self.valid_key)
|
76
|
-
self.assertIsInstance(encrypted_data, str)
|
77
|
-
self.assertNotEqual(encrypted_data, "")
|
78
|
-
|
79
|
-
|
80
|
-
class TestDecrypt(unittest.TestCase):
|
81
|
-
|
82
|
-
def setUp(self):
|
83
|
-
self.valid_key = EncrytionUtil.generate_encryption_key("StrongPass1")
|
84
|
-
self.invalid_key = "invalidkey"
|
85
|
-
self.test_data = "This is a test string."
|
86
|
-
self.encrypted_data = EncrytionUtil.encrypt(self.test_data, self.valid_key)
|
87
|
-
|
88
|
-
def test_valid_decryption(self):
|
89
|
-
decrypted_data = EncrytionUtil.decrypt(self.encrypted_data, self.valid_key)
|
90
|
-
self.assertIsInstance(decrypted_data, str)
|
91
|
-
self.assertEqual(decrypted_data, self.test_data)
|
92
|
-
|
93
|
-
def test_decryption_with_invalid_key(self):
|
94
|
-
with self.assertRaises(ValueError):
|
95
|
-
EncrytionUtil.decrypt(self.encrypted_data, self.invalid_key)
|
96
|
-
|
97
|
-
def test_with_non_string_data(self):
|
98
|
-
with self.assertRaises(AttributeError):
|
99
|
-
EncrytionUtil.decrypt(12345, self.valid_key)
|
100
|
-
|
101
|
-
def test_decryption_of_non_encrypted_string(self):
|
102
|
-
with self.assertRaises(InvalidToken):
|
103
|
-
EncrytionUtil.decrypt("plain text", self.valid_key)
|
104
|
-
|
105
|
-
|
106
|
-
class TestEncryptFile(unittest.TestCase):
|
107
|
-
|
108
|
-
def setUp(self):
|
109
|
-
self.valid_key = EncrytionUtil.generate_encryption_key("StrongPass1")
|
110
|
-
# Create a temporary file with some test data
|
111
|
-
self.temp_file = tempfile.NamedTemporaryFile(delete=False)
|
112
|
-
self.temp_file.write(b"This is a test file.")
|
113
|
-
self.temp_file.close()
|
114
|
-
|
115
|
-
def tearDown(self):
|
116
|
-
# Cleanup: Remove temporary files
|
117
|
-
os.remove(self.temp_file.name)
|
118
|
-
if os.path.exists(self.temp_file.name + '.enc'):
|
119
|
-
os.remove(self.temp_file.name + '.enc')
|
120
|
-
|
121
|
-
def test_encrypting_valid_file(self):
|
122
|
-
EncrytionUtil.encrypt_file(self.temp_file.name, self.valid_key)
|
123
|
-
self.assertTrue(os.path.exists(self.temp_file.name + '.enc'))
|
124
|
-
|
125
|
-
def test_with_non_existent_file_path(self):
|
126
|
-
with self.assertRaises(FileNotFoundError):
|
127
|
-
EncrytionUtil.encrypt_file("non_existent_file.txt", self.valid_key)
|
128
|
-
|
129
|
-
|
130
|
-
class TestDecryptFile(unittest.TestCase):
|
131
|
-
|
132
|
-
def setUp(self):
|
133
|
-
self.valid_key = EncrytionUtil.generate_encryption_key("StrongPass1")
|
134
|
-
# Create a temporary file and encrypt it
|
135
|
-
self.temp_file = tempfile.NamedTemporaryFile(delete=False)
|
136
|
-
self.temp_file.write(b"This is a test file.")
|
137
|
-
self.temp_file.close()
|
138
|
-
EncrytionUtil.encrypt_file(self.temp_file.name, self.valid_key)
|
139
|
-
|
140
|
-
def tearDown(self):
|
141
|
-
# Cleanup: Remove temporary files
|
142
|
-
os.remove(self.temp_file.name)
|
143
|
-
if os.path.exists(self.temp_file.name + '.enc'):
|
144
|
-
os.remove(self.temp_file.name + '.enc')
|
145
|
-
decrypted_file_path = self.temp_file.name.replace('.enc', '')
|
146
|
-
if os.path.exists(decrypted_file_path):
|
147
|
-
os.remove(decrypted_file_path)
|
148
|
-
|
149
|
-
def test_decrypting_valid_encrypted_file(self):
|
150
|
-
EncrytionUtil.decrypt_file(self.temp_file.name + '.enc', self.valid_key)
|
151
|
-
decrypted_file_path = self.temp_file.name.replace('.enc', '')
|
152
|
-
self.assertTrue(os.path.exists(decrypted_file_path))
|
153
|
-
|
154
|
-
def test_with_non_existent_encrypted_file_path(self):
|
155
|
-
with self.assertRaises(FileNotFoundError):
|
156
|
-
EncrytionUtil.decrypt_file("non_existent_file.txt.enc", self.valid_key)
|
157
|
-
|
158
|
-
def test_decrypting_with_invalid_key(self):
|
159
|
-
with self.assertRaises(ValueError):
|
160
|
-
EncrytionUtil.decrypt_file(self.temp_file.name + '.enc', 'invalidkey')
|
161
|
-
|
162
|
-
|
163
|
-
class TestIsEncrypted(unittest.TestCase):
|
164
|
-
|
165
|
-
def setUp(self):
|
166
|
-
self.valid_key = EncrytionUtil.generate_encryption_key("StrongPass1")
|
167
|
-
# Create a temporary file and encrypt it
|
168
|
-
self.temp_file = tempfile.NamedTemporaryFile(delete=False)
|
169
|
-
self.temp_file.write(b"This is a test file.")
|
170
|
-
self.temp_file.close()
|
171
|
-
EncrytionUtil.encrypt_file(self.temp_file.name, self.valid_key)
|
172
|
-
|
173
|
-
# Create a non-encrypted temporary file
|
174
|
-
self.non_encrypted_file = tempfile.NamedTemporaryFile(delete=False)
|
175
|
-
self.non_encrypted_file.write(b"This is a non-encrypted test file.")
|
176
|
-
self.non_encrypted_file.close()
|
177
|
-
|
178
|
-
def tearDown(self):
|
179
|
-
# Cleanup: Remove temporary files
|
180
|
-
os.remove(self.temp_file.name)
|
181
|
-
if os.path.exists(self.temp_file.name + '.enc'):
|
182
|
-
os.remove(self.temp_file.name + '.enc')
|
183
|
-
os.remove(self.non_encrypted_file.name)
|
184
|
-
|
185
|
-
def test_with_encrypted_file(self):
|
186
|
-
self.assertTrue(EncrytionUtil.is_encrypted(self.temp_file.name + '.enc', self.valid_key))
|
187
|
-
|
188
|
-
def test_with_non_encrypted_file(self):
|
189
|
-
self.assertFalse(EncrytionUtil.is_encrypted(self.non_encrypted_file.name, self.valid_key))
|
190
|
-
|
191
|
-
|
192
|
-
class TestDecompressFile(unittest.TestCase):
|
193
|
-
|
194
|
-
def setUp(self):
|
195
|
-
# Create a temporary directory
|
196
|
-
self.temp_dir = tempfile.mkdtemp()
|
197
|
-
|
198
|
-
# Create a temporary zip file with some content
|
199
|
-
self.temp_zip_file = os.path.join(self.temp_dir, 'test.zip')
|
200
|
-
with zipfile.ZipFile(self.temp_zip_file, 'w') as zipf:
|
201
|
-
zipf.writestr('test.txt', 'This is a test file.')
|
202
|
-
|
203
|
-
def tearDown(self):
|
204
|
-
# Cleanup: Remove temporary directory and its contents
|
205
|
-
for root, dirs, files in os.walk(self.temp_dir, topdown=False):
|
206
|
-
for name in files:
|
207
|
-
os.remove(os.path.join(root, name))
|
208
|
-
for name in dirs:
|
209
|
-
os.rmdir(os.path.join(root, name))
|
210
|
-
os.rmdir(self.temp_dir)
|
211
|
-
|
212
|
-
def test_decompressing_valid_zip_file(self):
|
213
|
-
EncrytionUtil.decompress_file(self.temp_zip_file, self.temp_dir)
|
214
|
-
self.assertTrue(os.path.exists(os.path.join(self.temp_dir, 'test.txt')))
|
215
|
-
|
216
|
-
def test_with_non_existent_zip_file_path(self):
|
217
|
-
with self.assertRaises(FileNotFoundError):
|
218
|
-
EncrytionUtil.decompress_file("non_existent_file.zip", self.temp_dir)
|
219
|
-
|
220
|
-
def test_with_invalid_zip_file(self):
|
221
|
-
invalid_zip_file = os.path.join(self.temp_dir, 'invalid.zip')
|
222
|
-
with open(invalid_zip_file, 'w') as f:
|
223
|
-
f.write("This is not a zip file.")
|
224
|
-
with self.assertRaises(zipfile.BadZipFile):
|
225
|
-
EncrytionUtil.decompress_file(invalid_zip_file, self.temp_dir)
|
226
|
-
|
227
|
-
|
228
|
-
class TestCompressFile(unittest.TestCase):
|
229
|
-
|
230
|
-
def setUp(self):
|
231
|
-
# Create a temporary file with some test data
|
232
|
-
self.temp_file = tempfile.NamedTemporaryFile(delete=False)
|
233
|
-
self.temp_file.write(b"This is a test file.")
|
234
|
-
self.temp_file.close()
|
235
|
-
|
236
|
-
def tearDown(self):
|
237
|
-
# Cleanup: Remove temporary files
|
238
|
-
os.remove(self.temp_file.name)
|
239
|
-
if os.path.exists(self.temp_file.name + '.zip'):
|
240
|
-
os.remove(self.temp_file.name + '.zip')
|
241
|
-
|
242
|
-
def test_compressing_valid_file(self):
|
243
|
-
EncrytionUtil.compress_file(self.temp_file.name)
|
244
|
-
self.assertTrue(os.path.exists(self.temp_file.name + '.zip'))
|
245
|
-
|
246
|
-
def test_with_non_existent_file_path(self):
|
247
|
-
with self.assertRaises(FileNotFoundError):
|
248
|
-
EncrytionUtil.compress_file("non_existent_file.txt")
|
249
|
-
|
250
|
-
|
251
|
-
class TestBinaryToHex(unittest.TestCase):
|
252
|
-
|
253
|
-
def test_with_valid_binary_data(self):
|
254
|
-
# Test a variety of binary data
|
255
|
-
self.assertEqual(EncrytionUtil.binary_to_hex(b'\x00\x0F'), '000f')
|
256
|
-
self.assertEqual(EncrytionUtil.binary_to_hex(b'hello'), '68656c6c6f')
|
257
|
-
self.assertEqual(EncrytionUtil.binary_to_hex(b'\xff\xfe\xfd\xfc'), 'fffefdfc')
|
258
|
-
|
259
|
-
def test_with_empty_bytes(self):
|
260
|
-
self.assertEqual(EncrytionUtil.binary_to_hex(b''), '')
|
261
|
-
|
262
|
-
|
263
|
-
class TestCreateHash(unittest.TestCase):
|
264
|
-
|
265
|
-
def test_hashing_with_default_algorithm(self):
|
266
|
-
data = "test"
|
267
|
-
expected_hash = hashlib.sha256(data.encode()).hexdigest()
|
268
|
-
self.assertEqual(EncrytionUtil.create_hash(data), expected_hash)
|
269
|
-
|
270
|
-
def test_hashing_with_different_algorithms(self):
|
271
|
-
data = "test"
|
272
|
-
algorithms = ['sha1', 'sha224', 'sha384', 'sha512']
|
273
|
-
for algo in algorithms:
|
274
|
-
with self.subTest(algorithm=algo):
|
275
|
-
expected_hash = hashlib.new(algo, data.encode()).hexdigest()
|
276
|
-
self.assertEqual(EncrytionUtil.create_hash(data, algo), expected_hash)
|
277
|
-
|
278
|
-
def test_with_unsupported_algorithm(self):
|
279
|
-
with self.assertRaises(ValueError):
|
280
|
-
EncrytionUtil.create_hash("test", "unsupported_algo")
|
281
|
-
|
282
|
-
|
283
|
-
class TestDecodeBase64(unittest.TestCase):
|
284
|
-
|
285
|
-
def test_with_valid_base64_encoded_strings(self):
|
286
|
-
# Test a variety of valid base64 encoded strings
|
287
|
-
test_cases = [
|
288
|
-
("SGVsbG8sIFdvcmxkIQ==", "Hello, World!"),
|
289
|
-
("VGhpcyBpcyBhIHRlc3Q=", "This is a test"),
|
290
|
-
("c29tZSBieXRlcw==", "some bytes")
|
291
|
-
]
|
292
|
-
for encoded, original in test_cases:
|
293
|
-
with self.subTest(encoded=encoded):
|
294
|
-
self.assertEqual(EncrytionUtil.decode_base64(encoded), original)
|
295
|
-
|
296
|
-
def test_with_invalid_base64_string(self):
|
297
|
-
invalid_data = "This is not base64!"
|
298
|
-
with self.assertRaises(Exception): # Replace Exception with the specific exception if known
|
299
|
-
EncrytionUtil.decode_base64(invalid_data)
|
300
|
-
|
301
|
-
def test_with_empty_string(self):
|
302
|
-
self.assertEqual(EncrytionUtil.decode_base64(""), "")
|
303
|
-
|
304
|
-
|
305
|
-
class TestEncodeBase64(unittest.TestCase):
|
306
|
-
|
307
|
-
def test_with_valid_strings(self):
|
308
|
-
# Test a variety of strings
|
309
|
-
test_cases = [
|
310
|
-
("Hello, World!", "SGVsbG8sIFdvcmxkIQ=="),
|
311
|
-
("This is a test", "VGhpcyBpcyBhIHRlc3Q="),
|
312
|
-
("some bytes", "c29tZSBieXRlcw==")
|
313
|
-
]
|
314
|
-
for original, encoded in test_cases:
|
315
|
-
with self.subTest(original=original):
|
316
|
-
self.assertEqual(EncrytionUtil.encode_base64(original), encoded)
|
317
|
-
|
318
|
-
def test_with_empty_string(self):
|
319
|
-
self.assertEqual(EncrytionUtil.encode_base64(""), "")
|
320
|
-
|
321
|
-
|
322
|
-
if __name__ == '__main__':
|
323
|
-
unittest.main()
|
lionagi/utils/encrypt_util.py
DELETED
@@ -1,283 +0,0 @@
|
|
1
|
-
import base64
|
2
|
-
import binascii
|
3
|
-
import hashlib
|
4
|
-
import os
|
5
|
-
import zipfile
|
6
|
-
from base64 import urlsafe_b64encode
|
7
|
-
from cryptography.fernet import Fernet, InvalidToken
|
8
|
-
from cryptography.hazmat.backends import default_backend
|
9
|
-
from cryptography.hazmat.primitives import hashes
|
10
|
-
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
11
|
-
from typing import Optional
|
12
|
-
|
13
|
-
|
14
|
-
class EncrytionUtil:
|
15
|
-
"""
|
16
|
-
A utility class for handling encryption, decryption, file operations, and password strength checking.
|
17
|
-
"""
|
18
|
-
|
19
|
-
@staticmethod
|
20
|
-
def password_strength_checker(password: str) -> bool:
|
21
|
-
"""
|
22
|
-
Check the strength of a password.
|
23
|
-
|
24
|
-
Args:
|
25
|
-
password (str): The password to check.
|
26
|
-
|
27
|
-
Returns:
|
28
|
-
bool: True if the password is strong, False otherwise.
|
29
|
-
|
30
|
-
Examples:
|
31
|
-
>>> password_strength_checker("Weakpass")
|
32
|
-
False
|
33
|
-
>>> password_strength_checker("Strongpass1")
|
34
|
-
True
|
35
|
-
"""
|
36
|
-
if len(password) < 8 or not any(char.isdigit() for char in password) or not any(char.isupper() for char in password):
|
37
|
-
return False
|
38
|
-
return True
|
39
|
-
|
40
|
-
@staticmethod
|
41
|
-
def generate_encryption_key(password: Optional[str] = None, salt: Optional[bytes] = None) -> str:
|
42
|
-
"""
|
43
|
-
Generate an encryption key from a password and salt.
|
44
|
-
|
45
|
-
Args:
|
46
|
-
password (Optional[str]): The password to derive the key from. If None, a random key is generated.
|
47
|
-
salt (Optional[bytes]): A salt for the key derivation. If None, a random salt is used.
|
48
|
-
|
49
|
-
Returns:
|
50
|
-
str: The generated encryption key as a URL-safe base64-encoded string.
|
51
|
-
|
52
|
-
Raises:
|
53
|
-
ValueError: If the password is too weak.
|
54
|
-
|
55
|
-
Examples:
|
56
|
-
>>> key = generate_encryption_key("Strongpass1")
|
57
|
-
>>> isinstance(key, str)
|
58
|
-
True
|
59
|
-
"""
|
60
|
-
if password:
|
61
|
-
if not EncrytionUtil.password_strength_checker(password):
|
62
|
-
raise ValueError("Password is too weak.")
|
63
|
-
if not salt:
|
64
|
-
salt = os.urandom(16)
|
65
|
-
kdf = PBKDF2HMAC(
|
66
|
-
algorithm=hashes.SHA256(),
|
67
|
-
length=32,
|
68
|
-
salt=salt,
|
69
|
-
iterations=100000,
|
70
|
-
backend=default_backend()
|
71
|
-
)
|
72
|
-
key = kdf.derive(password.encode())
|
73
|
-
return urlsafe_b64encode(key).decode()
|
74
|
-
else:
|
75
|
-
return Fernet.generate_key().decode()
|
76
|
-
|
77
|
-
@staticmethod
|
78
|
-
def encrypt(data: str, key: str) -> str:
|
79
|
-
"""
|
80
|
-
Encrypt the provided data using the provided key.
|
81
|
-
|
82
|
-
Args:
|
83
|
-
data (str): The data to encrypt.
|
84
|
-
key (str): The encryption key.
|
85
|
-
|
86
|
-
Returns:
|
87
|
-
str: The encrypted data.
|
88
|
-
|
89
|
-
Example:
|
90
|
-
>>> encrypt("This is some test data.", "esvCExTuhddRb8kSobU_gnNRYObyTRTI2LJF4nYai5I=")
|
91
|
-
'gAAAAABloX9m_S_G1VUtbfGUDB7ooHJNt8sPiSCwnp1ehe6dExvMEqtw_ua2ELk_uUbLoB6a1XkbKLOkM4UBvwmk6sMoY-yNvE-Lv-w-VNnfzf89zH82rgI='
|
92
|
-
"""
|
93
|
-
fernet = Fernet(key.encode())
|
94
|
-
return fernet.encrypt(data.encode()).decode()
|
95
|
-
|
96
|
-
@staticmethod
|
97
|
-
def decrypt(data: str, key: str) -> str:
|
98
|
-
"""
|
99
|
-
Decrypt the provided data using the provided key.
|
100
|
-
|
101
|
-
Args:
|
102
|
-
data (str): The data to decrypt.
|
103
|
-
key (str): The encryption key.
|
104
|
-
|
105
|
-
Returns:
|
106
|
-
str: The decrypted data.
|
107
|
-
|
108
|
-
Example:
|
109
|
-
>>> decrypt('gAAAAABloX9m_S_G1VUtbfGUDB7ooHJNt8sPiSCwnp1ehe6dExvMEqtw_ua2ELk_uUbLoB6a1XkbKLOkM4UBvwmk6sMoY-yNvE-Lv-w-VNnfzf89zH82rgI=', "esvCExTuhddRb8kSobU_gnNRYObyTRTI2LJF4nYai5I=")
|
110
|
-
'This is some test data.'
|
111
|
-
"""
|
112
|
-
fernet = Fernet(key.encode())
|
113
|
-
return fernet.decrypt(data.encode()).decode()
|
114
|
-
|
115
|
-
@staticmethod
|
116
|
-
def encrypt_file(file_path: str, key: str, output_path: str = None):
|
117
|
-
"""
|
118
|
-
Encrypt a file.
|
119
|
-
|
120
|
-
Args:
|
121
|
-
file_path (str): The path of the file to encrypt.
|
122
|
-
key (str): The encryption key.
|
123
|
-
output_path (str, optional): The path to save the encrypted file. If not provided, '.enc' is appended to the input file path.
|
124
|
-
|
125
|
-
Example:
|
126
|
-
>>> encrypt_file("test_file.txt", "esvCExTuhddRb8kSobU_gnNRYObyTRTI2LJF4nYai5I=")
|
127
|
-
"""
|
128
|
-
if not output_path:
|
129
|
-
output_path = file_path + '.enc'
|
130
|
-
with open(file_path, 'rb') as file_to_encrypt:
|
131
|
-
encrypted_data = EncrytionUtil.encrypt(file_to_encrypt.read().decode(), key)
|
132
|
-
with open(output_path, 'wb') as encrypted_file:
|
133
|
-
encrypted_file.write(encrypted_data.encode())
|
134
|
-
|
135
|
-
@staticmethod
|
136
|
-
def decrypt_file(encrypted_file_path: str, key: str, output_path: str = None):
|
137
|
-
"""
|
138
|
-
Decrypt a file.
|
139
|
-
|
140
|
-
Args:
|
141
|
-
encrypted_file_path (str): The path of the file to decrypt.
|
142
|
-
key (str): The encryption key.
|
143
|
-
output_path (str, optional): The path to save the decrypted file. If not provided, '.enc' is removed from the input file path.
|
144
|
-
|
145
|
-
Example:
|
146
|
-
>>> decrypt_file("test_file.txt.enc", "esvCExTuhddRb8kSobU_gnNRYObyTRTI2LJF4nYai5I=")
|
147
|
-
"""
|
148
|
-
if not output_path:
|
149
|
-
output_path = encrypted_file_path.replace('.enc', '')
|
150
|
-
with open(encrypted_file_path, 'rb') as encrypted_file:
|
151
|
-
decrypted_data = EncrytionUtil.decrypt(encrypted_file.read().decode(), key)
|
152
|
-
with open(output_path, 'wb') as decrypted_file:
|
153
|
-
decrypted_file.write(decrypted_data.encode())
|
154
|
-
|
155
|
-
@staticmethod
|
156
|
-
def is_encrypted(file_path: str, key: str) -> bool:
|
157
|
-
"""
|
158
|
-
Check if a file is encrypted.
|
159
|
-
|
160
|
-
Args:
|
161
|
-
file_path (str): The path of the file to check.
|
162
|
-
key (str): The encryption key.
|
163
|
-
|
164
|
-
Returns:
|
165
|
-
bool: True if the file is encrypted, False otherwise.
|
166
|
-
|
167
|
-
Example:
|
168
|
-
>>> is_encrypted("test_file.txt.enc", "esvCExTuhddRb8kSobU_gnNRYObyTRTI2LJF4nYai5I=")
|
169
|
-
True
|
170
|
-
"""
|
171
|
-
try:
|
172
|
-
EncrytionUtil.decrypt_file(file_path, key, "temp_decrypted_file")
|
173
|
-
os.remove("temp_decrypted_file")
|
174
|
-
return True
|
175
|
-
except InvalidToken:
|
176
|
-
return False
|
177
|
-
|
178
|
-
@staticmethod
|
179
|
-
def decompress_file(file_path: str, output_path: str = None):
|
180
|
-
"""
|
181
|
-
Decompress a file.
|
182
|
-
|
183
|
-
Args:
|
184
|
-
file_path (str): The path of the file to decompress.
|
185
|
-
output_path (str, optional): The path to save the decompressed file. If not provided, the file is decompressed in the same directory.
|
186
|
-
|
187
|
-
Example:
|
188
|
-
>>> decompress_file("test_file.txt.zip")
|
189
|
-
"""
|
190
|
-
if not output_path:
|
191
|
-
output_path = os.path.dirname(file_path)
|
192
|
-
with zipfile.ZipFile(file_path, 'r') as zipf:
|
193
|
-
zipf.extractall(output_path)
|
194
|
-
|
195
|
-
@staticmethod
|
196
|
-
def compress_file(file_path: str, output_path: str = None):
|
197
|
-
"""
|
198
|
-
Compress a file.
|
199
|
-
|
200
|
-
Args:
|
201
|
-
file_path (str): The path of the file to compress.
|
202
|
-
output_path (str, optional): The path to save the compressed file. If not provided, '.zip' is appended to the input file path.
|
203
|
-
|
204
|
-
Example:
|
205
|
-
>>> compress_file("test_file.txt")
|
206
|
-
"""
|
207
|
-
if not output_path:
|
208
|
-
output_path = file_path + '.zip'
|
209
|
-
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
210
|
-
zipf.write(file_path)
|
211
|
-
|
212
|
-
@staticmethod
|
213
|
-
def binary_to_hex(data: bytes) -> str:
|
214
|
-
"""
|
215
|
-
Convert binary data to a hexadecimal string representation.
|
216
|
-
|
217
|
-
Args:
|
218
|
-
data: A bytes object containing binary data.
|
219
|
-
|
220
|
-
Returns:
|
221
|
-
A string containing the hexadecimal representation of the binary data.
|
222
|
-
|
223
|
-
Examples:
|
224
|
-
>>> binary_to_hex(b'\x00\x0F')
|
225
|
-
'000f'
|
226
|
-
>>> binary_to_hex(b'hello')
|
227
|
-
'68656c6c6f'
|
228
|
-
"""
|
229
|
-
return binascii.hexlify(data).decode()
|
230
|
-
|
231
|
-
@staticmethod
|
232
|
-
def create_hash(data: str, algorithm: str = 'sha256') -> str:
|
233
|
-
"""
|
234
|
-
Create a hash of the given data using the specified algorithm.
|
235
|
-
|
236
|
-
Args:
|
237
|
-
data: The string to hash.
|
238
|
-
algorithm: The hashing algorithm to use (default is 'sha256').
|
239
|
-
|
240
|
-
Returns:
|
241
|
-
The hexadecimal digest of the hash.
|
242
|
-
|
243
|
-
Examples:
|
244
|
-
>>> create_hash('hello')
|
245
|
-
'2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
|
246
|
-
"""
|
247
|
-
hasher = hashlib.new(algorithm)
|
248
|
-
hasher.update(data.encode())
|
249
|
-
return hasher.hexdigest()
|
250
|
-
|
251
|
-
@staticmethod
|
252
|
-
def decode_base64(data: str) -> str:
|
253
|
-
"""
|
254
|
-
Decode a base64 encoded string.
|
255
|
-
|
256
|
-
Args:
|
257
|
-
data: A base64 encoded string.
|
258
|
-
|
259
|
-
Returns:
|
260
|
-
A decoded string.
|
261
|
-
|
262
|
-
Examples:
|
263
|
-
>>> decode_base64('SGVsbG8sIFdvcmxkIQ==')
|
264
|
-
'Hello, World!'
|
265
|
-
"""
|
266
|
-
return base64.b64decode(data).decode()
|
267
|
-
|
268
|
-
@staticmethod
|
269
|
-
def encode_base64(data: str) -> str:
|
270
|
-
"""
|
271
|
-
Encode a string using base64 encoding.
|
272
|
-
|
273
|
-
Args:
|
274
|
-
data: A string to be encoded.
|
275
|
-
|
276
|
-
Returns:
|
277
|
-
A base64 encoded string.
|
278
|
-
|
279
|
-
Examples:
|
280
|
-
>>> encode_base64("Hello, World!")
|
281
|
-
'SGVsbG8sIFdvcmxkIQ=='
|
282
|
-
"""
|
283
|
-
return base64.b64encode(data.encode()).decode()
|