pysxm


Namepysxm JSON
Version 1.5.0 PyPI version JSON
download
home_page
SummarySimple and extensible xml python marshaller
upload_time2024-01-26 17:37:02
maintainer
docs_urlNone
authorJosue Kouka
requires_python>2.7
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Simple XML Python Marshaller
============================

.. image:: https://travis-ci.org/josuebrunel/pysxm.svg?branch=master
    :target: https://travis-ci.org/josuebrunel/pysxm
.. image:: https://coveralls.io/repos/github/josuebrunel/pysxm/badge.svg?branch=master
    :target: https://coveralls.io/github/josuebrunel/pysxm?branch=master
.. image:: http://pepy.tech/badge/pysxm
    :target: http://pepy.tech/count/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
------------

.. code:: python

    pip install pysxm


Quickstart
----------

.. code:: python

    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.

.. code:: python

    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.

.. code:: python

    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.

.. code:: python

    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.

.. code:: python

    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

.. code:: python

    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.

.. code:: python

    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:

.. code:: python

    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**:

.. code:: python

    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:


.. code:: python

    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:

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "pysxm",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">2.7",
    "maintainer_email": "",
    "keywords": "",
    "author": "Josue Kouka",
    "author_email": "josuebrunel@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/3b/6f/7ec680a2cef12c9da11912e2e04f5c5d8fa3d9bcc436a157ecc48c027cff/pysxm-1.5.0.tar.gz",
    "platform": null,
    "description": "Simple XML Python Marshaller\n============================\n\n.. image:: https://travis-ci.org/josuebrunel/pysxm.svg?branch=master\n    :target: https://travis-ci.org/josuebrunel/pysxm\n.. image:: https://coveralls.io/repos/github/josuebrunel/pysxm/badge.svg?branch=master\n    :target: https://coveralls.io/github/josuebrunel/pysxm?branch=master\n.. image:: http://pepy.tech/badge/pysxm\n    :target: http://pepy.tech/count/pysxm\n\n\n**pysxm** is a simple and extensible xml python marshaller.\nIt comes with two simple and basic types:\n\n- SimpleType\n- ComplexType\n\nIt supports py2 and py3 and uses *lxml.objectify* under the hood.\n\n\nInstallation\n------------\n\n.. code:: python\n\n    pip install pysxm\n\n\nQuickstart\n----------\n\n.. code:: python\n\n    In [1]: from pysxm import ComplexType\n    In [2]: class Person(ComplexType):\n    ...:     attrib = {'description': 'a random person'}\n    ...:     def __init__(self, fname, lname):\n    ...:         self.fname = fname\n    ...:         self.lname = lname\n    ...:\n    In [3]: person = Person('token', 'black')\n    In [4]: print(person)\n    <person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" description=\"a random person\">\n        <lname>black</lname>\n        <fname>token</fname>\n    </person>\n\nLet's say, we want a different **tag** for our object.\nAn attribute **tagname** or **_tagname** can be set to define the **xml tag name** of the object.\n\n.. code:: python\n\n    In [5]: class Person(ComplexType):\n    ...:     attrib = {'description': 'a random person'}\n    ...:     tagname = 'student'\n    ...:     def __init__(self, fname, lname):\n    ...:         self.fname = fname\n    ...:         self.lname = lname\n    ...:\n    In [6]: person = Person('token', 'black')\n    In [7]: print(person)\n    <student xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" description=\"a random person\">\n        <lname>black</lname>\n        <fname>token</fname>\n    </student>\n\nA **sequence** or **_sequence** (tuple or list) attribute can be set to decide of the **order** or the **presence** of an subelement in the xml.\n\n.. code:: python\n\n    In [8]: class Person(ComplexType):\n    ...:     attrib = {'description': 'a random person'}\n    ...:     tagname = 'student'\n    ...:     _sequence = ('city', 'fname')\n    ...:\n    ...:     def __init__(self, fname, lname, city):\n    ...:         self.fname = fname\n    ...:         self.lname = lname\n    ...:         self.city = city\n    ...:\n    In [9]: person = Person('token', 'black', 'south park')\n    In [10]: print(person)\n    <student xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" description=\"a random person\">\n        <city>south park</city>\n        <fname>token</fname>\n    </student>\n\nLet's add a **namespace** to our object.\n\n.. code:: python\n\n    In [11]: class Person(ComplexType):\n    ...:     attrib = {'description': 'a random south park character'}\n    ...:     nsmap = {'sp': 'http://southpark/xml/'}\n    ...:\n    ...:     def __init__(self, fname, lname, city):\n    ...:         self.fname = fname\n    ...:         self.lname = lname\n    ...:         self.city = city\n    ...:\n    In [12]: person = Person('token', 'black', 'south park')\n    In [13]: print(person)\n    <sp:person xmlns:sp=\"http://southpark/xml/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" description=\"a random south park character\">\n        <sp:lname>black</sp:lname>\n        <sp:city>south park</sp:city>\n        <sp:fname>token</sp:fname>\n    </sp:person>\n\nLet's make sure that a *person*'s group is either *coon* or *goth*.\nTo do so, we can inherit from **SimpleType** object and define a restriction by overriding **check_restriction(self, value)** method.\n\n.. code:: python\n\n    In [7]: from pysxm import ComplexType, SimpleType\n    In [8]: class Group(SimpleType):\n    ...:     allowed_groups = ('coon', 'goth')\n    ...:     def check_restriction(self, value):\n    ...:         if value not in self.allowed_groups:\n    ...:             raise ValueError('<%s> value %s not in %s' % (self.tagname, value, self.allowed_groups))\n    ...:\n    In [9]: class Person(ComplexType):\n    ...:     def __init__(self, fname, lname, group):\n    ...:         self.fname = fname\n    ...:         self.lname = lname\n    ...:         self.group = Group(group)\n    ...:\n    In [10]: Person('token', 'black', 'boys')\n    ...\n    <ipython-input-8-116b49042116> in check_restriction(self, value)\n    3     def check_restriction(self, value):\n    4         if value not in self.allowed_groups:\n    ----> 5             raise ValueError('<%s> value %s not in %s' % (self.tagname, value, self.allowed_groups))\n    6\n    ValueError: <group> value boys not in ('coon', 'goth')\n\n    In [11]: print(Person('token', 'black', 'goth'))\n    <person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n        <lname>black</lname>\n        <group>goth</group>\n        <fname>token</fname>\n    </person>\n\n**Note**: *ComplexType* can have *ComplexType* and *SimpleType* as attribute\n\n.. code:: python\n\n    from pysxm import ComplexType, SimpleType\n\n\n    class AdultAge(SimpleType):\n\n        tagname = 'age'\n        attrib = {'minvalue': '18', 'maxvalue': '100'}\n\n        def check_restriction(self, value):\n            if int(value) < 18:\n                raise ValueError(\"<%s> '%d' < 18\" % (self.tagname, value))\n\n\n    class Credentials(ComplexType):\n\n        def __init__(self, login, password):\n            self.login = login\n            self.password = password\n\n\n    class Person(ComplexType):\n\n        def __init__(self, fname, lname, credentials, age):\n            self.fname = fname\n            self.lname = lname\n            self.credentials = Credentials(credentials['login'], credentials['password'])\n            self.age = AdultAge(age)\n\n    In [3]: data = {\n    ...:     'fname': 'token', 'lname': 'black',\n    ...:     'credentials': {'login': 't0ken', 'password': 'l33tolite'},\n    ...:     'age': '30'}\n    In [4]: person = Person(**data)\n    In [5]: print(person)\n    <person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n        <lname>black</lname>\n        <credentials>\n            <login>t0ken</login>\n            <password>l33tolite</password>\n        </credentials>\n        <age maxvalue=\"100\" minvalue=\"18\">30</age>\n        <fname>token</fname>\n    </person>\n    In [6]: person.save('token.xml')\n\nThe **save** method (*object.save(<filename>)*) allows you to save the xml result into a file.\n\n.. code:: python\n\n    In [7]: cat token.xml\n    <person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n        <lname>black</lname>\n        <credentials>\n            <login>t0ken</login>\n            <password>l33tolite</password>\n        </credentials>\n        <age maxvalue=\"100\" minvalue=\"18\">30</age>\n        <fname>token</fname>\n    </person>\n\n\nThe ext module\n^^^^^^^^^^^^^^\n\nPysxm comes with a couple of extended types. Those types are defined in *pysxm.ext* module.\n\nDataComplexType\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nThis is a simple *DataClass* of *ComplexType*. Here is how you can set one up:\n\n.. code:: python\n\n    from pysxm.ext import DataComplexType, XSimpleType\n\n\n    class Game(DataComplexType):\n         platform = XSimpleType('platform', ['xboxone', 'xboxx'], lambda v, av: v in av)\n\n    >>> game = Game(name='state of decay 2', editor='undead labs', platform='xboxone')\n    >>> print(game)\n    <game>\n        <name>state of decay 2</name>\n        <platform>xboxone</platform>\n        <editor>undead labs</editor>\n    </game>\n\nXSimpleType\n\"\"\"\"\"\"\"\"\"\"\"\n\nIt gets tiresome to subclass a *SimpleType* everytime you want to check a value. To overcome that, **pysxm** provides a **descriptor** called **XSimpleType**:\n\n.. code:: python\n\n    class XSimpleType(object):\n\n      def __init__(name=None, restriction=None, checker=None, error_msg=None, **kwargs):\n        '''name: it's the name of the attribute.\n        restriction: self explanatory\n        checker: the fucntion that checks the input value\n        error_msg: message returned when checking fails\n        kwargs: as tagname, attrib or nsmap\n        '''\n\nHere is an example:\n\n\n.. code:: python\n\n    class XboxGamer(ComplexType):\n        platform = XSimpleType('platform', ('xone', 'xbox360', 'xbox'), lambda v, av: v in av)\n        score = XSimpleType('score', (4000, 1000000), lambda v, av: int(av[0]) <= int(v) < int(av[1]))\n        lastlogin = XDateTimeType('lastlogin')\n\n        def __init__(self, gamertag, platform, score, lastlogin):\n            self.gamertag = gamertag\n            self.platform = platform\n            self.score = score\n            self.lastlogin = lastlogin\n\n    In [1]: print(gamer_data)\n    {'gamertag': 'LokingHD', 'platform': 'ps4', 'score': '22526', 'lastlogin': '2018-03-21'}\n    In [2]: XboxGamer(**gamer_data)\n    ---------------------------------------------------------------------------\n    ValueError                                Traceback (most recent call last)\n    <ipython-input-2-61f95466da46> in <module>()\n    ----> 1 XboxGamer(**gamer_data)\n    /home/josue/workspace/dev/pysxdb/pysxm/ext.pyc in check(self, instance, value)\n    77         if not self.checker(value, self.restriction_values):\n    78             raise ValueError('tagname <%s> value %s is invalid: expected (%s)'\n    ---> 79                              % (instance.tagname, value, self.restriction_values))\n        80\n    81     def check_restriction(self, instance, value):\n    ValueError: tagname <xboxgamer> value ps4 is invalid: expected (('xone', 'xbox360', 'xbox'))\n    In [3]: gamer_data['platform'] = 'xone'\n    In [4]: gamer = XboxGamer(**gamer_data)\n    In [5]: print(gamer)\n    <xboxgamer xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n        <gamertag>LokingHD</gamertag>\n        <platform>xone</platform>\n        <score>22526</score>\n        <lastlogin>2018-03-21T00:00:00</lastlogin>\n    </xboxgamer>\n\n\nMost of the types defined in *pysxm.ext* are descriptors and they're subclassable.\n\n\nVoila :wink:\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Simple and extensible xml python marshaller",
    "version": "1.5.0",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8f6f5c5059902b8b292eaef291cf3429065b01da005088f6811bef1f56e6a526",
                "md5": "366c2b13c6b459511d42709865dec204",
                "sha256": "826732fc9ed9faea4aa720fa0d4241c0bc5271cc48cdb8db2bc4b05376b5c327"
            },
            "downloads": -1,
            "filename": "pysxm-1.5.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "366c2b13c6b459511d42709865dec204",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">2.7",
            "size": 8362,
            "upload_time": "2024-01-26T17:37:00",
            "upload_time_iso_8601": "2024-01-26T17:37:00.531877Z",
            "url": "https://files.pythonhosted.org/packages/8f/6f/5c5059902b8b292eaef291cf3429065b01da005088f6811bef1f56e6a526/pysxm-1.5.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "3b6f7ec680a2cef12c9da11912e2e04f5c5d8fa3d9bcc436a157ecc48c027cff",
                "md5": "5ee745d9f2597c7c7d2256e6785fdb72",
                "sha256": "98c2e0f3a644d5dfd60d4829dcaf224bdebed6e1507c9427f794d689c2e9cd2a"
            },
            "downloads": -1,
            "filename": "pysxm-1.5.0.tar.gz",
            "has_sig": false,
            "md5_digest": "5ee745d9f2597c7c7d2256e6785fdb72",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">2.7",
            "size": 6280,
            "upload_time": "2024-01-26T17:37:02",
            "upload_time_iso_8601": "2024-01-26T17:37:02.032378Z",
            "url": "https://files.pythonhosted.org/packages/3b/6f/7ec680a2cef12c9da11912e2e04f5c5d8fa3d9bcc436a157ecc48c027cff/pysxm-1.5.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-26 17:37:02",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "pysxm"
}
        
Elapsed time: 0.21713s