Skip to content

Commit

Permalink
adding documentation and cleaning up code
Browse files Browse the repository at this point in the history
  • Loading branch information
Pat-pGuo committed Dec 11, 2024
1 parent d4fe7c4 commit f13d92d
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 58 deletions.
1 change: 0 additions & 1 deletion pyrad/datatypes/structural.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def get_value(self, attribute: 'Attribute', packet, offset):
raise ValueError('TLV length field too small')

sub_value, sub_offset = attribute[sub_type].get_value(packet, cursor)

sub_attrs.setdefault(sub_type, []).append(sub_value)

cursor += sub_offset
Expand Down
64 changes: 37 additions & 27 deletions pyrad/dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
from pyrad import bidict
from pyrad import dictfile
from copy import copy
import logging

from pyrad.datatypes import leaf, structural

Expand Down Expand Up @@ -132,28 +131,10 @@ def __str__(self):

return str


# class Attribute(object):
# def __init__(self, name, code, datatype, is_sub_attribute=False, vendor='', values=None,
# encrypt=0, has_tag=False):
# if datatype not in DATATYPES:
# raise ValueError('Invalid data type')
# self.name = name
# self.number = code
# # store a datatype object as the Attribute type
# self.type = DATATYPES[datatype]
# self.vendor = vendor
# self.encrypt = encrypt
# self.has_tag = has_tag
# self.values = bidict.BiDict()
# self.children = {}
# self.parent = None
# self.is_sub_attribute = is_sub_attribute
# if values:
# for (key, value) in values.items():
# self.values.Add(key, value)

class Attribute(object):
"""
class to represent an attribute as defined by the radius dictionaries
"""
def __init__(self, name, number, datatype, parent=None, vendor=None,
values=None, encrypt=0, tags=None):
if datatype not in DATATYPES:
Expand All @@ -168,6 +149,7 @@ def __init__(self, name, number, datatype, parent=None, vendor=None,
self.encrypt = encrypt
self.has_tag = tags

# values as specified in the dictionary
self.values = bidict.BiDict()
if values:
for key, value in values.items():
Expand Down Expand Up @@ -245,6 +227,9 @@ def __setitem__(self, key: str, value: 'Attribute'):
self.attrindex.Add(key, value.number)

class AttrStack:
"""
class representing the nested layers of attributes in dictionaries
"""
def __init__(self):
self.attributes = []
self.namespaces = []
Expand All @@ -258,12 +243,11 @@ def push(self, attr: Attribute, namespace: bidict.BiDict) -> None:
datatype), we have somewhat redundant code here.
@param attr: attribute to add children to
@param namespace: namespace defining
@return:
@return: None
"""
self.attributes.append(attr)
self.namespaces.append(namespace)


def pop(self) -> None:
"""
removes the top most layer
Expand All @@ -287,23 +271,43 @@ def top_namespace(self) -> bidict.BiDict:
return self.namespaces[-1]

class Vendor:
def __init__(self, name, number):
"""
class representing a vendor with its attributes
the existence of this class allows us to have a namespace for vendor
attributes. if vendor was only represented by an int or string in the
Vendor-Specific attribute (i.e., Vendor-Specific = { 16 = [ foo ] }), it is
difficult to have a nice namespace mapping of vendor attribute names to
numbers.
"""
def __init__(self, name: str, number: int):
"""
@param name: name of the vendor
@param number: vendor ID
"""
self.name = name
self.number = number

self.attributes = {}
self.attrindex = bidict.BiDict()

def __getitem__(self, key):
def __getitem__(self, key: str|int) -> Attribute:
# if using attribute number, first convert to attribute name
if isinstance(key, int):
if not self.attrindex.HasBackward(key):
raise KeyError(f'Non existent attribute {key}')
key = self.attrindex.GetBackward(key)

# return the attribute by name
return self.attributes[key]

def __setitem__(self, key, value):
def __setitem__(self, key: str, value: Attribute):
# key must be the attribute's name
if key != value.name:
raise ValueError('Key must be equal to Attribute name')

# update both the attribute and index dicts
self.attributes[key] = value
self.attrindex.Add(value.name, value.number)

Expand Down Expand Up @@ -354,6 +358,7 @@ def __getitem__(self, key):
# check to see if attribute exists
if not self.attrindex.HasBackward(key):
raise KeyError(f'Attribute number {key} not defined')
# gets attribute name from number using index
key = self.attrindex.GetBackward(key)
return self.attributes[key]

Expand Down Expand Up @@ -445,10 +450,15 @@ def keyval(o):
attribute = Attribute(name, code, datatype, parent, vendor,
encrypt=encrypt, tags=has_tag)

# if detected an inline vendor (vendor in the flags field), set the
# attribute under the vendor's attributes
# THIS FUNCTION IS NOT SUPPORTED IN FRv4 AND SUPPORT WILL BE REMOVED
if inline_vendor:
self.attributes['Vendor-Specific'][vendor][name] = attribute
else:
# add attribute name and number mapping to current namespace
self.stack.top_namespace().Add(name, code)
# add attribute to current namespace
self.stack.top_attr()[name] = attribute
if parent:
# add attribute to parent
Expand Down
Loading

0 comments on commit f13d92d

Please sign in to comment.