|
6 | 6 | [](https://github.com/itential/ipsdk/actions) |
7 | 7 | [](https://github.com/itential/ipsdk) |
8 | 8 |
|
9 | | -The Itential Python SDK provides a robust client implementation in Python for writing |
10 | | -scripts and applications that can make API calls to Itential Platform or Itential |
11 | | -Automation Gateway 4.x. |
| 9 | +> Python SDK for making API calls to Itential Platform and Itential Automation Gateway 4.x. |
12 | 10 |
|
13 | | -**Status**: Beta - Active development with comprehensive test coverage (100%) |
14 | | - |
15 | | -## Features |
16 | | - |
17 | | -- **Easy API Requests**: Automatic authentication on first API call with session management |
18 | | -- **Multiple Authentication Methods**: |
19 | | - - OAuth (client credentials) for Itential Platform |
20 | | - - Basic authentication (username/password) for both Platform and Gateway |
21 | | -- **Sync and Async Support**: Both synchronous and asynchronous HTTP clients via `want_async` parameter |
22 | | -- **Comprehensive Logging**: Custom logging system with multiple levels (including TRACE and FATAL) and httpx integration control |
23 | | -- **Flexible Configuration**: Customizable connection settings including TLS, certificate verification, and timeouts |
24 | | -- **Type Safety**: Full type hints for enhanced development experience |
25 | | -- **HTTP Methods**: Support for GET, POST, PUT, DELETE, and PATCH operations with automatic JSON handling |
26 | | - |
27 | | -## Getting started |
28 | | - |
29 | | -## Requirements |
30 | | - |
31 | | -- Python 3.10 or higher |
32 | | -- httpx >= 0.28.1 |
33 | | - |
34 | | -### Tested Python Versions |
35 | | - |
36 | | -| Python Version | Status | Notes | |
37 | | -|----------------|--------|-------| |
38 | | -| 3.10 | ✅ Tested | Minimum recommended version | |
39 | | -| 3.11 | ✅ Tested | Full support | |
40 | | -| 3.12 | ✅ Tested | Full support | |
41 | | -| 3.13 | ✅ Tested | Latest stable release | |
42 | | -| 3.14 | 🔄 Beta | Development/preview testing | |
43 | | - |
44 | | -The SDK is automatically tested against Python 3.10-3.13 in our CI pipeline to ensure compatibility across all supported versions. |
| 11 | +Provides sync and async HTTP clients with automatic authentication, session management, and sensitive data filtering. Single runtime dependency: [httpx](https://www.python-httpx.org/). |
45 | 12 |
|
46 | 13 | ## Installation |
47 | 14 |
|
48 | | -Install `ipsdk` using pip: |
49 | | - |
50 | 15 | ```bash |
51 | | -$ pip install ipsdk |
| 16 | +pip install ipsdk |
52 | 17 | ``` |
53 | 18 |
|
54 | | -Or using uv (recommended for development): |
| 19 | +Or with uv: |
55 | 20 |
|
56 | 21 | ```bash |
57 | | -$ uv add ipsdk |
| 22 | +uv add ipsdk |
58 | 23 | ``` |
59 | 24 |
|
60 | | -The `ipsdk` package provides factory functions for connecting to either |
61 | | -Itential Platform or Itential Automation Gateway. |
| 25 | +Requires Python 3.10+. |
62 | 26 |
|
63 | | -The `platform_factory(...)` function creates a connection to Itential Platform |
64 | | -The `gateway_factory(...)` function creates a connection to Itential Automation Gateway |
| 27 | +## Usage |
65 | 28 |
|
66 | | -### Basic Authentication |
67 | | - |
68 | | -Use basic authentication with username and password: |
| 29 | +### Platform — basic auth |
69 | 30 |
|
70 | 31 | ```python |
71 | | ->>> import ipsdk |
72 | | ->>> platform = ipsdk.platform_factory( |
73 | | -... host="platform.itential.dev", |
74 | | -... user="admin@pronghorn", |
75 | | -... password="your-password" |
76 | | -... ) |
77 | | ->>> res = platform.get("/health/server") |
78 | | ->>> res |
79 | | -<Response [200 OK]> |
80 | | ->>> res.text |
81 | | -'{"version":"15.8.10-2023.2.44","release":"2023.2.9"...` |
82 | | -``` |
| 32 | +import ipsdk |
| 33 | + |
| 34 | +platform = ipsdk.platform_factory( |
| 35 | + host="platform.itential.dev", |
| 36 | + user="admin@pronghorn", |
| 37 | + password="your-password" |
| 38 | +) |
83 | 39 |
|
84 | | -### OAuth Authentication |
| 40 | +res = platform.get("/health/server") |
| 41 | +print(res.json()) |
| 42 | +``` |
85 | 43 |
|
86 | | -For Itential Platform, you can use OAuth with client credentials: |
| 44 | +### Platform — OAuth (client credentials) |
87 | 45 |
|
88 | 46 | ```python |
89 | | ->>> import ipsdk |
90 | | ->>> platform = ipsdk.platform_factory( |
91 | | -... host="platform.itential.dev", |
92 | | -... client_id="your-client-id", |
93 | | -... client_secret="your-client-secret" |
94 | | -... ) |
95 | | ->>> res = platform.get("/adapters") |
96 | | -``` |
| 47 | +import ipsdk |
97 | 48 |
|
98 | | -### Gateway Connection |
| 49 | +platform = ipsdk.platform_factory( |
| 50 | + host="platform.itential.dev", |
| 51 | + client_id="your-client-id", |
| 52 | + client_secret="your-client-secret" |
| 53 | +) |
99 | 54 |
|
100 | | -Connecting to Itential Automation Gateway uses the same pattern: |
| 55 | +res = platform.get("/adapters") |
| 56 | +``` |
| 57 | + |
| 58 | +### Gateway |
101 | 59 |
|
102 | 60 | ```python |
103 | | ->>> import ipsdk |
104 | | ->>> gateway = ipsdk.gateway_factory( |
105 | | -... host="gateway.itential.dev", |
106 | | -... user="admin@itential", |
107 | | -... password="your-password" |
108 | | -... ) |
109 | | ->>> res = gateway.get("/devices") |
| 61 | +import ipsdk |
| 62 | + |
| 63 | +gateway = ipsdk.gateway_factory( |
| 64 | + host="gateway.itential.dev", |
| 65 | + user="admin@itential", |
| 66 | + password="your-password" |
| 67 | +) |
| 68 | + |
| 69 | +res = gateway.get("/devices") |
110 | 70 | ``` |
111 | 71 |
|
112 | | -### Async Support |
| 72 | +### Async |
113 | 73 |
|
114 | | -The SDK fully supports `asyncio` for asynchronous operations. Set `want_async=True` |
115 | | -when creating the connection: |
| 74 | +Pass `want_async=True` to get an async client: |
116 | 75 |
|
117 | 76 | ```python |
118 | 77 | import asyncio |
119 | 78 | import ipsdk |
120 | 79 |
|
121 | 80 | async def main(): |
122 | | - p = ipsdk.platform_factory( |
| 81 | + platform = ipsdk.platform_factory( |
123 | 82 | host="platform.itential.dev", |
124 | | - user="admin@pronghorn", |
| 83 | + client_id="your-client-id", |
| 84 | + client_secret="your-client-secret", |
125 | 85 | want_async=True |
126 | 86 | ) |
| 87 | + res = await platform.get("/adapters") |
| 88 | + print(res.json()) |
127 | 89 |
|
128 | | - res = await p.get("/adapters") |
129 | | - |
130 | | -if __name__ == "__main__": |
131 | | - asyncio.run(main()) |
| 90 | +asyncio.run(main()) |
132 | 91 | ``` |
133 | 92 |
|
134 | 93 | ## HTTP Methods |
135 | 94 |
|
136 | | -The connection object supports the following HTTP methods: |
137 | | - |
138 | | -- `GET` - Sends a HTTP GET request to the server and returns the results |
139 | | -- `POST` - Sends a HTTP POST request to the server and returns the results |
140 | | -- `PUT` - Sends a HTTP PUT request to the server and returns the results |
141 | | -- `DELETE` - Sends a HTTP DELETE request to the server and returns the results |
142 | | -- `PATCH` - Sends a HTTP PATCH request to the server and returns the results |
143 | | - |
144 | | -The following table shows the keyword arguments for each HTTP method: |
145 | | - |
146 | | - | Keyword | `GET` | `POST` | `PUT` | `DELETE` | `PATCH` | |
147 | | - |----------|---------------|----------|----------|---------------|----------| |
148 | | - | `path` | Required | Required | Required | Required | Required | |
149 | | - | `params` | Optional | Optional | Optional | Optional | Optional | |
150 | | - | `json` | Not Supported | Optional | Optional | Not Supported | Optional | |
| 95 | +All clients support `get`, `post`, `put`, `delete`, and `patch`. |
151 | 96 |
|
152 | | -The `path` argument specifies the relative path of the URI. This value is |
153 | | -prepended to the base URL. The base URL for Itential Platform is `<host>` and |
154 | | -the base URL for Itential Automation Gateway is `<host>/api/v2.0`. |
| 97 | +| Argument | `get` | `post` | `put` | `delete` | `patch` | |
| 98 | +|----------|----------|----------|----------|----------|----------| |
| 99 | +| `path` | required | required | required | required | required | |
| 100 | +| `params` | optional | optional | optional | optional | optional | |
| 101 | +| `json` | — | optional | optional | — | optional | |
155 | 102 |
|
156 | | -The `params` argument accepts a `dict` object that is transformed into the URL |
157 | | -query string. For example, if `params={"foo": "bar"}` the resulting query |
158 | | -string would be `?foo=bar` |
| 103 | +`path` is the relative URI appended to the base URL. `params` is a `dict` serialized to a query string. `json` accepts a `list` or `dict`; when provided, sets `Content-Type: application/json` automatically. |
159 | 104 |
|
160 | | -The `json` argument accepts the payload to send in the request as JSON. This |
161 | | -argument accepts either a `list` or `dict` object. When specified, the data |
162 | | -will automatically be converted to a JSON string and the `Content-Type` and |
163 | | -`Accept` headers will be set to `application/json`. |
| 105 | +**Base URLs:** |
| 106 | +- Platform: `https://host:port` |
| 107 | +- Gateway: `https://host:port/api/v2.0` |
164 | 108 |
|
165 | 109 | ## Configuration |
166 | 110 |
|
167 | | -Both the `platform_factory` and `gateway_factory` functions support |
168 | | -configuration using keyword arguments. The table below shows the keyword |
169 | | -arguments for each function along with their default value. |
170 | | - |
171 | | - | Keyword | `platform_factory` | `gateway_factory` | |
172 | | - |-----------------|--------------------|-------------------| |
173 | | - | `host` | `localhost` | `localhost` | |
174 | | - | `port` | `0` | `0` | |
175 | | - | `use_tls` | `True` | `True` | |
176 | | - | `verify` | `True` | `True` | |
177 | | - | `user` | `admin` | `admin@itential` | |
178 | | - | `password` | `admin` | `admin` | |
179 | | - | `client_id` | `None` | Not Supported | |
180 | | - | `client_secret` | `None` | Not Supported | |
181 | | - | `timeout` | `30` | `30` | |
182 | | - | `want_async` | `False` | `False` | |
| 111 | +| Parameter | `platform_factory` | `gateway_factory` | Description | |
| 112 | +|-----------------|--------------------|-------------------|--------------------------------------------------| |
| 113 | +| `host` | `"localhost"` | `"localhost"` | Hostname or IP | |
| 114 | +| `port` | `0` | `0` | Port; `0` = auto (443 for TLS, 80 for plain HTTP)| |
| 115 | +| `use_tls` | `True` | `True` | Use HTTPS | |
| 116 | +| `verify` | `True` | `True` | Verify TLS certificates | |
| 117 | +| `user` | `"admin"` | `"admin@itential"`| Username for basic auth | |
| 118 | +| `password` | `"admin"` | `"admin"` | Password for basic auth | |
| 119 | +| `client_id` | `None` | — | OAuth client ID (Platform only) | |
| 120 | +| `client_secret` | `None` | — | OAuth client secret (Platform only) | |
| 121 | +| `timeout` | `30` | `30` | Request timeout in seconds | |
| 122 | +| `ttl` | `0` | `0` | Re-authenticate after N seconds; `0` = disabled | |
| 123 | +| `want_async` | `False` | `False` | Return an async client | |
183 | 124 |
|
184 | 125 | ## Logging |
185 | 126 |
|
186 | | -The SDK includes a comprehensive logging system accessible via `ipsdk.logging`: |
187 | | - |
188 | 127 | ```python |
189 | 128 | import ipsdk |
190 | 129 |
|
191 | | -# Configure logging level |
192 | 130 | ipsdk.logging.set_level(ipsdk.logging.DEBUG) |
193 | | - |
194 | | -# Use convenience functions |
195 | 131 | ipsdk.logging.info("Connected to platform") |
196 | | -ipsdk.logging.debug("Request details: %s", request_data) |
197 | | -ipsdk.logging.error("API call failed") |
198 | 132 | ``` |
199 | 133 |
|
200 | | -**Logging Features**: |
201 | | -- **Multiple Log Levels**: TRACE (5), DEBUG, INFO, WARNING, ERROR, CRITICAL, FATAL (90), and NONE (100) |
202 | | -- **Convenience Functions**: `debug()`, `info()`, `warning()`, `error()`, `critical()`, `fatal()`, `exception()` |
203 | | -- **Function Tracing**: `@trace` decorator for automatic entry/exit logging with timing |
204 | | -- **Sensitive Data Filtering**: Automatic redaction of PII, API keys, passwords, and tokens |
205 | | -- **httpx Integration**: Optional control of httpx/httpcore logging via `propagate` parameter |
| 134 | +Available levels: `TRACE` (5), `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`, `FATAL` (90), `NONE` (100). |
206 | 135 |
|
207 | | -For detailed logging documentation, see the logging module docstrings. |
| 136 | +The `@ipsdk.logging.trace` decorator logs function entry/exit with timing. Sensitive data filtering (PII, passwords, tokens) is enabled by default and can be extended: |
208 | 137 |
|
209 | | -## Development |
| 138 | +```python |
| 139 | +ipsdk.logging.add_sensitive_data_pattern("ssn", r"\d{3}-\d{2}-\d{4}") |
| 140 | +``` |
210 | 141 |
|
211 | | -For development setup, testing, and contribution guidelines, see the [Development Guide](docs/development.md). |
| 142 | +## Development |
212 | 143 |
|
| 144 | +```bash |
| 145 | +# Install dependencies |
| 146 | +uv sync |
| 147 | + |
| 148 | +# Run checks (lint, format, security, tests, license headers) |
| 149 | +make premerge |
| 150 | + |
| 151 | +# Individual targets |
| 152 | +make test # pytest |
| 153 | +make coverage # pytest --cov (100% required) |
| 154 | +make lint # ruff check |
| 155 | +make format # ruff format |
| 156 | +make security # bandit scan |
| 157 | +make license # check GPL headers |
| 158 | + |
| 159 | +# Test across Python 3.10–3.13 |
| 160 | +uv run tox -p auto |
| 161 | +``` |
213 | 162 |
|
214 | 163 | ## License |
215 | 164 |
|
216 | | -This project is licensed under the GPLv3 open source license. See |
217 | | -[license](LICENSE) |
| 165 | +GPL-3.0-or-later. See [LICENSE](LICENSE). |
0 commit comments