Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Make asdict recurrent (#202)
Browse files Browse the repository at this point in the history
* Not working test.

* fix tests

* bump minor

* Rename servers

* skip test
  • Loading branch information
kagrski authored Mar 28, 2023
1 parent cc2fcf5 commit 5a87f4b
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 5 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "vmngclient"
version = "0.7.2"
version = "0.8.0"
description = "Universal vManage API"
authors = ["kagorski <[email protected]>"]
readme = "README.md"
Expand Down
4 changes: 2 additions & 2 deletions vmngclient/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ class TenantRadiusServer(DataclassBase):

timeout: int = field(default=3, metadata={FIELD_NAME: "timeout"})
retransmit: int = field(default=5, metadata={FIELD_NAME: "retransmit"})
server: List[RadiusServer] = field(factory=list, metadata={FIELD_NAME: "server"})
servers: List[RadiusServer] = field(factory=list, metadata={FIELD_NAME: "server"})


@define(frozen=True)
Expand All @@ -471,7 +471,7 @@ class TenantTacacsServer(DataclassBase):

timeout: int = field(default=3, metadata={FIELD_NAME: "timeout"})
authentication: str = field(default="PAP", metadata={FIELD_NAME: "authentication"})
server: List[TacacsServer] = field(factory=list, metadata={FIELD_NAME: "server"})
servers: List[TacacsServer] = field(factory=list, metadata={FIELD_NAME: "server"})


@define
Expand Down
132 changes: 132 additions & 0 deletions vmngclient/tests/test_creation_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# type: ignore
import json
import unittest
from typing import Optional

from attrs import define, field
from parameterized import parameterized

from vmngclient.dataclasses import TLOC, Device, PacketSetup, TacacsServer, TenantTacacsServer
from vmngclient.utils.creation_tools import FIELD_NAME, asdict
from vmngclient.utils.personality import Personality
from vmngclient.utils.reachability import Reachability


@define
class _TestObjectD:
d: int


@define
class _TestObjectC:
c: int
dd: Optional[_TestObjectD] = None


@define
class _TestObjectB:
rnd: int = field(metadata={FIELD_NAME: "RANDOM"})


@define
class _TestObjectA:
a: int = field(metadata={FIELD_NAME: "A"})
b: _TestObjectB = field(metadata={FIELD_NAME: "BBB"})
c: Optional[_TestObjectC] = None


class TestCreationTools(unittest.TestCase):
@parameterized.expand(
[
(TLOC(1, 1), {"color": 1, "encapsulation": 1}),
(PacketSetup(1, 2), {"sessionId": 1, "isNewSession": 2}),
(
Device(1, "vbond", *range(2), "reachable", 1),
{
"deviceId": 0,
"host-name": 1,
"local-system-ip": 1,
"memState": None,
"cpuState": None,
"cpuLoad": None,
"connectedVManages": [],
"device-model": None,
"board-serial": None,
"vedgeCertificateState": None,
"chasisNumber": None,
"uuid": 1,
"personality": Personality.VBOND,
"reachability": Reachability.REACHABLE,
"status": None,
"memUsage": None,
"state_description": None,
},
),
(_TestObjectA(1, _TestObjectB(2)), {"BBB": {"RANDOM": 2}, "A": 1, "c": None}),
(
_TestObjectA(1, _TestObjectB(2), _TestObjectC(1)),
{"BBB": {"RANDOM": 2}, "A": 1, "c": {"c": 1, "dd": None}},
),
(
_TestObjectA(1, _TestObjectB(2), _TestObjectC(1, _TestObjectD(111))),
{"BBB": {"RANDOM": 2}, "A": 1, "c": {"c": 1, "dd": {"d": 111}}},
),
(
TenantTacacsServer(1, "2", [TacacsServer(*range(7)), TacacsServer(*range(2, 9))]),
{
"timeout": 1,
"authentication": "2",
"server": [
{
"address": 0,
"authPort": 1,
"vpn": 2,
"vpnIpSubnet": 3,
"key": 4,
"secretKey": 5,
"priority": 6,
},
{
"address": 2,
"authPort": 3,
"vpn": 4,
"vpnIpSubnet": 5,
"key": 6,
"secretKey": 7,
"priority": 8,
},
],
},
),
]
)
def test_asdict(self, obj, serialized_obj):
# Arrange, Act
output = asdict(obj)
print(output)
# Assert
self.assertEqual(output, serialized_obj)

@parameterized.expand(
[
(TLOC(1, 1), '{"color": 1, "encapsulation": 1}'),
(PacketSetup(1, 2), '{"sessionId": 1, "isNewSession": 2}'),
(
Device(1, "vbond", *range(2), "reachable", 1),
'{"deviceId": 0, "host-name": 1, "local-system-ip": 1, "memState": null, "cpuState": null, '
'"cpuLoad": null, "connectedVManages": [], "device-model": null, "board-serial": null, '
'"vedgeCertificateState": null, "chasisNumber": null, "uuid": 1, "personality": "vbond", '
'"reachability": "reachable", "status": null, "memUsage": null, "state_description": null}',
),
]
)
def test_asdict_json(self, obj, serialized_obj):
# Arrange, Act
output = json.dumps(asdict(obj))
# Assert
print(output)
self.assertEqual(output, serialized_obj)


if __name__ == "__main__":
unittest.main()
2 changes: 2 additions & 0 deletions vmngclient/tests/test_devices_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from unittest.mock import patch

from parameterized import parameterized # type: ignore
from pytest import mark # type: ignore
from tenacity import RetryError # type: ignore

from vmngclient.api.basic_api import DevicesAPI, DeviceStateAPI, FailedSend
Expand Down Expand Up @@ -649,6 +650,7 @@ def answer():
# Assert
self.assertRaises(RetryError, answer)

@mark.skip(reason="10 minutes length")
@patch("vmngclient.session.vManageSession")
def test_wait_for_device_state(self, mock_session):
# Arrange
Expand Down
14 changes: 14 additions & 0 deletions vmngclient/utils/creation_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,26 @@ def asdict(dataclass: AttrsInstance) -> dict:
Returns:
dict: Serialized dict
"""

json_fields_excluded = attrs.asdict(dataclass, filter=lambda x, _: FIELD_NAME not in x.metadata)
json_fields = attrs.asdict(dataclass, filter=lambda x, _: FIELD_NAME in x.metadata)

for field in fields(dataclass.__class__):
field_value = getattr(dataclass, field.name)

json_field_name = field.metadata.get(FIELD_NAME, None)
if json_field_name:
json_fields[json_field_name] = json_fields.pop(field.name)
if isinstance(field_value, AttrsInstance):
json_fields[json_field_name] = asdict(field_value)

if isinstance(field_value, list): # tuple, List[AttrsInstance], set, frozenset
if len(field_value) > 0 and isinstance(field_value[0], AttrsInstance):
json_fields[json_field_name] = [asdict(_f) for _f in field_value]
else:
if isinstance(field_value, AttrsInstance):
json_fields_excluded[field.name] = asdict(field_value)

return {**json_fields, **json_fields_excluded}


Expand Down
2 changes: 1 addition & 1 deletion vmngclient/utils/personality.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from enum import Enum


class Personality(Enum):
class Personality(str, Enum):
VSMART = "vsmart"
VBOND = "vbond"
EDGE = "vedge"
Expand Down
2 changes: 1 addition & 1 deletion vmngclient/utils/reachability.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from enum import Enum


class Reachability(Enum):
class Reachability(str, Enum):
REACHABLE = "reachable"
UNREACHABLE = "unreachable"

0 comments on commit 5a87f4b

Please sign in to comment.