Python serializable objects json [duplicate] - python

This question already has answers here:
How to make a class JSON serializable
(41 answers)
Closed 6 months ago.
class gpagelet:
"""
Holds 1) the pagelet xpath, which is a string
2) the list of pagelet shingles, list
"""
def __init__(self, parent):
if not isinstance( parent, gwebpage):
raise Exception("Parent must be an instance of gwebpage")
self.parent = parent # This must be a gwebpage instance
self.xpath = None # String
self.visibleShingles = [] # list of tuples
self.invisibleShingles = [] # list of tuples
self.urls = [] # list of string
class gwebpage:
"""
Holds all the datastructure after the results have been parsed
holds: 1) lists of gpagelets
2) loc, string, location of the file that represents it
"""
def __init__(self, url):
self.url = url # Str
self.netloc = False # Str
self.gpagelets = [] # gpagelets instance
self.page_key = "" # str
Is there a way for me to make my class json serializable? The thing that I am worried is the recursive reference.

Write your own encoder and decoder, which can be very simple like return __dict__
e.g. here is a encoder to dump totally recursive tree structure, you can enhance it or use as it is for your own purpose
import json
class Tree(object):
def __init__(self, name, childTrees=None):
self.name = name
if childTrees is None:
childTrees = []
self.childTrees = childTrees
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if not isinstance(obj, Tree):
return super(MyEncoder, self).default(obj)
return obj.__dict__
c1 = Tree("c1")
c2 = Tree("c2")
t = Tree("t",[c1,c2])
print json.dumps(t, cls=MyEncoder)
it prints
{"childTrees": [{"childTrees": [], "name": "c1"}, {"childTrees": [], "name": "c2"}], "name": "t"}
you can similarly write a decoder but there you will somehow need to identify is it is your object or not, so may be you can put a type too if needed.

Indirect answer: instead of using JSON, you could use YAML, which has no problem doing what you want. (JSON is essentially a subset of YAML.)
Example:
import yaml
o1 = gwebpage("url")
o2 = gpagelet(o1)
o1.gpagelets = [o2]
print yaml.dump(o1)
In fact, YAML nicely handles cyclic references for you.

I implemented a very simple todict method with the help of https://stackoverflow.com/a/11637457/1766716
Iterate over properties that is not starts with __
Eliminate methods
Eliminate some properties manually which is not necessary (for my case, coming from sqlalcemy)
And used getattr to build dictionary.
class User(Base):
id = Column(Integer, primary_key=True)
firstname = Column(String(50))
lastname = Column(String(50))
password = Column(String(20))
def props(self):
return filter(
lambda a:
not a.startswith('__')
and a not in ['_decl_class_registry', '_sa_instance_state', '_sa_class_manager', 'metadata']
and not callable(getattr(self, a)),
dir(self))
def todict(self):
return {k: self.__getattribute__(k) for k in self.props()}

My solution for this was to extend the 'dict' class and perform checks around required/allowed attributes by overriding init, update, and set class methods.
class StrictDict(dict):
required=set()
at_least_one_required=set()
cannot_coexist=set()
allowed=set()
def __init__(self, iterable={}, **kwargs):
super(StrictDict, self).__init__({})
keys = set(iterable.keys()).union(set(kwargs.keys()))
if not keys.issuperset(self.required):
msg = str(self.__class__.__name__) + " requires: " + str([str(key) for key in self.required])
raise AttributeError(msg)
if len(list(self.at_least_one_required)) and len(list(keys.intersection(self.at_least_one_required))) < 1:
msg = str(self.__class__.__name__) + " requires at least one: " + str([str(key) for key in self.at_least_one_required])
raise AttributeError(msg)
for key, val in iterable.iteritems():
self.__setitem__(key, val)
for key, val in kwargs.iteritems():
self.__setitem__(key, val)
def update(self, E=None, **F):
for key, val in E.iteritems():
self.__setitem__(key, val)
for key, val in F.iteritems():
self.__setitem__(key, val)
super(StrictDict, self).update({})
def __setitem__(self, key, value):
all_allowed = self.allowed.union(self.required).union(self.at_least_one_required).union(self.cannot_coexist)
if key not in list(all_allowed):
msg = str(self.__class__.__name__) + " does not allow member '" + key + "'"
raise AttributeError(msg)
if key in list(self.cannot_coexist):
for item in list(self.cannot_coexist):
if key != item and item in self.keys():
msg = str(self.__class__.__name__) + "does not allow members '" + key + "' and '" + item + "' to coexist'"
raise AttributeError(msg)
super(StrictDict, self).__setitem__(key, value)
Example usage:
class JSONDoc(StrictDict):
"""
Class corresponding to JSON API top-level document structure
http://jsonapi.org/format/#document-top-level
"""
at_least_one_required={'data', 'errors', 'meta'}
allowed={"jsonapi", "links", "included"}
cannot_coexist={"data", "errors"}
def __setitem__(self, key, value):
if key == "included" and "data" not in self.keys():
msg = str(self.__class__.__name__) + " does not allow 'included' member if 'data' member is not present"
raise AttributeError(msg)
super(JSONDoc, self).__setitem__(key, value)
json_doc = JSONDoc(
data={
"id": 5,
"type": "movies"
},
links={
"self": "http://url.com"
}
)

Related

How to find Dictionary Key(s) from Value in a large nested dictionary of variable depth?

Say that I have a large dictionary full of nested values such as this:
large_dic ={
...
"key":{"sub-key1" :{"sub-key2": "Test"}},
"0key":{"0sub-key1": "0Test"},
"1key":{"1sub-key1":{"1sub-key2":{"1sub-key3":"1Test"}}}
...
}
What I would like to do is to be able to get for example from the final value:
"1Test"
the key(s) to access it, such as in this case:
large_dic["1key"]["1sub-key1"]["1sub-key2"]["1sub-key3"]
Thanks for the support.
Edit to add more infos: The dictionary trees I'm talking about are linear(YAML files converted into a python dictionary structure), there is never more than one key, the ending leaf values may not be unique.
Since OP is looking for hierarchical keys instead
I made this class :
class PointingSlice:
def __init__(self, obj, *slices) -> None:
self.obj = obj
self.slices = slices
def __str__(self):
return f"{str(self.obj)}{''.join(map(self._repr_slice, self.slices))}"
def _repr_slice(self, sliced: slice):
sqbrackets = "[{}]"
if not isinstance(sliced, slice):
return sqbrackets.format(repr(sliced))
items = [sliced.start, sliced.stop, sliced.step]
fn = lambda x: str() if x is None else str(x)
return sqbrackets.format(":".join(map(fn, items)))
def resolve(self):
obj = self.obj
for sliced in self.slices:
obj = obj.__getitem__(sliced)
return obj
and this function for instantiation :
def find_longest(mapping, key):
keys = [key]
value = mapping[key]
while isinstance(value, dict):
((k, value),) = value.items()
keys.append(k)
return PointingSlice(mapping, *keys)
Example use:
print(find_longest(large_dic, "1key"))
# output:
# {'key': {'sub-key1': {'sub-key2': 'Test'}}, '0key': {'0sub-key1': '0Test'}, '1key': {'1sub-key1': {'1sub-key2': {'1sub-key3': '1Test'}}}}['1key']['1sub-key1']['1sub-key2']['1sub-key3']
# do note that it is the same thing as large_dic['1key']['1sub-key1']['1sub-key2']['1sub-key3']
print(find_longest(large_dic, "1key").resolve()) # 1Test
So I made some changes and now it supports additional repr options matching your exact use case :
class PointingSlice:
def __init__(self, obj, *slices, object_name=None) -> None:
self.obj = obj
self.slices = slices
self.object_name = object_name
def __str__(self):
return f"{self.object_name or str(self.obj)}{''.join(map(self._repr_slice, self.slices))}"
def _repr_slice(self, sliced: slice):
sqbrackets = "[{}]"
if not isinstance(sliced, slice):
return sqbrackets.format(repr(sliced))
items = [sliced.start, sliced.stop, sliced.step]
fn = lambda x: str() if x is None else str(x)
return sqbrackets.format(":".join(map(fn, items)))
def resolve(self):
obj = self.obj
for sliced in self.slices:
obj = obj.__getitem__(sliced)
return obj
large_dic = {
"key": {"sub-key1": {"sub-key2": "Test"}},
"0key": {"0sub-key1": "0Test"},
"1key": {"1sub-key1": {"1sub-key2": {"1sub-key3": "1Test"}}},
}
def find_longest(mapping, key):
keys = [key]
value = mapping[key]
while isinstance(value, dict):
((k, value),) = value.items()
keys.append(k)
return PointingSlice(mapping, *keys)
f = find_longest(large_dic, "1key")
f.object_name = "large_dic" # for representational purposes, it works without this
print(f) # large_dic['1key']['1sub-key1']['1sub-key2']['1sub-key3']
print(f.resolve()) # 1Test
There are numerous ways to achieve this. You might want to look up "prefix tree traversal" (or "trie traversal").
A simple recursive solution with poor memory efficiency could look like this:
def find_trie_leaf_path(trie: dict, leaf_value, trie_path: list[str] = []):
for key, value in trie.items():
if isinstance(value, dict):
yield from find_trie_leaf_path(value, leaf_value, trie_path + [key])
elif value == leaf_value:
yield trie_path + [key]
large_dic = {
"key": {"sub-key1": {"sub-key2": "Test"}},
"0key": {"0sub-key1": "0Test"},
"1key": {"1sub-key1": {"1sub-key2": {"1sub-key3": "Test"}}},
}
first_match = next(find_trie_leaf_path(large_dic, "Test"))
all_matches = list(find_trie_leaf_path(large_dic, "Test"))
This should work even if your trie is very wide. If it is very high, I'd rather use an iterative algorithm.
I want to point out, though, that prefix trees are usually used the other way round. If you find yourself needing this search a lot, you should consider a different data structure.
Yes, it's totally possible. Here's the function to get the deeply nested value:
def get_final_value(mapping, key):
value = mapping[key]
while isinstance(value, dict):
(value,) = value.values()
return value
Example use:
>>> get_final_value(large_dic, "key")
'Test'
>>> get_final_value(large_dic, "0key")
'0Test'
>>> get_final_value(large_dic, "1key")
'1Test'
>>>
Can the parent keys be deduced from your final value in any way or is the tree structure rather random? If latter is the case then you'll probably just end up searching your tree until you find your value, what path search algorithm you choose for that again depends on the tree structure you have. As already asked in the comments, does each node only have one other node or is it binary or can it have many child nodes?

marshmallow `validates_schema` to reject unknown fields with `pass_many=True`

I struggle to understand how to handle unknown fields when the Schema is passed a list of objects for validation. I got so far :
class MySchema(Schema):
# fields ...
#marshmallow_decorators.validates_schema(pass_original=True)
def check_unknown_fields(self, data, original_data):
if isinstance(original_data, list):
for dct in original_data:
self._assert_no_unknown_field(dct)
else:
self._assert_no_unknown_field(original_data)
def _assert_no_unknown_field(self, dct):
unknown = set(dct.keys()) - set(self.fields)
if unknown:
raise MarshmallowValidationError('Unknown field', unknown)
But that obviously doesn't work, as the validator is ran for all items in the list every time. Therefore the first error will be caught, and returned on all items :
items = [
{'a': 1, 'b': 2, 'unknown1': 3},
{'a': 4, 'b': 5, 'unknown2': 6},
]
errors = MySchema(many=True).validate(items)
# {0: {'unknown1': ['Unknown field']}, 1: {'unknown1': ['Unknown field']}}
I was trying to think of a way to get only the single item from original_data corresponding to the data argument and validate only that one, but I can't really do that, as items have no id, or field that would make them searchable ...
Am I missing something? Is there a solution to this?
This is a workaround I came up with ... I wish it was simpler, but here it is :
from marshmallow import Schema, ValidationError as MarshmallowValidationError, fields
UNKNOWN_MESSAGE = 'unknown field'
class _RejectUnknownMixin(object):
def _collect_unknown_fields_errors(self, schema, data):
"""
Checks `data` against `schema` and returns a dictionary `{<field>: <error>}`
if unknown fields detected, or `{0: {<field>: <error>}, ... N: <field>: <error>}`
if `data` is a list.
"""
if isinstance(data, list):
validation_errors = {}
for i, datum in enumerate(data):
datum_validation_errors = self._collect_unknown_fields_errors(schema, datum)
if datum_validation_errors:
validation_errors[i] = datum_validation_errors
return validation_errors
else:
unknown = set(data.keys()) - set(schema.fields)
return {name: [UNKNOWN_MESSAGE] for name in unknown}
class NestedRejectUnknown(fields.Nested, _RejectUnknownMixin):
"""
Nested field that returns validation errors if unknown fields are detected.
"""
def _deserialize(self, value, attr, data):
validation_errors = {}
try:
result = super(NestedRejectUnknown, self)._deserialize(value, attr, data)
except MarshmallowValidationError as err:
validation_errors = err.normalized_messages()
# Merge with unknown field errors
validation_errors = _merge_dicts(
self._collect_unknown_fields_errors(self.schema, value), validation_errors)
if validation_errors:
raise MarshmallowValidationError(validation_errors)
return result
class SchemaRejectUnknown(Schema, _RejectUnknownMixin):
"""
Schema that return validation errors if unknown fields are detected
"""
def validate(self, data, **kwargs):
validation_errors = super(SchemaRejectUnknown, self).validate(data, **kwargs)
return _merge_dicts(
self._collect_unknown_fields_errors(self, data), validation_errors)
def _merge_dicts(a, b, path=None):
"""
Ref : https://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge
merges b into a
"""
if path is None:
path = []
for key in b:
if key in a:
if isinstance(a[key], dict) and isinstance(b[key], dict):
_merge_dicts(a[key], b[key], path + [str(key)])
elif a[key] == b[key]:
# same leaf value
pass
else:
raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
else:
a[key] = b[key]
return a
In marshmallow 3.0+ there is the unknown field in Meta, i.e.:
def test_validate(self):
class ModelSchema(Schema):
class Meta:
unknown = RAISE
name = fields.String()
schema = ModelSchema()
data = dict(name='jfaleiro', xyz=2)
schema.validate(data) # passes
schema.load(data) # fails (as intended)
It is a bit contradictory why it passes validate and fails load though.

Converting Nested Json into Python object

I have nested json as below
{
"product" : "name",
"protocol" : "scp",
"read_logs" : {
"log_type" : "failure",
"log_url" : "htttp:url"
}
}
I am trying to create Python class object with the below code.
import json
class Config (object):
"""
Argument: JSON Object from the configuration file.
"""
def __init__(self, attrs):
if 'log_type' in attrs:
self.log_type = attrs['log_type']
self.log_url = attrs['log_url']
else:
self.product = attrs["product"]
self.protocol = attrs["protocol"]
def __str__(self):
return "%s;%s" %(self.product, self.log_type)
def get_product(self):
return self.product
def get_logurl(self):
return self.log_url
class ConfigLoader (object):
'''
Create a confiuration loaded which can read JSON config files
'''
def load_config (self, attrs):
with open (attrs) as data_file:
config = json.load(data_file, object_hook=load_json)
return config
def load_json (json_object):
return Config (json_object)
loader = ConfigLoader()
config = loader.load_config('../config/product_config.json')
print config.get_protocol()
But, the object_hook is invoking the load_json recursively and the Class Config init is being called twice. So the final object that I created does not contain the nested JSON data.
Is there any way to read the entire nested JSON object into a single Python class ?
Thanks
A variation on Pankaj Singhal's idea, but using a "generic" namespace class instead of namedtuples:
import json
class Generic:
#classmethod
def from_dict(cls, dict):
obj = cls()
obj.__dict__.update(dict)
return obj
data = '{"product": "name", "read_logs": {"log_type": "failure", "log_url": "123"}}'
x = json.loads(data, object_hook=Generic.from_dict)
print(x.product, x.read_logs.log_type, x.read_logs.log_url)
namedtuple & object_hook can help create a one-liner:
# Create an object with attributes corresponding to JSON keys.
def json_to_obj(data): return json.loads(data, object_hook=lambda converted_dict: namedtuple('X', converted_dict.keys())(*converted_dict.values()))
OR Create a more readable function like below:
def _object_hook(converted_dict): return namedtuple('X', converted_dict.keys())(*converted_dict.values())
def json_to_obj(data): return json.loads(data, object_hook=_object_hook)
Below is the code snippet to use it:
import json
from collections import namedtuple
data = '{"product": "name", "read_logs": {"log_type": "failure", "log_url": htttp:url}}'
x = json_to_obj(data)
print x.product, x.read_logs.log_type, x.read_logs.log_url
NOTE: Check out namedtuple's rename parameter.
I wrote a simple DFS algorithm to do this job.
Convert nested item as a flat dictionary. In my case, I joined the keys of json item with a dash.
For example, nested item { "a":[{"b": "c"}, {"d":"e"}] } will be transformed as {'a-0-b': 'c', 'a-1-d': 'e'}.
def DFS(item, headItem, heads, values):
if type(item) == type({}):
for k in item.keys():
DFS(item[k], headItem + [k], heads, values)
elif type(item) == type([]):
for i in range(len(item)):
DFS(item[i], headItem + [str(i)], heads, values)
else:
headItemStr = '-'.join(headItem)
heads.append(headItemStr)
values.append(item)
return
def reduce(jsonItem):
heads, values = [], []
DFS(jsonItem, [], heads, values)
return heads, values
def json2dict(jsonItem):
head, value = reduce(jsonItem)
dictHeadValue = { head[i] : value[i] for i in range(len(head))}
return dictHeadValue

finds key but not KEY.lower() in dictionary Python

So I need to write this program where I create a class and an object of that class is a dictionary with categories as keys, and words that are included in such categories are the values (Example: {'name' : {'patrick', 'jane'}, 'discipline' : {'geography',...}, ...}).
At some point in the program (in that class) I have to create a method which takes a the name of a category as an argument. I then have to pick a random word out of that category. In the dictionary all keys(categories) need to be lowercase but when I give a category to choose a word from that shouldn't matter.
Here is my code first (part of it):
import random
class MadLibs:
def __init__(self, woordenschat = {}):
self.woordenschat = woordenschat
def suggereren(self, categorie):
assert categorie.lower() in self.woordenschat, 'onbekende categorie'
randwoord = random.choice(list(self.woordenschat[categorie.lower()]))
if categorie.isupper():
return randwoord.upper()
elif categorie.islower():
return randwoord
else:
return randwoord.capitalize()
so say I got a category 'name' as key in my dictionary with a sequence of words, when I then use the method suggereren and give as argument 'name' it works, but when I give 'NAME' then self.woordenschat[category.lower()] returns an empty list (see the line where I initialize randwoord )
Would somebody be able to tell me why this happens?
UPDATE:
this is how you add the words in the dictionary, categorie is where you give the category, and woorden is where you give new words that belong to that category
def leren(self, categorie, woorden):
if isinstance(woorden, (tuple, list, set)):
woorden = set(woorden)
else:
woorden = {woorden}
if categorie in self.woordenschat:
self.woordenschat[categorie.lower()].add(woord.lower() for woord in woorden)
else:
self.woordenschat[categorie.lower()] = (woord.lower() for woord in woorden)
return None
UPDATE:
seems like the way I added the words in leren was the problem an error something like: object 'generator' does not have ... 'add'
here's my new code:
def leren(self, categorie, woorden):
if isinstance(woorden, (tuple, list, set)):
woorden = set(woorden)
else:
woorden = {woorden}
set_to_add = {woord.lower() for woord in woorden}
if categorie in self.woordenschat:
self.woordenschat[categorie.lower()].union(set_to_add)
else:
self.woordenschat[categorie.lower()] = (set_to_add)
return None
now the only problem left is that my object doesn't really get updated when I add new words to an existing category I'll try to find it first but if I don't I'll just ask a new question.
update: nevermind found it, twas a stupid mistake
actually , in the requests sources code , there have a solution about the caselessdict object maybe satisfied you need.
import collections
class CaseInsensitiveDict(collections.MutableMapping):
def __init__(self, data=None, **kwargs):
self._store = dict()
if data is None:
data = {}
self.update(data, **kwargs)
def __setitem__(self, key, value):
# Use the lowercased key for lookups, but store the actual
# key alongside the value.
self._store[key.lower()] = (key, value)
def __getitem__(self, key):
return self._store[key.lower()][1]
def __delitem__(self, key):
del self._store[key.lower()]
def __iter__(self):
return (casedkey for casedkey, mappedvalue in self._store.values())
def __len__(self):
return len(self._store)
def lower_items(self):
"""Like iteritems(), but with all lowercase keys."""
return (
(lowerkey, keyval[1])
for (lowerkey, keyval)
in self._store.items()
)
def __eq__(self, other):
if isinstance(other, collections.Mapping):
other = CaseInsensitiveDict(other)
else:
return NotImplemented
# Compare insensitively
return dict(self.lower_items()) == dict(other.lower_items())
# Copy is required
def copy(self):
return CaseInsensitiveDict(self._store.values())
def __repr__(self):
return str(dict(self.items()))
#property
def keys(self):
return [i for i in self]
#property
def values(self):
return [self[i] for i in self]

Python XML dot name constructor

I have a Solace JMS Messaging Box which I am automating the administration of, and the device uses lots of very small XML posts to configure. Since the device has so very many commands in its XML spec, I need a way to create arbitrary XML requests.
The XML looks like:
<rpc semp-version="soltr/5_5">
<create>
<message-vpn>
<vpn-name>developer.testvpn</vpn-name>
</message-vpn>
</create>
</rpc>
And a second call to change a setting might look like this:
<rpc semp-version="soltr/5_5">
<message-vpn>
<vpn-name>developer.testvpn</vpn-name>
<export-policy>
<no>
<export-subscriptions/>
</no>
</export-policy>
</message-vpn>
</rpc>
Since there are many commands in the XML spec, I'm looking for a way to create them freely from something like dot name space. eg:
mycall = SolaceXML()
mycall.create.message_vpn.vpn_name="developer.testvpn"
mycall.message_vpn.vpn_name='developer.testvpn'
mycall.message_vpn.export_policy.no.export_subscription
UPDATE
I have posted my solution below. Its not as small as I'd like it but it works for me.
K
I have found a solution in the mean time. Hopefully this helps someone else. This solution builds nested dictionary objects from dot name space calls, and then converts it to XML.
from xml.dom.minidom import Document
import copy
import re
from collections import OrderedDict
class d2x:
''' Converts Dictionary to XML '''
def __init__(self, structure):
self.doc = Document()
if len(structure) == 1:
rootName = str(structure.keys()[0])
self.root = self.doc.createElement(rootName)
self.doc.appendChild(self.root)
self.build(self.root, structure[rootName])
def build(self, father, structure):
if type(structure) == dict:
for k in structure:
tag = self.doc.createElement(k)
father.appendChild(tag)
self.build(tag, structure[k])
elif type(structure) == OrderedDict:
for k in structure:
tag = self.doc.createElement(k)
father.appendChild(tag)
self.build(tag, structure[k])
elif type(structure) == list:
grandFather = father.parentNode
tagName = father.tagName
grandFather.removeChild(father)
for l in structure:
tag = self.doc.createElement(tagName)
self.build(tag, l)
grandFather.appendChild(tag)
else:
data = str(structure)
tag = self.doc.createTextNode(data)
father.appendChild(tag)
def display(self):
# I render from the root instead of doc to get rid of the XML header
#return self.root.toprettyxml(indent=" ")
return self.root.toxml()
class SolaceNode:
''' a sub dictionary builder '''
def __init__(self):
self.__dict__ = OrderedDict()
def __getattr__(self, name):
name = re.sub("_", "-", name)
try:
return self.__dict__[name]
except:
self.__dict__[name] = SolaceNode()
return self.__dict__[name]
def __str__(self):
return str(self.__dict__)
def __repr__(self):
return str(self.__dict__)
def __call__(self, *args, **kwargs):
return self.__dict__
def __setattr__(self, name, value):
name = re.sub("_", "-", name)
self.__dict__[name] = value
class SolaceXMLBuilder(object):
''' main dictionary builder
Any dot-name-space like calling of a instance of SolaceXMLBuilder will create
nested dictionary keys. These are converted to XML whenever the instance
representation is called ( __repr__ )
Example
a=SolaceXMLBuilder()
a.foo.bar.baz=2
str(a)
'<rpc semp-version="soltr/5_5">\n<foo><bar><baz>2</baz></bar></foo></rpc>'
'''
def __init__(self):
self.__dict__ = OrderedDict()
self.__setattr__ = None
def __getattr__(self, name):
name = re.sub("_", "-", name)
try:
return self.__dict__[name]
except:
self.__dict__[name] = SolaceNode()
return self.__dict__[name]
def __repr__(self):
# Show XML
myxml = d2x(eval(str(self.__dict__)))
# I had to conjur up my own header cause solace doesnt like </rpc> to have attribs
#return str('<rpc semp-version="soltr/5_5">\n%s</rpc>' % myxml.display())
return str('<rpc semp-version="soltr/5_5">\n%s</rpc>' % myxml.display())
def __call__(self, *args, **kwargs):
return self.__dict__
# def __setattr__(self, name, value):
# raise Exception('no you cant create assignments here, only on sub-elements')
if __name__ == '__main__':
x = SolaceXMLBuilder()
x.create.message_vpn.vpn_name='NEWVPN'
print(x)
# <?xml version="1.0" ?>
# <rpc semp-version="soltr/5_5">
# <create>
# <message-vpn>
# <vpn-name>
# NEWVPN
# </vpn-name>
# </message-vpn>
# </create>
# </rpc semp-version="soltr/5_5">
x=SolaceXMLBuilder()
x.message_vpn.vpn_name='NEWVPN'
x.message_vpn.no.feature_X
print(x)
# <?xml version="1.0" ?>
# <rpc semp-version="soltr/5_5">
# <message-vpn>
# <vpn-name>
# NEWVPN
# </vpn-name>
# <no>
# <feature-X/>
# </no>
# </message-vpn>
# </rpc semp-version="soltr/5_5">
# >>> client = SolaceAPI('pt1')
# >>> xml = SolaceXMLBuilder()
# >>> xml.create.message_vpn.vpn_name='NEWVPN'
# >>> client.rpc(str(xml))
# {u'rpc-reply': {u'execute-result': {u'#code': u'ok'}, u'#semp-version': u'soltr/5_5'}}

Categories