Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix get_with_service_details typings #355

Merged
merged 1 commit into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 131 additions & 5 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) ⇒ [<code>TypeApplication</code>](#typeapplication)
- [get_id(slug_or_uuid_or_id)](#application.get_id) ⇒ <code>int</code>
- [get_target_release_hash(slug_or_uuid_or_id)](#application.get_target_release_hash) ⇒ <code>Union[str, None]</code>
- [get_with_device_service_details(slug_or_uuid_or_id, options)](#application.get_with_device_service_details) ⇒ [<code>TypeApplication</code>](#typeapplication)
- [get_with_device_service_details(slug_or_uuid_or_id, options)](#application.get_with_device_service_details) ⇒ [<code>TypeApplicationWithDeviceServiceDetails</code>](#typeapplicationwithdeviceservicedetails)
- [grant_support_access(slug_or_uuid_or_id, expiry_timestamp)](#application.grant_support_access) ⇒ <code>None</code>
- [has(slug_or_uuid_or_id)](#application.has) ⇒ <code>bool</code>
- [has_any()](#application.has_any) ⇒ <code>bool</code>
Expand Down Expand Up @@ -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) ⇒ <code>SupervisorStateType</code>
- [get_supervisor_target_state(uuid_or_id)](#device.get_supervisor_target_state) ⇒ <code>Any</code>
- [get_supervisor_target_state_for_app(slug_or_uuid_or_id, release)](#device.get_supervisor_target_state_for_app) ⇒ <code>Any</code>
- [get_with_service_details(uuid_or_id, options)](#device.get_with_service_details) ⇒ [<code>TypeDevice</code>](#typedevice)
- [get_with_service_details(uuid_or_id, options)](#device.get_with_service_details) ⇒ [<code>TypeDeviceWithServices</code>](#typedevicewithservices)
- [grant_support_access(uuid_or_id_or_ids, expiry_timestamp)](#device.grant_support_access) ⇒ <code>None</code>
- [has(uuid_or_id)](#device.has) ⇒ <code>bool</code>
- [has_device_url(uuid_or_id)](#device.has_device_url) ⇒ <code>bool</code>
Expand Down Expand Up @@ -569,7 +569,7 @@ Get the hash of the current release for a specific application.
```

<a name="application.get_with_device_service_details"></a>
### Function: get_with_device_service_details(slug_or_uuid_or_id, options) ⇒ [<code>TypeApplication</code>](#typeapplication)
### Function: get_with_device_service_details(slug_or_uuid_or_id, options) ⇒ [<code>TypeApplicationWithDeviceServiceDetails</code>](#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
Expand Down Expand Up @@ -1614,7 +1614,7 @@ Get the supervisor target state on a device
```

<a name="device.get_with_service_details"></a>
### Function: get_with_service_details(uuid_or_id, options) ⇒ [<code>TypeDevice</code>](#typedevice)
### Function: get_with_service_details(uuid_or_id, options) ⇒ [<code>TypeDeviceWithServices</code>](#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
Expand Down Expand Up @@ -4544,7 +4544,7 @@ 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],
Expand All @@ -4557,6 +4557,63 @@ The name must be a string; the optional doc argument can have any type.
```


### 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],
"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]
}
```


### TypeCurrentService


```python
{
"id": int,
"image_id": int,
"service_id": int,
"download_progress": int,
"status": str,
"install_date": str
}
```


### TypeDevice


Expand Down Expand Up @@ -4636,6 +4693,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, List[TypeCurrentService]]
}
```


### TypeVar


Expand Down
3 changes: 2 additions & 1 deletion balena/models/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
TypeApplication,
BaseTagType,
EnvironmentVariableBase,
TypeApplicationWithDeviceServiceDetails,
)
from ..utils import (
generate_current_service_details,
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions balena/models/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
21 changes: 19 additions & 2 deletions balena/types/models.py
Original file line number Diff line number Diff line change
@@ -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")

Expand Down Expand Up @@ -154,7 +154,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"]
Expand All @@ -165,6 +165,10 @@ class TypeApplication(TypedDict):
can_use__application_as_host: ReverseNavigationResource[ApplicationHostedOnApplication]


class TypeApplicationWithDeviceServiceDetails(TypeApplication):
owns__device: List["TypeDeviceWithServices"] # type: ignore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW this is necessary as by default Python type hints won't allow overriding properties on TypedDicts


class APIKeyInfoType(TypedDict, total=False):
name: str
description: Optional[str]
Expand Down Expand Up @@ -339,6 +343,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
Expand Down
15 changes: 8 additions & 7 deletions balena/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down
Loading