Skip to main content

Simple and extensible xml python marshaller

Project description

https://travis-ci.org/josuebrunel/pysxm.svg?branch=master https://coveralls.io/repos/github/josuebrunel/pysxm/badge.svg?branch=master http://pepy.tech/badge/pysxm

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pysxm-1.5.0.tar.gz (6.3 kB view details)

Uploaded Source

Built Distribution

pysxm-1.5.0-py2.py3-none-any.whl (8.4 kB view details)

Uploaded Python 2 Python 3

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

Hashes for pysxm-1.5.0.tar.gz
Algorithm Hash digest
SHA256 98c2e0f3a644d5dfd60d4829dcaf224bdebed6e1507c9427f794d689c2e9cd2a
MD5 5ee745d9f2597c7c7d2256e6785fdb72
BLAKE2b-256 3b6f7ec680a2cef12c9da11912e2e04f5c5d8fa3d9bcc436a157ecc48c027cff

See more details on using hashes here.

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

Hashes for pysxm-1.5.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 826732fc9ed9faea4aa720fa0d4241c0bc5271cc48cdb8db2bc4b05376b5c327
MD5 366c2b13c6b459511d42709865dec204
BLAKE2b-256 8f6f5c5059902b8b292eaef291cf3429065b01da005088f6811bef1f56e6a526

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page