Skip to main content

pjdev-armis-sdk

PyPI - Version PyPI - Python Version


Async Python SDK for the Armis API, built on httpx and pydantic.

Table of Contents

Installation

pip install pjdev-armis-sdk

Usage

Configure once at startup (reads from environment variables prefixed with ARMIS_):

from pjdev_armis_sdk import config_service

config_service.init(
    instance_url="https://your-tenant.armis.com",
    secret_key="your-secret-key",
)

Then call any of the resource modules:

from pjdev_armis_sdk import devices, search

# AQL search
result = await search.aql_search("in:devices type:MOBILE_PHONE")

# Lookup a single device by id
device = await devices.get_device(id=12345)

Auth (Authorization header with a temporary access token) is handled automatically by the underlying httpx.AsyncClient. Tokens are refreshed on the fly when they expire or when the API returns 401.

Retries and backoff

Every endpoint call retries transient failures with capped, jittered exponential backoff. Retry N waits http_retry_delay_seconds * 2 ** (N - 1) seconds, clamped to http_retry_max_delay_seconds and then scaled by a random factor in [0.5, 1.0]. A Retry-After header on a retried response is honored instead — both the delay-seconds and HTTP-date forms — clamped to the same ceiling.

Config knobs (all readable as ARMIS_-prefixed environment variables):

Setting Default Meaning
http_retry_max_count 5 Maximum attempts per call.
http_retry_delay_seconds 2 Base delay; doubles each retry.
http_retry_max_delay_seconds 60.0 Ceiling for any single wait.
http_retry_jitter True Spread out callers that failed together.

What is retried: any status not listed in a call's status_codes_to_ignore, plus transport failures (httpx.TransportError — connect errors, read/write and pool timeouts, protocol errors). 400, 403 and 404 are treated as deterministic and fail immediately.

401 is retried, with one deliberate exception. For ordinary endpoints a 401 means a stale access token, and it is worth retrying — note that ArmisAccessTokenAuth has already re-authenticated and replayed the request once, with no delay, before the retry layer ever sees it, so what retrying adds is elapsed time for a transient condition to clear. Against the token endpoint itself a 401 means the secret key is wrong, which no retry can fix, so access_token.get_access_token() and failed token fetches inside the auth flow fail fast on any 4xx and retry only on 429 or 5xx.

Consumers that need different behavior can override per call site without changing the shared defaults:

from pjdev_armis_sdk.api_utilities import async_retry_http

# Retry a status that this call site would otherwise treat as fatal.
@async_retry_http(status_codes_to_ignore=[400, 403], retry_status_codes=[409])
async def my_call() -> None: ...

retry_status_codes takes precedence over status_codes_to_ignore; passing only the latter behaves exactly as it always has. It is an override layered on the base rule, never an allowlist — it widens what is retried, never narrows it.

Writes that are not safe to repeat

Creates, and actions like _run_now/ that trigger work, are marked idempotent=False. On those calls the SDK retries only failures that prove the request never landed:

Never landed — safe to retry ConnectError, ConnectTimeout, PoolTimeout (no connection was ever established, so nothing was transmitted) and 401 (rejected at the authentication boundary before the handler runs)
May have landed — not retried ReadTimeout, WriteTimeout, ReadError, WriteError, RemoteProtocolError (the request was on the wire and the response was lost) and every 4xx/5xx other than 401

The question for a write is not "is this failure transient?" but "could the server have applied the write and still returned this?" A 504 or a ReadTimeout means the request arrived and the response was lost — the write may well have landed, so repeating it creates a duplicate. Armis offers no idempotency key, so nothing about the request lets the SDK work this out for itself; it has to be declared at the call site.

Note this is not a read/write split. A connection refused mid-deploy is the commonest transient failure there is, and it stays retryable on every endpoint including creates, because a refused connection cannot have written anything.

Affected: create_user, create_site, create_boundary, create_integration, create_integration_v2, run_silk_integration, run_va_integration, add_site_integration_id, add_site_network_equipment, bulk_add_site_network_equipment.

The last three are a deliberate conservative guess, not a known fact: they POST an id into a collection, and if Armis stores that collection as a set they are harmless to repeat and the flag costs retry resilience for nothing. The guess is made on cost asymmetry — a wrong False costs availability, a wrong True costs duplicate data — and confirmation from Armis that POSTing an already-present id is a no-op would settle it.

Not affected, because repeating them is harmless: every read, the update_* / patch_* calls (they set fields to given values), the delete_* calls, add_device_tags / remove_device_tags (set semantics), and bulk_upsert_devices (upsert keyed by macAddress).

Upgrading

Which statuses retry is unchanged for callers that pass only status_codes_to_ignore. Two timing changes are visible without any code change on your side:

  • Transport failures other than ConnectError — read/write and pool timeouts, protocol errors — are now retried instead of propagating after one attempt. A call that used to fail fast on a ReadTimeout now consumes its retry budget and the wall-clock time that goes with it.

  • Jitter is on by default, so a delay is 0.5x–1.0x of the computed value. At the default http_retry_delay_seconds=2 the schedule was 2, 4, 8, 16 and is now 1–2, 2–4, 4–8, 8–16. Set http_retry_jitter=False for the exact old schedule.

  • Creates no longer survive a transient 5xx or 429. This is the change most likely to affect you, and it is a reduction in write resilience, not only a bug fix. The ten non-idempotent calls listed above previously retried those statuses up to http_retry_max_count times; they now fail on the first one. If you have code relying on create_user riding out a brief 503, it will now raise where it used to succeed, and the caller has to decide whether to retry.

    The trade is deliberate: a duplicate user is worse than a failed create the caller can retry on purpose. Note this closes a pre-existing hole as well as a recent one — a 504 on a create could already produce duplicate rows before this release, because any status outside status_codes_to_ignore was retried. Connection failures are unaffected and still retry, since they cannot duplicate anything.

License

pjdev-armis-sdk is distributed under the terms of the MIT license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pjdev_armis_sdk-5.2.0.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pjdev_armis_sdk-5.2.0-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file pjdev_armis_sdk-5.2.0.tar.gz.

File metadata

  • Download URL: pjdev_armis_sdk-5.2.0.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Hatch/1.18.0 {"ci":true,"cpu":"aarch64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.12.3"},"installer":{"name":"hatch","version":"1.18.0"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.12.3","system":{"name":"Linux","release":"7.0.12-linuxkit"}} HTTPX2/2.12.0

File hashes

Hashes for pjdev_armis_sdk-5.2.0.tar.gz
Algorithm Hash digest
SHA256 5adaecc82302923512a040adfed567d97481b8113501c1e34f2e6fc75304957f
MD5 bd9f09a2c04742212b9a32fc829f9fb0
BLAKE2b-256 81921fd47e895e440aa3ff56c8015545125e2b87fe518a7c3e1deb9851710c2e

See more details on using hashes here.

File details

Details for the file pjdev_armis_sdk-5.2.0-py3-none-any.whl.

File metadata

  • Download URL: pjdev_armis_sdk-5.2.0-py3-none-any.whl
  • Upload date:
  • Size: 25.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Hatch/1.18.0 {"ci":true,"cpu":"aarch64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.12.3"},"installer":{"name":"hatch","version":"1.18.0"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.12.3","system":{"name":"Linux","release":"7.0.12-linuxkit"}} HTTPX2/2.12.0

File hashes

Hashes for pjdev_armis_sdk-5.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 46254ee56f444c86bd21493cc90e401fa5048d1df2aeaae60469ef42278460fb
MD5 1ff781c5aef2c5bf1a26fd9e48e1a90d
BLAKE2b-256 3627bf36c9b0c8f23526f937eca680fbed168b7ce7b83195d93dffa3ae2efb7b

See more details on using hashes here.

Release history Release notifications | RSS feed

5.2.1

2 files

This release

5.2.0 This release

2 files

5.1.14

2 files

5.1.13

2 files

5.1.12

2 files

5.1.10

2 files

5.1.9

2 files

5.1.7

2 files

5.1.6

2 files

5.1.5

2 files

5.1.4

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page