koios-client 1.0.0rc1__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 (151) hide show
  1. koios_client-1.0.0rc1/PKG-INFO +537 -0
  2. koios_client-1.0.0rc1/README.md +508 -0
  3. koios_client-1.0.0rc1/pyproject.toml +117 -0
  4. koios_client-1.0.0rc1/setup.cfg +4 -0
  5. koios_client-1.0.0rc1/src/koios_client/__init__.py +80 -0
  6. koios_client-1.0.0rc1/src/koios_client/_auth.py +214 -0
  7. koios_client-1.0.0rc1/src/koios_client/_generated/__init__.py +1424 -0
  8. koios_client-1.0.0rc1/src/koios_client/_generated/acknowledge_all_events.py +40 -0
  9. koios_client-1.0.0rc1/src/koios_client/_generated/acknowledge_event.py +40 -0
  10. koios_client-1.0.0rc1/src/koios_client/_generated/acknowledge_events.py +40 -0
  11. koios_client-1.0.0rc1/src/koios_client/_generated/base_client.py +199 -0
  12. koios_client-1.0.0rc1/src/koios_client/_generated/base_model.py +30 -0
  13. koios_client-1.0.0rc1/src/koios_client/_generated/client.py +4245 -0
  14. koios_client-1.0.0rc1/src/koios_client/_generated/create_component_environment.py +39 -0
  15. koios_client-1.0.0rc1/src/koios_client/_generated/create_component_instance.py +39 -0
  16. koios_client-1.0.0rc1/src/koios_client/_generated/create_device.py +39 -0
  17. koios_client-1.0.0rc1/src/koios_client/_generated/create_device_set.py +39 -0
  18. koios_client-1.0.0rc1/src/koios_client/_generated/create_endpoint_client.py +41 -0
  19. koios_client-1.0.0rc1/src/koios_client/_generated/create_local_value.py +39 -0
  20. koios_client-1.0.0rc1/src/koios_client/_generated/create_model.py +39 -0
  21. koios_client-1.0.0rc1/src/koios_client/_generated/create_scan_group.py +39 -0
  22. koios_client-1.0.0rc1/src/koios_client/_generated/create_tag.py +39 -0
  23. koios_client-1.0.0rc1/src/koios_client/_generated/create_trend.py +38 -0
  24. koios_client-1.0.0rc1/src/koios_client/_generated/create_trend_item.py +38 -0
  25. koios_client-1.0.0rc1/src/koios_client/_generated/create_wire.py +37 -0
  26. koios_client-1.0.0rc1/src/koios_client/_generated/delete_component_environment.py +39 -0
  27. koios_client-1.0.0rc1/src/koios_client/_generated/delete_component_instance.py +39 -0
  28. koios_client-1.0.0rc1/src/koios_client/_generated/delete_component_library.py +43 -0
  29. koios_client-1.0.0rc1/src/koios_client/_generated/delete_device.py +38 -0
  30. koios_client-1.0.0rc1/src/koios_client/_generated/delete_device_set.py +39 -0
  31. koios_client-1.0.0rc1/src/koios_client/_generated/delete_device_sets.py +17 -0
  32. koios_client-1.0.0rc1/src/koios_client/_generated/delete_devices.py +17 -0
  33. koios_client-1.0.0rc1/src/koios_client/_generated/delete_endpoint_client.py +38 -0
  34. koios_client-1.0.0rc1/src/koios_client/_generated/delete_events.py +17 -0
  35. koios_client-1.0.0rc1/src/koios_client/_generated/delete_local_value.py +39 -0
  36. koios_client-1.0.0rc1/src/koios_client/_generated/delete_local_values.py +19 -0
  37. koios_client-1.0.0rc1/src/koios_client/_generated/delete_model.py +38 -0
  38. koios_client-1.0.0rc1/src/koios_client/_generated/delete_models.py +17 -0
  39. koios_client-1.0.0rc1/src/koios_client/_generated/delete_scan_group.py +39 -0
  40. koios_client-1.0.0rc1/src/koios_client/_generated/delete_scan_groups.py +17 -0
  41. koios_client-1.0.0rc1/src/koios_client/_generated/delete_tag.py +38 -0
  42. koios_client-1.0.0rc1/src/koios_client/_generated/delete_tags.py +17 -0
  43. koios_client-1.0.0rc1/src/koios_client/_generated/delete_trend.py +38 -0
  44. koios_client-1.0.0rc1/src/koios_client/_generated/delete_trend_item.py +38 -0
  45. koios_client-1.0.0rc1/src/koios_client/_generated/delete_wire.py +37 -0
  46. koios_client-1.0.0rc1/src/koios_client/_generated/duplicate_device.py +39 -0
  47. koios_client-1.0.0rc1/src/koios_client/_generated/duplicate_model.py +39 -0
  48. koios_client-1.0.0rc1/src/koios_client/_generated/duplicate_tag.py +38 -0
  49. koios_client-1.0.0rc1/src/koios_client/_generated/duplicate_trend.py +39 -0
  50. koios_client-1.0.0rc1/src/koios_client/_generated/enums.py +527 -0
  51. koios_client-1.0.0rc1/src/koios_client/_generated/exceptions.py +85 -0
  52. koios_client-1.0.0rc1/src/koios_client/_generated/get_bindings.py +97 -0
  53. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_definition.py +44 -0
  54. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_definitions.py +42 -0
  55. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_environment.py +69 -0
  56. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_environment_live.py +30 -0
  57. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_environments.py +40 -0
  58. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_environments_live.py +35 -0
  59. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_instance.py +56 -0
  60. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_instances.py +50 -0
  61. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_libraries.py +38 -0
  62. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_library.py +73 -0
  63. koios_client-1.0.0rc1/src/koios_client/_generated/get_component_library_groups.py +36 -0
  64. koios_client-1.0.0rc1/src/koios_client/_generated/get_device.py +111 -0
  65. koios_client-1.0.0rc1/src/koios_client/_generated/get_device_live.py +32 -0
  66. koios_client-1.0.0rc1/src/koios_client/_generated/get_device_set.py +37 -0
  67. koios_client-1.0.0rc1/src/koios_client/_generated/get_device_sets.py +43 -0
  68. koios_client-1.0.0rc1/src/koios_client/_generated/get_devices.py +53 -0
  69. koios_client-1.0.0rc1/src/koios_client/_generated/get_devices_live.py +37 -0
  70. koios_client-1.0.0rc1/src/koios_client/_generated/get_endpoint_client.py +48 -0
  71. koios_client-1.0.0rc1/src/koios_client/_generated/get_endpoint_clients.py +49 -0
  72. koios_client-1.0.0rc1/src/koios_client/_generated/get_event_count_summary.py +18 -0
  73. koios_client-1.0.0rc1/src/koios_client/_generated/get_events.py +61 -0
  74. koios_client-1.0.0rc1/src/koios_client/_generated/get_failed_counts.py +19 -0
  75. koios_client-1.0.0rc1/src/koios_client/_generated/get_license_detail.py +26 -0
  76. koios_client-1.0.0rc1/src/koios_client/_generated/get_local_values.py +45 -0
  77. koios_client-1.0.0rc1/src/koios_client/_generated/get_model.py +121 -0
  78. koios_client-1.0.0rc1/src/koios_client/_generated/get_model_files.py +46 -0
  79. koios_client-1.0.0rc1/src/koios_client/_generated/get_model_live.py +57 -0
  80. koios_client-1.0.0rc1/src/koios_client/_generated/get_models.py +70 -0
  81. koios_client-1.0.0rc1/src/koios_client/_generated/get_models_live.py +62 -0
  82. koios_client-1.0.0rc1/src/koios_client/_generated/get_platform_version.py +29 -0
  83. koios_client-1.0.0rc1/src/koios_client/_generated/get_protocol.py +32 -0
  84. koios_client-1.0.0rc1/src/koios_client/_generated/get_protocols.py +32 -0
  85. koios_client-1.0.0rc1/src/koios_client/_generated/get_scan_group.py +54 -0
  86. koios_client-1.0.0rc1/src/koios_client/_generated/get_scan_group_live.py +31 -0
  87. koios_client-1.0.0rc1/src/koios_client/_generated/get_scan_groups.py +40 -0
  88. koios_client-1.0.0rc1/src/koios_client/_generated/get_scan_groups_live.py +36 -0
  89. koios_client-1.0.0rc1/src/koios_client/_generated/get_services.py +33 -0
  90. koios_client-1.0.0rc1/src/koios_client/_generated/get_system_health.py +17 -0
  91. koios_client-1.0.0rc1/src/koios_client/_generated/get_system_info.py +35 -0
  92. koios_client-1.0.0rc1/src/koios_client/_generated/get_tag.py +127 -0
  93. koios_client-1.0.0rc1/src/koios_client/_generated/get_tag_history.py +29 -0
  94. koios_client-1.0.0rc1/src/koios_client/_generated/get_tag_live.py +39 -0
  95. koios_client-1.0.0rc1/src/koios_client/_generated/get_tags.py +76 -0
  96. koios_client-1.0.0rc1/src/koios_client/_generated/get_tags_history.py +32 -0
  97. koios_client-1.0.0rc1/src/koios_client/_generated/get_tags_live.py +44 -0
  98. koios_client-1.0.0rc1/src/koios_client/_generated/get_trend.py +72 -0
  99. koios_client-1.0.0rc1/src/koios_client/_generated/get_trend_items.py +58 -0
  100. koios_client-1.0.0rc1/src/koios_client/_generated/get_trends.py +32 -0
  101. koios_client-1.0.0rc1/src/koios_client/_generated/get_wires.py +74 -0
  102. koios_client-1.0.0rc1/src/koios_client/_generated/input_types.py +1748 -0
  103. koios_client-1.0.0rc1/src/koios_client/_generated/mark_all_events_seen.py +39 -0
  104. koios_client-1.0.0rc1/src/koios_client/_generated/mark_event_seen.py +39 -0
  105. koios_client-1.0.0rc1/src/koios_client/_generated/obtain_client_token.py +40 -0
  106. koios_client-1.0.0rc1/src/koios_client/_generated/refresh_token.py +40 -0
  107. koios_client-1.0.0rc1/src/koios_client/_generated/regenerate_client_secret.py +39 -0
  108. koios_client-1.0.0rc1/src/koios_client/_generated/set_endpoint_client_permissions.py +50 -0
  109. koios_client-1.0.0rc1/src/koios_client/_generated/set_protocol_visible.py +39 -0
  110. koios_client-1.0.0rc1/src/koios_client/_generated/update_binding.py +44 -0
  111. koios_client-1.0.0rc1/src/koios_client/_generated/update_component_environment.py +39 -0
  112. koios_client-1.0.0rc1/src/koios_client/_generated/update_component_instance.py +39 -0
  113. koios_client-1.0.0rc1/src/koios_client/_generated/update_device.py +39 -0
  114. koios_client-1.0.0rc1/src/koios_client/_generated/update_device_set.py +39 -0
  115. koios_client-1.0.0rc1/src/koios_client/_generated/update_device_sets.py +19 -0
  116. koios_client-1.0.0rc1/src/koios_client/_generated/update_devices.py +20 -0
  117. koios_client-1.0.0rc1/src/koios_client/_generated/update_endpoint_client.py +40 -0
  118. koios_client-1.0.0rc1/src/koios_client/_generated/update_local_value.py +39 -0
  119. koios_client-1.0.0rc1/src/koios_client/_generated/update_local_values.py +21 -0
  120. koios_client-1.0.0rc1/src/koios_client/_generated/update_model.py +39 -0
  121. koios_client-1.0.0rc1/src/koios_client/_generated/update_models.py +20 -0
  122. koios_client-1.0.0rc1/src/koios_client/_generated/update_scan_group.py +39 -0
  123. koios_client-1.0.0rc1/src/koios_client/_generated/update_scan_groups.py +20 -0
  124. koios_client-1.0.0rc1/src/koios_client/_generated/update_tag.py +39 -0
  125. koios_client-1.0.0rc1/src/koios_client/_generated/update_tags.py +20 -0
  126. koios_client-1.0.0rc1/src/koios_client/_generated/update_trend.py +38 -0
  127. koios_client-1.0.0rc1/src/koios_client/_generated/update_trend_item.py +38 -0
  128. koios_client-1.0.0rc1/src/koios_client/_generated/update_wire.py +37 -0
  129. koios_client-1.0.0rc1/src/koios_client/_generated/verify_token.py +10 -0
  130. koios_client-1.0.0rc1/src/koios_client/client.py +1105 -0
  131. koios_client-1.0.0rc1/src/koios_client/exceptions.py +82 -0
  132. koios_client-1.0.0rc1/src/koios_client/py.typed +0 -0
  133. koios_client-1.0.0rc1/src/koios_client/resources/__init__.py +33 -0
  134. koios_client-1.0.0rc1/src/koios_client/resources/_base.py +96 -0
  135. koios_client-1.0.0rc1/src/koios_client/resources/_helpers.py +80 -0
  136. koios_client-1.0.0rc1/src/koios_client/resources/bindings.py +44 -0
  137. koios_client-1.0.0rc1/src/koios_client/resources/device_sets.py +87 -0
  138. koios_client-1.0.0rc1/src/koios_client/resources/devices.py +167 -0
  139. koios_client-1.0.0rc1/src/koios_client/resources/models.py +191 -0
  140. koios_client-1.0.0rc1/src/koios_client/resources/protocols.py +54 -0
  141. koios_client-1.0.0rc1/src/koios_client/resources/scan_groups.py +112 -0
  142. koios_client-1.0.0rc1/src/koios_client/resources/tags.py +134 -0
  143. koios_client-1.0.0rc1/src/koios_client/types.py +138 -0
  144. koios_client-1.0.0rc1/src/koios_client.egg-info/PKG-INFO +537 -0
  145. koios_client-1.0.0rc1/src/koios_client.egg-info/SOURCES.txt +149 -0
  146. koios_client-1.0.0rc1/src/koios_client.egg-info/dependency_links.txt +1 -0
  147. koios_client-1.0.0rc1/src/koios_client.egg-info/requires.txt +9 -0
  148. koios_client-1.0.0rc1/src/koios_client.egg-info/top_level.txt +1 -0
  149. koios_client-1.0.0rc1/tests/test_auth.py +205 -0
  150. koios_client-1.0.0rc1/tests/test_client.py +473 -0
  151. koios_client-1.0.0rc1/tests/test_resources.py +850 -0
@@ -0,0 +1,537 @@
1
+ Metadata-Version: 2.4
2
+ Name: koios-client
3
+ Version: 1.0.0rc1
4
+ Summary: Python client library for the Koios IoT platform — typed GraphQL & REST wrapper
5
+ Author: Ai-OPs, Inc.
6
+ License: Proprietary
7
+ Project-URL: Homepage, https://www.ai-op.com
8
+ Project-URL: Documentation, https://docs.ai-op.com
9
+ Project-URL: Repository, https://github.com/Ai-Ops-Inc/koios-client
10
+ Keywords: koios,api,graphql,client,iot,industrial
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: httpx>=0.27.0
22
+ Requires-Dist: pydantic<3.0.0,>=2.0.0
23
+ Requires-Dist: python-dateutil>=2.8.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: ariadne-codegen>=0.14.0; extra == "dev"
26
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
27
+ Requires-Dist: pytest-httpx>=0.30.0; extra == "dev"
28
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
29
+
30
+ # Koios Client
31
+
32
+ Typed Python SDK for the [Koios IoT platform](https://ai-op.com). Provides two API layers:
33
+
34
+ - **High-level resource API** — `Device`, `Tag`, `Model` objects with intuitive methods like `.enable()`, `.update()`, `.delete()`
35
+ - **Low-level GraphQL client** — fully-typed generated client via `client.gql` with IDE autocomplete
36
+
37
+ Plus REST helpers for file operations, import/export, backups, and trend data.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install koios-client
43
+ ```
44
+
45
+ Or install from source:
46
+
47
+ ```bash
48
+ pip install -e ".[dev]"
49
+ ```
50
+
51
+ ## Quick Start
52
+
53
+ ```python
54
+ from koios_client import KoiosClient
55
+
56
+ client = KoiosClient(
57
+ hostname="koios.example.com",
58
+ client_id="your-client-uuid",
59
+ client_secret="your-client-secret",
60
+ )
61
+
62
+ # High-level resource API — fetch by ID (default) or slug
63
+ device = client.device(1)
64
+ device.enable()
65
+ for tag in device.tags():
66
+ print(tag.name, tag.value)
67
+
68
+ # Low-level GraphQL (fully typed — IDE autocomplete works)
69
+ result = client.gql.get_devices()
70
+ for device in result.devices.results:
71
+ print(device.name, device.status)
72
+
73
+ client.close()
74
+ ```
75
+
76
+ Use as a context manager for automatic cleanup:
77
+
78
+ ```python
79
+ with KoiosClient("koios.example.com", "client-id", "secret") as client:
80
+ device = client.device(1)
81
+ print(device.name, device.enabled)
82
+ ```
83
+
84
+ ## High-Level Resource API
85
+
86
+ The resource layer wraps the generated GraphQL client with intuitive Python objects. All resource classes are importable from the top-level package:
87
+
88
+ ```python
89
+ from koios_client import Device, Tag, Model, PaginatedList
90
+ ```
91
+
92
+ ### Fetching Resources
93
+
94
+ Every resource can be fetched by **ID** (default positional arg) or **slug** (UUID).
95
+
96
+ ```python
97
+ # By ID (default — integer database primary key)
98
+ device = client.device(1)
99
+ tag = client.tag(42)
100
+ model = client.model(5)
101
+
102
+ # By slug (UUID — useful when you already have the identifier)
103
+ device = client.device(slug="550e8400-e29b-41d4-a716-446655440000")
104
+
105
+ # By name — use the list query with filters
106
+ from koios_client.types import DeviceFilter, StrFilterLookup
107
+ devices = client.devices(filters=DeviceFilter(name=StrFilterLookup(exact="My Device")))
108
+ device = devices[0]
109
+
110
+ # List with filtering, ordering, and pagination
111
+ from koios_client.types import OffsetPaginationInput
112
+
113
+ devices = client.devices(
114
+ filters=DeviceFilter(enabled=True),
115
+ pagination=OffsetPaginationInput(limit=50),
116
+ )
117
+ print(f"{devices.total_count} total devices")
118
+ for device in devices:
119
+ print(device.name, device.slug, device.enabled)
120
+ ```
121
+
122
+ `PaginatedList` supports iteration, indexing, `len()`, and `bool()`:
123
+
124
+ ```python
125
+ tags = client.tags()
126
+ print(len(tags)) # Number of items on this page
127
+ print(tags.total_count) # Total matching items on server
128
+ first = tags[0] # Index access
129
+ ```
130
+
131
+ ### CRUD Operations
132
+
133
+ ```python
134
+ from koios_client.types import DeviceInput
135
+
136
+ # Create
137
+ device = client.create_device(DeviceInput(
138
+ name="New Device",
139
+ protocol_id="1",
140
+ enabled=True,
141
+ ))
142
+
143
+ # Update (returns a fresh object with all fields refreshed)
144
+ device = device.update(name="Renamed Device", scan_rate=5.0)
145
+
146
+ # Enable / Disable (convenience wrappers around update)
147
+ device = device.enable()
148
+ device = device.disable()
149
+
150
+ # Duplicate
151
+ copy = device.duplicate("Device Copy", description="Cloned from original")
152
+
153
+ # Delete
154
+ device.delete()
155
+ ```
156
+
157
+ ### Parent-Child Accessors
158
+
159
+ ```python
160
+ # Device → Tags
161
+ device = client.device(1)
162
+ tags = device.tags(
163
+ filters=TagFilter(enabled=True),
164
+ pagination=OffsetPaginationInput(limit=100),
165
+ )
166
+
167
+ # Model → Bindings
168
+ model = client.model(5)
169
+ for binding in model.bindings():
170
+ print(binding.name, binding.usage, binding.normalization_type)
171
+ binding.update(normalization_type="MIN_MAX")
172
+ ```
173
+
174
+ ### Bulk Operations
175
+
176
+ ```python
177
+ # Bulk enable / disable
178
+ client.enable_devices(["1", "2", "3"])
179
+ client.disable_tags(["10", "11", "12"])
180
+
181
+ # Bulk delete
182
+ client.delete_devices(["1", "2", "3"])
183
+ client.delete_tags(["10", "11", "12"])
184
+ client.delete_models(["20", "21"])
185
+ client.delete_scan_groups(["30", "31"])
186
+ client.delete_device_sets(["40", "41"])
187
+ ```
188
+
189
+ ### Live Data
190
+
191
+ Fetch real-time values from the Redis cache:
192
+
193
+ ```python
194
+ device = client.device(1)
195
+ live = device.live()
196
+ print(live.get("status"), live.get("error_message"))
197
+
198
+ tag = client.tag(42)
199
+ live = tag.live()
200
+ print(live.get("value"), live.get("timestamp"), live.get("quality"))
201
+ ```
202
+
203
+ ### Import / Export with Resources
204
+
205
+ ```python
206
+ # Import with dry_run (default) — returns preview without applying
207
+ preview = client.import_devices("devices.csv")
208
+ print(preview)
209
+
210
+ # Import for real
211
+ result = client.import_devices("devices.csv", dry_run=False)
212
+
213
+ # Export a single device/model
214
+ csv_bytes = device.export_csv()
215
+ zip_bytes = model.export()
216
+ ```
217
+
218
+ ### All Resource Types
219
+
220
+ All singular methods accept `id` (positional, integer) or `slug=` (UUID). Exactly one must be provided.
221
+
222
+ | Method | Returns | Notes |
223
+ |--------|---------|-------|
224
+ | `client.device(id, slug=)` | `Device` | |
225
+ | `client.devices(...)` | `PaginatedList[Device]` | filters, order, pagination |
226
+ | `client.create_device(data)` | `Device` | |
227
+ | `client.enable_devices(ids)` | `list[Device]` | |
228
+ | `client.disable_devices(ids)` | `list[Device]` | |
229
+ | `client.delete_devices(ids)` | `None` | |
230
+ | `client.import_devices(file)` | `dict` | dry_run=True by default |
231
+ | `client.tag(id, slug=)` | `Tag` | |
232
+ | `client.tags(...)` | `PaginatedList[Tag]` | |
233
+ | `client.create_tag(data)` | `Tag` | |
234
+ | `client.enable_tags(ids)` | `list[Tag]` | |
235
+ | `client.disable_tags(ids)` | `list[Tag]` | |
236
+ | `client.delete_tags(ids)` | `None` | |
237
+ | `client.import_tags(file)` | `dict` | dry_run=True by default |
238
+ | `client.model(id, slug=)` | `Model` | |
239
+ | `client.models(...)` | `PaginatedList[Model]` | |
240
+ | `client.create_model(data)` | `Model` | |
241
+ | `client.enable_models(ids)` | `list[Model]` | |
242
+ | `client.disable_models(ids)` | `list[Model]` | |
243
+ | `client.delete_models(ids)` | `None` | |
244
+ | `client.import_models(file)` | `dict` | dry_run=True by default |
245
+ | `client.scan_group(id, slug=)` | `ScanGroup` | |
246
+ | `client.scan_groups(...)` | `PaginatedList[ScanGroup]` | |
247
+ | `client.create_scan_group(data)` | `ScanGroup` | |
248
+ | `client.enable_scan_groups(ids)` | `list[ScanGroup]` | |
249
+ | `client.disable_scan_groups(ids)` | `list[ScanGroup]` | |
250
+ | `client.delete_scan_groups(ids)` | `None` | |
251
+ | `client.device_set(id, slug=)` | `DeviceSet` | |
252
+ | `client.device_sets(...)` | `PaginatedList[DeviceSet]` | |
253
+ | `client.create_device_set(data)` | `DeviceSet` | |
254
+ | `client.delete_device_sets(ids)` | `None` | |
255
+ | `client.protocol(id, slug=)` | `Protocol` | read-only |
256
+ | `client.protocols()` | `list[Protocol]` | not paginated |
257
+
258
+ ### Endpoint Clients
259
+
260
+ ```python
261
+ # List endpoint clients
262
+ clients = client.endpoint_clients()
263
+
264
+ # Get a single endpoint client by ID
265
+ ec = client.endpoint_client("123")
266
+
267
+ # Create a new endpoint client (returns one-time secret)
268
+ result = client.create_endpoint_client("My Integration", description="Data pipeline")
269
+
270
+ # Set permissions
271
+ client.set_endpoint_client_permissions(
272
+ client_id="123",
273
+ permission_ids=["1", "2", "3"],
274
+ )
275
+ ```
276
+
277
+ ## Low-Level GraphQL Client
278
+
279
+ All GraphQL queries and mutations are available via `client.gql` with fully typed parameters and return values.
280
+
281
+ ### Querying Data
282
+
283
+ ```python
284
+ from koios_client.types import (
285
+ DeviceFilter,
286
+ OffsetPaginationInput,
287
+ StatusChoices,
288
+ )
289
+
290
+ # Paginated queries
291
+ devices = client.gql.get_devices(
292
+ pagination=OffsetPaginationInput(limit=50),
293
+ )
294
+ print(f"Total: {devices.devices.total_count}")
295
+ for device in devices.devices.results:
296
+ print(device.name, device.status, device.protocol.name)
297
+
298
+ # Filtered queries
299
+ tags = client.gql.get_tags(
300
+ filters=TagFilter(enabled=True),
301
+ pagination=OffsetPaginationInput(limit=100),
302
+ )
303
+
304
+ # Single item by slug
305
+ device = client.gql.get_device(slug="my-device")
306
+ tag = client.gql.get_tag(slug="my-tag")
307
+ ```
308
+
309
+ ### Mutations
310
+
311
+ Single-item mutations return a union of the entity type or `OperationInfo`. Use `check_operation` to unwrap:
312
+
313
+ ```python
314
+ from koios_client.types import DeviceInput
315
+
316
+ raw = client.gql.create_device(data=DeviceInput(
317
+ name="New Device",
318
+ protocol_id="1",
319
+ enabled=True,
320
+ ))
321
+
322
+ # Raises OperationError if the server returned validation/permission errors
323
+ device = KoiosClient.check_operation(raw.create_device)
324
+ print(f"Created: {device.name} ({device.slug})")
325
+ ```
326
+
327
+ ### Available Enums
328
+
329
+ All GraphQL enums are available as typed Python enums:
330
+
331
+ ```python
332
+ from koios_client.types import (
333
+ StatusChoices, # RUNNING, STOPPED, FAILED
334
+ UsageChoices, # INPUT, OUTPUT, VIRTUAL
335
+ AggregateFunction, # MEAN, SUM, MIN, MAX, FIRST, LAST, COUNT
336
+ DeviceErrorCodeChoices,
337
+ TagErrorCodeChoices,
338
+ ProtocolReferenceCodeChoices, # OPCUA, MODBUS_TCP, ETHERNET_IP, ...
339
+ )
340
+ ```
341
+
342
+ ## REST API
343
+
344
+ Operations that involve file uploads, background tasks, or binary responses use REST endpoints exposed directly on the client.
345
+
346
+ ### Export / Import
347
+
348
+ ```python
349
+ # Export devices as CSV
350
+ csv_bytes = client.export_devices_csv()
351
+ with open("devices.csv", "wb") as f:
352
+ f.write(csv_bytes)
353
+
354
+ # Export specific tags
355
+ csv_bytes = client.export_tags_csv(ids=[1, 2, 3])
356
+
357
+ # Export models as ZIP (includes bindings)
358
+ zip_bytes = client.export_models()
359
+
360
+ # Two-step import: preview then confirm
361
+ preview = client.import_tags_preview("tags.csv")
362
+ print(f"Will import {preview['result']['total_rows']} rows")
363
+ if preview["can_import"]:
364
+ result = client.import_tags_confirm(
365
+ preview["tmp_storage_name"],
366
+ preview["file_name"],
367
+ )
368
+ print(f"Imported {result['imported_count']} tags")
369
+ ```
370
+
371
+ ### Model Files
372
+
373
+ ```python
374
+ # Upload a model file
375
+ result = client.upload_model_file(
376
+ "model.onnx",
377
+ model_slug="my-model",
378
+ version="1.0",
379
+ set_active=True,
380
+ )
381
+
382
+ # Download a model file
383
+ model_bytes = client.download_model_file("model-file-slug")
384
+
385
+ # Get model structure (weights stripped for ONNX)
386
+ structure = client.get_model_file_structure("model-file-slug")
387
+ ```
388
+
389
+ ### Backups
390
+
391
+ ```python
392
+ # Create a backup
393
+ task = client.create_backup(tier="full")
394
+
395
+ # Poll for completion
396
+ import time
397
+ while True:
398
+ status = client.get_backup_status(task["task_id"])
399
+ if status["status"] == "completed":
400
+ break
401
+ time.sleep(2)
402
+
403
+ # List and download
404
+ backups = client.list_backups()
405
+ for backup in backups["backups"]:
406
+ print(backup["filename"], backup["size_bytes"])
407
+
408
+ data = client.download_backup(backups["backups"][0]["filename"])
409
+
410
+ # Restore from backup
411
+ upload = client.upload_restore_file("backup.tar.gz")
412
+ task = client.start_restore(upload["restore_file_path"])
413
+ ```
414
+
415
+ ### Trend Data Export
416
+
417
+ ```python
418
+ # Start an export task
419
+ task = client.create_trend_export(
420
+ tag_ids=[1, 2, 3],
421
+ start="2026-01-01T00:00:00Z",
422
+ stop="2026-02-01T00:00:00Z",
423
+ mode="resampled",
424
+ resample_interval="5m",
425
+ aggregate_fn="mean",
426
+ output_format="csv",
427
+ )
428
+
429
+ # Poll and download
430
+ status = client.get_trend_export_status(task["task_id"])
431
+ if status["status"] == "completed":
432
+ data = client.download_trend_export(status["filename"])
433
+
434
+ # Estimate before exporting
435
+ estimate = client.estimate_trend_export(
436
+ tag_ids=[1, 2, 3],
437
+ export_all=True,
438
+ )
439
+ print(f"~{estimate['estimated_size_bytes'] / 1e6:.1f} MB")
440
+ ```
441
+
442
+ ### Component Libraries
443
+
444
+ ```python
445
+ result = client.upload_component_library("my-component.kcl")
446
+ print(f"Uploaded: {result['name']} v{result['version']}")
447
+ ```
448
+
449
+ ### OPC-UA Certificates
450
+
451
+ ```python
452
+ # Upload a certificate + key pair
453
+ result = client.upload_opcua_certificate(
454
+ "cert.der", "key.pem", name="My Certificate"
455
+ )
456
+
457
+ # Download cert or key
458
+ cert_bytes = client.download_opcua_certificate("cert-slug")
459
+ key_bytes = client.download_opcua_key("cert-slug")
460
+ ```
461
+
462
+ ### EDS Files
463
+
464
+ ```python
465
+ # Upload an EDS file for a device
466
+ result = client.upload_eds_file("device.eds")
467
+
468
+ # Delete the EDS file from a device
469
+ client.delete_eds_file(device_id=1)
470
+ ```
471
+
472
+ ### Log Downloads
473
+
474
+ ```python
475
+ log = client.download_device_log("my-device")
476
+ log = client.download_model_log("my-model")
477
+ log = client.download_scan_group_log("scan-group-1")
478
+ log = client.download_component_log("instance-1")
479
+ log = client.download_service_log("datacollector")
480
+ ```
481
+
482
+ ## Connection Options
483
+
484
+ ```python
485
+ client = KoiosClient(
486
+ hostname="koios.example.com",
487
+ client_id="your-uuid",
488
+ client_secret="your-secret",
489
+ port=443, # Default: 443 (HTTPS) or 80 (HTTP)
490
+ ssl=True, # Default: True
491
+ verify_ssl=True, # Default: True (set False for self-signed certs)
492
+ timeout=30.0, # Default: 30 seconds
493
+ )
494
+ ```
495
+
496
+ ## Error Handling
497
+
498
+ ```python
499
+ from koios_client import (
500
+ KoiosError, # Base exception
501
+ AuthenticationError, # Bad credentials or expired token
502
+ NotFoundError, # Resource not found (e.g. client.device(999))
503
+ OperationError, # Mutation returned OperationInfo
504
+ GraphQLError, # GraphQL response errors
505
+ KoiosConnectionError, # Network connectivity issues
506
+ KoiosPermissionError, # Insufficient permissions
507
+ ValidationError, # Input validation failures
508
+ )
509
+
510
+ try:
511
+ device = client.device(1)
512
+ device.update(name="New Name")
513
+ except NotFoundError:
514
+ print("Device not found")
515
+ except OperationError as e:
516
+ for msg in e.messages:
517
+ print(f"{msg.kind}: {msg.field}: {msg.message}")
518
+ except AuthenticationError:
519
+ print("Check your client credentials")
520
+ ```
521
+
522
+ ## Development
523
+
524
+ ```bash
525
+ # Install with dev dependencies
526
+ pip install -e ".[dev]"
527
+
528
+ # Run tests
529
+ python3 -m pytest tests/ -v
530
+
531
+ # Regenerate GraphQL client (requires running Koios server)
532
+ make codegen
533
+ ```
534
+
535
+ ## License
536
+
537
+ Copyright 2024-2026 Ai-OPs, Inc. All rights reserved.