titangpt 0.1.5__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.
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: titangpt
3
+ Version: 0.1.5
4
+ Summary: Official Python client for TitanGPT API
5
+ Home-page: https://github.com/TitanGPT/titangpt
6
+ Author: TitanGPT
7
+ Author-email: info@titangpt.ru
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.7
10
+ Classifier: Programming Language :: Python :: 3.8
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Requires-Python: >=3.7
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: requests>=2.28.0
19
+ Requires-Dist: aiohttp>=3.8.0
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: description-content-type
25
+ Dynamic: home-page
26
+ Dynamic: requires-dist
27
+ Dynamic: requires-python
28
+ Dynamic: summary
29
+
30
+ # TitanGPT.ru Python Client
31
+
32
+ Official Python client for TitanGPT.ru API - OpenAI compatible interface.
@@ -0,0 +1,3 @@
1
+ # TitanGPT.ru Python Client
2
+
3
+ Official Python client for TitanGPT.ru API - OpenAI compatible interface.
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,32 @@
1
+ from setuptools import setup, find_packages
2
+ from pathlib import Path
3
+
4
+ long_description = Path("README.md").read_text(encoding="utf-8")
5
+
6
+ setup(
7
+ name="titangpt",
8
+ version="0.1.5",
9
+ author="TitanGPT",
10
+ author_email="info@titangpt.ru",
11
+ description="Official Python client for TitanGPT API",
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ url="https://github.com/TitanGPT/titangpt",
15
+ packages=find_packages(),
16
+ classifiers=[
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.7",
19
+ "Programming Language :: Python :: 3.8",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ ],
26
+ python_requires=">=3.7",
27
+ install_requires=[
28
+ "requests>=2.28.0",
29
+ "aiohttp>=3.8.0",
30
+ ],
31
+ include_package_data=True,
32
+ )
@@ -0,0 +1,373 @@
1
+ """
2
+ Asynchronous client tests for TitanGPT.
3
+
4
+ This module contains comprehensive tests for the asynchronous client functionality,
5
+ including connection handling, request/response processing, error handling, and
6
+ concurrent operations.
7
+ """
8
+
9
+ import asyncio
10
+ import pytest
11
+ from unittest.mock import AsyncMock, MagicMock, patch
12
+ from typing import Any, Dict, List
13
+
14
+ # Import async client and related components
15
+ # Adjust imports based on your actual project structure
16
+ try:
17
+ from titangpt.async_client import AsyncClient
18
+ from titangpt.exceptions import (
19
+ TitanGPTException,
20
+ ConnectionError as TitanConnectionError,
21
+ TimeoutError as TitanTimeoutError,
22
+ AuthenticationError,
23
+ )
24
+ except ImportError:
25
+ # Fallback for testing structure
26
+ AsyncClient = None
27
+
28
+
29
+ @pytest.mark.asyncio
30
+ class TestAsyncClientInitialization:
31
+ """Tests for AsyncClient initialization and configuration."""
32
+
33
+ @pytest.mark.asyncio
34
+ async def test_client_initialization(self):
35
+ """Test basic client initialization."""
36
+ if AsyncClient is None:
37
+ pytest.skip("AsyncClient not available")
38
+
39
+ client = AsyncClient(api_key="test_key")
40
+ assert client is not None
41
+ await client.close()
42
+
43
+ @pytest.mark.asyncio
44
+ async def test_client_with_custom_config(self):
45
+ """Test client initialization with custom configuration."""
46
+ if AsyncClient is None:
47
+ pytest.skip("AsyncClient not available")
48
+
49
+ config = {
50
+ "timeout": 30,
51
+ "max_retries": 3,
52
+ "base_url": "https://api.example.com",
53
+ }
54
+ client = AsyncClient(api_key="test_key", **config)
55
+ assert client is not None
56
+ await client.close()
57
+
58
+ @pytest.mark.asyncio
59
+ async def test_client_missing_api_key(self):
60
+ """Test client initialization without API key."""
61
+ if AsyncClient is None:
62
+ pytest.skip("AsyncClient not available")
63
+
64
+ with pytest.raises((ValueError, TypeError)):
65
+ AsyncClient()
66
+
67
+
68
+ @pytest.mark.asyncio
69
+ class TestAsyncClientRequests:
70
+ """Tests for async client request handling."""
71
+
72
+ @pytest.fixture
73
+ async def client(self):
74
+ """Provide an async client instance."""
75
+ if AsyncClient is None:
76
+ pytest.skip("AsyncClient not available")
77
+
78
+ client = AsyncClient(api_key="test_key")
79
+ yield client
80
+ await client.close()
81
+
82
+ @pytest.mark.asyncio
83
+ async def test_simple_request(self, client):
84
+ """Test making a simple asynchronous request."""
85
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
86
+ mock_send.return_value = {"status": "success", "data": "test_response"}
87
+
88
+ # Assuming a method like query() exists
89
+ if hasattr(client, 'query'):
90
+ result = await client.query("test prompt")
91
+ assert result is not None
92
+ mock_send.assert_called_once()
93
+
94
+ @pytest.mark.asyncio
95
+ async def test_request_with_parameters(self, client):
96
+ """Test request with multiple parameters."""
97
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
98
+ mock_send.return_value = {"status": "success", "data": "response"}
99
+
100
+ params = {
101
+ "temperature": 0.7,
102
+ "max_tokens": 100,
103
+ "top_p": 0.9,
104
+ }
105
+
106
+ if hasattr(client, 'query'):
107
+ result = await client.query("prompt", **params)
108
+ assert result is not None
109
+
110
+ @pytest.mark.asyncio
111
+ async def test_concurrent_requests(self, client):
112
+ """Test handling multiple concurrent requests."""
113
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
114
+ mock_send.return_value = {"status": "success", "data": "response"}
115
+
116
+ if hasattr(client, 'query'):
117
+ tasks = [
118
+ client.query(f"prompt {i}")
119
+ for i in range(5)
120
+ ]
121
+ results = await asyncio.gather(*tasks)
122
+ assert len(results) == 5
123
+ assert mock_send.call_count == 5
124
+
125
+
126
+ @pytest.mark.asyncio
127
+ class TestAsyncClientErrorHandling:
128
+ """Tests for error handling in async client."""
129
+
130
+ @pytest.fixture
131
+ async def client(self):
132
+ """Provide an async client instance."""
133
+ if AsyncClient is None:
134
+ pytest.skip("AsyncClient not available")
135
+
136
+ client = AsyncClient(api_key="test_key")
137
+ yield client
138
+ await client.close()
139
+
140
+ @pytest.mark.asyncio
141
+ async def test_connection_error_handling(self, client):
142
+ """Test handling of connection errors."""
143
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
144
+ mock_send.side_effect = TitanConnectionError("Connection failed")
145
+
146
+ if hasattr(client, 'query'):
147
+ with pytest.raises((TitanConnectionError, Exception)):
148
+ await client.query("test prompt")
149
+
150
+ @pytest.mark.asyncio
151
+ async def test_timeout_handling(self, client):
152
+ """Test handling of timeout errors."""
153
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
154
+ mock_send.side_effect = TitanTimeoutError("Request timeout")
155
+
156
+ if hasattr(client, 'query'):
157
+ with pytest.raises((TitanTimeoutError, Exception, asyncio.TimeoutError)):
158
+ await client.query("test prompt")
159
+
160
+ @pytest.mark.asyncio
161
+ async def test_authentication_error(self, client):
162
+ """Test handling of authentication errors."""
163
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
164
+ mock_send.side_effect = AuthenticationError("Invalid API key")
165
+
166
+ if hasattr(client, 'query'):
167
+ with pytest.raises((AuthenticationError, Exception)):
168
+ await client.query("test prompt")
169
+
170
+ @pytest.mark.asyncio
171
+ async def test_rate_limit_error(self, client):
172
+ """Test handling of rate limit errors."""
173
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
174
+ mock_send.side_effect = TitanGPTException("Rate limit exceeded")
175
+
176
+ if hasattr(client, 'query'):
177
+ with pytest.raises((TitanGPTException, Exception)):
178
+ await client.query("test prompt")
179
+
180
+ @pytest.mark.asyncio
181
+ async def test_retry_on_failure(self, client):
182
+ """Test retry mechanism on transient failures."""
183
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
184
+ # First call fails, second succeeds
185
+ mock_send.side_effect = [
186
+ TitanTimeoutError("Timeout"),
187
+ {"status": "success", "data": "response"}
188
+ ]
189
+
190
+ if hasattr(client, 'query') and hasattr(client, '_retry'):
191
+ # This assumes the client has retry logic
192
+ try:
193
+ result = await client.query("test prompt")
194
+ assert result is not None
195
+ except Exception:
196
+ pass # Expected if retry not implemented
197
+
198
+
199
+ @pytest.mark.asyncio
200
+ class TestAsyncClientContextManager:
201
+ """Tests for async context manager functionality."""
202
+
203
+ @pytest.mark.asyncio
204
+ async def test_context_manager_usage(self):
205
+ """Test using client as async context manager."""
206
+ if AsyncClient is None:
207
+ pytest.skip("AsyncClient not available")
208
+
209
+ async with AsyncClient(api_key="test_key") as client:
210
+ assert client is not None
211
+
212
+ @pytest.mark.asyncio
213
+ async def test_context_manager_cleanup(self):
214
+ """Test that cleanup happens when exiting context."""
215
+ if AsyncClient is None:
216
+ pytest.skip("AsyncClient not available")
217
+
218
+ with patch('titangpt.async_client.AsyncClient.close', new_callable=AsyncMock) as mock_close:
219
+ try:
220
+ async with AsyncClient(api_key="test_key") as client:
221
+ assert client is not None
222
+ except Exception:
223
+ pass # May fail if __aenter__/__aexit__ not implemented
224
+
225
+ # close() should be called on exit
226
+
227
+
228
+ @pytest.mark.asyncio
229
+ class TestAsyncClientStreaming:
230
+ """Tests for streaming responses in async client."""
231
+
232
+ @pytest.fixture
233
+ async def client(self):
234
+ """Provide an async client instance."""
235
+ if AsyncClient is None:
236
+ pytest.skip("AsyncClient not available")
237
+
238
+ client = AsyncClient(api_key="test_key")
239
+ yield client
240
+ await client.close()
241
+
242
+ @pytest.mark.asyncio
243
+ async def test_stream_response(self, client):
244
+ """Test streaming response handling."""
245
+ if not hasattr(client, 'stream'):
246
+ pytest.skip("Streaming not implemented")
247
+
248
+ async def mock_stream():
249
+ for chunk in ["Hello", " ", "World"]:
250
+ yield chunk
251
+
252
+ with patch.object(client, 'stream', new_callable=AsyncMock) as mock_stream_method:
253
+ mock_stream_method.return_value = mock_stream()
254
+
255
+ chunks = []
256
+ async for chunk in await mock_stream_method("test prompt"):
257
+ chunks.append(chunk)
258
+
259
+ assert len(chunks) > 0
260
+
261
+ @pytest.mark.asyncio
262
+ async def test_stream_with_error(self, client):
263
+ """Test error handling in streaming."""
264
+ if not hasattr(client, 'stream'):
265
+ pytest.skip("Streaming not implemented")
266
+
267
+ async def mock_stream_with_error():
268
+ yield "chunk1"
269
+ raise TitanGPTException("Stream error")
270
+
271
+ with patch.object(client, 'stream', new_callable=AsyncMock) as mock_stream_method:
272
+ mock_stream_method.return_value = mock_stream_with_error()
273
+
274
+ with pytest.raises(TitanGPTException):
275
+ async for chunk in await mock_stream_method("test prompt"):
276
+ pass
277
+
278
+
279
+ @pytest.mark.asyncio
280
+ class TestAsyncClientResourceManagement:
281
+ """Tests for resource management in async client."""
282
+
283
+ @pytest.mark.asyncio
284
+ async def test_connection_pool_management(self):
285
+ """Test that connection pools are properly managed."""
286
+ if AsyncClient is None:
287
+ pytest.skip("AsyncClient not available")
288
+
289
+ client = AsyncClient(api_key="test_key")
290
+
291
+ # Verify client has necessary session management
292
+ assert hasattr(client, 'close') or hasattr(client, '__aexit__')
293
+
294
+ await client.close()
295
+
296
+ @pytest.mark.asyncio
297
+ async def test_multiple_client_instances(self):
298
+ """Test creating multiple independent client instances."""
299
+ if AsyncClient is None:
300
+ pytest.skip("AsyncClient not available")
301
+
302
+ clients = [AsyncClient(api_key=f"key_{i}") for i in range(3)]
303
+
304
+ assert len(clients) == 3
305
+
306
+ for client in clients:
307
+ await client.close()
308
+
309
+ @pytest.mark.asyncio
310
+ async def test_client_reusability(self):
311
+ """Test that a single client can handle multiple requests."""
312
+ if AsyncClient is None:
313
+ pytest.skip("AsyncClient not available")
314
+
315
+ client = AsyncClient(api_key="test_key")
316
+
317
+ with patch.object(client, '_send_request', new_callable=AsyncMock) as mock_send:
318
+ mock_send.return_value = {"status": "success"}
319
+
320
+ if hasattr(client, 'query'):
321
+ for i in range(5):
322
+ try:
323
+ await client.query(f"prompt {i}")
324
+ except Exception:
325
+ pass
326
+
327
+ await client.close()
328
+
329
+
330
+ @pytest.mark.asyncio
331
+ class TestAsyncClientConfiguration:
332
+ """Tests for client configuration and customization."""
333
+
334
+ @pytest.mark.asyncio
335
+ async def test_custom_timeout(self):
336
+ """Test setting custom timeout."""
337
+ if AsyncClient is None:
338
+ pytest.skip("AsyncClient not available")
339
+
340
+ client = AsyncClient(api_key="test_key", timeout=60)
341
+ await client.close()
342
+
343
+ @pytest.mark.asyncio
344
+ async def test_custom_headers(self):
345
+ """Test setting custom headers."""
346
+ if AsyncClient is None:
347
+ pytest.skip("AsyncClient not available")
348
+
349
+ headers = {"X-Custom-Header": "value"}
350
+ client = AsyncClient(api_key="test_key", headers=headers)
351
+ await client.close()
352
+
353
+ @pytest.mark.asyncio
354
+ async def test_proxy_configuration(self):
355
+ """Test proxy configuration."""
356
+ if AsyncClient is None:
357
+ pytest.skip("AsyncClient not available")
358
+
359
+ client = AsyncClient(api_key="test_key", proxy="http://proxy.example.com:8080")
360
+ await client.close()
361
+
362
+
363
+ # Async fixture for pytest-asyncio
364
+ @pytest.fixture
365
+ def event_loop():
366
+ """Create an event loop for async tests."""
367
+ loop = asyncio.get_event_loop_policy().new_event_loop()
368
+ yield loop
369
+ loop.close()
370
+
371
+
372
+ if __name__ == "__main__":
373
+ pytest.main([__file__, "-v"])