Open nickovs opened 4 years ago
For Python 3.6 there's a backport available so that's easily fixed: https://pypi.org/project/dataclasses/ The requirement would be:
dataclasses; python_version < '3.7'
Another question would be how this new API would be exposed. The way I see it there are a few options:
client.list_clients()
returns this object when the new API is enabledclient.list_client()
so it returns the new styleclient.clients
would be a collection class that is both iterable and subscriptable using something like client.clients[mac_address]
.dict
api to the dataclasses to maintain backwards compatibilityMy vote would be option 3, but that's your decision :)
Example:
@dataclasses.dataclass
class Client:
_id: str
assoc_time: int
authorized: bool
first_seen: int
ip: str
is_guest: bool
is_wired: bool
last_seen: int
latest_assoc_time: int
mac: str
oui: str
qos_policy_applied: bool
rx_bytes: int
rx_bytes_r: int
rx_packets: int
site_id: str
tx_bytes: int
tx_bytes_r: int
tx_packets: int
tx_retries: int
uptime: int
user_id: str
wifi_tx_attempts: int
_is_guest_by_uap: bool = None
_is_guest_by_ugw: bool = None
_is_guest_by_usw: bool = None
_last_seen_by_uap: int = 0
_last_seen_by_ugw: int = 0
_last_seen_by_usw: int = 0
_uptime_by_uap: int = 0
_uptime_by_ugw: int = 0
_uptime_by_usw: int = 0
anomalies: int = 0
ap_mac: str = ''
bssid: str = ''
bytes_r: int = 0
ccq: int = 0
channel: int = 0
confidence: int = 0
dev_cat: int = 0
dev_family: int = 0
dev_id: int = 0
dev_vendor: int = 0
device_name: str = ''
dhcpend_time: int = 0
essid: str = ''
fingerprint_source: int = 0
fixed_ip: str = ''
fw_version: str = ''
gw_mac: str = ''
hostname: str = ''
idletime: int = 0
is_11r: bool = None
name: str = ''
network: str = ''
network_id: str = ''
noise: int = 0
noted: bool = None
os_class: int = 0
os_name: int = 0
powersave_enabled: bool = None
priority: int = 0
radio: str = ''
radio_name: str = ''
radio_proto: str = ''
roam_count: int = 0
rssi: int = 0
rx_rate: int = 0
satisfaction: int = 0
score: int = 0
signal: int = 0
sw_depth: int = 0
sw_mac: str = ''
sw_port: int = 0
tx_power: int = 0
tx_rate: int = 0
use_fixedip: bool = None
usergroup_id: str = ''
vlan: int = 0
Generated by:
import collections
keys = collections.defaultdict(list)
counter = 0
for data in client.list_clients():
counter += 1
data = {k.replace('-', '_'): v for k, v in data.items()}
for key, value in data.items():
keys[key].append(value)
required = dict()
optional = dict()
for key, values in sorted(keys.items()):
type_ = type(values[0])
if type_ is int:
default = 0
elif type_ is str:
default = ''
elif type_ is bool:
default = None
else:
raise TypeError()
type_str = f'{type_.__name__}'
if len(values) == counter:
required[key] = type_str
else:
optional[key] = f'{type_str} = {default!r}'
for key, type_ in sorted(required.items()):
print(f'{key}: {type_}')
for key, type_ in sorted(optional.items()):
print(f'{key}: {type_}')
Using these we can create a high-level API that could work something like this:
fixed_hosts = dict(...)
for client in api.clients:
fixed_host = fixed_hosts.get(client.mac)
if not fixed_host:
continue
client.name = fixed_hostname.name
client.fixed_ip = fixed_hostname.ip
# Or:
for mac, fixed_host in fixed_hosts.items():
api.clients[mac].name = fixed_host.name
api.clients[mac].fixed_ip = fixed_host.ip
Currently the representation of clients in
unificontrol
is just the raw data that comes back from the underlying API. In a comment on another issue @WoLpH suggested that it would be useful to have an abstraction that represents clients as their own data objects and provide a higher level API for manipulating them.