Skip to content
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
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,19 +210,19 @@ api = wrap(device)
friendly_name = api.friendly_name
# or manually
response = device.get(nodes / "netRemote.sys.info.friendlyName")
if response.status == FS_OK:
if response.success:
#_ Again, type(content) = nodes.BaseSysInfoFriendlyName
friendly_name = response.content.value

# Apply a new name via wrapper
api.friendly_name = "FooBar"
# or manually
device.put(nodes / "netRemote.sys.info.friendlyName", value="FooBar")
# Apply a new name via wrapper
api.friendly_name = "FooBar"
# or manually
device.put(nodes / "netRemote.sys.info.friendlyName", value="FooBar")

# get all elements of a list
valid_modes = api.ls_valid_modes()
# get a certain amount of elements beginning at index 3
valid_mpdes = api.ls_valid_modes(_pos=3, max_items=10)
valid_modes = api.ls_valid_modes(_pos=3, max_items=10)
```

## Software Update
Expand Down
2 changes: 1 addition & 1 deletion docs/api-examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ devices:
friendly_name = api.friendly_name
# or manually
response = device.get(nodes / "netRemote.sys.info.friendlyName")
if response.status == FS_OK:
if response.success:
#_ Again, type(content) = nodes.BaseSysInfoFriendlyName
friendly_name = response.content.value

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
project = 'fsapi-tools'
copyright = '2022, MatrixEditor'
author = 'MatrixEditor'
release = '2.0.1'
release = '2.0.2'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 1 addition & 1 deletion fsapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@
>>> python3 -m fsapi --help
"""

__version__ = "2.0.1"
__version__ = "2.0.2"
__author__ = 'MatrixEditor'
2 changes: 1 addition & 1 deletion fsapi/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from fsapi.netremote.cli import main
from fsapi.net.cli import main

if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion fsapi/isu/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def _run(argv, target: pathlib.Path, pp: DataclassPrinter):
# Don't include the data section if no explicitly activated
values["archive"].pop("data")

with open(str(out_path), "w") as fp:
with open(str(out_path), "w", encoding="utf-8") as fp:
json.dump(values, fp, cls=BytesJSONEncoder)
pp.print_msg(Fore.LIGHTBLACK_EX, "[out] JSON saved to", str(out_path))
else:
Expand Down
17 changes: 3 additions & 14 deletions fsapi/isu/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def is_compressed(self) -> bool:
@dataclass_struct
class ISUArchiveIndexDirectoryEntry:
entry_count: int = csfield(cs.Int8ul)
entries: list[ISUArchiveIndexEntry] = subcsfield(
entries: t.List[ISUArchiveIndexEntry] = subcsfield(
ISUArchiveIndexEntry, cs.Array(cs.this.entry_count, ISUArchiveIndexEntry.struct)
)

Expand All @@ -147,7 +147,7 @@ class ISUArchiveIndex:
length: int = csfield(cs.Int8ul)
name: bytes = csfield(cs.Bytes(cs.this.length)) # always 0
entry_count: int = csfield(cs.Int8ul)
entries: list[ISUArchiveIndexEntry] = subcsfield(
entries: t.List[ISUArchiveIndexEntry] = subcsfield(
ISUArchiveIndexEntry, cs.Array(cs.this.entry_count, ISUArchiveIndexEntry.struct)
)

Expand All @@ -162,17 +162,6 @@ class ISUArchive:
data: bytes = csfield(cs.Bytes(cs.this.size - cs.this.index_size - 4))


@dataclass_struct
class ISUDataField:
length: int = csfield(cs.Int16ul)
unknown_1: int = csfield(cs.Int16ul)
name_length: int = csfield(cs.Int16ul)
flags: int = csfield(cs.Int16ul)
name: str = csfield(cs.PaddedString(16, "utf-8"))
value: int | None = csfield(cs.If(cs.this.length == 32, cs.Int32ul))
unknown_2: int | None = csfield(cs.If(cs.this.length == 32, cs.Int32ul))


@dataclass_struct
class ISUDataSection:
magic: int = csfield(cs.Int8ul)
Expand Down Expand Up @@ -381,7 +370,7 @@ def __init__(self, isu: ISU) -> None:
self.isu = isu
self._fields = self._parse_fields()

def _parse_fields(self) -> list[ISUDataField]:
def _parse_fields(self) -> t.List[ISUDataField]:
index = self.isu.stream.find(b"DecompBuffer")
if index == -1:
# Rather return an empty list than raising an error
Expand Down
3 changes: 2 additions & 1 deletion fsapi/isu/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import dataclasses
import enum
import xml.etree.ElementTree as xmltree
import typing as t

from typing import Optional, Union
from fsapi.netconfig import FSNetConfiguration
Expand Down Expand Up @@ -153,7 +154,7 @@ class UpdateRequest:
"""

status: Union[UpdateStatus, int] = UpdateStatus.ERROR
updates: list[ISUSoftwareElement] = dataclasses.field(default_factory=list)
updates: t.List[ISUSoftwareElement] = dataclasses.field(default_factory=list)
error: Optional[Exception] = None

@property
Expand Down
10 changes: 6 additions & 4 deletions fsapi/net/_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import sys
import enum

from typing import Optional

class FSAlarmSource(enum.IntEnum):
BUZZER = 0
Expand Down Expand Up @@ -121,14 +122,15 @@ class FSEQPreset(enum.IntEnum):
NEWS = enum.auto()


def enum_value_name(value: int, enum: str) -> str | None:
member = get_enum(enum)
def enum_value_name(value: int, enum_: str) -> Optional[str]:
member = get_enum(enum_)
if member is None:
return None
return member._value2member_map_[value]

return getattr(member, "_value2member_map_")[value]

def get_enum(field_name: str, path: str = None) -> type | None:

def get_enum(field_name: str, path: str = None) -> Optional[type]:
module = sys.modules[__name__]
internal_name = f"FS_{field_name.upper()}"

Expand Down
2 changes: 1 addition & 1 deletion fsapi/net/_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
# ============================================================================


class netRemote_debug_incidentReport_lastCreatedKey_nt(NodeList):
class netRemote_debug_incidentReport_list_nt(NodeList):
class Meta:
path = "netRemote.debug.incidentReport.list"
name = "BaseDebugIncidentReportList"
Expand Down
17 changes: 8 additions & 9 deletions fsapi/net/_wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class APICall(t.Generic[_T]):
def __init__(self, node_path: str) -> None:
self.node_path = NodePath(node_path)

def __get__(self, __instance: t.Any, __owner: type | None = None) -> _T:
def __get__(self, __instance: t.Any, __owner: t.Optional[type] = None) -> _T:
return self.get(__instance)

def __set__(self, __instance: t.Any, __value: _T) -> None:
Expand Down Expand Up @@ -119,7 +119,7 @@ def put(self, wrapper: _Wrapper, value: _T) -> None:
wrapper.device.put(self.node_path, value=value)


class ListAPICall(APICall["list[NodeListItem]"]):
class ListAPICall(APICall[t.List[NodeListItem]]):
"""Representation for a list API call.

This class behaves differently compared to standard API call variables
Expand All @@ -137,22 +137,22 @@ def __init__(self, node_path: str) -> None:
super().__init__(node_path)
self.__instance = None

def __get__(self, __instance: t.Any, __owner: type | None = None) -> ListAPICall:
def __get__(self, __instance: t.Any, __owner: t.Optional[type] = None) -> ListAPICall:
self.__instance = __instance
return self

def __call__(self, _pos=-1, max_items=0xFFFF, **argv) -> list[NodeListItem] | None:
def __call__(self, _pos=-1, max_items=0xFFFF, **argv) -> t.List[NodeListItem]:
argv["_pos"] = _pos
argv["maxItems"] = max_items
return self.get(self.__instance, **argv)

def get(self, wrapper: _Wrapper, **argv) -> list[NodeListItem] | None:
def get(self, wrapper: _Wrapper, **argv) -> t.List[NodeListItem]:
"""Returns a list of items.

:param wrapper: the api wrapper instance
:type wrapper: _Wrapper
:return: the list returned by the device
:rtype: list[NodeListItem] | None
:rtype: t.List[NodeListItem]
"""
response = wrapper.device.list_get_next(self.node_path, **argv)
if response.status != Status.FS_OK:
Expand Down Expand Up @@ -226,13 +226,13 @@ def device(self) -> FSDevice:
return self.__device()
return self.__device

def get_field(self, name: str) -> APICall | ListAPICall:
def get_field(self, name: str) -> t.Union[APICall, ListAPICall]:
"""Returns a field of this instance named by the provided string.

:param name: the field's name
:type name: str
:return: the api call wrapper instance
:rtype: APICall | ListAPICall
:rtype: t.Union[APICall, ListAPICall]
"""
return getattr(self, name)

Expand Down Expand Up @@ -287,4 +287,3 @@ def get_field(self, name: str) -> APICall | ListAPICall:
ls_incident_reports: _lac = ListAPICall("netRemote.debug.incidentReport.list")
ls_clock_sources: _lac = ListAPICall("netRemote.sys.caps.clockSourceList")
ls_languages: _lac = ListAPICall("netRemote.sys.caps.validLang")
ls_: _lac = ListAPICall("netRemote.sys.caps.clockSourceList")
14 changes: 7 additions & 7 deletions fsapi/net/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ def cacheable(cls) -> bool:
return cls._meta["cacheable"]

@property
def prototype(cls) -> list[Argument] | _Dynamic:
def prototype(cls) -> t.List[Argument] | _Dynamic:
"""Returns the prototype if this node."""
return cls._meta["prototype"]

Expand Down Expand Up @@ -512,11 +512,11 @@ def __eq__(self, __value: object) -> bool:
return super().__eq__(__value)

@property
def value(self) -> int | str | list[NodeListItem] | NodeValue:
def value(self) -> int | str | t.List[NodeListItem] | NodeValue:
"""The node's value

:return: the currently applied node value or None
:rtype: int | str | list[NodeListItem] | NodeValue
:rtype: int | str | t.List[NodeListItem] | NodeValue
"""
return self.__value

Expand Down Expand Up @@ -731,11 +731,11 @@ def __repr__(self) -> str:
return f"NodeListItem({repr(self.attrib)})"

@property
def fields(self) -> list[str]:
def fields(self) -> t.List[str]:
"""Returns a list of field names.

:return: all field names stored by this item.
:rtype: list[str]
:rtype: t.List[str]
"""
return list(self.attrib)

Expand Down Expand Up @@ -776,11 +776,11 @@ def __iter__(self) -> Iterator[NodeListItem]:
return iter(self.items)

@property
def items(self) -> list[NodeListItem]:
def items(self) -> t.List[NodeListItem]:
"""Returns the stored items as a list.

:return: the stored list items
:rtype: list[NodeListItem]
:rtype: t.List[NodeListItem]
"""
return self.value

Expand Down
4 changes: 2 additions & 2 deletions fsapi/net/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def View(value: str, search=False, disable_color=False, **kwds) -> None:
def Get(
host: str,
pin: str,
nodes: list[str],
nodes: t.List[str],
force_session=False,
disable_color=False,
simulate=False,
Expand Down Expand Up @@ -423,7 +423,7 @@ def Scan(
method = Method.GET
node_cls = (nodes / node).get_node_type()
if node_cls.is_list:
method = method.LIST_GET_NEXT
method = Method.LIST_GET_NEXT

if simulate:
pp.print_url(device.get_url(method, node))
Expand Down
25 changes: 14 additions & 11 deletions fsapi/net/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def __init__(
# The new value will be mapped automatically
self.new_session()

def get(self, *__nodes: t.Iterable[_NodeType]) -> FSResponse | list[FSResponse]:
def get(self, *__nodes: t.Iterable[_NodeType]) -> t.Union[FSResponse, t.List[FSResponse]]:
nodes = list(__nodes)
if len(nodes) == 1:
return self.node_request(Method.GET, nodes[0])
Expand All @@ -194,7 +194,7 @@ def list_get_next(self, node: _NodeType, **argv) -> FSResponse:
def list_get_prev(self, node: _NodeType, **argv) -> FSResponse:
return self.node_request(Method.LIST_GET_PREV, node, **argv)

def get_notifies(self) -> list[Node]:
def get_notifies(self) -> t.List[Node]:
if self.sid is None or self.sid == -1:
# NOTE: The unit will only execute this command if the user sends
# a valid Session ID
Expand Down Expand Up @@ -288,20 +288,20 @@ def node_request(
def node_request_multiple(
self,
method: Method,
nodes: list[_NodeType],
nodes: t.List[_NodeType],
config: FSNetConfiguration = None,
**argv,
) -> list[FSResponse]:
) -> t.List[FSResponse]:
"""Performs a multiple node request.

:param method: the API method
:type method: Method
:param nodes: the list of nodes to query
:type nodes: list[_NodeType]
:type nodes: t.List[_NodeType]
:param config: the network configuration, defaults to None
:type config: FSNetConfiguration, optional
:return: a list of response objects storing the de-serialized data.
:rtype: list[FSResponse]
:rtype: t.List[FSResponse]
"""
node_paths = list(map(self._to_node_path, nodes))
path_elements = ["fsapi", method.name]
Expand Down Expand Up @@ -387,18 +387,18 @@ def _create_url(self, path: str, parameters: dict) -> str:
def _build_parameters(self, parameters: dict) -> str:
# NOTE: These parameters must occur before any other custom
# parameter as GET_MULTIPLE would result in errors.
query_params = [f"pin={quote(self.pin)}"]
query_params = [f"pin={self._quote(self.pin)}"]
if self.sid is not None and self.sid != -1:
query_params.append(f"sid={quote(self.sid)}")
query_params.append(f"sid={self._quote(self.sid)}")

for key in parameters:
name = quote(key)
name = self._quote(key)
value = parameters[key]
if isinstance(value, list):
for list_element in value:
query_params.append(f"{name}={quote(str(list_element))}")
query_params.append(f"{name}={self._quote(list_element)}")
else:
query_params.append(f"{name}={quote(str(value))}")
query_params.append(f"{name}={self._quote(value)}")
return "&".join(query_params)

def _unmarshal(self, node_path: NodePath, tree: ElementTree.ElementTree) -> Node:
Expand Down Expand Up @@ -428,3 +428,6 @@ def _to_node_path(self, node: _NodeType) -> NodePath:
raise TypeError(f"Invalid node path type: {type(node)}")

return node_path

def _quote(self, obj: t.Any) -> str:
return quote(str(obj))
2 changes: 1 addition & 1 deletion nodes/fsapi_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def get_enum_class(java_class: str) -> str:
return content.replace("\n", "").replace(" ", "")


def get_list_prototype(java_class) -> list[str]:
def get_list_prototype(java_class) -> t.List[str]:
prototype = java_class[java_class.find("Prototype == null") :]
return prototype[prototype.find("{") + 1 : prototype.find("}")].split("\n")

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "fsapi-tools"
version = "2.0.1"
version = "2.0.2"
description="Frontier Smart Firmware Tools and FSAPI Implementation."
authors = [
{ name="MatrixEditor", email="not@supported.com" },
Expand Down