fundamental-client 0.2.4__tar.gz → 0.2.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.
Files changed (75) hide show
  1. fundamental_client-0.2.5/.release-please-manifest.json +3 -0
  2. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/CHANGELOG.md +7 -0
  3. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/CONTRIBUTING.md +9 -6
  4. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/PKG-INFO +422 -3
  5. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/README.md +46 -20
  6. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/pyproject.toml +3 -2
  7. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/scripts/bootstrap +1 -1
  8. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/__init__.py +8 -3
  9. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/clients/__init__.py +2 -2
  10. fundamental_client-0.2.4/src/fundamental/clients/ec2.py → fundamental_client-0.2.5/src/fundamental/clients/aws_marketplace.py +5 -5
  11. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/config.py +3 -3
  12. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/constants.py +1 -1
  13. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/utils/http.py +3 -3
  14. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/uv.lock +7 -7
  15. fundamental_client-0.2.4/.release-please-manifest.json +0 -3
  16. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  17. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  18. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  19. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/dependabot.yml +0 -0
  20. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/labeler.yml +0 -0
  21. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/settings.yml +0 -0
  22. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/ci.yml +0 -0
  23. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/e2e-pr-comment.yml +0 -0
  24. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/integration-tests.yml +0 -0
  25. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/labeler.yml +0 -0
  26. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/pr-name-validation.yml +0 -0
  27. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/publish-codeartifact-dev.yml +0 -0
  28. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/publish-codeartifact.yml +0 -0
  29. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/publish-pypi.yml +0 -0
  30. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/publish-testpypi.yml +0 -0
  31. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.github/workflows/release-please.yml +0 -0
  32. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.gitignore +0 -0
  33. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.pre-commit-config.yaml +0 -0
  34. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/.yamllint +0 -0
  35. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/CODEOWNERS +0 -0
  36. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/LICENSE +0 -0
  37. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/noxfile.py +0 -0
  38. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/release-please-config.json +0 -0
  39. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/scripts/format +0 -0
  40. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/scripts/generate-models +0 -0
  41. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/scripts/integration-tests +0 -0
  42. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/scripts/lint +0 -0
  43. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/scripts/test +0 -0
  44. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/scripts/unit-tests +0 -0
  45. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/clients/base.py +0 -0
  46. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/clients/fundamental.py +0 -0
  47. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/deprecated.py +0 -0
  48. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/estimator/__init__.py +0 -0
  49. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/estimator/base.py +0 -0
  50. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/estimator/classification.py +0 -0
  51. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/estimator/nexus_estimator.py +0 -0
  52. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/estimator/regression.py +0 -0
  53. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/exceptions.py +0 -0
  54. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/models/__init__.py +0 -0
  55. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/models/generated.py +0 -0
  56. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/services/__init__.py +0 -0
  57. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/services/feature_importance.py +0 -0
  58. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/services/inference.py +0 -0
  59. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/services/models.py +0 -0
  60. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/utils/__init__.py +0 -0
  61. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/utils/data.py +0 -0
  62. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/utils/polling.py +0 -0
  63. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/src/fundamental/utils/safetensors_deserialize.py +0 -0
  64. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/conftest.py +0 -0
  65. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/integration/__init__.py +0 -0
  66. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/integration/test_classification.py +0 -0
  67. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/integration/test_regression.py +0 -0
  68. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/__init__.py +0 -0
  69. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/conftest.py +0 -0
  70. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/test_backward_compatibility.py +0 -0
  71. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/test_config.py +0 -0
  72. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/test_data_utils.py +0 -0
  73. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/test_estimators.py +0 -0
  74. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/test_safetensors_deserialize.py +0 -0
  75. {fundamental_client-0.2.4 → fundamental_client-0.2.5}/tests/unit/test_sklearn_compliance.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.5"
3
+ }
@@ -2,6 +2,13 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## [0.2.5](https://github.com/Fundamental-Technologies/fundamental-client/compare/0.2.4...0.2.5) (2026-02-05)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * improve README and version reporting (ENG-594) ([#68](https://github.com/Fundamental-Technologies/fundamental-client/issues/68)) ([2c1bfc5](https://github.com/Fundamental-Technologies/fundamental-client/commit/2c1bfc5795203ef70cc066352d35f1b775e92b65))
11
+
5
12
  ## [0.2.4](https://github.com/Fundamental-Technologies/fundamental-client/compare/0.2.3...0.2.4) (2026-02-04)
6
13
 
7
14
 
@@ -4,7 +4,7 @@ We welcome contributions to the Fundamental Python SDK! Whether it's a bug fix,
4
4
 
5
5
  ## Reporting Issues
6
6
 
7
- Go to this repository's [issues page](https://github.com/fundamental/fundamental-python/issues) and click "New Issue". Please check if the issue has already been reported before creating a new one.
7
+ Go to this repository's [issues page](https://github.com/Fundamental-Technologies/fundamental-client/issues) and click "New Issue". Please check if the issue has already been reported before creating a new one.
8
8
 
9
9
  Include the following information:
10
10
 
@@ -18,8 +18,8 @@ Include the following information:
18
18
  Fork the repository and clone it locally:
19
19
 
20
20
  ```bash
21
- git clone https://github.com/YOUR-USERNAME/fundamental-python
22
- cd fundamental-python
21
+ git clone https://github.com/YOUR-USERNAME/fundamental-client
22
+ cd fundamental-client
23
23
  git checkout -b my-feature-branch main
24
24
  ```
25
25
 
@@ -34,8 +34,11 @@ We recommend using our bootstrap script for easy setup:
34
34
  ### Manual Installation
35
35
 
36
36
  ```bash
37
- # Install with development dependencies using UV
38
- uv sync --group dev
37
+ # Install with development dependencies using uv (recommended)
38
+ uv sync --extra dev
39
+
40
+ # Or (pip-compatible) install in editable mode
41
+ uv pip install -e ".[dev]"
39
42
 
40
43
  # Or with pip
41
44
  pip install -e ".[dev]"
@@ -146,7 +149,7 @@ Make sure all CI checks pass before requesting review.
146
149
 
147
150
  ## Getting Help
148
151
 
149
- - **Issues**: [GitHub Issues](https://github.com/fundamental/fundamental-python/issues) for bugs and feature requests
152
+ - **Issues**: [GitHub Issues](https://github.com/Fundamental-Technologies/fundamental-client/issues) for bugs and feature requests
150
153
  - **Email**: support@fundamental.tech for questions
151
154
  - **Documentation**: See README.md for usage examples
152
155
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fundamental-client
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: Scikit-learn–compatible client SDK for NEXUS, Fundamental's large model for tabular data
5
5
  Project-URL: documentation, https://launch.fundamental.tech/docs/guides/sdk/user-guide
6
6
  Author-email: Fundamental Tech <support@fundamental.tech>
@@ -225,6 +225,8 @@ Requires-Dist: pyarrow>=19.0.0
225
225
  Requires-Dist: pydantic<3.0.0,>=2.10.0
226
226
  Requires-Dist: safetensors>=0.5.0
227
227
  Requires-Dist: scikit-learn<2.0.0,>=1.5.0
228
+ Provides-Extra: aws-marketplace
229
+ Requires-Dist: boto3>=1.34.0; extra == 'aws-marketplace'
228
230
  Provides-Extra: dev
229
231
  Requires-Dist: datamodel-code-generator[http]>=0.26.0; extra == 'dev'
230
232
  Requires-Dist: minimum-dependencies; extra == 'dev'
@@ -237,5 +239,422 @@ Requires-Dist: pytest-mock>=3.15.1; extra == 'dev'
237
239
  Requires-Dist: pytest>=8.4.2; extra == 'dev'
238
240
  Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
239
241
  Requires-Dist: ruff>=0.13.1; extra == 'dev'
240
- Provides-Extra: ec2
241
- Requires-Dist: boto3>=1.34.0; extra == 'ec2'
242
+ Description-Content-Type: text/markdown
243
+
244
+ # Fundamental Python SDK
245
+
246
+ [![PyPI version](https://img.shields.io/pypi/v/fundamental-client.svg?label=pypi%20package)](https://pypi.org/project/fundamental-client/)
247
+ [![Python Versions](https://img.shields.io/pypi/pyversions/fundamental-client?color=%2334D058)](https://pypi.org/project/fundamental-client)
248
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
249
+
250
+ A scikit-learn compatible Python SDK for NEXUS, Fundamental's large model for tabular data.
251
+
252
+ ## Table of Contents
253
+
254
+ - [Installation](#installation)
255
+ - [Usage](#usage)
256
+ - [Quick Start](#quick-start)
257
+ - [Using Pre-trained Models](#using-pre-trained-models)
258
+ - [Async Training](#async-training)
259
+ - [Model Management](#model-management)
260
+ - [Explainability & Insights](#explainability--insights)
261
+ - [Feature Importance](#feature-importance)
262
+ - [Configuration](#configuration)
263
+ - [Client Configuration](#client-configuration)
264
+ - [API Key](#api-key)
265
+ - [AWS Marketplace](#aws-marketplace)
266
+ - [Timeouts and Retries](#timeouts-and-retries)
267
+ - [Model Configuration](#model-configuration)
268
+ - [Mode](#mode)
269
+ - [Supported Data Types](#supported-data-types)
270
+ - [Handling Errors](#handling-errors)
271
+ - [Diagnostics and Support Information](#diagnostics-and-support-information)
272
+ - [Exception Types](#exception-types)
273
+ - [Troubleshooting](#troubleshooting)
274
+ - [Versioning](#versioning)
275
+ - [Requirements](#requirements)
276
+ - [License](#license)
277
+ - [Security](#security)
278
+ - [Support](#support)
279
+
280
+ ## Installation
281
+
282
+ ```sh
283
+ # install from PyPI
284
+ pip install fundamental-client
285
+ ```
286
+
287
+ ## Usage
288
+
289
+ The Fundamental SDK provides scikit-learn compatible estimators for classification and regression tasks, along with a flexible client for API interactions.
290
+
291
+
292
+ ### Quick Start
293
+
294
+ Make sure `FUNDAMENTAL_API_KEY` is set (or call `fundamental.set_client(...)`) before running the examples below.
295
+
296
+ ```python
297
+ from sklearn.datasets import load_breast_cancer, load_diabetes
298
+ from sklearn.model_selection import train_test_split
299
+ from fundamental import NEXUSClassifier, NEXUSRegressor
300
+
301
+ # Load classification data
302
+ X, y = load_breast_cancer(return_X_y=True)
303
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)
304
+
305
+ # Classification
306
+ classifier = NEXUSClassifier()
307
+ classifier.fit(X_train, y_train)
308
+
309
+ # After fitting, the model ID can be saved and used later
310
+ print(f"Trained model ID: {classifier.trained_model_id_}")
311
+
312
+ predictions = classifier.predict(X_test)
313
+ probabilities = classifier.predict_proba(X_test)
314
+
315
+ # Load regression data
316
+ X, y = load_diabetes(return_X_y=True)
317
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)
318
+
319
+ # Regression
320
+ regressor = NEXUSRegressor()
321
+ regressor.fit(X_train, y_train)
322
+ predictions = regressor.predict(X_test)
323
+ ```
324
+
325
+ ### Using Pre-trained Models
326
+
327
+ If you have a trained model from a previous session, you can use it directly without retraining:
328
+
329
+ ```python
330
+ from fundamental import NEXUSClassifier, NEXUSRegressor
331
+
332
+ classifier = NEXUSClassifier().load_model(trained_model_id="model_abc123")
333
+ predictions = classifier.predict(X_test)
334
+ probabilities = classifier.predict_proba(X_test)
335
+
336
+ regressor = NEXUSRegressor().load_model(trained_model_id="model_def456")
337
+ predictions = regressor.predict(X_test)
338
+ ```
339
+
340
+ ### Async Training
341
+
342
+ Model training is often a long-running operation. To support non-blocking workflows, you can submit training via `submit_fit_task()` and poll for completion. Once submitted, the training job runs in the background and its status can be queried at any time.
343
+
344
+ ```python
345
+ from fundamental import NEXUSClassifier
346
+ import time
347
+
348
+ classifier = NEXUSClassifier()
349
+
350
+ # Submit training task without waiting
351
+ task_id = classifier.submit_fit_task(X_train, y_train)
352
+ print(f"Training task submitted: {task_id}")
353
+
354
+ # Poll status periodically
355
+ result = None
356
+ while result is None:
357
+ result = classifier.poll_fit_result(task_id)
358
+ if result is None:
359
+ print("Training in progress...")
360
+ time.sleep(10) # Wait before polling again
361
+
362
+ # Model is now fitted and ready for predictions
363
+ predictions = classifier.predict(X_test)
364
+ ```
365
+
366
+ ### Model Management
367
+
368
+ The client provides methods for managing your trained models:
369
+
370
+ ```python
371
+ from fundamental import Fundamental
372
+
373
+ # Create a client
374
+ client = Fundamental()
375
+
376
+ # List all available models
377
+ models = client.models.list()
378
+ print(f"Available models: {models}")
379
+
380
+ # Get information about a specific model
381
+ model_info = client.models.get("model_id_123")
382
+ print(f"Model info: {model_info}")
383
+ print(f"Attributes: {model_info.attributes}")
384
+
385
+ # Delete a model
386
+ client.models.delete("model_id_123")
387
+ ```
388
+
389
+ #### Model Attributes
390
+
391
+ You can set attributes on your models to help organize and identify them.
392
+ We recommend always setting a `name` attribute; if omitted, the name will default to
393
+ `<model_version> [id:<model_id_suffix>]`.
394
+
395
+ ```python
396
+ # Set attributes directly on a fitted model
397
+ classifier.set_attributes({"name": "Breast Cancer Classifier", "stage": "prod"})
398
+
399
+ # Or using the client
400
+ client.models.set_attributes(
401
+ "model_id_123",
402
+ attributes={"name": "Breast Cancer Classifier", "description": "Production model v1"}
403
+ )
404
+ ```
405
+
406
+ ### Explainability & Insights
407
+
408
+ #### Feature Importance
409
+
410
+ After fitting a model, you can compute feature importance to quantify the contribution of each input feature to the model's output:
411
+
412
+ ```python
413
+ from sklearn.datasets import load_breast_cancer
414
+ from sklearn.model_selection import train_test_split
415
+ from fundamental import NEXUSClassifier
416
+
417
+
418
+ # Load data
419
+ X, y = load_breast_cancer(return_X_y=True)
420
+ X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.5, random_state=42)
421
+ # Fit the model
422
+ classifier = NEXUSClassifier()
423
+ classifier.fit(X_train, y_train)
424
+ # Get feature importance (waits for computation to complete)
425
+ feature_importance = classifier.get_feature_importance(X_val)
426
+ print(f"Feature importance: {feature_importance}")
427
+ ```
428
+
429
+ Feature importance computation can take a significant amount of time. If you prefer to submit the task and check its status periodically, you can use the asynchronous approach:
430
+
431
+ ```python
432
+ # Submit task without waiting
433
+ task_id = classifier.submit_feature_importance_task(X_val)
434
+
435
+ # Poll status later
436
+ result = classifier.poll_feature_importance_result(task_id)
437
+ if result is not None:
438
+ print(f"Feature importance: {result}")
439
+ ```
440
+
441
+ ## Configuration
442
+
443
+ ### Client Configuration
444
+
445
+ Configure the SDK client through environment variables or programmatically.
446
+
447
+ #### API Key
448
+
449
+ You can provide your API key in two ways:
450
+
451
+ ```python
452
+ # 1. Programmatic
453
+ import fundamental
454
+ from fundamental import Fundamental, NEXUSClassifier
455
+
456
+ fundamental.set_client(Fundamental(api_key="your_api_key_here"))
457
+ classifier = NEXUSClassifier()
458
+ ```
459
+
460
+ ```bash
461
+ # 2. Environment variable
462
+ export FUNDAMENTAL_API_KEY="your_api_key_here"
463
+ ```
464
+
465
+ #### AWS Marketplace
466
+
467
+ For AWS Marketplace deployments, use the `FundamentalAWSMarketplaceClient` which authenticates using AWS IAM roles via SigV4 signing instead of API keys:
468
+
469
+ ```python
470
+ import fundamental
471
+ from fundamental import FundamentalAWSMarketplaceClient, NEXUSClassifier
472
+
473
+ # Set the AWS Marketplace client with your deployment URL and AWS region
474
+ fundamental.set_client(FundamentalAWSMarketplaceClient(
475
+ aws_region="us-west-2", # Required
476
+ api_url="http://your-private-server:8000"
477
+ ))
478
+
479
+ # Use the SDK as normal
480
+ classifier = NEXUSClassifier()
481
+ classifier.fit(X_train, y_train)
482
+ predictions = classifier.predict(X_test)
483
+ ```
484
+
485
+ The `FundamentalAWSMarketplaceClient` automatically uses AWS credentials from the environment (IAM role, environment variables, or AWS config file) to sign requests. No API key is needed.
486
+
487
+ You can also configure using environment variables:
488
+
489
+ ```bash
490
+ export FUNDAMENTAL_API_URL="http://your-private-server:8000"
491
+ ```
492
+
493
+ ```python
494
+ fundamental.set_client(
495
+ FundamentalAWSMarketplaceClient(
496
+ aws_region="us-west-2", # Required
497
+ # api_url="http://your-private-server:8000", # Optional; overrides FUNDAMENTAL_API_URL
498
+ )
499
+ )
500
+ ```
501
+
502
+ #### Timeouts and Retries
503
+
504
+ Configure timeouts and retries when creating a client:
505
+
506
+ > **Note**: Timeouts apply only to the processing phase, starting after the dataset upload has completed.
507
+
508
+ ```python
509
+ import fundamental
510
+ from fundamental import Fundamental, NEXUSClassifier
511
+
512
+ # Create and set a client with custom timeouts and retries
513
+ fundamental.set_client(Fundamental(
514
+ fit_timeout=600, # 10 minutes for training (default: 3 hours)
515
+ predict_timeout=30, # 30 seconds for predictions (default: 1 hour)
516
+ retries=0 # Number of retries (default: 1)
517
+ ))
518
+
519
+ # Estimators will use the global client
520
+ classifier = NEXUSClassifier()
521
+ ```
522
+
523
+ ### Model Configuration
524
+
525
+ Configure model behavior and training parameters.
526
+
527
+ #### Mode
528
+
529
+ NEXUS offers two training modes to balance between speed and accuracy:
530
+
531
+ - **`quality` mode (default)**: Optimizes for the highest accuracy. This mode uses more comprehensive training processes and may take longer to complete.
532
+ - **`speed` mode**: Optimizes for faster training times while maintaining good accuracy.
533
+
534
+ ```python
535
+ import fundamental
536
+ from fundamental import NEXUSClassifier, NEXUSRegressor
537
+
538
+ # Use quality mode (default)
539
+ classifier = NEXUSClassifier(mode="quality")
540
+ classifier.fit(X_train, y_train)
541
+
542
+ # Use speed mode for faster training
543
+ classifier_fast = NEXUSClassifier(mode="speed")
544
+ classifier_fast.fit(X_train, y_train)
545
+
546
+ # Same for regression
547
+ regressor = NEXUSRegressor(mode="speed")
548
+ regressor.fit(X_train, y_train)
549
+ ```
550
+
551
+ ## Supported Data Types
552
+
553
+ The SDK supports flexible input formats:
554
+
555
+ - **Input features (X)**:
556
+ - `pandas.DataFrame`
557
+ - `numpy.ndarray`
558
+
559
+ - **Target values (y)**:
560
+ - `numpy.ndarray`
561
+ - `pandas.Series`
562
+
563
+ > **Note**: Data must be serializable to Parquet via PyArrow. If you hit a serialization error, ensure columns have consistent numeric or string dtypes; complex numbers are not supported.
564
+
565
+ ## Handling Errors
566
+
567
+ The SDK provides detailed error handling with specific exception types:
568
+
569
+ ```python
570
+ from fundamental import NEXUSClassifier
571
+ from fundamental.exceptions import (
572
+ NEXUSError,
573
+ ValidationError,
574
+ AuthenticationError,
575
+ RateLimitError,
576
+ ServerError
577
+ )
578
+
579
+ classifier = NEXUSClassifier()
580
+
581
+ try:
582
+ classifier.fit(X_train, y_train)
583
+ except ValidationError as e:
584
+ print(f"Invalid input data: {e}")
585
+ print(f"Status code: {e.status_code}")
586
+ except AuthenticationError as e:
587
+ print("Authentication failed - check your API key")
588
+ except RateLimitError as e:
589
+ print("Rate limit exceeded - please wait before retrying")
590
+ except ServerError as e:
591
+ print("Server error - please try again later")
592
+ except NEXUSError as e:
593
+ print(f"An error occurred: {e}")
594
+ ```
595
+
596
+ ### Diagnostics and Support Information
597
+
598
+ All exceptions include a `trace_id` attribute that you can share with Fundamental support to help diagnose issues more quickly.
599
+
600
+ ```python
601
+ except ServerError as e:
602
+ if e.trace_id:
603
+ print(f"Error trace_id: {e.trace_id}")
604
+ ```
605
+
606
+ ### Exception Types
607
+
608
+ | Error Type | Description | Status Code |
609
+ | ---------- | ----------- | ----------- |
610
+ | `ValidationError` | Input validation failed (bad request) | 400 |
611
+ | `AuthenticationError` | Authentication failed (missing/invalid API key) | 401 |
612
+ | `AuthorizationError` | Authorization failed (insufficient permissions) | 403 |
613
+ | `NotFoundError` | Resource not found | 404 |
614
+ | `RateLimitError` | API rate limit exceeded | 429 |
615
+ | `ServerError` | Server-side error | 500+ |
616
+ | `NetworkError` | Network connectivity issues | 503 |
617
+ | `RequestTimeoutError` | Request timed out | 504 |
618
+
619
+ ## Troubleshooting
620
+
621
+ - **Missing API key** (`ValueError: API key is required...`): set `FUNDAMENTAL_API_KEY` or configure a client via `fundamental.set_client(...)`.
622
+ - **Serialization errors (PyArrow)**: ensure `X`/`y` contain consistent numeric or string types; avoid mixed-type/object columns.
623
+ - **Large datasets / memory use**: datasets are serialized to Parquet in-memory before upload. If you run into memory or upload issues, try sampling, reducing columns, or using batching.
624
+
625
+ To enable debug logs:
626
+
627
+ ```python
628
+ import logging
629
+ logging.basicConfig(level=logging.DEBUG)
630
+ ```
631
+
632
+ ## Versioning
633
+
634
+ This package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions.
635
+
636
+ To check the installed version:
637
+
638
+ ```python
639
+ import fundamental
640
+ print(fundamental.__version__)
641
+ ```
642
+
643
+ ## Requirements
644
+
645
+ - Python 3.10 or higher
646
+ - See [pyproject.toml](pyproject.toml) for full dependency list
647
+
648
+ ## License
649
+
650
+ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
651
+
652
+ ## Security
653
+
654
+ If you believe you’ve found a security vulnerability, please email [support@fundamental.tech](mailto:support@fundamental.tech) and include a minimal reproduction. Please do not open a public GitHub issue.
655
+
656
+ ## Support
657
+
658
+ - **SDK docs**: [SDK User Guide](https://launch.fundamental.tech/docs/guides/sdk/user-guide)
659
+ - **Issues**: [GitHub Issues](https://github.com/Fundamental-Technologies/fundamental-client/issues)
660
+ - **Email**: [support@fundamental.tech](mailto:support@fundamental.tech)
@@ -19,7 +19,7 @@ A scikit-learn compatible Python SDK for NEXUS, Fundamental's large model for ta
19
19
  - [Configuration](#configuration)
20
20
  - [Client Configuration](#client-configuration)
21
21
  - [API Key](#api-key)
22
- - [Private Deployment (EC2)](#private-deployment-ec2)
22
+ - [AWS Marketplace](#aws-marketplace)
23
23
  - [Timeouts and Retries](#timeouts-and-retries)
24
24
  - [Model Configuration](#model-configuration)
25
25
  - [Mode](#mode)
@@ -27,9 +27,11 @@ A scikit-learn compatible Python SDK for NEXUS, Fundamental's large model for ta
27
27
  - [Handling Errors](#handling-errors)
28
28
  - [Diagnostics and Support Information](#diagnostics-and-support-information)
29
29
  - [Exception Types](#exception-types)
30
+ - [Troubleshooting](#troubleshooting)
30
31
  - [Versioning](#versioning)
31
32
  - [Requirements](#requirements)
32
33
  - [License](#license)
34
+ - [Security](#security)
33
35
  - [Support](#support)
34
36
 
35
37
  ## Installation
@@ -46,12 +48,14 @@ The Fundamental SDK provides scikit-learn compatible estimators for classificati
46
48
 
47
49
  ### Quick Start
48
50
 
51
+ Make sure `FUNDAMENTAL_API_KEY` is set (or call `fundamental.set_client(...)`) before running the examples below.
52
+
49
53
  ```python
50
54
  from sklearn.datasets import load_breast_cancer, load_diabetes
51
55
  from sklearn.model_selection import train_test_split
52
- from fundamental import Fundamental, NEXUSClassifier, NEXUSRegressor
56
+ from fundamental import NEXUSClassifier, NEXUSRegressor
53
57
 
54
- # Load classifaction data
58
+ # Load classification data
55
59
  X, y = load_breast_cancer(return_X_y=True)
56
60
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)
57
61
 
@@ -80,19 +84,19 @@ predictions = regressor.predict(X_test)
80
84
  If you have a trained model from a previous session, you can use it directly without retraining:
81
85
 
82
86
  ```python
83
- from fundamental import Fundamental, NEXUSClassifier, NEXUSRegressor
87
+ from fundamental import NEXUSClassifier, NEXUSRegressor
84
88
 
85
89
  classifier = NEXUSClassifier().load_model(trained_model_id="model_abc123")
86
90
  predictions = classifier.predict(X_test)
87
91
  probabilities = classifier.predict_proba(X_test)
88
92
 
89
- regressor = NEXUSRegressor().load_model(trained_model_id="model_def456")
93
+ regressor = NEXUSRegressor().load_model(trained_model_id="model_def456")
90
94
  predictions = regressor.predict(X_test)
91
95
  ```
92
96
 
93
97
  ### Async Training
94
98
 
95
- Model training is often a long-running operation. To support non-blocking workflows, fit() can be executed asynchronously. Once submitted, the training job runs in the background and its status can be queried at any time.
99
+ Model training is often a long-running operation. To support non-blocking workflows, you can submit training via `submit_fit_task()` and poll for completion. Once submitted, the training job runs in the background and its status can be queried at any time.
96
100
 
97
101
  ```python
98
102
  from fundamental import NEXUSClassifier
@@ -163,6 +167,8 @@ client.models.set_attributes(
163
167
  After fitting a model, you can compute feature importance to quantify the contribution of each input feature to the model's output:
164
168
 
165
169
  ```python
170
+ from sklearn.datasets import load_breast_cancer
171
+ from sklearn.model_selection import train_test_split
166
172
  from fundamental import NEXUSClassifier
167
173
 
168
174
 
@@ -213,27 +219,27 @@ classifier = NEXUSClassifier()
213
219
  export FUNDAMENTAL_API_KEY="your_api_key_here"
214
220
  ```
215
221
 
216
- #### Private Deployment (EC2)
222
+ #### AWS Marketplace
217
223
 
218
- For private deployments running on AWS EC2/ECS/EKS, use the `FundamentalEC2Client` which authenticates using AWS IAM roles via SigV4 signing instead of API keys:
224
+ For AWS Marketplace deployments, use the `FundamentalAWSMarketplaceClient` which authenticates using AWS IAM roles via SigV4 signing instead of API keys:
219
225
 
220
226
  ```python
221
227
  import fundamental
222
- from fundamental import FundamentalEC2Client, FTMClassifier
228
+ from fundamental import FundamentalAWSMarketplaceClient, NEXUSClassifier
223
229
 
224
- # Set the EC2 client with your private deployment URL and AWS region
225
- fundamental.set_client(FundamentalEC2Client(
230
+ # Set the AWS Marketplace client with your deployment URL and AWS region
231
+ fundamental.set_client(FundamentalAWSMarketplaceClient(
226
232
  aws_region="us-west-2", # Required
227
233
  api_url="http://your-private-server:8000"
228
234
  ))
229
235
 
230
236
  # Use the SDK as normal
231
- classifier = FTMClassifier()
237
+ classifier = NEXUSClassifier()
232
238
  classifier.fit(X_train, y_train)
233
239
  predictions = classifier.predict(X_test)
234
240
  ```
235
241
 
236
- The `FundamentalEC2Client` automatically uses AWS credentials from the environment (IAM role, environment variables, or AWS config file) to sign requests. No API key is needed.
242
+ The `FundamentalAWSMarketplaceClient` automatically uses AWS credentials from the environment (IAM role, environment variables, or AWS config file) to sign requests. No API key is needed.
237
243
 
238
244
  You can also configure using environment variables:
239
245
 
@@ -242,9 +248,12 @@ export FUNDAMENTAL_API_URL="http://your-private-server:8000"
242
248
  ```
243
249
 
244
250
  ```python
245
- fundamental.set_client(FundamentalEC2Client(
246
- aws_region="us-west-2" # Required; api_url from env var
247
- ))
251
+ fundamental.set_client(
252
+ FundamentalAWSMarketplaceClient(
253
+ aws_region="us-west-2", # Required
254
+ # api_url="http://your-private-server:8000", # Optional; overrides FUNDAMENTAL_API_URL
255
+ )
256
+ )
248
257
  ```
249
258
 
250
259
  #### Timeouts and Retries
@@ -259,9 +268,9 @@ from fundamental import Fundamental, NEXUSClassifier
259
268
 
260
269
  # Create and set a client with custom timeouts and retries
261
270
  fundamental.set_client(Fundamental(
262
- fit_timeout=600, # 10 minutes for training (default: 1 hour)
271
+ fit_timeout=600, # 10 minutes for training (default: 3 hours)
263
272
  predict_timeout=30, # 30 seconds for predictions (default: 1 hour)
264
- retries=0 # Number of retries (default: 2)
273
+ retries=0 # Number of retries (default: 1)
265
274
  ))
266
275
 
267
276
  # Estimators will use the global client
@@ -308,7 +317,7 @@ The SDK supports flexible input formats:
308
317
  - `numpy.ndarray`
309
318
  - `pandas.Series`
310
319
 
311
- > **Note**: Data must contain numeric types only. Object dtypes (strings, mixed types) and complex numbers are not supported. Please convert categorical data to numeric encoding before fitting.
320
+ > **Note**: Data must be serializable to Parquet via PyArrow. If you hit a serialization error, ensure columns have consistent numeric or string dtypes; complex numbers are not supported.
312
321
 
313
322
  ## Handling Errors
314
323
 
@@ -364,6 +373,18 @@ except ServerError as e:
364
373
  | `NetworkError` | Network connectivity issues | 503 |
365
374
  | `RequestTimeoutError` | Request timed out | 504 |
366
375
 
376
+ ## Troubleshooting
377
+
378
+ - **Missing API key** (`ValueError: API key is required...`): set `FUNDAMENTAL_API_KEY` or configure a client via `fundamental.set_client(...)`.
379
+ - **Serialization errors (PyArrow)**: ensure `X`/`y` contain consistent numeric or string types; avoid mixed-type/object columns.
380
+ - **Large datasets / memory use**: datasets are serialized to Parquet in-memory before upload. If you run into memory or upload issues, try sampling, reducing columns, or using batching.
381
+
382
+ To enable debug logs:
383
+
384
+ ```python
385
+ import logging
386
+ logging.basicConfig(level=logging.DEBUG)
387
+ ```
367
388
 
368
389
  ## Versioning
369
390
 
@@ -385,7 +406,12 @@ print(fundamental.__version__)
385
406
 
386
407
  This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
387
408
 
409
+ ## Security
410
+
411
+ If you believe you’ve found a security vulnerability, please email [support@fundamental.tech](mailto:support@fundamental.tech) and include a minimal reproduction. Please do not open a public GitHub issue.
412
+
388
413
  ## Support
389
414
 
390
- - **Documentation**: [fundamental.tech/docs](https://fundamental.tech/docs)
415
+ - **SDK docs**: [SDK User Guide](https://launch.fundamental.tech/docs/guides/sdk/user-guide)
416
+ - **Issues**: [GitHub Issues](https://github.com/Fundamental-Technologies/fundamental-client/issues)
391
417
  - **Email**: [support@fundamental.tech](mailto:support@fundamental.tech)
@@ -4,8 +4,9 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fundamental-client"
7
- version = "0.2.4"
7
+ version = "0.2.5"
8
8
  description = "Scikit-learn–compatible client SDK for NEXUS, Fundamental's large model for tabular data"
9
+ readme = {file = "README.md", content-type = "text/markdown"}
9
10
  authors = [{name = "Fundamental Tech", email = "support@fundamental.tech"}]
10
11
  license = {file = "LICENSE"}
11
12
  requires-python = ">=3.10"
@@ -33,7 +34,7 @@ dependencies = [
33
34
  ]
34
35
 
35
36
  [project.optional-dependencies]
36
- ec2 = [
37
+ aws-marketplace = [
37
38
  "boto3>=1.34.0"
38
39
  ]
39
40
  dev = [
@@ -14,7 +14,7 @@ if ! command -v uv &>/dev/null; then
14
14
  fi
15
15
 
16
16
  echo "Installing dependencies with uv..."
17
- uv pip install -e ".[dev]"
17
+ uv sync --extra dev
18
18
 
19
19
  echo "Setting up pre-commit hooks..."
20
20
  uv run pre-commit install
@@ -1,14 +1,19 @@
1
1
  """Fundamental Python SDK for tabular machine learning."""
2
2
 
3
+ from importlib.metadata import PackageNotFoundError, version
3
4
  from typing import Optional
4
5
 
5
- from fundamental.clients import BaseClient, Fundamental, FundamentalEC2Client
6
+ from fundamental.clients import BaseClient, Fundamental, FundamentalAWSMarketplaceClient
6
7
 
7
8
  # Deprecated aliases
8
9
  from fundamental.deprecated import FTMClassifier, FTMRegressor
9
10
  from fundamental.estimator import NEXUSClassifier, NEXUSRegressor
10
11
 
11
- __version__ = "0.1.4"
12
+ try:
13
+ # Distribution name on PyPI is `fundamental-client` (import name is `fundamental`).
14
+ __version__ = version("fundamental-client")
15
+ except PackageNotFoundError: # pragma: no cover
16
+ __version__ = "unknown"
12
17
 
13
18
  _global_client: Optional[BaseClient] = None
14
19
 
@@ -26,7 +31,7 @@ __all__ = [
26
31
  "FTMClassifier",
27
32
  "FTMRegressor",
28
33
  "Fundamental",
29
- "FundamentalEC2Client",
34
+ "FundamentalAWSMarketplaceClient",
30
35
  "NEXUSClassifier",
31
36
  "NEXUSRegressor",
32
37
  "get_client",
@@ -1,7 +1,7 @@
1
1
  """Client implementations for Fundamental API."""
2
2
 
3
+ from fundamental.clients.aws_marketplace import FundamentalAWSMarketplaceClient
3
4
  from fundamental.clients.base import BaseClient
4
- from fundamental.clients.ec2 import FundamentalEC2Client
5
5
  from fundamental.clients.fundamental import Fundamental
6
6
 
7
- __all__ = ["BaseClient", "Fundamental", "FundamentalEC2Client"]
7
+ __all__ = ["BaseClient", "Fundamental", "FundamentalAWSMarketplaceClient"]
@@ -1,4 +1,4 @@
1
- """Fundamental EC2 client for private deployment with AWS SigV4 authentication."""
1
+ """Fundamental AWS Marketplace client with AWS SigV4 authentication."""
2
2
 
3
3
  from typing import Any, Optional
4
4
 
@@ -6,10 +6,10 @@ from fundamental.clients.base import BaseClient
6
6
  from fundamental.config import Config
7
7
 
8
8
 
9
- class FundamentalEC2Client(BaseClient):
10
- """Client for Fundamental API on private EC2 deployments using AWS SigV4 authentication.
9
+ class FundamentalAWSMarketplaceClient(BaseClient):
10
+ """Client for Fundamental API on AWS Marketplace deployments using AWS SigV4 authentication.
11
11
 
12
- This client is pre-configured for private deployment mode where authentication
12
+ This client is designed for AWS Marketplace deployments where authentication
13
13
  is done via AWS IAM roles instead of API keys. It uses SigV4 signing to
14
14
  authenticate requests using the AWS credentials available in the environment.
15
15
  """
@@ -20,7 +20,7 @@ class FundamentalEC2Client(BaseClient):
20
20
  api_url: Optional[str] = None,
21
21
  **kwargs: Any, # noqa: ANN401
22
22
  ):
23
- """Initialize the Fundamental EC2 client.
23
+ """Initialize the Fundamental AWS Marketplace client.
24
24
 
25
25
  Args:
26
26
  aws_region: AWS region for SigV4 signing (required)
@@ -2,7 +2,7 @@
2
2
 
3
3
  import os
4
4
  from dataclasses import dataclass
5
- from importlib.metadata import version
5
+ from importlib.metadata import PackageNotFoundError, version
6
6
  from typing import Optional
7
7
 
8
8
  from fundamental.constants import (
@@ -133,6 +133,6 @@ class Config:
133
133
  def get_version(self) -> str:
134
134
  """Get the SDK version."""
135
135
  try:
136
- return version("fundamental")
137
- except Exception:
136
+ return version("fundamental-client")
137
+ except PackageNotFoundError:
138
138
  return "unknown"
@@ -37,5 +37,5 @@ X_TRAIN_FILE_NAME = "x_train_file"
37
37
  Y_TRAIN_FILE_NAME = "y_train_file"
38
38
  X_TEST_FILE_NAME = "x_test_file"
39
39
 
40
- # EC2/SigV4 authentication
40
+ # AWS Marketplace/SigV4 authentication
41
41
  SIGV4_SERVICE_NAME = "execute-api"
@@ -40,9 +40,9 @@ def _sign_request_sigv4(
40
40
  from botocore.awsrequest import AWSRequest # pyright: ignore[reportMissingImports]
41
41
  except ImportError as e:
42
42
  raise ImportError(
43
- "boto3 is required for EC2/SigV4 authentication. "
44
- 'Install it with: pip install "fundamental-client[ec2]" '
45
- 'or: uv add "fundamental-client[ec2]"'
43
+ "boto3 is required for AWS Marketplace/SigV4 authentication."
44
+ 'Install it with: pip install "fundamental-client[aws-marketplace]" '
45
+ 'or: uv add "fundamental-client[aws-marketplace]"'
46
46
  ) from e
47
47
 
48
48
  session = boto3.Session()
@@ -1,5 +1,5 @@
1
1
  version = 1
2
- revision = 2
2
+ revision = 3
3
3
  requires-python = ">=3.10"
4
4
  resolution-markers = [
5
5
  "python_full_version >= '3.13'",
@@ -398,7 +398,7 @@ wheels = [
398
398
 
399
399
  [[package]]
400
400
  name = "fundamental-client"
401
- version = "0.2.3"
401
+ version = "0.2.4"
402
402
  source = { editable = "." }
403
403
  dependencies = [
404
404
  { name = "httpx" },
@@ -412,6 +412,9 @@ dependencies = [
412
412
  ]
413
413
 
414
414
  [package.optional-dependencies]
415
+ aws-marketplace = [
416
+ { name = "boto3" },
417
+ ]
415
418
  dev = [
416
419
  { name = "datamodel-code-generator", extra = ["http"] },
417
420
  { name = "minimum-dependencies" },
@@ -425,13 +428,10 @@ dev = [
425
428
  { name = "python-dotenv" },
426
429
  { name = "ruff" },
427
430
  ]
428
- ec2 = [
429
- { name = "boto3" },
430
- ]
431
431
 
432
432
  [package.metadata]
433
433
  requires-dist = [
434
- { name = "boto3", marker = "extra == 'ec2'", specifier = ">=1.34.0" },
434
+ { name = "boto3", marker = "extra == 'aws-marketplace'", specifier = ">=1.34.0" },
435
435
  { name = "datamodel-code-generator", extras = ["http"], marker = "extra == 'dev'", specifier = ">=0.26.0" },
436
436
  { name = "httpx", specifier = ">=0.25.2" },
437
437
  { name = "minimum-dependencies", marker = "extra == 'dev'" },
@@ -452,7 +452,7 @@ requires-dist = [
452
452
  { name = "safetensors", specifier = ">=0.5.0" },
453
453
  { name = "scikit-learn", specifier = ">=1.5.0,<2.0.0" },
454
454
  ]
455
- provides-extras = ["ec2", "dev"]
455
+ provides-extras = ["aws-marketplace", "dev"]
456
456
 
457
457
  [[package]]
458
458
  name = "genson"
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.2.4"
3
- }