diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index 3b124a36..2ea6e972 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -95,7 +95,7 @@ hesitate to open an issue in GitHub](https://github.com/balena-io/balena-sdk-pyt
- [get_directly_accessible(slug_or_uuid_or_id, options)](#application.get_directly_accessible) ⇒ [TypeApplication
](#typeapplication)
- [get_id(slug_or_uuid_or_id)](#application.get_id) ⇒ int
- [get_target_release_hash(slug_or_uuid_or_id)](#application.get_target_release_hash) ⇒ Union[str, None]
- - [get_with_device_service_details(slug_or_uuid_or_id, options)](#application.get_with_device_service_details) ⇒ [TypeApplication
](#typeapplication)
+ - [get_with_device_service_details(slug_or_uuid_or_id, options)](#application.get_with_device_service_details) ⇒ [TypeApplicationWithDeviceServiceDetails
](#typeapplicationwithdeviceservicedetails)
- [grant_support_access(slug_or_uuid_or_id, expiry_timestamp)](#application.grant_support_access) ⇒ None
- [has(slug_or_uuid_or_id)](#application.has) ⇒ bool
- [has_any()](#application.has_any) ⇒ bool
@@ -171,7 +171,7 @@ hesitate to open an issue in GitHub](https://github.com/balena-io/balena-sdk-pyt
- [get_supervisor_state(uuid_or_id)](#device.get_supervisor_state) ⇒ SupervisorStateType
- [get_supervisor_target_state(uuid_or_id)](#device.get_supervisor_target_state) ⇒ Any
- [get_supervisor_target_state_for_app(slug_or_uuid_or_id, release)](#device.get_supervisor_target_state_for_app) ⇒ Any
- - [get_with_service_details(uuid_or_id, options)](#device.get_with_service_details) ⇒ [TypeDevice
](#typedevice)
+ - [get_with_service_details(uuid_or_id, options)](#device.get_with_service_details) ⇒ [TypeDeviceWithServices
](#typedevicewithservices)
- [grant_support_access(uuid_or_id_or_ids, expiry_timestamp)](#device.grant_support_access) ⇒ None
- [has(uuid_or_id)](#device.has) ⇒ bool
- [has_device_url(uuid_or_id)](#device.has_device_url) ⇒ bool
@@ -569,7 +569,7 @@ Get the hash of the current release for a specific application.
```
-### Function: get_with_device_service_details(slug_or_uuid_or_id, options) ⇒ [TypeApplication
](#typeapplication)
+### Function: get_with_device_service_details(slug_or_uuid_or_id, options) ⇒ [TypeApplicationWithDeviceServiceDetails
](#typeapplicationwithdeviceservicedetails)
This method does not map exactly to the underlying model: it runs a
larger prebuilt query, and reformats it into an easy to use and
@@ -1614,7 +1614,7 @@ Get the supervisor target state on a device
```
-### Function: get_with_service_details(uuid_or_id, options) ⇒ [TypeDevice
](#typedevice)
+### Function: get_with_service_details(uuid_or_id, options) ⇒ [TypeDeviceWithServices
](#typedevicewithservices)
This method does not map exactly to the underlying model: it runs a
larger prebuilt query, and reformats it into an easy to use and
@@ -4540,7 +4540,49 @@ The name must be a string; the optional doc argument can have any type.
"application_environment_variable": Union[List[EnvironmentVariableBase], None],
"build_environment_variable": Union[List[EnvironmentVariableBase], None],
"application_tag": Union[List[BaseTagType], None],
- "owns__device": Union[List[DeviceTypeType], None],
+ "owns__device": Union[List[TypeDevice], None],
+ "owns__public_device": Union[List[PublicDeviceType], None],
+ "owns__release": Union[List[ReleaseType], None],
+ "service": Union[List[ServiceType], None],
+ "is_depended_on_by__application": Union[List[ApplicationType], None],
+ "is_directly_accessible_by__user": Union[List[UserType], None],
+ "user_application_membership": Union[List[ApplicationMembershipType], None],
+ "team_application_access": Union[List[TeamApplicationAccessType], None],
+ "can_use__application_as_host": Union[List[ApplicationHostedOnApplication], None]
+}
+```
+
+
+### TypeApplicationWithDeviceServiceDetails
+
+
+```python
+{
+ "id": int,
+ "created_at": str,
+ "app_name": str,
+ "actor": Union[List[ActorType], int],
+ "slug": str,
+ "uuid": str,
+ "is_accessible_by_support_until__date": str,
+ "is_host": bool,
+ "should_track_latest_release": bool,
+ "is_public": bool,
+ "is_of__class": Literal["fleet", "block", "app"],
+ "is_archived": bool,
+ "is_discoverable": bool,
+ "is_stored_at__repository_url": str,
+ "public_organization": Union[List[PublicOrganizationType], PineDeferred, None],
+ "application_type": Union[List[ApplicationType], PineDeferred],
+ "is_for__device_type": Union[List[DeviceTypeType], PineDeferred],
+ "depends_on__application": Union[List[ApplicationType], PineDeferred, None],
+ "organization": Union[List[OrganizationType], PineDeferred],
+ "should_be_running__release": Union[List[ReleaseType], PineDeferred, None],
+ "application_config_variable": Union[List[EnvironmentVariableBase], None],
+ "application_environment_variable": Union[List[EnvironmentVariableBase], None],
+ "build_environment_variable": Union[List[EnvironmentVariableBase], None],
+ "application_tag": Union[List[BaseTagType], None],
+ "owns__device": List[TypeDeviceWithServices],
"owns__public_device": Union[List[PublicDeviceType], None],
"owns__release": Union[List[ReleaseType], None],
"service": Union[List[ServiceType], None],
@@ -4632,6 +4674,75 @@ The name must be a string; the optional doc argument can have any type.
```
+### TypeDeviceWithServices
+
+
+```python
+{
+ "id": int,
+ "actor": Union[List[ActorType], int],
+ "created_at": str,
+ "modified_at": str,
+ "custom_latitude": str,
+ "custom_longitude": str,
+ "device_name": str,
+ "download_progress": int,
+ "ip_address": str,
+ "public_address": str,
+ "mac_address": str,
+ "is_accessible_by_support_until__date": str,
+ "is_connected_to_vpn": bool,
+ "is_locked_until__date": str,
+ "is_web_accessible": bool,
+ "is_active": bool,
+ "is_frozen": bool,
+ "is_online": bool,
+ "last_connectivity_event": str,
+ "last_vpn_event": str,
+ "latitude": str,
+ "local_id": str,
+ "location": str,
+ "longitude": str,
+ "note": str,
+ "os_variant": str,
+ "os_version": str,
+ "provisioning_progress": int,
+ "provisioning_state": str,
+ "state": TypeDeviceState,
+ "status": str,
+ "status_sort_index": int,
+ "supervisor_version": str,
+ "uuid": str,
+ "vpn_address": str,
+ "api_heartbeat_state": Literal["online", "offline", "timeout", "unknown"],
+ "memory_usage": int,
+ "memory_total": int,
+ "storage_block_device": str,
+ "storage_usage": int,
+ "storage_total": int,
+ "cpu_usage": int,
+ "cpu_temp": int,
+ "cpu_id": str,
+ "is_undervolted": bool,
+ "overall_status": Any,
+ "overall_progress": int,
+ "is_of__device_type": Union[List[DeviceTypeType], PineDeferred],
+ "belongs_to__application": Union[List[TypeApplication], PineDeferred],
+ "belongs_to__user": Union[List[UserType], PineDeferred, None],
+ "is_running__release": Union[List[ReleaseType], PineDeferred, None],
+ "should_be_running__release": Union[List[ReleaseType], PineDeferred, None],
+ "is_managed_by__service_instance": Union[List[ServiceInstanceType], PineDeferred, None],
+ "should_be_managed_by__supervisor_release": Union[List[SupervisorReleaseType], PineDeferred, None],
+ "device_config_variable": Union[List[EnvironmentVariableBase], None],
+ "device_environment_variable": Union[List[EnvironmentVariableBase], None],
+ "device_tag": Union[List[BaseTagType], None],
+ "service_install": Union[List[ServiceInstanceType], None],
+ "image_install": Union[List[ImageInstallType], None],
+ "current_services": Dict[str, Any]
+}
+```
+
+
### TypeVar
diff --git a/balena/models/application.py b/balena/models/application.py
index b90693e1..7c0d0f67 100644
--- a/balena/models/application.py
+++ b/balena/models/application.py
@@ -15,6 +15,7 @@
TypeApplication,
BaseTagType,
EnvironmentVariableBase,
+ TypeApplicationWithDeviceServiceDetails,
)
from ..utils import (
generate_current_service_details,
@@ -292,7 +293,7 @@ def get_with_device_service_details(
self,
slug_or_uuid_or_id: Union[str, int],
options: AnyObject = {},
- ) -> TypeApplication:
+ ) -> TypeApplicationWithDeviceServiceDetails:
"""
This method does not map exactly to the underlying model: it runs a
larger prebuilt query, and reformats it into an easy to use and
diff --git a/balena/models/device.py b/balena/models/device.py
index 20e89b7e..34a659c0 100644
--- a/balena/models/device.py
+++ b/balena/models/device.py
@@ -18,7 +18,7 @@
from ..resources import Message
from ..settings import Settings
from ..types import AnyObject
-from ..types.models import BaseTagType, DeviceMetricsType, EnvironmentVariableBase, TypeDevice
+from ..types.models import BaseTagType, DeviceMetricsType, EnvironmentVariableBase, TypeDevice, TypeDeviceWithServices
from ..utils import (
ensure_version_compatibility,
generate_current_service_details,
@@ -404,7 +404,7 @@ def get(self, uuid_or_id: Union[str, int], options: AnyObject = {}) -> TypeDevic
return device
- def get_with_service_details(self, uuid_or_id: Union[str, int], options: AnyObject = {}) -> TypeDevice:
+ def get_with_service_details(self, uuid_or_id: Union[str, int], options: AnyObject = {}) -> TypeDeviceWithServices:
"""
This method does not map exactly to the underlying model: it runs a
larger prebuilt query, and reformats it into an easy to use and
diff --git a/balena/types/models.py b/balena/types/models.py
index f14e0518..181aef69 100644
--- a/balena/types/models.py
+++ b/balena/types/models.py
@@ -1,4 +1,4 @@
-from typing import Any, List, Literal, Optional, TypedDict, Union, TypeVar
+from typing import Any, List, Literal, Optional, TypedDict, Union, TypeVar, Dict
__T = TypeVar("__T")
@@ -146,7 +146,7 @@ class TypeApplication(TypedDict):
application_environment_variable: ReverseNavigationResource["EnvironmentVariableBase"]
build_environment_variable: ReverseNavigationResource["EnvironmentVariableBase"]
application_tag: ReverseNavigationResource["BaseTagType"]
- owns__device: ReverseNavigationResource["DeviceTypeType"]
+ owns__device: ReverseNavigationResource["TypeDevice"]
owns__public_device: ReverseNavigationResource[PublicDeviceType]
owns__release: ReverseNavigationResource["ReleaseType"]
service: ReverseNavigationResource["ServiceType"]
@@ -157,6 +157,10 @@ class TypeApplication(TypedDict):
can_use__application_as_host: ReverseNavigationResource[ApplicationHostedOnApplication]
+class TypeApplicationWithDeviceServiceDetails(TypeApplication):
+ owns__device: List["TypeDeviceWithServices"] # type: ignore
+
+
class APIKeyInfoType(TypedDict, total=False):
name: str
description: Optional[str]
@@ -331,6 +335,19 @@ class TypeDevice(TypedDict):
image_install: ReverseNavigationResource[ImageInstallType]
+class TypeCurrentService(TypedDict):
+ id: int
+ image_id: int
+ service_id: int
+ download_progress: int
+ status: str
+ install_date: str
+
+
+class TypeDeviceWithServices(TypeDevice):
+ current_services: Dict[str, List[TypeCurrentService]]
+
+
class DeviceMetricsType(TypedDict):
memory_usage: int
memory_total: int
diff --git a/balena/utils.py b/balena/utils.py
index 0def449d..dd0dd833 100644
--- a/balena/utils.py
+++ b/balena/utils.py
@@ -2,6 +2,7 @@
import re
from collections import defaultdict
from typing import Any, Callable, Dict, Literal, Optional, TypeVar
+from .types.models import TypeDevice, TypeDeviceWithServices
from semver.version import Version
@@ -198,21 +199,21 @@ def get_single_install_summary(raw_data: Any) -> Any:
return install
-def generate_current_service_details(raw_device: Any) -> Any:
+def generate_current_service_details(raw_device: TypeDevice) -> TypeDeviceWithServices:
# TODO: Please compare me to node-sdk version
grouped_services = defaultdict(list)
- for obj in [get_single_install_summary(i) for i in raw_device.get("image_install", [])]:
+ for obj in [get_single_install_summary(i) for i in raw_device.get("image_install", [])]: # type: ignore
grouped_services[obj.pop("service_name", None)].append(obj)
- raw_device["current_services"] = dict(grouped_services)
- raw_device["current_gateway_downloads"] = [
+ raw_device["current_services"] = dict(grouped_services) # type: ignore
+ raw_device["current_gateway_downloads"] = [ # type: ignore
get_single_install_summary(i) for i in raw_device.get("gateway_download", [])
]
- raw_device.pop("image_install", None)
- raw_device.pop("gateway_download", None)
+ raw_device.pop("image_install", None) # type: ignore
+ raw_device.pop("gateway_download", None) # type: ignore
- return raw_device
+ return raw_device # type: ignore
def is_provisioned(device: Any) -> bool: