Simple and extensible xml python marshaller
Project description
pysxm is a simple and extensible xml python marshaller. It comes with two simple and basic types:
SimpleType
ComplexType
It supports py2 and py3 and uses lxml.objectify under the hood.
Installation
pip install pysxm
Quickstart
In [1]: from pysxm import ComplexType
In [2]: class Person(ComplexType):
...: attrib = {'description': 'a random person'}
...: def __init__(self, fname, lname):
...: self.fname = fname
...: self.lname = lname
...:
In [3]: person = Person('token', 'black')
In [4]: print(person)
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" description="a random person">
<lname>black</lname>
<fname>token</fname>
</person>
Let’s say, we want a different tag for our object. An attribute tagname or _tagname can be set to define the xml tag name of the object.
In [5]: class Person(ComplexType):
...: attrib = {'description': 'a random person'}
...: tagname = 'student'
...: def __init__(self, fname, lname):
...: self.fname = fname
...: self.lname = lname
...:
In [6]: person = Person('token', 'black')
In [7]: print(person)
<student xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" description="a random person">
<lname>black</lname>
<fname>token</fname>
</student>
A sequence or _sequence (tuple or list) attribute can be set to decide of the order or the presence of an subelement in the xml.
In [8]: class Person(ComplexType):
...: attrib = {'description': 'a random person'}
...: tagname = 'student'
...: _sequence = ('city', 'fname')
...:
...: def __init__(self, fname, lname, city):
...: self.fname = fname
...: self.lname = lname
...: self.city = city
...:
In [9]: person = Person('token', 'black', 'south park')
In [10]: print(person)
<student xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" description="a random person">
<city>south park</city>
<fname>token</fname>
</student>
Let’s add a namespace to our object.
In [11]: class Person(ComplexType):
...: attrib = {'description': 'a random south park character'}
...: nsmap = {'sp': 'http://southpark/xml/'}
...:
...: def __init__(self, fname, lname, city):
...: self.fname = fname
...: self.lname = lname
...: self.city = city
...:
In [12]: person = Person('token', 'black', 'south park')
In [13]: print(person)
<sp:person xmlns:sp="http://southpark/xml/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" description="a random south park character">
<sp:lname>black</sp:lname>
<sp:city>south park</sp:city>
<sp:fname>token</sp:fname>
</sp:person>
Let’s make sure that a person’s group is either coon or goth. To do so, we can inherit from SimpleType object and define a restriction by overriding check_restriction(self, value) method.
In [7]: from pysxm import ComplexType, SimpleType
In [8]: class Group(SimpleType):
...: allowed_groups = ('coon', 'goth')
...: def check_restriction(self, value):
...: if value not in self.allowed_groups:
...: raise ValueError('<%s> value %s not in %s' % (self.tagname, value, self.allowed_groups))
...:
In [9]: class Person(ComplexType):
...: def __init__(self, fname, lname, group):
...: self.fname = fname
...: self.lname = lname
...: self.group = Group(group)
...:
In [10]: Person('token', 'black', 'boys')
...
<ipython-input-8-116b49042116> in check_restriction(self, value)
3 def check_restriction(self, value):
4 if value not in self.allowed_groups:
----> 5 raise ValueError('<%s> value %s not in %s' % (self.tagname, value, self.allowed_groups))
6
ValueError: <group> value boys not in ('coon', 'goth')
In [11]: print(Person('token', 'black', 'goth'))
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<lname>black</lname>
<group>goth</group>
<fname>token</fname>
</person>
Note: ComplexType can have ComplexType and SimpleType as attribute
from pysxm import ComplexType, SimpleType
class AdultAge(SimpleType):
tagname = 'age'
attrib = {'minvalue': '18', 'maxvalue': '100'}
def check_restriction(self, value):
if int(value) < 18:
raise ValueError("<%s> '%d' < 18" % (self.tagname, value))
class Credentials(ComplexType):
def __init__(self, login, password):
self.login = login
self.password = password
class Person(ComplexType):
def __init__(self, fname, lname, credentials, age):
self.fname = fname
self.lname = lname
self.credentials = Credentials(credentials['login'], credentials['password'])
self.age = AdultAge(age)
In [3]: data = {
...: 'fname': 'token', 'lname': 'black',
...: 'credentials': {'login': 't0ken', 'password': 'l33tolite'},
...: 'age': '30'}
In [4]: person = Person(**data)
In [5]: print(person)
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<lname>black</lname>
<credentials>
<login>t0ken</login>
<password>l33tolite</password>
</credentials>
<age maxvalue="100" minvalue="18">30</age>
<fname>token</fname>
</person>
In [6]: person.save('token.xml')
The save method (object.save(<filename>)) allows you to save the xml result into a file.
In [7]: cat token.xml
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<lname>black</lname>
<credentials>
<login>t0ken</login>
<password>l33tolite</password>
</credentials>
<age maxvalue="100" minvalue="18">30</age>
<fname>token</fname>
</person>
The ext module
Pysxm comes with a couple of extended types. Those types are defined in pysxm.ext module.
DataComplexType
This is a simple DataClass of ComplexType. Here is how you can set one up:
from pysxm.ext import DataComplexType, XSimpleType
class Game(DataComplexType):
platform = XSimpleType('platform', ['xboxone', 'xboxx'], lambda v, av: v in av)
>>> game = Game(name='state of decay 2', editor='undead labs', platform='xboxone')
>>> print(game)
<game>
<name>state of decay 2</name>
<platform>xboxone</platform>
<editor>undead labs</editor>
</game>
XSimpleType
It gets tiresome to subclass a SimpleType everytime you want to check a value. To overcome that, pysxm provides a descriptor called XSimpleType:
class XSimpleType(object):
def __init__(name=None, restriction=None, checker=None, error_msg=None, **kwargs):
'''name: it's the name of the attribute.
restriction: self explanatory
checker: the fucntion that checks the input value
error_msg: message returned when checking fails
kwargs: as tagname, attrib or nsmap
'''
Here is an example:
class XboxGamer(ComplexType):
platform = XSimpleType('platform', ('xone', 'xbox360', 'xbox'), lambda v, av: v in av)
score = XSimpleType('score', (4000, 1000000), lambda v, av: int(av[0]) <= int(v) < int(av[1]))
lastlogin = XDateTimeType('lastlogin')
def __init__(self, gamertag, platform, score, lastlogin):
self.gamertag = gamertag
self.platform = platform
self.score = score
self.lastlogin = lastlogin
In [1]: print(gamer_data)
{'gamertag': 'LokingHD', 'platform': 'ps4', 'score': '22526', 'lastlogin': '2018-03-21'}
In [2]: XboxGamer(**gamer_data)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-2-61f95466da46> in <module>()
----> 1 XboxGamer(**gamer_data)
/home/josue/workspace/dev/pysxdb/pysxm/ext.pyc in check(self, instance, value)
77 if not self.checker(value, self.restriction_values):
78 raise ValueError('tagname <%s> value %s is invalid: expected (%s)'
---> 79 % (instance.tagname, value, self.restriction_values))
80
81 def check_restriction(self, instance, value):
ValueError: tagname <xboxgamer> value ps4 is invalid: expected (('xone', 'xbox360', 'xbox'))
In [3]: gamer_data['platform'] = 'xone'
In [4]: gamer = XboxGamer(**gamer_data)
In [5]: print(gamer)
<xboxgamer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<gamertag>LokingHD</gamertag>
<platform>xone</platform>
<score>22526</score>
<lastlogin>2018-03-21T00:00:00</lastlogin>
</xboxgamer>
Most of the types defined in pysxm.ext are descriptors and they’re subclassable.
Voila :wink:
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pysxm-1.5.0.tar.gz
.
File metadata
- Download URL: pysxm-1.5.0.tar.gz
- Upload date:
- Size: 6.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.10.12 Linux/6.5.0-15-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 98c2e0f3a644d5dfd60d4829dcaf224bdebed6e1507c9427f794d689c2e9cd2a |
|
MD5 | 5ee745d9f2597c7c7d2256e6785fdb72 |
|
BLAKE2b-256 | 3b6f7ec680a2cef12c9da11912e2e04f5c5d8fa3d9bcc436a157ecc48c027cff |
File details
Details for the file pysxm-1.5.0-py2.py3-none-any.whl
.
File metadata
- Download URL: pysxm-1.5.0-py2.py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.10.12 Linux/6.5.0-15-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 826732fc9ed9faea4aa720fa0d4241c0bc5271cc48cdb8db2bc4b05376b5c327 |
|
MD5 | 366c2b13c6b459511d42709865dec204 |
|
BLAKE2b-256 | 8f6f5c5059902b8b292eaef291cf3429065b01da005088f6811bef1f56e6a526 |