aimodelshare 0.1.55__py3-none-any.whl → 0.1.59__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.

Potentially problematic release.


This version of aimodelshare might be problematic. Click here for more details.

Files changed (35) hide show
  1. aimodelshare/__init__.py +94 -14
  2. aimodelshare/aimsonnx.py +263 -82
  3. aimodelshare/api.py +13 -12
  4. aimodelshare/auth.py +163 -0
  5. aimodelshare/base_image.py +1 -1
  6. aimodelshare/containerisation.py +1 -1
  7. aimodelshare/data_sharing/download_data.py +133 -83
  8. aimodelshare/generatemodelapi.py +7 -6
  9. aimodelshare/main/authorization.txt +275 -275
  10. aimodelshare/main/eval_lambda.txt +81 -13
  11. aimodelshare/model.py +492 -196
  12. aimodelshare/modeluser.py +22 -0
  13. aimodelshare/moral_compass/README.md +367 -0
  14. aimodelshare/moral_compass/__init__.py +58 -0
  15. aimodelshare/moral_compass/_version.py +3 -0
  16. aimodelshare/moral_compass/api_client.py +553 -0
  17. aimodelshare/moral_compass/challenge.py +365 -0
  18. aimodelshare/moral_compass/config.py +187 -0
  19. aimodelshare/playground.py +26 -14
  20. aimodelshare/preprocessormodules.py +60 -6
  21. aimodelshare/pyspark/authorization.txt +258 -258
  22. aimodelshare/pyspark/eval_lambda.txt +1 -1
  23. aimodelshare/reproducibility.py +20 -5
  24. aimodelshare/utils/__init__.py +78 -0
  25. aimodelshare/utils/optional_deps.py +38 -0
  26. aimodelshare-0.1.59.dist-info/METADATA +258 -0
  27. {aimodelshare-0.1.55.dist-info → aimodelshare-0.1.59.dist-info}/RECORD +30 -24
  28. aimodelshare-0.1.59.dist-info/licenses/LICENSE +5 -0
  29. {aimodelshare-0.1.55.dist-info → aimodelshare-0.1.59.dist-info}/top_level.txt +0 -1
  30. aimodelshare-0.1.55.dist-info/METADATA +0 -63
  31. aimodelshare-0.1.55.dist-info/licenses/LICENSE +0 -2
  32. tests/__init__.py +0 -0
  33. tests/test_aimsonnx.py +0 -135
  34. tests/test_playground.py +0 -721
  35. {aimodelshare-0.1.55.dist-info → aimodelshare-0.1.59.dist-info}/WHEEL +0 -0
aimodelshare/modeluser.py CHANGED
@@ -10,6 +10,27 @@ import datetime
10
10
  import regex as re
11
11
  from aimodelshare.exceptions import AuthorizationError, AWSAccessError, AWSUploadError
12
12
 
13
+ def decode_token_unverified(token: str):
14
+ """Decode a JWT without verifying signature or audience, compatible with PyJWT<2 and >=2 versions.
15
+
16
+ Parameters
17
+ ----------
18
+ token : str
19
+ The JWT token to decode
20
+
21
+ Returns
22
+ -------
23
+ dict
24
+ The decoded token payload
25
+ """
26
+ import jwt
27
+ try:
28
+ return jwt.decode(token, options={"verify_signature": False, "verify_aud": False})
29
+ except TypeError:
30
+ # PyJWT >=2 may require specifying algorithms if verification is enabled; here we keep it disabled
31
+ return jwt.decode(token, options={"verify_signature": False, "verify_aud": False}, algorithms=["HS256"])
32
+
33
+
13
34
  def get_jwt_token(username, password):
14
35
 
15
36
  config = botocore.config.Config(signature_version=botocore.UNSIGNED)
@@ -124,4 +145,5 @@ def create_user_getkeyandpassword():
124
145
  __all__ = [
125
146
  get_jwt_token,
126
147
  create_user_getkeyandpassword,
148
+ decode_token_unverified,
127
149
  ]
@@ -0,0 +1,367 @@
1
+ # moral_compass API Client
2
+
3
+ Production-ready Python client for the moral_compass REST API.
4
+
5
+ ## Features
6
+
7
+ - **Automatic API Discovery**: Finds API base URL from environment variables, cached terraform outputs, or terraform command
8
+ - **Retry Logic**: Automatic retries for network errors and 5xx server errors with exponential backoff
9
+ - **Pagination**: Simple iterator helpers for paginating through large result sets
10
+ - **Type Safety**: Dataclasses for all API responses
11
+ - **Structured Exceptions**: Specific exceptions for different error types (NotFoundError, ServerError)
12
+ - **Backward Compatibility**: Available via both `aimodelshare.moral_compass` and `moral_compass` import paths
13
+ - **Authentication**: Automatic JWT token attachment from environment variables
14
+ - **Ownership Enforcement**: Table-level ownership and authorization controls
15
+ - **Naming Conventions**: Enforced naming patterns for moral compass tables
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install -e . # Install in development mode
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```python
26
+ from aimodelshare.moral_compass import MoralcompassApiClient
27
+
28
+ # Create client (auto-discovers API URL from environment)
29
+ client = MoralcompassApiClient()
30
+
31
+ # Or specify URL explicitly
32
+ client = MoralcompassApiClient(api_base_url="https://api.example.com")
33
+
34
+ # Check API health
35
+ health = client.health()
36
+ print(health)
37
+
38
+ # Create a table
39
+ client.create_table("my-table", "My Display Name")
40
+
41
+ # Get table info
42
+ table = client.get_table("my-table")
43
+ print(f"Table: {table.table_id}, Users: {table.user_count}")
44
+
45
+ # List all tables with automatic pagination
46
+ for table in client.iter_tables():
47
+ print(f"- {table.table_id}: {table.display_name}")
48
+
49
+ # Add a user to a table
50
+ client.put_user("my-table", "user1", submission_count=10, total_count=100)
51
+
52
+ # Get user stats
53
+ user = client.get_user("my-table", "user1")
54
+ print(f"User {user.username}: {user.submission_count} submissions")
55
+
56
+ # List all users in a table
57
+ for user in client.iter_users("my-table"):
58
+ print(f"- {user.username}: {user.submission_count} submissions")
59
+ ```
60
+
61
+ ## Authentication & Authorization
62
+
63
+ The moral compass API supports authentication and authorization controls when `AUTH_ENABLED=true` on the server.
64
+
65
+ > **⚠️ SECURITY WARNING**
66
+ > JWT signature verification is currently a **stub implementation** that performs unverified token decoding.
67
+ > **DO NOT use in production** for security-critical operations without implementing JWKS-based signature verification.
68
+ > This is suitable for development and testing only.
69
+
70
+ ### Authentication Token
71
+
72
+ The client automatically attaches JWT authentication tokens from environment variables:
73
+
74
+ ```bash
75
+ # Preferred: Use JWT_AUTHORIZATION_TOKEN
76
+ export JWT_AUTHORIZATION_TOKEN="your.jwt.token"
77
+
78
+ # Legacy: AWS_TOKEN (deprecated, triggers warning)
79
+ export AWS_TOKEN="your.aws.token"
80
+ ```
81
+
82
+ You can also provide the token explicitly:
83
+
84
+ ```python
85
+ from aimodelshare.moral_compass import MoralcompassApiClient
86
+
87
+ # Explicit token
88
+ client = MoralcompassApiClient(auth_token="your.jwt.token")
89
+
90
+ # Auto-discover from environment
91
+ client = MoralcompassApiClient() # Uses JWT_AUTHORIZATION_TOKEN or AWS_TOKEN
92
+ ```
93
+
94
+ ### Table Ownership
95
+
96
+ When authentication is enabled, tables have ownership metadata:
97
+
98
+ ```python
99
+ # Create a table for a playground (stores owner identity)
100
+ response = client.create_table(
101
+ table_id="my-playground-mc",
102
+ display_name="My Moral Compass Table",
103
+ playground_url="https://example.com/playground/my-playground"
104
+ )
105
+ # Response is a dict with structure:
106
+ # {
107
+ # 'tableId': 'my-playground-mc',
108
+ # 'displayName': 'My Moral Compass Table',
109
+ # 'ownerPrincipal': 'user@example.com', # Owner's identity
110
+ # 'playgroundId': 'my-playground',
111
+ # 'message': 'Table created successfully'
112
+ # }
113
+ print(response['ownerPrincipal']) # Shows who created the table
114
+
115
+ # Convenience method to create with naming convention
116
+ response = client.create_table_for_playground(
117
+ playground_url="https://example.com/playground/my-playground",
118
+ suffix="-mc" # Creates table: my-playground-mc
119
+ )
120
+ ```
121
+
122
+ ### Naming Convention
123
+
124
+ When `MC_ENFORCE_NAMING=true` on the server, moral compass tables must follow the pattern: `<playgroundId>-mc`
125
+
126
+ ```python
127
+ # Valid: Follows naming convention
128
+ client.create_table(
129
+ table_id="my-playground-mc",
130
+ playground_url="https://example.com/playground/my-playground"
131
+ )
132
+
133
+ # Invalid: Will return 400 error if MC_ENFORCE_NAMING=true
134
+ client.create_table(
135
+ table_id="random-name",
136
+ playground_url="https://example.com/playground/my-playground"
137
+ )
138
+ ```
139
+
140
+ ### Authorization Rules
141
+
142
+ When `AUTH_ENABLED=true`:
143
+
144
+ - **Table Creation**: Only authenticated users can create tables
145
+ - **Table Deletion**: Only the owner or admin can delete tables (requires `ALLOW_TABLE_DELETE=true`)
146
+ - **User Updates**: Only the user themselves or admin can update their progress
147
+ - **Read Operations**: Public by default when `ALLOW_PUBLIC_READ=true`
148
+
149
+ ```python
150
+ # Delete a table (owner or admin only)
151
+ client.delete_table("my-playground-mc")
152
+
153
+ # Update own progress
154
+ client.update_moral_compass(
155
+ table_id="my-playground-mc",
156
+ username="my-username",
157
+ metrics={"accuracy": 0.85},
158
+ tasks_completed=3,
159
+ total_tasks=6
160
+ )
161
+ ```
162
+
163
+ ### Helper Functions
164
+
165
+ Use the `aimodelshare.auth` module for identity management:
166
+
167
+ ```python
168
+ from aimodelshare.auth import get_primary_token, get_identity_claims
169
+
170
+ # Get token from environment
171
+ token = get_primary_token()
172
+
173
+ # Extract identity claims (DEVELOPMENT ONLY - signature not verified)
174
+ if token:
175
+ # Currently verify=False (stub implementation)
176
+ # TODO: Use verify=True after implementing JWKS verification for production
177
+ claims = get_identity_claims(token, verify=False)
178
+ print(f"User: {claims['principal']}")
179
+ print(f"Email: {claims.get('email')}")
180
+ print(f"Subject: {claims['sub']}")
181
+ ```
182
+
183
+ ## API Base URL Configuration
184
+
185
+ The client discovers the API base URL using the following priority:
186
+
187
+ 1. **Environment Variable**: `MORAL_COMPASS_API_BASE_URL` or `AIMODELSHARE_API_BASE_URL`
188
+ 2. **Cached Terraform Outputs**: `infra/terraform_outputs.json`
189
+ 3. **Terraform Command**: Runs `terraform output -raw api_base_url` in the `infra/` directory
190
+ 4. **Explicit Parameter**: Pass `api_base_url` to the client constructor
191
+
192
+ ```bash
193
+ # Set via environment variable
194
+ export MORAL_COMPASS_API_BASE_URL="https://your-api.example.com"
195
+ ```
196
+
197
+ ## Error Handling
198
+
199
+ ```python
200
+ from aimodelshare.moral_compass import (
201
+ MoralcompassApiClient,
202
+ NotFoundError,
203
+ ServerError,
204
+ ApiClientError
205
+ )
206
+
207
+ client = MoralcompassApiClient()
208
+
209
+ try:
210
+ table = client.get_table("nonexistent-table")
211
+ except NotFoundError:
212
+ print("Table not found (404)")
213
+ except ServerError:
214
+ print("Server error (5xx)")
215
+ except ApiClientError as e:
216
+ print(f"API error: {e}")
217
+ ```
218
+
219
+ ## Pagination
220
+
221
+ ### Manual Pagination
222
+
223
+ ```python
224
+ # Get first page
225
+ response = client.list_tables(limit=10)
226
+ tables = response["tables"]
227
+ last_key = response.get("lastKey")
228
+
229
+ # Get next page if available
230
+ if last_key:
231
+ response = client.list_tables(limit=10, last_key=last_key)
232
+ tables.extend(response["tables"])
233
+ ```
234
+
235
+ ### Automatic Pagination with Iterators
236
+
237
+ ```python
238
+ # Automatically handles pagination behind the scenes
239
+ for table in client.iter_tables(limit=50):
240
+ print(table.table_id)
241
+
242
+ for user in client.iter_users("my-table", limit=50):
243
+ print(user.username)
244
+ ```
245
+
246
+ ## Dataclasses
247
+
248
+ ### MoralcompassTableMeta
249
+
250
+ ```python
251
+ from aimodelshare.moral_compass import MoralcompassTableMeta
252
+
253
+ table = MoralcompassTableMeta(
254
+ table_id="my-table",
255
+ display_name="My Table",
256
+ created_at="2024-01-01T00:00:00Z",
257
+ is_archived=False,
258
+ user_count=42
259
+ )
260
+ ```
261
+
262
+ ### MoralcompassUserStats
263
+
264
+ ```python
265
+ from aimodelshare.moral_compass import MoralcompassUserStats
266
+
267
+ user = MoralcompassUserStats(
268
+ username="user1",
269
+ submission_count=10,
270
+ total_count=100,
271
+ last_updated="2024-01-01T12:00:00Z"
272
+ )
273
+ ```
274
+
275
+ ## Backward Compatibility
276
+
277
+ Both import paths are supported:
278
+
279
+ ```python
280
+ # New path (recommended)
281
+ from aimodelshare.moral_compass import MoralcompassApiClient
282
+
283
+ # Legacy path (backward compatible)
284
+ from moral_compass import MoralcompassApiClient
285
+ ```
286
+
287
+ ## API Methods
288
+
289
+ ### Tables
290
+
291
+ - `create_table(table_id, display_name=None, playground_url=None)` - Create a new table
292
+ - `create_table_for_playground(playground_url, suffix='-mc', display_name=None)` - Create table with naming convention
293
+ - `list_tables(limit=50, last_key=None)` - List tables with pagination
294
+ - `iter_tables(limit=50)` - Iterate all tables with automatic pagination
295
+ - `get_table(table_id)` - Get specific table metadata
296
+ - `patch_table(table_id, display_name=None, is_archived=None)` - Update table metadata
297
+ - `delete_table(table_id)` - Delete a table (requires owner/admin auth)
298
+
299
+ ### Users
300
+
301
+ - `put_user(table_id, username, submission_count, total_count)` - Create/update user
302
+ - `get_user(table_id, username)` - Get user stats
303
+ - `list_users(table_id, limit=50, last_key=None)` - List users with pagination
304
+ - `iter_users(table_id, limit=50)` - Iterate all users with automatic pagination
305
+ - `update_moral_compass(table_id, username, metrics, tasks_completed=0, total_tasks=0, questions_correct=0, total_questions=0, primary_metric=None)` - Update user's moral compass score
306
+
307
+ ### Health
308
+
309
+ - `health()` - Check API health status
310
+
311
+ ## Testing
312
+
313
+ ### Unit Tests
314
+
315
+ ```bash
316
+ # Run all tests except integration tests
317
+ pytest -m "not integration"
318
+ ```
319
+
320
+ ### Integration Tests
321
+
322
+ ```bash
323
+ # Requires deployed API with MORAL_COMPASS_API_BASE_URL set
324
+ export MORAL_COMPASS_API_BASE_URL="https://your-api.example.com"
325
+ pytest -m integration tests/test_moral_compass_client_minimal.py -v
326
+ ```
327
+
328
+ ## CI/CD Integration
329
+
330
+ The deploy-infra workflow automatically:
331
+ 1. Caches terraform outputs
332
+ 2. Verifies API health endpoint is reachable
333
+ 3. Installs the package in editable mode
334
+ 4. Runs integration tests
335
+
336
+ See `.github/workflows/deploy-infra.yml` for details.
337
+
338
+ ## Scripts
339
+
340
+ ### Cache Terraform Outputs
341
+
342
+ ```bash
343
+ bash scripts/cache_terraform_outputs.sh
344
+ ```
345
+
346
+ Exports `MORAL_COMPASS_API_BASE_URL` and writes `infra/terraform_outputs.json`.
347
+
348
+ ### Verify API Health
349
+
350
+ ```bash
351
+ bash scripts/verify_api_reachable.sh [API_BASE_URL]
352
+ ```
353
+
354
+ Checks that the `/health` endpoint is reachable with retries.
355
+
356
+ ## Version
357
+
358
+ Current version: 0.1.0
359
+
360
+ ```python
361
+ from aimodelshare.moral_compass import __version__
362
+ print(__version__) # "0.1.0"
363
+ ```
364
+
365
+ ## License
366
+
367
+ Same as parent aimodelshare package.
@@ -0,0 +1,58 @@
1
+ """
2
+ aimodelshare.moral_compass - Production-ready client for moral_compass REST API
3
+
4
+ This submodule provides a client for interacting with the moral_compass API
5
+ with support for pagination, retries, and structured exceptions.
6
+
7
+ Example usage:
8
+ from aimodelshare.moral_compass import MoralcompassApiClient, ChallengeManager
9
+
10
+ client = MoralcompassApiClient()
11
+
12
+ # Create a table
13
+ client.create_table("my-table", "My Display Name")
14
+
15
+ # List tables with pagination
16
+ for table in client.iter_tables():
17
+ print(f"Table: {table.table_id} - {table.display_name}")
18
+
19
+ # Get specific table
20
+ table = client.get_table("my-table")
21
+
22
+ # Manage users
23
+ client.put_user("my-table", "user1", submission_count=10, total_count=100)
24
+ user = client.get_user("my-table", "user1")
25
+
26
+ # Use ChallengeManager for multi-metric tracking
27
+ manager = ChallengeManager("my-table", "user1")
28
+ manager.set_metric("accuracy", 0.85, primary=True)
29
+ manager.set_metric("fairness", 0.92)
30
+ manager.set_progress(tasks_completed=5, total_tasks=10)
31
+ manager.sync()
32
+ """
33
+
34
+ from ._version import __version__
35
+ from .api_client import (
36
+ MoralcompassApiClient,
37
+ MoralcompassTableMeta,
38
+ MoralcompassUserStats,
39
+ ApiClientError,
40
+ NotFoundError,
41
+ ServerError,
42
+ )
43
+ from .config import get_api_base_url, get_aws_region
44
+ from .challenge import ChallengeManager, JusticeAndEquityChallenge
45
+
46
+ __all__ = [
47
+ "__version__",
48
+ "MoralcompassApiClient",
49
+ "MoralcompassTableMeta",
50
+ "MoralcompassUserStats",
51
+ "ApiClientError",
52
+ "NotFoundError",
53
+ "ServerError",
54
+ "get_api_base_url",
55
+ "get_aws_region",
56
+ "ChallengeManager",
57
+ "JusticeAndEquityChallenge",
58
+ ]
@@ -0,0 +1,3 @@
1
+ """Version information for aimodelshare.moral_compass"""
2
+
3
+ __version__ = "0.1.0"