Skip to content

SpectrumX SDK Changelog

0.2.1 - 2026-07-09

  • Fixes:

    • Fixed file descriptor leak: replaced multiprocessing.RLock with threading.RLock in file models and gateway client to prevent OS-level file descriptor leakage in long-running sessions.
    • Connection pooling in gateway client: the gateway now uses requests.Session with a configured retry strategy instead of opening a new connection on every API call, reducing TCP connection churn and associated FD leakage.
    • Network errors now raise NetworkError: connection failures in the gateway are now wrapped in the SDK's NetworkError exception instead of bare requests exceptions, making them catchable by existing error-handling patterns in user code.
  • Housekeeping:

    • Expanded test coverage: added new test modules (test_base.py, test_datasets.py, test_enums.py, test_files.py, test_permission.py, test_user.py, test_config.py, test_errors.py, test_gateway.py) with comprehensive model, config, error, and gateway tests — 4,272 lines of additional test coverage.
    • log_cli=true removed from pytest config: disabled noisy CLI log capture in pytest defaults to reduce test output noise.
    • Version bump to 0.2.1.

0.2.0 - 2026-07-06

  • Features:

    • Byte-level progress bars for file downloads: file downloads now show a byte-level progress bar with throttled tqdm callbacks (~100 KB refresh rate), providing smooth visual feedback during multi-file downloads — matching the upload progress bar experience introduced in v0.1.15. When total bytes are unknown (e.g. paginated results), a file-level fallback progress bar is used instead.
    • Configurable periodic progress logging: new progress_log_period_secs config option (default: 30 seconds) controls how often structured progress log entries are emitted during long-running uploads and downloads. Set via environment variable or .env file.
    • Custom structured log path: new log_file config option allows setting a custom path for the structured JSONL log file via environment variable, .env file, or Client(log_file=...) parameter.
  • Observability:

    • Structured JSONL logging system: new enable_structured_logging() function configures the SDK to write machine-parseable JSON lines to ~/.local/state/spectrumx/logs/YYYY-MM-DD.jsonl. Each log line includes timestamp, process ID, severity, category, and message. Use jq to filter and analyze:
    # Show only download operations
    jq 'select(.cat == "download")' ~/.local/state/spectrumx/logs/*.jsonl
    
    # Show warnings and errors
    jq 'select(.lvl == "WARNING" or .lvl == "ERROR")' ~/.local/state/spectrumx/logs/*.jsonl
    
    + Boot message with SDK version, OS platform, and Python version on every
      session.
    + Log categories: `config`, `auth`, `network`, `filesystem`, `download`,
      `upload`, `log`.
    + Scoped context via `LogContext` context manager for per-operation fields (e.g.
      upload ID, directory).
    + Persistent context via `set_persistent_log_context()` for cross-operation
      fields (e.g. API key prefix).
    + Error entries include exception type and message in `exc_info` field.
    + Re-configurable at runtime — calling `enable_structured_logging()` with a new
      path switches to the new file and emits a fresh boot message.
    
    • Upload workflow now emits structured log entries:
      • Periodic progress every progress_log_period_secs with completed/total files, bytes uploaded/total, failures, in-progress, and skipped counts.
      • Completion summary with elapsed time, average speed, and status (clean/interrupted).
      • Per-file operation log context via log_context(upload_id=..., upload_dir=...).
    • Download workflow now emits structured log entries:
      • Per-file completion with file name and size.
      • Periodic progress every progress_log_period_secs with completed/total files, bytes downloaded/total, and failure count.
      • Completion summary with elapsed time, average speed, and status (clean/interrupted).
    • Configuration events tagged with LogCategory.CONFIG — config loading, env file discovery, and attribute setting now emit structured log entries for easier debugging.
  • Housekeeping:

    • Developer demo script: added scripts/demo_progress_bars.py that simulates upload/download transfers at configurable rates to let developers preview progress bar visuals without a live gateway.
    • Improved test coverage:
      • New test_structured_logging.py module (9 tests): JSONL file paths, boot message emission, core fields on every log line, contextual field binding, category filtering, scoped context lifecycle, persistent context, path re-configuration, and state reset.
      • New download byte progress tests in test_client.py covering skipped content credit and partial stream accounting.
      • New upload progress tests in test_uploads_workflow.py covering unstreamed byte credit, metadata-only uploads, and concurrent progress bar byte counting.
      • New credit_unstreamed_file_bytes tests in test_utils.py.
    • Version bump to 0.2.0.

0.1.20 - 2026-06-02

  • Fixes:
    • Fixed crash when owner and related fields are missing from API responses: the Capture.owner field (and User.name/User.email for cascading partial data) are now optional with None defaults. Previously, the SDK would raise a Pydantic ValidationError when the server omitted these fields from capture payloads during file and capture listing, causing the entire operation to fail.

0.1.19 - 2026-05-15

0.1.18 - 2026-04-30

0.1.17 - 2025-12-20

  • Fixes:
    • Improved file downloads: more reliability for file downloads when they need to be resumed.
      • File downloads now use a temporary file during download to avoid partial files being left behind if the download is interrupted.
      • When overwrite is False and a local file would be overwritten, we skip re-downloading it.
      • When overwrite is True and the checksums don't match with server, we re-download and replace the local file to match the server's.
      • If local file is identical to server's, we now skip the download entirely, even when overwrite is True.

0.1.16 - 2025-12-16

  • Fixes:
  • Reliability:
    • Relaxed validation in capture listing: capture listing is now more tolerant of cases where a given capture fails validation, now listing the ones that can be loaded correctly instead of failing the whole operations. Container fields like files now also default to empty ones if missing, instead of failing validation.

0.1.15 - 2025-12-02

  • Features:
    • Added support for Python 3.14: the SDK is now compatible with Python 3.14. We're thus dropping support for version 3.10 in this and future releases.
    • Improved UX for file uploads: the new file upload process:
      • Backwards compatible with previous method.
      • Discovery step lists all files before starting upload.
      • Concurrent uploads with asyncio: up to 5 streams by default.
      • Progress tracking the number of files and bytes, in human-friendly units.
      • Tracking completed :white_check_mark:, failed :x: , in progress :hourglass_flowing_sand:️ and skipped:rabbit2: files. On Windows, we use ASCII characters for better compatibility.
    • New file upload persistence: we now keep a local copy of the upload state of files.
      • This makes resuming interrupted uploads faster. The persistence mode can be bypassed with persist_state=False in upload methods in case users want to force the file checks (previous behavior).
  • Reliability:
    • Increased the battery of tests for file uploads and progress tracking.
    • Several new tests covering features of upload state persistence.

0.1.14 - 2025-10-07

0.1.13 - 2025-08-26

0.1.12 - 2025-08-12

0.1.11 - 2025-07-03

0.1.10 - 2025-06-05

0.1.9 - 2025-05-08

  • Features:
    • Capture deletions: captures may now be deleted using the SDK with sds_client.captures.delete().
    • Advanced searches: introducing preliminary support for advanced capture searches using OpenSearch queries. See the OpenSearch Query Tips for details about the syntax. The SDK endpoint is sds_client.captures.advanced_search(): the method's docstring has information on arguments and links to documentation.
  • Usage improvements:
    • Allowing positional args: SDK methods that receive a single UUID as an argument now allow it to be passed as a positional argument e.g. sds_client.get_file(<uuid>) is equivalent to sds_client.get_file(uuid=<uuid>).
    • Capture uploads: new high-level method that combines the upload of a directory of files with a capture creation: sds_client.upload_capture().
    • Usage guide updates: the SDK usage guide now includes information on how to check the results returned by a directory upload.
    • Logging control:: client's verbose flag propagates to submodules and sub-APIs.
  • Bugfixes and reliability improvements:
    • Bugfix: File.local_path attribute of some downloaded files was not correctly set.
    • Path usage tests:: new tests to cover regressions of different ways to use paths from SDK methods.
    • Capture read test: tests for client.capture.read() now check the number of files associated to the capture is correct.

0.1.8 - 2025-03-24

  • Features and improvements:
    • #72 Added Windows compatibility.
    • #79 SDS files may now be deleted using the SDK.
    • #78 The capture_type argument of sds_client.captures.listing() is now optional.
    • #78 The method sds_client.captures.read() is now available for reading a single capture, complementing the existing sds_client.captures.listing() method.
    • #78 When retrieving a single capture with capture = read(<uuid>), the list of files associated to it is available in capture.files.
      • Note these are CaptureFile instances, which hold a subset of the information in an SDS' File instance. To get all metadata on a file, use sds_client.get_file(<uuid>).
  • Fixes:
    • #77 Fixed incorrect file name being set when the file contents are already in SDS.
    • #77 local_path is now set for uploaded files across all three upload modes.
    • #71 File permissions are now included in file uploads; redesigned handling of permission flags.
  • Housekeeping:
    • #76 Fixed documentation typos; Updated and expanded note on concurrent access in the usage guide.

0.1.7 - 2025-03-07

  • Features:
    • spectrumx.api.captures.create() now accepts a scan_group for RadioHound captures.
    • index_name from spectrumx.api.captures.create() is dropped: the index is automatically chosen from the capture type.

0.1.6 - 2025-02-24

  • New features:
    • Support for Python 3.10 and 3.11.

0.1.5 - 2025-02-10

  • Breaking changes:
    • spectrumx.models.File moved to spectrumx.models.files.File.
  • New features:
    • SDS Capture creation and listing.
  • Housekeeping:
    • Refactored client by branching its method implementations and client configuration to separate modules.

0.1.4 - 2025-01-17

  • New features:
    • File listing with lazy-loaded paginated results.
    • Introduced new file upload modes to avoid re-uploading files already in SDS.
  • Housekeeping:
    • Usage documentation updated.
    • See tests/e2e_examples/check_build_acceptance.py for more SDK usage examples.
    • Refactoring of internal modules.
    • Improved test coverage.