Internal Design
The intention was always to have a python class per OCICommand element from the Broadworks AS schema.
To make this easier the process_schema.py
program was produced to break
down the Broadworks schema into its component parts, which are represented as
python classes.
The classes are broken down into types
, requests
(commands that are sent
to the Broadworks system), and responses
(the replies back from the
Broadworks system). Unfortunately this means that each of those files is
huge.
The classes themselves are described by a tuple of ElementInfo
instances -
one per property in the schema class, and a class property for each schema
property. Naming of these is in the more pythonic snake case rather than the
Java-esque CamelCase.
The ElementInfo
class is used mainly to guide the XML serialisation and
deserialisation of each object. They contain the python and XML names of each
property and some flags about the propery - for example is this a required
element is_required
, an array like element is_array
, a tabular set of
data is_table
or a complex element (ie containing sub-elements)
is_complex
.
All of the component classes of the system are intended to be immutable. There are currently no helpers to aid creating a modified instance from an existing instance because these operations do not appear to be part of a normal Broadworks workflow.
Implementation
The ElementInfo
class was originally a named tuple, but this was changed
later to an attrs
based class for speed and to
give some type checking.
The generated classes were all based on Michael DeHaan's[ClassForge
]
(https://classforge.io/) object system. However although this system fitted
my reuirements very nicely and allowed the mkdocstrings
auto documentation
to work I was concerned that there were no other packages that used this
system, there have been no updates or releases for well over a year and that
the website had gone defunct. Therefore I moved to another class base.
Attrs
mostly worked well as a base for the
classes, but added an approximately 5 second startup cost on a fairly fast
machine. The same occurred with using python's internal dataclass
- and
also forced a very recent version of python if support for immutable objects
was required.
Therefore the current version is based on a class python objects using a
customised __init__()
method to set up the attributes from an array of
ElementInfo
objects. A hack is used to make these objects immutable. The
objects have __slots__
defined to make them dict-less - although this might
be overkill for the memory and speed benefits. Unfortunately this broke the
mkdocstrings
documentation (or at least made it take an absolutely vast
amount of time to run), so the documentation for the types
, requests
and
responses
is generated statically.
Returned tables (only found in response
objects), are defined as
NamedTuple
s with a class name taken from the XML table name, with the
elements within them using names taken from the table definition.
Due to the huge number of component classes, and that they need to have the
session id associated with them on creation (since the objects themselves are
immutable), the BroadworksAPI
class has a set of helper methods to create and
send the serialised commands to the server and then return the results.
In practice a user only interacts with the BroadworksAPI
methods.
Problems
There is no easy way that I can find - especially when autogenerated - to
replicate the XML schema choice
elements - effectively a union between
different possibilities. As such any element within a choice
element has
been expressed as a non-required element, and it is up to the library user to
apply appropriate values to make the generated XML work.
As an example of this, look at the UnboundedPositiveInt
elements within
the usage example, which may have either a positive numeric quantity
value
or have unlimited
set true.
Additionally in the example the surrounding ServicePackAuthorization
element may have either unauthorized=True
or authorized_quantity
set
to a UnboundedPositiveInt
.
Additionally in version 2.0.1
onwards, schema sequence
sets, within schema
choice
elements are similarly handled - all the contained attributes are
made optional.
I can think of some ways to make the currently xfail
flagged tests in
test_faulty_command.py
be handled correctly - at the cost of adding more
complexity to the information stored about each command type and making the
__init__
function more complex. However I am not fully convinced that this
library should be performing that level of input checking - although the
library will accept illegal combinations, the Broadworks server will quickly
tell you that you are wrong!.
The tables returned in many command responses have no type information in the
schema as to how to treat them - the column information is also passed within
the response itself. This means that often there are boolean or numeric
values that are represented as strings. In particular the booleans will have
textual values of either true
or false
- all in lower case.