Skip to main content

A decorator for generating xsd, xml and parsers from dataclasses

Project description

XMLable

An easy xml/xsd generator and parser for python dataclasses!

@xmlify
@dataclass
class Config:
    date: str
    number_of_cores: int
    codes: list[int]
    show_logs: bool


write_xsd(THIS_DIR / "config.xsd", Config)
write_xml_template(THIS_DIR / "config_xml_template.xml", Config)

original = Config(
    date="31/02/2023",
    number_of_cores=48,
    codes=[101, 345, 42, 67],
    show_logs=False,
)
write_xml_value(THIS_DIR / "config_xml_example.xml", original)

read_config: Config = parse_file(Config, THIS_DIR / "config_xml_example.xml")

assert read_config == original

See more in examples

Capabilities

Types

Currently supports the types:

int, float, str, dict, tuple, set, list, None
# as well as unions!
int | float | None

And dataclasses that have been @xmlify-ed.

These can be combined for types such as:

@xmlify
@dataclass
class Complex:
    a: dict[tuple[int, str], list[tuple[dict[int, float | str], set[bool]]]]

c1 = Complex(
    a={(3, "hello"): [({3: 0.4}, {True, False}), ({2: "str"}, {False})]}
)

Custom Classes

The xmlify interface can be implemented by adding methods described in xmlify Once the class is_xmlified it can be used just as if generated by @xmlify

from xmlable._xobject import XObject
from xmlable._user import IXmlify
from xmlable._manual import manual_xmlify

@manual_xmlify
class MyClass(IXmlify):
    def get_xobject() -> XObject:
        class XMyClass(XObject):
            def xsd_out(self, name: str, attribs: dict[str, str] = {}, add_ns: dict[str, str] = {}) -> _Element:
                pass

            def xml_temp(self, name: str) -> _Element:
                pass

            def xml_out(self, name: str, val: Any, ctx: XErrorCtx) -> _Element:
                pass

            def xml_in(self, obj: ObjectifiedElement, ctx: XErrorCtx) -> Any:
                pass

        return XMyClass() # must be an instance of XMyClass, not the class

    def xsd_forward(add_ns: dict[str, str]) -> _Element:
        pass

    def xsd_dependencies() -> set[type]:
        return {MyClass}

See the user define example for implementation.

Limitations

Unions of Generic Types

Generating xsd works, parsing works, however generating an xml template can fail if they type is not determinable at runtime.

  • Values do not have type arguments carried with them
  • Many types are indistinguishable in python

For example:

@xmlify
@dataclass
class GenericUnion:
    u: dict[int, float] | dict[int, str]

GenericUnion(u={}) # which variant in the xml should {} have??named_

In this case an error is raised

To Develop

git clone # this project

# Can use hatch to build, run
hatch run check:test      # run tests/
hatch run check:lint      # check formatting
hatch run check:typecheck # mypy for src/ and all examples

hatch run auto:examplegen # regenerate the example code
hatch run auto:lint       # format code

# Alternatively can just create a normal env
python3.11 -m venv .venv
source .venv/bin/activate # activate virtual environment

pip install -e .      # install this project in the venv
pip install -e .[dev] # install optional dev dependencies (mypy, black and pytest)

black . # to reformat
mypy    # type check
pytest  # to run tests

Hatch is used for build, test and pypi publish.

To Improve

Fuzzing

(As a fun weekend project) generate arbitrary python data types with values, and dataclasses. Then @xmlify all and validate as in the current tests

Etree vs Objectify

Currently using objectify for parsing and etree for construction, I want to move parsing to use etree

  • previously used objectify for quick prototype.

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

xmlable-2.0.4.tar.gz (21.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xmlable-2.0.4-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

File details

Details for the file xmlable-2.0.4.tar.gz.

File metadata

  • Download URL: xmlable-2.0.4.tar.gz
  • Upload date:
  • Size: 21.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for xmlable-2.0.4.tar.gz
Algorithm Hash digest
SHA256 bb6917e185b1e38d3b0785a5ecca31132817dc1d357c037f9b63de7498370c48
MD5 bb1059625ebfcdb27dcb2abe12fd95e0
BLAKE2b-256 8f55caeea930621cf5f2120c1add89bc3b2ed09582a3fd6fb5f868b876345029

See more details on using hashes here.

File details

Details for the file xmlable-2.0.4-py3-none-any.whl.

File metadata

  • Download URL: xmlable-2.0.4-py3-none-any.whl
  • Upload date:
  • Size: 18.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for xmlable-2.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 295b290ad8611251d8bd4fa08de1a636fd6aaf7b82ff9aca998d5ec9d6c89f3a
MD5 d836fda77c16ba208f489e40f23e97c3
BLAKE2b-256 8c0a8ac6c37bed43bf16a26ec2efd738064e04e99e5770bde566d4c67bb0f9f6

See more details on using hashes here.

Supported by

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