Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
# can happen on none-text nodes like comments
# ignore this
pass
@staticmethod
def node_name(node):
"""
Strips the namespace from the node-tag and returns the remaining
part as node-name.
"""
if isinstance(node.tag, str):
return node.tag.split('}')[-1]
return node.tag
class SpecVersion(AbstractDescriptionNode):
"""
Specification version node holding the description file
specification version from the schema device or service
informations.
"""
@property
def version(self):
return f'{self.major}.{self.minor}'
class Service(AbstractDescriptionNode):
"""
Storage for service attributes, like:
serviceType: urn:schemas-upnp-org:service:WANIPConnection:1
serviceId: urn:upnp-org:serviceId:WANIPConn1
return node.tag
class SpecVersion(AbstractDescriptionNode):
"""
Specification version node holding the description file
specification version from the schema device or service
informations.
"""
@property
def version(self):
return f'{self.major}.{self.minor}'
class Service(AbstractDescriptionNode):
"""
Storage for service attributes, like:
serviceType: urn:schemas-upnp-org:service:WANIPConnection:1
serviceId: urn:upnp-org:serviceId:WANIPConn1
controlURL: /igdupnp/control/WANIPConn1
eventSubURL: /igdupnp/control/WANIPConn1
SCPDURL: /igdconnSCPD.xml
"""
scpd = None
@property
def name(self):
return self.serviceId.split(':')[-1]
@property
super().__init__(root)
self.root_device = self.device[0]
self.services = self.root_device.collect_services()
@property
def spec_version(self):
return self.specVersion[0].version
@property
def device_model_name(self):
return self.root_device.model_name
# scpd-section ----------------------------------
class AllowedValueList(AbstractDescriptionNode):
"""stores a list of allowed values."""
sequences = {'values': None}
def process_node(self, node):
"""
node can be a repeated allowedValue tag without subnodes.
Therefor the tag.text has to be collected here.
"""
self.values.append(node.text.strip())
class AllowedValueRange(AbstractDescriptionNode):
"""
Stores attributes of an allowed range like
'minimum', 'maximum', 'step'
def load_scpd(self, address, port):
"""Loads the scpd data"""
protocol = 'http'
url = f'{protocol}://{address}:{port}{self.SCPDURL}'
root = get_xml_root(url)
self.scpd = Scpd(root)
@sequencer('service')
class ServiceList(AbstractDescriptionNode):
"""Storage for Service objects"""
sequences = {'service': Service}
class Device(AbstractDescriptionNode):
"""
Storage for devices attributes:
deviceType: urn:schemas-upnp-org:device:InternetGatewayDevice:1
friendlyName: FRITZ!Box 7590
manufacturer: AVM Berlin
manufacturerURL: http://www.avm.de
modelDescription: FRITZ!Box 7590
modelName: FRITZ!Box 7590
modelNumber: avm
modelURL: http://www.avm.de
UDN: uuid:<a id="">
Stores also Services in the serviceList and sub-devices in the
deviceList. 'deviceList' is None because of a circular dependency
and set later at import time (a deviceList stores devices and
a device has a deviceList for storing subdevices).</a>
class Argument(AbstractDescriptionNode):
"""
Container class for the attributes:
'name', 'direction', 'relatedStateVariable'
"""
@sequencer('argument')
class ArgumentList(AbstractDescriptionNode):
"""Sequence of Arguments."""
sequences = {'argument': Argument}
class Action(AbstractDescriptionNode):
"""
Class representing an Action with a 'name' and an ArgumentList. The
Argument objects can be accessed by name via the 'self.arguments'
dictionary.
"""
sequences = {'argumentList': ArgumentList}
arguments = {}
def __init__(self, root):
super().__init__(root)
if self.argumentList:
self.arguments = {
arg.name: arg for arg in self.argumentList[0]
}
def process_node(self, node):
"""
node can be a repeated allowedValue tag without subnodes.
Therefor the tag.text has to be collected here.
"""
self.values.append(node.text.strip())
class AllowedValueRange(AbstractDescriptionNode):
"""
Stores attributes of an allowed range like
'minimum', 'maximum', 'step'
"""
class StateVariable(AbstractDescriptionNode):
"""
collects 'name', 'dataType' and 'defaultValue' or 'allowedValueList'
of action parameter data.
A StateVariable instance also known its tag_attributes, which is a
dictionary: i.e. given the tag then
the value "no" can accessed by:
>>> sv = StateVariable(root)
>>> sv.tag_attributes['sendEvents']
'no'
"""
sequences = {
'allowedValueList': AllowedValueList,
'allowedValueRange': AllowedValueRange,
class ServiceStateTable(AbstractDescriptionNode):
"""
Collection of StateVariables. Is iterable and can access the
StateVariables by name by the dict 'self.state_variables'.
"""
sequences = {'stateVariable': StateVariable}
def __init__(self, root):
super().__init__(root)
self.state_variables = {
sv.name: sv for sv in self.stateVariable
}
class Argument(AbstractDescriptionNode):
"""
Container class for the attributes:
'name', 'direction', 'relatedStateVariable'
"""
@sequencer('argument')
class ArgumentList(AbstractDescriptionNode):
"""Sequence of Arguments."""
sequences = {'argument': Argument}
class Action(AbstractDescriptionNode):
"""
Class representing an Action with a 'name' and an ArgumentList. The
def __init__(self, root):
super().__init__(root)
if self.argumentList:
self.arguments = {
arg.name: arg for arg in self.argumentList[0]
}
@sequencer('action')
class ActionList(AbstractDescriptionNode):
"""Sequence of Actions."""
sequences = {'action': Action}
class Scpd(AbstractDescriptionNode):
"""
Service description object, specific for every service. Hold the
namespace, specVersion and an actionList with all available Actions.
The Actions can also be accessed by name by the 'actions' attribute
(which is a dictionary).
This class also hold a dictionary of StateVariable instances with
the names of the StateVariables as keys.
"""
sequences = {
'specVersion': SpecVersion,
'actionList': ActionList,
'serviceStateTable': ServiceStateTable,
}
actions = {}
state_variables = {}
def __init__(self, root):
super().__init__(root)
self.state_variables = {
sv.name: sv for sv in self.stateVariable
}
class Argument(AbstractDescriptionNode):
"""
Container class for the attributes:
'name', 'direction', 'relatedStateVariable'
"""
@sequencer('argument')
class ArgumentList(AbstractDescriptionNode):
"""Sequence of Arguments."""
sequences = {'argument': Argument}
class Action(AbstractDescriptionNode):
"""
Class representing an Action with a 'name' and an ArgumentList. The
Argument objects can be accessed by name via the 'self.arguments'
dictionary.
"""
sequences = {'argumentList': ArgumentList}
arguments = {}
def __init__(self, root):
return self.deviceList[0]
return self.deviceList
def collect_services(self):
"""
Returns a dictionary of the services in serviceList. Service
names are the keys, the service objects are the values.
"""
services = {service.name: service for service in self.services}
for device in self.devices:
services.update(device.collect_services())
return services
@sequencer('device')
class DeviceList(AbstractDescriptionNode):
"""Collection of Device objects."""
sequences = {'device': Device}
# backward declaration/injection of the DeviceList
Device.sequences['deviceList'] = DeviceList
class Description(AbstractDescriptionNode):
"""
Root class for a given description information like igddesc.xml or
tr64desc.xml
Instances have the attributes:
- root_device: Device instance of the root device