dmn-sdk 0.1.0__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.
- dmn_sdk-0.1.0/LICENSE +158 -0
- dmn_sdk-0.1.0/PKG-INFO +237 -0
- dmn_sdk-0.1.0/README.md +209 -0
- dmn_sdk-0.1.0/dmn_sdk/__init__.py +48 -0
- dmn_sdk-0.1.0/dmn_sdk/_version.py +9 -0
- dmn_sdk-0.1.0/dmn_sdk/auth.py +123 -0
- dmn_sdk-0.1.0/dmn_sdk/client.py +365 -0
- dmn_sdk-0.1.0/dmn_sdk/errors.py +73 -0
- dmn_sdk-0.1.0/dmn_sdk/types.py +33 -0
- dmn_sdk-0.1.0/dmn_sdk.egg-info/PKG-INFO +237 -0
- dmn_sdk-0.1.0/dmn_sdk.egg-info/SOURCES.txt +16 -0
- dmn_sdk-0.1.0/dmn_sdk.egg-info/dependency_links.txt +1 -0
- dmn_sdk-0.1.0/dmn_sdk.egg-info/requires.txt +6 -0
- dmn_sdk-0.1.0/dmn_sdk.egg-info/top_level.txt +1 -0
- dmn_sdk-0.1.0/pyproject.toml +85 -0
- dmn_sdk-0.1.0/setup.cfg +4 -0
- dmn_sdk-0.1.0/tests/test_auth.py +130 -0
- dmn_sdk-0.1.0/tests/test_client.py +224 -0
dmn_sdk-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# DMN Mesh — Restricted-Use Evaluation Licence
|
|
2
|
+
|
|
3
|
+
**Issuer:** Tata Communications Limited ("**TCL**")
|
|
4
|
+
**Software:** dmn-ucpe and the DMN Mesh agent, dashboard, SDK and associated artefacts (collectively, the "**Software**")
|
|
5
|
+
**Classification:** Internal — Restricted Evaluation Release
|
|
6
|
+
**Status:** This is a **pre-release / testing build**. It is not a production-grade product.
|
|
7
|
+
|
|
8
|
+
> **NOTICE — DRAFT FOR LEGAL REVIEW.** This text is a working draft authored for an internal evaluation programme. It must be reviewed and signed off by TCL Legal before being presented to any tenant for acceptance.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Acceptance
|
|
13
|
+
|
|
14
|
+
1.1. By logging in to the DMN Mesh dashboard or invoking the DMN Mesh APIs as a tenant operator, the legal entity on whose behalf the tenant was provisioned (the "**Tenant**") is presented with this Licence and must indicate acceptance before any tenant-scoped feature becomes available.
|
|
15
|
+
|
|
16
|
+
1.2. Acceptance is recorded as an immutable, hash-chained audit entry signed by the issuing DMN agent, including the OpenID Connect (OIDC) identity of the human operator who acted, the software version, and the cryptographic digest of the Licence text shown at the time of acceptance.
|
|
17
|
+
|
|
18
|
+
1.3. **Acceptance is required again whenever a new release of the Software is installed on the mesh, or whenever the text of this Licence changes.** Previously recorded acceptances do not carry forward across release boundaries.
|
|
19
|
+
|
|
20
|
+
1.4. The person clicking "Accept" warrants that they are duly authorised to bind the Tenant to this Licence.
|
|
21
|
+
|
|
22
|
+
## 2. Limited Evaluation Grant
|
|
23
|
+
|
|
24
|
+
2.1. Subject to the Tenant's continued compliance with this Licence, TCL grants the Tenant a **non-exclusive, non-transferable, non-sublicensable, revocable** licence to access and use the Software **solely within the DMN mesh instance operated by TCL** for the Tenant's **internal evaluation and operational testing** purposes.
|
|
25
|
+
|
|
26
|
+
2.2. The grant is limited to use through the named tenant identity provisioned by TCL. The Tenant has no right to use the Software outside that tenant scope, on behalf of any third party, or for any commercial purpose other than the Tenant's own internal evaluation.
|
|
27
|
+
|
|
28
|
+
2.3. No title, ownership or intellectual property right in the Software is transferred to the Tenant. All rights not expressly granted are reserved by TCL.
|
|
29
|
+
|
|
30
|
+
## 3. Restrictions — Anti-Copying and Anti-Redistribution
|
|
31
|
+
|
|
32
|
+
The Tenant **shall not, and shall not permit any person under its control or instruction to**:
|
|
33
|
+
|
|
34
|
+
3.1. **Copy, mirror, archive, snapshot, image or export** the Software (in binary, source, container, image, package, configuration, key-material or any other form) outside the TCL-operated DMN mesh.
|
|
35
|
+
|
|
36
|
+
3.2. **Install, deploy, run, register, attach, join or attempt to onboard** the Software onto any node, device, hardware, virtual machine, container, cloud account, partner network or third-party environment that has not been explicitly authorised in writing by TCL.
|
|
37
|
+
|
|
38
|
+
3.3. **Redistribute, sublicense, lease, lend, sell, rent, host as a service, or otherwise make the Software available** to any third party.
|
|
39
|
+
|
|
40
|
+
3.4. **Reverse engineer, decompile, disassemble, decrypt, extract, or attempt to derive the source code, structure, internal logic, keying material, or trade secrets** of the Software, except to the minimum extent expressly required by applicable law and only after notifying TCL in writing.
|
|
41
|
+
|
|
42
|
+
3.5. **Remove, obscure, alter, or interfere with** any proprietary notice, copyright marker, licence banner, watermark, audit hook, attestation envelope, signature envelope, or telemetry channel embedded in the Software.
|
|
43
|
+
|
|
44
|
+
3.6. **Publish or disclose** any benchmark, performance number, comparison, screenshot, defect report, security finding, training output, derived dataset, or analytical result obtained through the Software, in any external venue, without TCL's prior written consent.
|
|
45
|
+
|
|
46
|
+
3.7. **Share, delegate, federate or transfer** the tenant identity, the OIDC credentials, the cryptographic keys, the signed manifests, or any session token issued by the Software, to any person other than employees of the Tenant who are individually bound by confidentiality obligations no less protective than those in this Licence.
|
|
47
|
+
|
|
48
|
+
3.8. **Use the Software to circumvent or attempt to circumvent** any access control, policy gate, capability gate, attestation check, signature check, audit log, tenant scoping, or rate limit imposed by the Software or by TCL.
|
|
49
|
+
|
|
50
|
+
## 4. Pre-Release Software Notice and Risk Acknowledgement
|
|
51
|
+
|
|
52
|
+
4.1. **The Software is a pre-release, experimental, testing build.** It is provided for the Tenant's evaluation only and is **not warranted, certified, or intended for production, mission-critical, regulated, safety-of-life, or revenue-generating workloads**.
|
|
53
|
+
|
|
54
|
+
4.2. **The operational impact of the Software on the Tenant's existing systems, networks, applications, security posture, regulatory compliance, data integrity, or service availability has not been measured, validated, or certified** by TCL. The Tenant acknowledges that the Software may interact with the Tenant's environment in ways that are not fully characterised.
|
|
55
|
+
|
|
56
|
+
4.3. **The Software is expected to contain defects, regressions, breaking changes, behavioural surprises, performance variability, and undocumented behaviour.** Frequent releases — including releases that alter, remove, or replace capabilities the Tenant currently relies on — are anticipated.
|
|
57
|
+
|
|
58
|
+
4.4. **The Tenant agrees to use the Software with the utmost caution and responsibility**, including but not limited to: deploying it first in non-critical environments, maintaining independent backups and rollback paths, isolating it from systems whose continued operation is materially important, and treating every release as a fresh evaluation event.
|
|
59
|
+
|
|
60
|
+
4.5. The Tenant acknowledges that this Licence and the Software may be modified, suspended, withdrawn or terminated by TCL at any time, with or without notice, including in response to operational risk.
|
|
61
|
+
|
|
62
|
+
## 5. Tenant Responsibilities — Monitoring, Review, and Reporting
|
|
63
|
+
|
|
64
|
+
The Tenant shall, on a continuing basis and at the Tenant's sole cost:
|
|
65
|
+
|
|
66
|
+
5.1. **Continuously monitor** the behaviour, output, resource consumption, network activity, and security posture of the Software within the Tenant's environment.
|
|
67
|
+
|
|
68
|
+
5.2. **Periodically review** the Software's effects on the Tenant's connected systems, including any unexpected change in performance, latency, traffic patterns, data flows, model outputs, or third-party integrations.
|
|
69
|
+
|
|
70
|
+
5.3. **Promptly report** to TCL, through the channel TCL designates, any of the following: suspected defect; suspected security vulnerability; suspected data leakage; suspected policy violation; suspected unauthorised access; unexpected behaviour of any kind; any third-party complaint, dispute, regulatory enquiry, or incident response engagement that relates in any way to the Software.
|
|
71
|
+
|
|
72
|
+
5.4. **Cooperate in good faith** with any TCL investigation, including by providing relevant logs, audit chain entries, configuration, and signed manifests on TCL's reasonable request.
|
|
73
|
+
|
|
74
|
+
5.5. **Not delay** reporting under section 5.3 for commercial, reputational, or convenience reasons. The Tenant acknowledges that silence on a known defect or vulnerability is itself a material breach of this Licence.
|
|
75
|
+
|
|
76
|
+
## 6. Disclaimer of Warranties
|
|
77
|
+
|
|
78
|
+
6.1. **THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE", WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND.** To the maximum extent permitted by applicable law, TCL expressly disclaims all warranties, conditions, representations and terms — whether express, implied, statutory, contractual, customary, or otherwise — including without limitation any warranty of **merchantability, fitness for a particular purpose, accuracy, completeness, reliability, availability, timeliness, security, non-infringement, quiet enjoyment, title, or course of dealing**.
|
|
79
|
+
|
|
80
|
+
6.2. **TCL does not warrant** that the Software will meet the Tenant's requirements, operate without interruption, be free of defects, be free of vulnerabilities, produce correct results, preserve any data, prevent unauthorised access, comply with any standard, integrate with any third-party product, or be compatible with any future version of itself.
|
|
81
|
+
|
|
82
|
+
6.3. **No advice or information**, whether oral or written, obtained from TCL or through the Software, shall create any warranty not expressly stated in this Licence.
|
|
83
|
+
|
|
84
|
+
## 7. Limitation of Liability and Indemnity
|
|
85
|
+
|
|
86
|
+
7.1. **TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, TCL SHALL NOT BE LIABLE TO THE TENANT, ITS AFFILIATES, ITS PERSONNEL, ITS CUSTOMERS, OR ANY THIRD PARTY** for any direct, indirect, incidental, special, consequential, exemplary, punitive, or any other damages whatsoever arising out of, related to, or in connection with the Software, this Licence, or the Tenant's use of, inability to use, or reliance on the Software — including without limitation damages for loss of profits, loss of revenue, loss of business, loss of goodwill, loss of data, loss of use, loss of customers, cost of substitute products, regulatory fines, third-party claims, downtime, breach of security, breach of confidentiality, or any other commercial or operational loss — even if TCL has been advised of, or could have foreseen, the possibility of such damages.
|
|
87
|
+
|
|
88
|
+
7.2. The Tenant acknowledges that **the aggregate liability of TCL** under or in connection with this Licence and the Software, on any theory of liability whatsoever (including contract, tort, strict liability, statute, or otherwise), shall **not exceed zero (₹0)**, the parties having expressly priced the Software as a no-fee evaluation release.
|
|
89
|
+
|
|
90
|
+
7.3. **The Tenant shall defend, indemnify, and hold harmless** TCL, its affiliates, and their respective officers, directors, employees, and agents from and against any and all third-party claims, demands, actions, proceedings, damages, liabilities, losses, costs and expenses (including reasonable legal fees) arising out of or in connection with: (a) the Tenant's breach of this Licence; (b) the Tenant's use of the Software in violation of section 3; (c) the Tenant's failure to monitor, review, or report as required by section 5; or (d) any data, content or input the Tenant introduces into the Software.
|
|
91
|
+
|
|
92
|
+
7.4. The exclusions and limitations in this section 7 apply regardless of whether the remedies in this Licence are found to have failed of their essential purpose. They form an essential basis of the bargain between the parties; absent them, TCL would not provide the Software on a no-fee evaluation basis.
|
|
93
|
+
|
|
94
|
+
## 8. Audit, Logging and Telemetry
|
|
95
|
+
|
|
96
|
+
8.1. The Tenant acknowledges and consents that the Software records, and that TCL may collect and retain, **a hash-chained audit log of all Tenant-initiated state changes**, including without limitation: acceptance of this Licence, app and API onboarding, pipeline operations, model promotion, round abort, tenant withdrawal, and any operator action through the dashboard.
|
|
97
|
+
|
|
98
|
+
8.2. Audit entries are append-only, signed, and chained by cryptographic hash. The Tenant shall not delete, alter, redact, exfiltrate, or interfere with the audit log.
|
|
99
|
+
|
|
100
|
+
8.3. TCL may use audit data to investigate suspected breach of this Licence, to respond to incidents, to improve the Software, and to satisfy regulatory or contractual obligations.
|
|
101
|
+
|
|
102
|
+
## 9. Suspension and Termination
|
|
103
|
+
|
|
104
|
+
9.1. TCL may **suspend or terminate** this Licence, the Tenant's access to the Software, or any specific capability, at any time, with or without notice, for any reason or no reason, including suspected breach of section 3 (Restrictions), section 5 (Reporting), or section 8 (Audit).
|
|
105
|
+
|
|
106
|
+
9.2. The Tenant may terminate this Licence by ceasing all use of the Software and requesting tenant withdrawal through the dashboard.
|
|
107
|
+
|
|
108
|
+
9.3. **Effect of tenant deletion.** Upon withdrawal or deletion of the Tenant from the mesh — whether by the Tenant, by TCL, or automatically as a consequence of suspension — this Licence is automatically terminated, the Tenant's acceptance record is tombstoned, and the agreement becomes **null and void** as between the parties on a go-forward basis. Sections 3, 5.3, 6, 7, 8 and 11 survive termination.
|
|
109
|
+
|
|
110
|
+
9.4. Termination does not entitle the Tenant to a refund or any other remedy; the Software is provided at no charge.
|
|
111
|
+
|
|
112
|
+
## 10. No Support, No Service Level
|
|
113
|
+
|
|
114
|
+
10.1. TCL is under **no obligation** to provide support, bug fixes, updates, upgrades, patches, security advisories, migrations, or professional services in connection with the Software.
|
|
115
|
+
|
|
116
|
+
10.2. No service-level agreement, availability commitment, or response-time commitment of any kind applies to the Software.
|
|
117
|
+
|
|
118
|
+
## 11. Confidentiality
|
|
119
|
+
|
|
120
|
+
11.1. The Software, its design, its internal interfaces, the contents of any audit or telemetry data shared with the Tenant, and any defect or security finding the Tenant becomes aware of through use of the Software, are **TCL Confidential Information**.
|
|
121
|
+
|
|
122
|
+
11.2. The Tenant shall protect TCL Confidential Information with at least the same degree of care it uses for its own most sensitive confidential information, and in no event less than a reasonable degree of care.
|
|
123
|
+
|
|
124
|
+
## 12. Compliance with Law
|
|
125
|
+
|
|
126
|
+
12.1. The Tenant shall use the Software in compliance with all applicable laws and regulations, including without limitation laws governing data protection, privacy, cryptography, export control, sanctions, and information security.
|
|
127
|
+
|
|
128
|
+
12.2. The Software contains cryptographic components. The Tenant is solely responsible for ensuring that its use, possession, import or transmission of such components is lawful in every jurisdiction in which the Tenant operates.
|
|
129
|
+
|
|
130
|
+
## 13. Governing Law and Jurisdiction
|
|
131
|
+
|
|
132
|
+
13.1. This Licence is governed by and construed in accordance with the laws of the Republic of India, without regard to its conflict-of-laws principles.
|
|
133
|
+
|
|
134
|
+
13.2. The courts at **Mumbai, Maharashtra, India** shall have exclusive jurisdiction over any dispute arising out of or in connection with this Licence.
|
|
135
|
+
|
|
136
|
+
## 14. Entire Agreement; Severability; No Waiver
|
|
137
|
+
|
|
138
|
+
14.1. This Licence is the entire agreement between the parties with respect to the Software and supersedes any prior or contemporaneous agreement, representation, or understanding.
|
|
139
|
+
|
|
140
|
+
14.2. If any provision of this Licence is held to be unenforceable, the remaining provisions shall continue in full force and effect, and the unenforceable provision shall be replaced by an enforceable provision that most closely reflects the parties' intent.
|
|
141
|
+
|
|
142
|
+
14.3. No failure or delay by TCL in exercising any right under this Licence shall operate as a waiver of that right.
|
|
143
|
+
|
|
144
|
+
## 15. Acceptance Mechanism
|
|
145
|
+
|
|
146
|
+
15.1. Acceptance is captured electronically by the DMN Mesh dashboard, signed by the issuing agent, and stored as an immutable, hash-chained audit entry. Each acceptance entry binds together:
|
|
147
|
+
|
|
148
|
+
- the canonical name of the Tenant on the mesh;
|
|
149
|
+
- the software version and the SHA-256 digest of this Licence text;
|
|
150
|
+
- the OIDC issuer, subject, and bearer-token digest of the human operator who acted;
|
|
151
|
+
- the hybrid logical clock and wall-clock timestamps of the action; and
|
|
152
|
+
- the identity of the agent that witnessed the acceptance.
|
|
153
|
+
|
|
154
|
+
15.2. The Tenant agrees that this electronic record constitutes valid, enforceable evidence of acceptance, equivalent to a handwritten signature.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
*End of Licence.* © Tata Communications Limited. All rights reserved.
|
dmn_sdk-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dmn-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for the DMN mesh — call tenant APIs from your code.
|
|
5
|
+
Author-email: inno8cube <dmn-dev@inno8cube.com>
|
|
6
|
+
License-Expression: LicenseRef-RestrictedUseEvaluation
|
|
7
|
+
Project-URL: Homepage, https://github.com/dmn-ucpe/dmn-ucpe
|
|
8
|
+
Project-URL: Documentation, https://github.com/dmn-ucpe/dmn-ucpe/blob/main/docs/SDK.md
|
|
9
|
+
Project-URL: Source, https://github.com/dmn-ucpe/dmn-ucpe/tree/main/sdk/python
|
|
10
|
+
Keywords: dmn,mesh,ndn,sdk,iot,telemetry
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: requests<3,>=2.31
|
|
23
|
+
Requires-Dist: websocket-client<2,>=1.7
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
26
|
+
Requires-Dist: responses>=0.23; extra == "dev"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# dmn-sdk
|
|
30
|
+
|
|
31
|
+
Python client for the DMN mesh. Call tenant APIs from your own code with one import.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
From a checkout:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install ./sdk/python/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
From PyPI (v0.282.3+):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install dmn-sdk
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Requires Python 3.9+. Pulls in `requests` and `websocket-client`.
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import dmn_sdk as dmn
|
|
53
|
+
|
|
54
|
+
client = dmn.connect() # reads DMN_API_TOKEN env
|
|
55
|
+
ingestor = client.tenant("/tata/dmn/acme").app("ingestor")
|
|
56
|
+
|
|
57
|
+
# Unary POST
|
|
58
|
+
resp = ingestor.post("/telemetry", json={"sensor": "s1", "value": 23.4})
|
|
59
|
+
print(resp.status_code, resp.json())
|
|
60
|
+
|
|
61
|
+
# Subscribe to a topic
|
|
62
|
+
for msg in ingestor.subscribe("telemetry"):
|
|
63
|
+
print(msg.seq, msg.payload)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Authentication
|
|
67
|
+
|
|
68
|
+
Three sources, in priority order:
|
|
69
|
+
|
|
70
|
+
1. **Explicit kwargs** to `dmn.connect(token=..., base_url=...)`
|
|
71
|
+
2. **Environment**: `DMN_API_TOKEN` + `DMN_API_BASE_URL` + (optional) `DMN_PROFILE`
|
|
72
|
+
3. **Config file** `~/.dmn/credentials` (INI-style)
|
|
73
|
+
|
|
74
|
+
### Env var setup
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Mint a token at /ui/dev/tokens/ on the dashboard,
|
|
78
|
+
# then export:
|
|
79
|
+
export DMN_API_TOKEN="eyJhbGc...the wire JWT..."
|
|
80
|
+
export DMN_API_BASE_URL="https://console.dmn.inno8cube.com"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Config file setup
|
|
84
|
+
|
|
85
|
+
`~/.dmn/credentials`:
|
|
86
|
+
|
|
87
|
+
```ini
|
|
88
|
+
[default]
|
|
89
|
+
token = eyJhbGc...
|
|
90
|
+
base_url = https://console.dmn.inno8cube.com
|
|
91
|
+
|
|
92
|
+
[acme-prod]
|
|
93
|
+
token = eyJhbGc...
|
|
94
|
+
base_url = https://console.dmn.acme.io
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Pick a profile:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
client = dmn.connect(profile="acme-prod")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or via env: `export DMN_PROFILE=acme-prod`.
|
|
104
|
+
|
|
105
|
+
## API reference
|
|
106
|
+
|
|
107
|
+
### `dmn.connect(...)`
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
def connect(
|
|
111
|
+
token: str | None = None,
|
|
112
|
+
base_url: str | None = None,
|
|
113
|
+
*,
|
|
114
|
+
profile: str | None = None,
|
|
115
|
+
config_path: str | None = None,
|
|
116
|
+
timeout: float = 30,
|
|
117
|
+
ws_timeout: float = 30,
|
|
118
|
+
verify_tls: bool = True,
|
|
119
|
+
user_agent: str | None = None,
|
|
120
|
+
) -> Client
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Returns a `Client`. Raises `dmn.ConfigError` if no source can supply `token` + `base_url`.
|
|
124
|
+
|
|
125
|
+
### `Client.tenant(name)`
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
def tenant(self, name: str) -> Tenant
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`name` must be a full NDN name starting with `/`, e.g. `"/tata/dmn/acme"`. Returns a `Tenant`.
|
|
132
|
+
|
|
133
|
+
### `Tenant.app(name)`
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
def app(self, name: str) -> App
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Returns an `App` handle.
|
|
140
|
+
|
|
141
|
+
### Unary methods on `App`
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
app.get(path, **kwargs) -> Response
|
|
145
|
+
app.post(path, **kwargs) -> Response
|
|
146
|
+
app.put(path, **kwargs) -> Response
|
|
147
|
+
app.patch(path, **kwargs) -> Response
|
|
148
|
+
app.delete(path, **kwargs) -> Response
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`**kwargs` are passed through to `requests.Session.request` — most useful ones: `json=`, `data=`, `params=`, `headers=`, `timeout=`.
|
|
152
|
+
|
|
153
|
+
### `App.subscribe(topic)`
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
def subscribe(self, topic: str) -> Iterator[Message]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Opens a WebSocket to the gateway's subscribe bridge. Yields `Message(seq, topic, payload, ts)` objects as they arrive. The iterator runs until the server closes the connection or you `break`. Re-iterating opens a fresh connection.
|
|
160
|
+
|
|
161
|
+
### `Response`
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
resp.status_code -> int
|
|
165
|
+
resp.ok -> bool # True for 2xx
|
|
166
|
+
resp.headers -> dict[str,str]
|
|
167
|
+
resp.text -> str
|
|
168
|
+
resp.content -> bytes
|
|
169
|
+
resp.json() -> Any
|
|
170
|
+
resp.raw -> requests.Response # power-user escape hatch
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `Message`
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
@dataclass(frozen=True)
|
|
177
|
+
class Message:
|
|
178
|
+
seq: int # per-topic monotonic sequence number
|
|
179
|
+
topic: str # which topic this message was on
|
|
180
|
+
payload: Any # decoded JSON body
|
|
181
|
+
ts: int # unix timestamp (seconds) at the publisher
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Errors
|
|
185
|
+
|
|
186
|
+
All raised by the SDK descend from `dmn.DMNError`:
|
|
187
|
+
|
|
188
|
+
| Exception | When |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `dmn.ConfigError` | Missing token/base_url, malformed config file, unknown profile |
|
|
191
|
+
| `dmn.AuthError` | Gateway returned 401 or 403 |
|
|
192
|
+
| `dmn.NotFoundError` | Gateway returned 404 (tenant/app not in routing table) |
|
|
193
|
+
| `dmn.BackendError` | 5xx from the backend, transport failures, gateway-streamed error frame |
|
|
194
|
+
| `dmn.APIError` | Other non-2xx responses |
|
|
195
|
+
|
|
196
|
+
Most application code wants:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
try:
|
|
200
|
+
resp = ingestor.post("/telemetry", json={...})
|
|
201
|
+
except dmn.AuthError:
|
|
202
|
+
# Token issue — re-mint or re-auth
|
|
203
|
+
raise
|
|
204
|
+
except dmn.NotFoundError:
|
|
205
|
+
# Misconfigured route
|
|
206
|
+
raise
|
|
207
|
+
except dmn.BackendError as e:
|
|
208
|
+
# Retryable
|
|
209
|
+
print(f"retrying: {e}")
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Examples
|
|
213
|
+
|
|
214
|
+
See `examples/`:
|
|
215
|
+
|
|
216
|
+
- `post_telemetry.py` — single-shot POST to the reference ingestor
|
|
217
|
+
- `subscribe_topic.py` — WebSocket-backed iterator consuming a topic
|
|
218
|
+
|
|
219
|
+
## Dev notes
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Run tests
|
|
223
|
+
cd sdk/python
|
|
224
|
+
pip install -e ".[dev]"
|
|
225
|
+
pytest -v
|
|
226
|
+
|
|
227
|
+
# Lint (if installed)
|
|
228
|
+
ruff check dmn_sdk tests
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Versioning
|
|
232
|
+
|
|
233
|
+
The SDK version tracks the DMN agent's compatible wire format. v0.282.x is the first stable line; breaking changes to the gateway's REST/WS surface will bump the major. Backwards-compatible additions bump the minor.
|
|
234
|
+
|
|
235
|
+
## License
|
|
236
|
+
|
|
237
|
+
Restricted-Use Evaluation Licence — see `../../docs/RESTRICTED-USE-LICENSE.md`.
|
dmn_sdk-0.1.0/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# dmn-sdk
|
|
2
|
+
|
|
3
|
+
Python client for the DMN mesh. Call tenant APIs from your own code with one import.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
From a checkout:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install ./sdk/python/
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
From PyPI (v0.282.3+):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install dmn-sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires Python 3.9+. Pulls in `requests` and `websocket-client`.
|
|
20
|
+
|
|
21
|
+
## Quickstart
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import dmn_sdk as dmn
|
|
25
|
+
|
|
26
|
+
client = dmn.connect() # reads DMN_API_TOKEN env
|
|
27
|
+
ingestor = client.tenant("/tata/dmn/acme").app("ingestor")
|
|
28
|
+
|
|
29
|
+
# Unary POST
|
|
30
|
+
resp = ingestor.post("/telemetry", json={"sensor": "s1", "value": 23.4})
|
|
31
|
+
print(resp.status_code, resp.json())
|
|
32
|
+
|
|
33
|
+
# Subscribe to a topic
|
|
34
|
+
for msg in ingestor.subscribe("telemetry"):
|
|
35
|
+
print(msg.seq, msg.payload)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Authentication
|
|
39
|
+
|
|
40
|
+
Three sources, in priority order:
|
|
41
|
+
|
|
42
|
+
1. **Explicit kwargs** to `dmn.connect(token=..., base_url=...)`
|
|
43
|
+
2. **Environment**: `DMN_API_TOKEN` + `DMN_API_BASE_URL` + (optional) `DMN_PROFILE`
|
|
44
|
+
3. **Config file** `~/.dmn/credentials` (INI-style)
|
|
45
|
+
|
|
46
|
+
### Env var setup
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Mint a token at /ui/dev/tokens/ on the dashboard,
|
|
50
|
+
# then export:
|
|
51
|
+
export DMN_API_TOKEN="eyJhbGc...the wire JWT..."
|
|
52
|
+
export DMN_API_BASE_URL="https://console.dmn.inno8cube.com"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Config file setup
|
|
56
|
+
|
|
57
|
+
`~/.dmn/credentials`:
|
|
58
|
+
|
|
59
|
+
```ini
|
|
60
|
+
[default]
|
|
61
|
+
token = eyJhbGc...
|
|
62
|
+
base_url = https://console.dmn.inno8cube.com
|
|
63
|
+
|
|
64
|
+
[acme-prod]
|
|
65
|
+
token = eyJhbGc...
|
|
66
|
+
base_url = https://console.dmn.acme.io
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Pick a profile:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
client = dmn.connect(profile="acme-prod")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or via env: `export DMN_PROFILE=acme-prod`.
|
|
76
|
+
|
|
77
|
+
## API reference
|
|
78
|
+
|
|
79
|
+
### `dmn.connect(...)`
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
def connect(
|
|
83
|
+
token: str | None = None,
|
|
84
|
+
base_url: str | None = None,
|
|
85
|
+
*,
|
|
86
|
+
profile: str | None = None,
|
|
87
|
+
config_path: str | None = None,
|
|
88
|
+
timeout: float = 30,
|
|
89
|
+
ws_timeout: float = 30,
|
|
90
|
+
verify_tls: bool = True,
|
|
91
|
+
user_agent: str | None = None,
|
|
92
|
+
) -> Client
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Returns a `Client`. Raises `dmn.ConfigError` if no source can supply `token` + `base_url`.
|
|
96
|
+
|
|
97
|
+
### `Client.tenant(name)`
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
def tenant(self, name: str) -> Tenant
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`name` must be a full NDN name starting with `/`, e.g. `"/tata/dmn/acme"`. Returns a `Tenant`.
|
|
104
|
+
|
|
105
|
+
### `Tenant.app(name)`
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
def app(self, name: str) -> App
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Returns an `App` handle.
|
|
112
|
+
|
|
113
|
+
### Unary methods on `App`
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
app.get(path, **kwargs) -> Response
|
|
117
|
+
app.post(path, **kwargs) -> Response
|
|
118
|
+
app.put(path, **kwargs) -> Response
|
|
119
|
+
app.patch(path, **kwargs) -> Response
|
|
120
|
+
app.delete(path, **kwargs) -> Response
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`**kwargs` are passed through to `requests.Session.request` — most useful ones: `json=`, `data=`, `params=`, `headers=`, `timeout=`.
|
|
124
|
+
|
|
125
|
+
### `App.subscribe(topic)`
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
def subscribe(self, topic: str) -> Iterator[Message]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Opens a WebSocket to the gateway's subscribe bridge. Yields `Message(seq, topic, payload, ts)` objects as they arrive. The iterator runs until the server closes the connection or you `break`. Re-iterating opens a fresh connection.
|
|
132
|
+
|
|
133
|
+
### `Response`
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
resp.status_code -> int
|
|
137
|
+
resp.ok -> bool # True for 2xx
|
|
138
|
+
resp.headers -> dict[str,str]
|
|
139
|
+
resp.text -> str
|
|
140
|
+
resp.content -> bytes
|
|
141
|
+
resp.json() -> Any
|
|
142
|
+
resp.raw -> requests.Response # power-user escape hatch
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `Message`
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
@dataclass(frozen=True)
|
|
149
|
+
class Message:
|
|
150
|
+
seq: int # per-topic monotonic sequence number
|
|
151
|
+
topic: str # which topic this message was on
|
|
152
|
+
payload: Any # decoded JSON body
|
|
153
|
+
ts: int # unix timestamp (seconds) at the publisher
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Errors
|
|
157
|
+
|
|
158
|
+
All raised by the SDK descend from `dmn.DMNError`:
|
|
159
|
+
|
|
160
|
+
| Exception | When |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `dmn.ConfigError` | Missing token/base_url, malformed config file, unknown profile |
|
|
163
|
+
| `dmn.AuthError` | Gateway returned 401 or 403 |
|
|
164
|
+
| `dmn.NotFoundError` | Gateway returned 404 (tenant/app not in routing table) |
|
|
165
|
+
| `dmn.BackendError` | 5xx from the backend, transport failures, gateway-streamed error frame |
|
|
166
|
+
| `dmn.APIError` | Other non-2xx responses |
|
|
167
|
+
|
|
168
|
+
Most application code wants:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
try:
|
|
172
|
+
resp = ingestor.post("/telemetry", json={...})
|
|
173
|
+
except dmn.AuthError:
|
|
174
|
+
# Token issue — re-mint or re-auth
|
|
175
|
+
raise
|
|
176
|
+
except dmn.NotFoundError:
|
|
177
|
+
# Misconfigured route
|
|
178
|
+
raise
|
|
179
|
+
except dmn.BackendError as e:
|
|
180
|
+
# Retryable
|
|
181
|
+
print(f"retrying: {e}")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Examples
|
|
185
|
+
|
|
186
|
+
See `examples/`:
|
|
187
|
+
|
|
188
|
+
- `post_telemetry.py` — single-shot POST to the reference ingestor
|
|
189
|
+
- `subscribe_topic.py` — WebSocket-backed iterator consuming a topic
|
|
190
|
+
|
|
191
|
+
## Dev notes
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Run tests
|
|
195
|
+
cd sdk/python
|
|
196
|
+
pip install -e ".[dev]"
|
|
197
|
+
pytest -v
|
|
198
|
+
|
|
199
|
+
# Lint (if installed)
|
|
200
|
+
ruff check dmn_sdk tests
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Versioning
|
|
204
|
+
|
|
205
|
+
The SDK version tracks the DMN agent's compatible wire format. v0.282.x is the first stable line; breaking changes to the gateway's REST/WS surface will bump the major. Backwards-compatible additions bump the minor.
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
Restricted-Use Evaluation Licence — see `../../docs/RESTRICTED-USE-LICENSE.md`.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""dmn-sdk — Python client for the DMN mesh.
|
|
2
|
+
|
|
3
|
+
Quickstart:
|
|
4
|
+
|
|
5
|
+
import dmn
|
|
6
|
+
|
|
7
|
+
client = dmn.connect() # reads DMN_API_TOKEN env
|
|
8
|
+
ingestor = client.tenant("/tata/dmn/acme").app("ingestor")
|
|
9
|
+
|
|
10
|
+
resp = ingestor.post("/telemetry", json={"sensor": "s1", "value": 23.4})
|
|
11
|
+
print(resp.json())
|
|
12
|
+
|
|
13
|
+
for msg in ingestor.subscribe("telemetry"):
|
|
14
|
+
print(msg.seq, msg.payload)
|
|
15
|
+
|
|
16
|
+
See https://github.com/dmn-ucpe/dmn-ucpe/blob/main/docs/SDK.md
|
|
17
|
+
for the full reference.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from ._version import __version__
|
|
23
|
+
from .client import Client, Response, Tenant, App, connect
|
|
24
|
+
from .errors import (
|
|
25
|
+
DMNError,
|
|
26
|
+
ConfigError,
|
|
27
|
+
AuthError,
|
|
28
|
+
NotFoundError,
|
|
29
|
+
BackendError,
|
|
30
|
+
APIError,
|
|
31
|
+
)
|
|
32
|
+
from .types import Message
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"__version__",
|
|
36
|
+
"connect",
|
|
37
|
+
"Client",
|
|
38
|
+
"Tenant",
|
|
39
|
+
"App",
|
|
40
|
+
"Response",
|
|
41
|
+
"Message",
|
|
42
|
+
"DMNError",
|
|
43
|
+
"ConfigError",
|
|
44
|
+
"AuthError",
|
|
45
|
+
"NotFoundError",
|
|
46
|
+
"BackendError",
|
|
47
|
+
"APIError",
|
|
48
|
+
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Single source of truth for the SDK version.
|
|
2
|
+
|
|
3
|
+
Kept in its own module so it can be imported during
|
|
4
|
+
package build (setuptools' dynamic version lookup) +
|
|
5
|
+
imported at runtime by tests / log statements without
|
|
6
|
+
pulling in the rest of the SDK.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|