sentor-ml 1.2.0__py3-none-any.whl → 1.3.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.
sentor/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
- from .client import SentorClient
2
-
3
- __all__ = ["SentorClient"]
1
+ from .client import SentorClient
2
+
3
+ __all__ = ["SentorClient"]
sentor/client.py CHANGED
@@ -1,86 +1,96 @@
1
- import requests
2
- from .exceptions import SentorAPIError, RateLimitError, AuthenticationError
3
- from typing import TypedDict, List
4
-
5
-
6
- class DocumentInput(TypedDict):
7
- """Represents a document to be analyzed with its metadata."""
8
-
9
- doc_id: str
10
- doc: str
11
- entities: List[str]
12
-
13
-
14
- class SentorClient:
15
- """Client for interacting with the Sentor ML API."""
16
-
17
- def __init__(
18
- self,
19
- api_key: str,
20
- base_url: str = "https://sentor.app/api",
21
- timeout: int = 30,
22
- ):
23
- """
24
- Initialize the Sentor client with API credentials and configuration.
25
- """
26
- self.api_key = api_key
27
- self.base_url = base_url
28
- self.timeout = timeout
29
- self.headers = {
30
- "x-api-key": self.api_key,
31
- "Content-Type": "application/json",
32
- }
33
-
34
- def analyze(self, documents: List[DocumentInput]):
35
- """Analyze documents for sentiment and entity extraction.
36
-
37
- Args:
38
- documents: List of documents to analyze
39
-
40
- Returns:
41
- dict: Analysis results
42
-
43
- Raises:
44
- ValueError: If input is empty
45
- RateLimitError: If API rate limit is exceeded
46
- AuthenticationError: If API key is invalid
47
- SentorAPIError: For other API errors
48
- """
49
- if not documents:
50
- raise ValueError("Input is required")
51
-
52
- url = f"{self.base_url}/predicts"
53
- payload = {"docs": documents}
54
- response = requests.post(
55
- url, json=payload, headers=self.headers, timeout=self.timeout
56
- )
57
-
58
- if response.status_code == 200 or response.status_code == 201:
59
- return response.json()
60
- elif response.status_code == 429:
61
- raise RateLimitError(response.json())
62
- elif response.status_code == 401:
63
- raise AuthenticationError(response.json())
64
- else:
65
- raise SentorAPIError(response.json())
66
-
67
- def check_health(self):
68
- """Check the health status of the Sentor API.
69
-
70
- Returns:
71
- dict: Health status information
72
-
73
- Raises:
74
- SentorAPIError: If health check fails
75
- """
76
- url = f"{self.base_url}/predicts/health"
77
- response = requests.get(
78
- url,
79
- headers=self.headers,
80
- timeout=self.timeout,
81
- )
82
-
83
- if response.status_code == 200:
84
- return response.json()
85
- else:
86
- raise SentorAPIError(response.json())
1
+ import requests
2
+ from .exceptions import SentorAPIError, RateLimitError, AuthenticationError
3
+ from typing import TypedDict, List
4
+
5
+
6
+ class DocumentInput(TypedDict):
7
+ """Represents a document to be predicted with its metadata."""
8
+
9
+ doc_id: str
10
+ doc: str
11
+ entities: List[str]
12
+
13
+
14
+ class SentorClient:
15
+ """Client for interacting with the Sentor ML API."""
16
+
17
+ def __init__(
18
+ self,
19
+ api_key: str,
20
+ base_url: str = "https://sentor.app/api",
21
+ timeout: int = 30,
22
+ ):
23
+ """
24
+ Initialize the Sentor client with API credentials and configuration.
25
+ """
26
+ self.api_key = api_key
27
+ self.base_url = base_url
28
+ self.timeout = timeout
29
+ self.headers = {
30
+ "x-api-key": self.api_key,
31
+ "Content-Type": "application/json",
32
+ }
33
+
34
+ def predict(self, documents: List[DocumentInput], language: str = "en"):
35
+ """Predict sentiment and entity extraction for documents.
36
+
37
+ Args:
38
+ documents: List of documents to predict
39
+ language: Language code for prediction (default: "en").
40
+ Supported languages: "en", "nl"
41
+
42
+ Returns:
43
+ dict: Prediction results
44
+
45
+ Raises:
46
+ ValueError: If input is empty or invalid language is provided
47
+ RateLimitError: If API rate limit is exceeded
48
+ AuthenticationError: If API key is invalid
49
+ SentorAPIError: For other API errors
50
+ """
51
+ if not documents:
52
+ raise ValueError("Input is required")
53
+
54
+ if language not in ["en", "nl"]:
55
+ raise ValueError("Language must be 'en' or 'nl'")
56
+
57
+ url = f"{self.base_url}/predicts"
58
+ params = {"language": language}
59
+ payload = {"docs": documents}
60
+ response = requests.post(
61
+ url,
62
+ json=payload,
63
+ headers=self.headers,
64
+ timeout=self.timeout,
65
+ params=params,
66
+ )
67
+
68
+ if response.status_code == 200 or response.status_code == 201:
69
+ return response.json()
70
+ elif response.status_code == 429:
71
+ raise RateLimitError(response.json())
72
+ elif response.status_code == 401:
73
+ raise AuthenticationError(response.json())
74
+ else:
75
+ raise SentorAPIError(response.json())
76
+
77
+ def check_health(self):
78
+ """Check the health status of the Sentor API.
79
+
80
+ Returns:
81
+ dict: Health status information
82
+
83
+ Raises:
84
+ SentorAPIError: If health check fails
85
+ """
86
+ url = f"{self.base_url}/predicts/health"
87
+ response = requests.get(
88
+ url,
89
+ headers=self.headers,
90
+ timeout=self.timeout,
91
+ )
92
+
93
+ if response.status_code == 200:
94
+ return response.json()
95
+ else:
96
+ raise SentorAPIError(response.json())
sentor/exceptions.py CHANGED
@@ -1,21 +1,21 @@
1
- class SentorAPIError(Exception):
2
- """Base exception for all Sentor API errors."""
3
-
4
- def __init__(self, response):
5
- self.message = response.get("detail", "An error occurred")
6
- self.code = response.get("status_code", "unknown")
7
- super().__init__(self.message)
8
-
9
-
10
- class RateLimitError(SentorAPIError):
11
- """Exception raised when API rate limit is exceeded."""
12
-
13
- def __init__(self, response):
14
- super().__init__(response)
15
- self.retry_after = response.get("retry_after", 60)
16
-
17
-
18
- class AuthenticationError(SentorAPIError):
19
- """Exception raised when API authentication fails."""
20
-
21
- pass
1
+ class SentorAPIError(Exception):
2
+ """Base exception for all Sentor API errors."""
3
+
4
+ def __init__(self, response):
5
+ self.message = response.get("detail", "An error occurred")
6
+ self.code = response.get("status_code", "unknown")
7
+ super().__init__(self.message)
8
+
9
+
10
+ class RateLimitError(SentorAPIError):
11
+ """Exception raised when API rate limit is exceeded."""
12
+
13
+ def __init__(self, response):
14
+ super().__init__(response)
15
+ self.retry_after = response.get("retry_after", 60)
16
+
17
+
18
+ class AuthenticationError(SentorAPIError):
19
+ """Exception raised when API authentication fails."""
20
+
21
+ pass
@@ -1,209 +1,232 @@
1
- Metadata-Version: 2.4
2
- Name: sentor-ml
3
- Version: 1.2.0
4
- Summary: A Python SDK for interacting with the Sentor ML API for sentiment analysis
5
- Home-page: https://github.com/NIKX-Tech/sentor-ml-python-sdk
6
- Author: NIKX Technologies
7
- Author-email: sentor@nikx.one
8
- Classifier: Development Status :: 4 - Beta
9
- Classifier: Intended Audience :: Developers
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Operating System :: OS Independent
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.7
14
- Classifier: Programming Language :: Python :: 3.8
15
- Classifier: Programming Language :: Python :: 3.9
16
- Classifier: Programming Language :: Python :: 3.10
17
- Classifier: Programming Language :: Python :: 3.11
18
- Requires-Python: >=3.7
19
- Description-Content-Type: text/markdown
20
- Requires-Dist: requests>=2.28.0
21
- Dynamic: author
22
- Dynamic: author-email
23
- Dynamic: classifier
24
- Dynamic: description
25
- Dynamic: description-content-type
26
- Dynamic: home-page
27
- Dynamic: requires-dist
28
- Dynamic: requires-python
29
- Dynamic: summary
30
-
31
- # Sentor Python SDK
32
-
33
- A Python SDK for interacting with the Sentor ML API for sentiment analysis. This SDK provides a simple and intuitive interface for sentiment analysis operations.
34
-
35
- ## Features
36
-
37
- - 🚀 Python 3.7+ support
38
- - ⚡ Simple and intuitive API
39
- - 🌍 Support for multiple languages
40
- - 📦 Batch processing capabilities
41
- - 🛡️ Comprehensive error handling
42
- - 🔄 Real-time sentiment analysis
43
-
44
- ## Installation
45
-
46
- ```bash
47
- pip install sentor-ml
48
- ```
49
-
50
- ### Work like a PRO
51
-
52
- 1. Go to [Sentor ML API](https://sentor.app/api)
53
- 2. Subscribe to the Starter plan
54
- 3. Get your API key
55
-
56
- ## Usage
57
-
58
- ### Basic Usage
59
-
60
- ```python
61
- from sentor import SentorClient
62
-
63
- # Initialize the client
64
- client = SentorClient('your-api-key')
65
-
66
- # Analyze sentiment
67
- input_data = [
68
- {
69
- "doc": "In the competitive landscape of consumer electronics, Apple and Samsung continue to lead the market with innovative products and strong brand loyalty. While Apple focuses on a tightly integrated ecosystem with devices like the iPhone, iPad, and Mac, Samsung excels in offering a wide range of options across various price points, especially in its Galaxy smartphone lineup. Both companies push the boundaries of technology, from cutting-edge chipsets to advanced camera systems, often setting industry trends that others follow.",
70
- "doc_id": "0",
71
- "entities": [
72
- "Apple",
73
- "Samsung",
74
- "camera"
75
- ]
76
- },
77
- {
78
- "doc": "Apple's new iPhone is amazing!",
79
- "doc_id": "1",
80
- "entities": [
81
- "Apple",
82
- "iPhone"
83
- ]
84
- },
85
- {
86
- "doc": "Samsung's new phone is amazing!",
87
- "doc_id": "2",
88
- "entities": [
89
- "Samsung",
90
- "phone"
91
- ]
92
- }
93
- ]
94
- result = client.analyze(input_data)
95
- print(result)
96
- ```
97
-
98
- ### Sample Output
99
-
100
- ```json
101
- {
102
- "results": [
103
- {
104
- "doc_id": "0",
105
- "predicted_class": 2,
106
- "predicted_label": "positive",
107
- "probabilities": {
108
- "negative": 0.00007679959526285529,
109
- "neutral": 0.0002924697764683515,
110
- "positive": 0.9996306896209717
111
- },
112
- "details": [
113
- {
114
- "sentence_index": 0,
115
- "sentence_text": "In the competitive landscape of consumer electronics, Apple and Samsung continue to lead the market with innovative products and strong brand loyalty.",
116
- "predicted_class": 2,
117
- "predicted_label": "positive",
118
- "probabilities": {
119
- "negative": 0.00009389198385179043,
120
- "neutral": 0.00032428017584607005,
121
- "positive": 0.9995818734169006
122
- }
123
- },
124
- {
125
- "sentence_index": 1,
126
- "sentence_text": "While Apple focuses on a tightly integrated ecosystem with devices like the iPhone, iPad, and Mac, Samsung excels in offering a wide range of options across various price points, especially in its Galaxy smartphone lineup.",
127
- "predicted_class": 2,
128
- "predicted_label": "positive",
129
- "probabilities": {
130
- "negative": 0.00005746580063714646,
131
- "neutral": 0.00012963586777914315,
132
- "positive": 0.99981290102005
133
- }
134
- },
135
- {
136
- "sentence_index": 2,
137
- "sentence_text": "Both companies push the boundaries of technology, from cutting-edge chipsets to advanced camera systems, often setting industry trends that others follow.",
138
- "predicted_class": 2,
139
- "predicted_label": "positive",
140
- "probabilities": {
141
- "negative": 0.00006366783054545522,
142
- "neutral": 0.00044553453335538507,
143
- "positive": 0.9994907379150391
144
- }
145
- }
146
- ]
147
- },
148
- {
149
- "doc_id": "1",
150
- "predicted_class": 2,
151
- "predicted_label": "positive",
152
- "probabilities": {
153
- "negative": 0.00010637375817168504,
154
- "neutral": 0.0002509312762413174,
155
- "positive": 0.9996427297592163
156
- },
157
- "details": [
158
- {
159
- "sentence_index": 0,
160
- "sentence_text": "Apple's new iPhone is amazing!",
161
- "predicted_class": 2,
162
- "predicted_label": "positive",
163
- "probabilities": {
164
- "negative": 0.00010637375817168504,
165
- "neutral": 0.0002509312762413174,
166
- "positive": 0.9996427297592163
167
- }
168
- }
169
- ]
170
- },
171
- {
172
- "doc_id": "2",
173
- "predicted_class": 2,
174
- "predicted_label": "positive",
175
- "probabilities": {
176
- "negative": 0.00010637375817168504,
177
- "neutral": 0.0002509312762413174,
178
- "positive": 0.9996427297592163
179
- },
180
- "details": [
181
- {
182
- "sentence_index": 0,
183
- "sentence_text": "Samsung's new phone is amazing!",
184
- "predicted_class": 2,
185
- "predicted_label": "positive",
186
- "probabilities": {
187
- "negative": 0.00010637375817168504,
188
- "neutral": 0.0002509312762413174,
189
- "positive": 0.9996427297592163
190
- }
191
- }
192
- ]
193
- }
194
- ]
195
- }
196
- ```
197
-
198
- ## API Reference
199
-
200
- Please refer to the [Sentor ML API Documentation](https://sentor.app/docs) for more details.
201
- You can also try the API in the [Sentor ML API Swagger Playground](https://sentor.app/docs).
202
-
203
- ## Contributing
204
-
205
- Contributions are welcome! Please feel free to submit a Pull Request.
206
-
207
- ## License
208
-
209
- MIT License - see the [LICENSE](LICENSE) file for details.
1
+ Metadata-Version: 2.4
2
+ Name: sentor-ml
3
+ Version: 1.3.0
4
+ Summary: A Python SDK for interacting with the Sentor ML API for sentiment analysis
5
+ Home-page: https://github.com/NIKX-Tech/sentor-ml-python-sdk
6
+ Author: NIKX Technologies
7
+ Author-email: sentor@nikx.one
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.7
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Requires-Python: >=3.7
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: requests>=2.28.0
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ # Sentor Python SDK
32
+
33
+ A Python SDK for interacting with the Sentor ML API for sentiment analysis. This SDK provides a simple and intuitive interface for sentiment analysis operations.
34
+
35
+ ## Features
36
+
37
+ - 🚀 Python 3.7+ support
38
+ - ⚡ Simple and intuitive API
39
+ - 🌍 Multi-language support (English and Dutch)
40
+ - 📦 Batch processing capabilities
41
+ - 🛡️ Comprehensive error handling
42
+ - 🔄 Real-time sentiment analysis
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install sentor-ml
48
+ ```
49
+
50
+ ### Work like a PRO
51
+
52
+ 1. Go to [Sentor ML API](https://sentor.app/api)
53
+ 2. Subscribe to the Starter plan
54
+ 3. Get your API key
55
+
56
+ ## Usage
57
+
58
+ ### Basic Usage
59
+
60
+ ```python
61
+ from sentor import SentorClient
62
+
63
+ # Initialize the client
64
+ client = SentorClient('your-api-key')
65
+
66
+ # Predict sentiment
67
+ input_data = [
68
+ {
69
+ "doc": "In the competitive landscape of consumer electronics, Apple and Samsung continue to lead the market with innovative products and strong brand loyalty. While Apple focuses on a tightly integrated ecosystem with devices like the iPhone, iPad, and Mac, Samsung excels in offering a wide range of options across various price points, especially in its Galaxy smartphone lineup. Both companies push the boundaries of technology, from cutting-edge chipsets to advanced camera systems, often setting industry trends that others follow.",
70
+ "doc_id": "0",
71
+ "entities": [
72
+ "Apple",
73
+ "Samsung",
74
+ "camera"
75
+ ]
76
+ },
77
+ {
78
+ "doc": "Apple's new iPhone is amazing!",
79
+ "doc_id": "1",
80
+ "entities": [
81
+ "Apple",
82
+ "iPhone"
83
+ ]
84
+ },
85
+ {
86
+ "doc": "Samsung's new phone is amazing!",
87
+ "doc_id": "2",
88
+ "entities": [
89
+ "Samsung",
90
+ "phone"
91
+ ]
92
+ }
93
+ ]
94
+ # Predict with default language (English)
95
+ result = client.predict(input_data)
96
+ print(result)
97
+
98
+ # Predict with Dutch language
99
+ result_nl = client.predict(input_data, language="nl")
100
+ print(result_nl)
101
+ ```
102
+
103
+ ### Language Support
104
+
105
+ The SDK supports multi-language sentiment analysis with the following options:
106
+
107
+ - `"en"` (default): English language prediction
108
+ - `"nl"`: Dutch language prediction
109
+
110
+ ```python
111
+ # Default English prediction
112
+ result_en = client.predict(documents)
113
+
114
+ # Explicitly specify English
115
+ result_en = client.predict(documents, language="en")
116
+
117
+ # Dutch language prediction
118
+ result_nl = client.predict(documents, language="nl")
119
+ ```
120
+
121
+ ### Sample Output
122
+
123
+ ```json
124
+ {
125
+ "results": [
126
+ {
127
+ "doc_id": "0",
128
+ "predicted_class": 2,
129
+ "predicted_label": "positive",
130
+ "probabilities": {
131
+ "negative": 0.00007679959526285529,
132
+ "neutral": 0.0002924697764683515,
133
+ "positive": 0.9996306896209717
134
+ },
135
+ "details": [
136
+ {
137
+ "sentence_index": 0,
138
+ "sentence_text": "In the competitive landscape of consumer electronics, Apple and Samsung continue to lead the market with innovative products and strong brand loyalty.",
139
+ "predicted_class": 2,
140
+ "predicted_label": "positive",
141
+ "probabilities": {
142
+ "negative": 0.00009389198385179043,
143
+ "neutral": 0.00032428017584607005,
144
+ "positive": 0.9995818734169006
145
+ }
146
+ },
147
+ {
148
+ "sentence_index": 1,
149
+ "sentence_text": "While Apple focuses on a tightly integrated ecosystem with devices like the iPhone, iPad, and Mac, Samsung excels in offering a wide range of options across various price points, especially in its Galaxy smartphone lineup.",
150
+ "predicted_class": 2,
151
+ "predicted_label": "positive",
152
+ "probabilities": {
153
+ "negative": 0.00005746580063714646,
154
+ "neutral": 0.00012963586777914315,
155
+ "positive": 0.99981290102005
156
+ }
157
+ },
158
+ {
159
+ "sentence_index": 2,
160
+ "sentence_text": "Both companies push the boundaries of technology, from cutting-edge chipsets to advanced camera systems, often setting industry trends that others follow.",
161
+ "predicted_class": 2,
162
+ "predicted_label": "positive",
163
+ "probabilities": {
164
+ "negative": 0.00006366783054545522,
165
+ "neutral": 0.00044553453335538507,
166
+ "positive": 0.9994907379150391
167
+ }
168
+ }
169
+ ]
170
+ },
171
+ {
172
+ "doc_id": "1",
173
+ "predicted_class": 2,
174
+ "predicted_label": "positive",
175
+ "probabilities": {
176
+ "negative": 0.00010637375817168504,
177
+ "neutral": 0.0002509312762413174,
178
+ "positive": 0.9996427297592163
179
+ },
180
+ "details": [
181
+ {
182
+ "sentence_index": 0,
183
+ "sentence_text": "Apple's new iPhone is amazing!",
184
+ "predicted_class": 2,
185
+ "predicted_label": "positive",
186
+ "probabilities": {
187
+ "negative": 0.00010637375817168504,
188
+ "neutral": 0.0002509312762413174,
189
+ "positive": 0.9996427297592163
190
+ }
191
+ }
192
+ ]
193
+ },
194
+ {
195
+ "doc_id": "2",
196
+ "predicted_class": 2,
197
+ "predicted_label": "positive",
198
+ "probabilities": {
199
+ "negative": 0.00010637375817168504,
200
+ "neutral": 0.0002509312762413174,
201
+ "positive": 0.9996427297592163
202
+ },
203
+ "details": [
204
+ {
205
+ "sentence_index": 0,
206
+ "sentence_text": "Samsung's new phone is amazing!",
207
+ "predicted_class": 2,
208
+ "predicted_label": "positive",
209
+ "probabilities": {
210
+ "negative": 0.00010637375817168504,
211
+ "neutral": 0.0002509312762413174,
212
+ "positive": 0.9996427297592163
213
+ }
214
+ }
215
+ ]
216
+ }
217
+ ]
218
+ }
219
+ ```
220
+
221
+ ## API Reference
222
+
223
+ Please refer to the [Sentor ML API Documentation](https://sentor.app/docs) for more details.
224
+ You can also try the API in the [Sentor ML API Swagger Playground](https://sentor.app/docs).
225
+
226
+ ## Contributing
227
+
228
+ Contributions are welcome! Please feel free to submit a Pull Request.
229
+
230
+ ## License
231
+
232
+ MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,10 @@
1
+ sentor/__init__.py,sha256=Eg5MxBR7AgFAISpY3b4qNvRphTEv1y6Qyy8Qvz3L1cI,61
2
+ sentor/client.py,sha256=WFHBXkzlqjuLwLzRUbAhIkUKZ7k_ouWjQjdB3yjTwe8,2849
3
+ sentor/exceptions.py,sha256=xxL1JZxYLZCzoCrSzLnFDxtOreMMBKrwxXhlMl4UI_Q,627
4
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ tests/test_client.py,sha256=sYEe7Vf0dumhSxsLkxVGAdx9gEgO7EurphIGwpcuVkM,6070
6
+ sentor_ml-1.3.0.dist-info/METADATA,sha256=E2uY8w2SfHohHyPELJhxbKYjysfzuG5Y_JgPZkZcL6M,6906
7
+ sentor_ml-1.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
8
+ sentor_ml-1.3.0.dist-info/entry_points.txt,sha256=iYoIGXM8AusRG36JhqnBREngOd0iDOYN0C8PpiHtgXE,46
9
+ sentor_ml-1.3.0.dist-info/top_level.txt,sha256=nVfiI7y35XyGm5wyA94o24nDInXLiheycaaRtkR10ko,13
10
+ sentor_ml-1.3.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
tests/test_client.py CHANGED
@@ -1,132 +1,192 @@
1
- import pytest
2
- from sentor import SentorClient
3
- from sentor.exceptions import (
4
- SentorAPIError,
5
- RateLimitError,
6
- AuthenticationError,
7
- )
8
- from unittest.mock import Mock, patch
9
-
10
-
11
- @pytest.fixture
12
- def mock_client():
13
- """Create a mock SentorClient instance for testing."""
14
- client = SentorClient("test-key")
15
- return client
16
-
17
-
18
- def test_client_initialization():
19
- """Test proper initialization of SentorClient with default parameters."""
20
- client = SentorClient(api_key="test-key")
21
- assert isinstance(client, SentorClient)
22
- assert client.api_key == "test-key"
23
- assert client.base_url == "https://sentor.app/api"
24
- assert client.timeout == 30
25
-
26
-
27
- @patch("requests.post")
28
- def test_analyze_success(mock_post):
29
- """Test successful document analysis with positive sentiment."""
30
- # Setup mock response
31
- mock_response = Mock()
32
- mock_response.status_code = 200
33
- mock_response.json.return_value = {
34
- "results": [
35
- {
36
- "predicted_label": "positive",
37
- "probabilities": {"positive": 0.95},
38
- }
39
- ]
40
- }
41
- mock_post.return_value = mock_response
42
-
43
- # Test the analyze method
44
- client = SentorClient("test-key")
45
- documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
46
- result = client.analyze(documents)
47
-
48
- assert result["results"][0]["predicted_label"] == "positive"
49
- assert result["results"][0]["probabilities"]["positive"] == 0.95
50
- mock_post.assert_called_once()
51
-
52
-
53
- @patch("requests.post")
54
- def test_analyze_rate_limit(mock_post):
55
- """Test rate limit error handling during document analysis."""
56
- # Setup mock response for rate limit error
57
- mock_response = Mock()
58
- mock_response.status_code = 429
59
- mock_response.json.return_value = {
60
- "detail": "Rate limit exceeded",
61
- "retry_after": 60,
62
- }
63
- mock_post.return_value = mock_response
64
-
65
- # Test rate limit error
66
- client = SentorClient("test-key")
67
- documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
68
-
69
- with pytest.raises(RateLimitError) as exc_info:
70
- client.analyze(documents)
71
-
72
- assert exc_info.value.retry_after == 60
73
-
74
-
75
- @patch("requests.post")
76
- def test_analyze_auth_error(mock_post):
77
- """Test authentication error handling during document analysis."""
78
- # Setup mock response for authentication error
79
- mock_response = Mock()
80
- mock_response.status_code = 401
81
- mock_response.json.return_value = {"detail": "Invalid API key"}
82
- mock_post.return_value = mock_response
83
-
84
- # Test authentication error
85
- client = SentorClient("test-key")
86
- documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
87
-
88
- with pytest.raises(AuthenticationError):
89
- client.analyze(documents)
90
-
91
-
92
- def test_analyze_empty_input():
93
- """Test validation of empty input in document analysis."""
94
- client = SentorClient("test-key")
95
- with pytest.raises(ValueError, match="Input is required"):
96
- client.analyze([])
97
-
98
-
99
- @patch("requests.get")
100
- def test_check_health_success(mock_get):
101
- """Test successful health check response."""
102
- # Setup mock response
103
- mock_response = Mock()
104
- mock_response.status_code = 200
105
- mock_response.json.return_value = {"status": "healthy"}
106
- mock_get.return_value = mock_response
107
-
108
- # Test health check
109
- client = SentorClient("test-key")
110
- result = client.check_health()
111
-
112
- assert result["status"] == "healthy"
113
- mock_get.assert_called_once()
114
-
115
-
116
- @patch("requests.get")
117
- def test_check_health_error(mock_get):
118
- """Test error handling during health check."""
119
- # Setup mock response for error
120
- mock_response = Mock()
121
- mock_response.status_code = 500
122
- mock_response.json.return_value = {"detail": "Internal server error"}
123
- mock_get.return_value = mock_response
124
-
125
- # Test health check error
126
- client = SentorClient("test-key")
127
- with pytest.raises(SentorAPIError):
128
- client.check_health()
129
-
130
-
131
- if __name__ == "__main__":
132
- pytest.main([__file__])
1
+ import pytest
2
+ from sentor import SentorClient
3
+ from sentor.exceptions import (
4
+ SentorAPIError,
5
+ RateLimitError,
6
+ AuthenticationError,
7
+ )
8
+ from unittest.mock import Mock, patch
9
+
10
+
11
+ @pytest.fixture
12
+ def mock_client():
13
+ """Create a mock SentorClient instance for testing."""
14
+ client = SentorClient("test-key")
15
+ return client
16
+
17
+
18
+ def test_client_initialization():
19
+ """Test proper initialization of SentorClient with default parameters."""
20
+ client = SentorClient(api_key="test-key")
21
+ assert isinstance(client, SentorClient)
22
+ assert client.api_key == "test-key"
23
+ assert client.base_url == "https://sentor.app/api"
24
+ assert client.timeout == 30
25
+
26
+
27
+ @patch("requests.post")
28
+ def test_predict_success(mock_post):
29
+ """Test successful document prediction with positive sentiment."""
30
+ # Setup mock response
31
+ mock_response = Mock()
32
+ mock_response.status_code = 200
33
+ mock_response.json.return_value = {
34
+ "results": [
35
+ {
36
+ "predicted_label": "positive",
37
+ "probabilities": {"positive": 0.95},
38
+ }
39
+ ]
40
+ }
41
+ mock_post.return_value = mock_response
42
+
43
+ # Test the predict method
44
+ client = SentorClient("test-key")
45
+ documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
46
+ result = client.predict(documents)
47
+
48
+ assert result["results"][0]["predicted_label"] == "positive"
49
+ assert result["results"][0]["probabilities"]["positive"] == 0.95
50
+ mock_post.assert_called_once()
51
+
52
+ # Verify the language parameter was passed correctly
53
+ call_args = mock_post.call_args
54
+ assert call_args[1]["params"] == {"language": "en"}
55
+
56
+
57
+ @patch("requests.post")
58
+ def test_predict_rate_limit(mock_post):
59
+ """Test rate limit error handling during document prediction."""
60
+ # Setup mock response for rate limit error
61
+ mock_response = Mock()
62
+ mock_response.status_code = 429
63
+ mock_response.json.return_value = {
64
+ "detail": "Rate limit exceeded",
65
+ "retry_after": 60,
66
+ }
67
+ mock_post.return_value = mock_response
68
+
69
+ # Test rate limit error
70
+ client = SentorClient("test-key")
71
+ documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
72
+
73
+ with pytest.raises(RateLimitError) as exc_info:
74
+ client.predict(documents)
75
+
76
+ assert exc_info.value.retry_after == 60
77
+
78
+
79
+ @patch("requests.post")
80
+ def test_predict_auth_error(mock_post):
81
+ """Test authentication error handling during document prediction."""
82
+ # Setup mock response for authentication error
83
+ mock_response = Mock()
84
+ mock_response.status_code = 401
85
+ mock_response.json.return_value = {"detail": "Invalid API key"}
86
+ mock_post.return_value = mock_response
87
+
88
+ # Test authentication error
89
+ client = SentorClient("test-key")
90
+ documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
91
+
92
+ with pytest.raises(AuthenticationError):
93
+ client.predict(documents)
94
+
95
+
96
+ def test_predict_empty_input():
97
+ """Test validation of empty input in document prediction."""
98
+ client = SentorClient("test-key")
99
+ with pytest.raises(ValueError, match="Input is required"):
100
+ client.predict([])
101
+
102
+
103
+ @patch("requests.post")
104
+ def test_predict_with_dutch_language(mock_post):
105
+ """Test document prediction with Dutch language parameter."""
106
+ # Setup mock response
107
+ mock_response = Mock()
108
+ mock_response.status_code = 200
109
+ mock_response.json.return_value = {
110
+ "results": [
111
+ {
112
+ "predicted_label": "positive",
113
+ "probabilities": {"positive": 0.95},
114
+ }
115
+ ]
116
+ }
117
+ mock_post.return_value = mock_response
118
+
119
+ # Test the predict method with Dutch language
120
+ client = SentorClient("test-key")
121
+ documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
122
+ result = client.predict(documents, language="nl")
123
+
124
+ assert result["results"][0]["predicted_label"] == "positive"
125
+
126
+ # Verify the language parameter was passed correctly
127
+ call_args = mock_post.call_args
128
+ assert call_args[1]["params"] == {"language": "nl"}
129
+
130
+
131
+ def test_predict_invalid_language():
132
+ """Test validation of invalid language parameter."""
133
+ client = SentorClient("test-key")
134
+ documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
135
+
136
+ with pytest.raises(ValueError, match="Language must be 'en' or 'nl'"):
137
+ client.predict(documents, language="invalid")
138
+
139
+
140
+ def test_predict_explicit_english_language():
141
+ """Test document prediction with explicit English language parameter."""
142
+ client = SentorClient("test-key")
143
+ documents = [{"doc_id": "1", "doc": "Test text", "entities": []}]
144
+
145
+ # This should not raise an error
146
+ with patch("requests.post") as mock_post:
147
+ mock_response = Mock()
148
+ mock_response.status_code = 200
149
+ mock_response.json.return_value = {"results": []}
150
+ mock_post.return_value = mock_response
151
+
152
+ client.predict(documents, language="en")
153
+
154
+ # Verify the language parameter was passed correctly
155
+ call_args = mock_post.call_args
156
+ assert call_args[1]["params"] == {"language": "en"}
157
+
158
+
159
+ @patch("requests.get")
160
+ def test_check_health_success(mock_get):
161
+ """Test successful health check response."""
162
+ # Setup mock response
163
+ mock_response = Mock()
164
+ mock_response.status_code = 200
165
+ mock_response.json.return_value = {"status": "healthy"}
166
+ mock_get.return_value = mock_response
167
+
168
+ # Test health check
169
+ client = SentorClient("test-key")
170
+ result = client.check_health()
171
+
172
+ assert result["status"] == "healthy"
173
+ mock_get.assert_called_once()
174
+
175
+
176
+ @patch("requests.get")
177
+ def test_check_health_error(mock_get):
178
+ """Test error handling during health check."""
179
+ # Setup mock response for error
180
+ mock_response = Mock()
181
+ mock_response.status_code = 500
182
+ mock_response.json.return_value = {"detail": "Internal server error"}
183
+ mock_get.return_value = mock_response
184
+
185
+ # Test health check error
186
+ client = SentorClient("test-key")
187
+ with pytest.raises(SentorAPIError):
188
+ client.check_health()
189
+
190
+
191
+ if __name__ == "__main__":
192
+ pytest.main([__file__])
@@ -1,10 +0,0 @@
1
- sentor/__init__.py,sha256=K0z9SVT_Bkif2bj3Yqr7QtvQNTJll6an3DCuE0-rD0c,64
2
- sentor/client.py,sha256=lonitKFt2I0z4K3ok26L2gobbwuDCWFIZxb985YLPPg,2554
3
- sentor/exceptions.py,sha256=MY5uFUJd_WBhCMc0zNxVvoasC1rME4Brqv82MwhDM7c,648
4
- tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- tests/test_client.py,sha256=QMCyMt1n5e_-guT3yf5yVk_vKssHjkaGBuKd18ZixKg,4098
6
- sentor_ml-1.2.0.dist-info/METADATA,sha256=gLnTitSAnJCE4EVpQTOBE5lVBgwm3OuPAGAzVjXbgVE,6525
7
- sentor_ml-1.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- sentor_ml-1.2.0.dist-info/entry_points.txt,sha256=iYoIGXM8AusRG36JhqnBREngOd0iDOYN0C8PpiHtgXE,46
9
- sentor_ml-1.2.0.dist-info/top_level.txt,sha256=nVfiI7y35XyGm5wyA94o24nDInXLiheycaaRtkR10ko,13
10
- sentor_ml-1.2.0.dist-info/RECORD,,