# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['pysdf']

package_data = \
{'': ['*']}

install_requires = \
['lxml>=4.8.0,<5.0.0', 'numpy>=1.0,<2.0']

setup_kwargs = {
    'name': 'python-sdformat',
    'version': '0.3.0',
    'description': 'Python Parser for SDFormat files.',
    'long_description': '# PySDF (python-sdformat)\n\nPySDF is a set of python bindings for [SDFormat XML](http://sdformat.org/). The\nidea is to provide a method for working with SDF that feels as fast as (or\nfaster than) XML, but with the added convenience of syntax highlighting,\nauto-completion, validation, and some degree of verification.\n\nThe current bindings read SDF from _any_ version and will parse it into a\ngeneric representation. Modifications are not validated or verified by default,\nallowing for more flexibility, but methods for optional validation and\nverification will be added in the future.\n\n## Installation\n\n```\npip install python-sdformat\n```\n\n## Usage\n\nThe elements of the binding are grouped following the [official SDF\nspec](http://sdformat.org/spec) with a few exceptions. This means that you can\nfind the item you are looking for by following the spec\'s nesting, e.g., the\n`/sensor/imu/angular_velocity/x` element has the corresponding class\n`pysdf.Sensor.Imu.AngularVelocity.X` and can - inside an SDF - be accessed as\n`parsed_sensor.imu.angular_velocity.x`. The previously mentioned exceptions to\nthis are:\n\n- The bindings use `snake_case` for variable names and `CamelCase` for class names\n- If an element may occur more than once inside its parent, its corresponding attribute\n  will be a tuple its name will be plural, e.g. `world.models[idx]`.\n- The elements `Pose`, `Frame`, `Plugin`, and `Include` occur frequently across\n  several elements and promoted to the top level, i.e., you\'d use `pysdf.Pose` not\n  `pysdf.Model.Pose`.\n\n## Examples\n\n**Basic Reading and Writing**\n\n```python\nfrom pysdf import SDF\n\nsample_sdf = """<?xml version="1.0" ?>\n<sdf version="1.6">\n    <model name="empty_axis">\n        <link name="link1" />\n        <link name="link2" />\n        <joint name="joint" type="fixed">\n        <parent>link1</parent>\n        <child>link2</child>\n        <axis/>\n        </joint>\n    </model>\n</sdf>\n"""\n\n# string round-trip\nparsed = SDF.from_xml(sample_sdf)\nsdf_string = parsed.to_xml()\n\n# file round-trip\nparsed.to_file("sample.sdf")\nparsed = SDF.from_file("sample.sdf")\n\n# prettify/reformat SDF to have nice indentation\nparsed = SDF.from_file("sample.sdf", remove_blank_text=True)\nparsed.to_file("sample.sdf", pretty_print=True)\n\n```\n\n**Building SDF manually**\n\n```python\nfrom pysdf import SDF, Link, Joint, Model\n\nreference_sdf = """\n<sdf version="1.6">\n    <model name="empty_axis">\n        <link name="link1" />\n        <link name="link2" />\n        <joint name="joint" type="fixed">\n            <parent>link1</parent>\n            <child>link2</child>\n        </joint>\n    </model>\n</sdf>\n"""\n\nelement = SDF(\n    Model(\n        Link(name="link1"),\n        Link(name="link2"),\n        Joint(\n            Joint.Parent(text="link1"),\n            Joint.Child(text="link2"),\n            # attributes are set at the end\n            # because python only accepts kwargs at the end.\n            name="joint",\n            type="fixed",\n        ),\n        name="empty_axis",\n    ),\n    version="1.6",\n)\n\nelement.to_file("sample.sdf", pretty_print=True)\n```\n\n**Basic Modifications**\n\n```python\nfrom pysdf import Link, State, Model, Link\n\n# Complex elements (with own children) are added on first read\nelement = Link()\nelement.to_xml()  # "<link/>"\nelement.inertial\nelement.to_xml()  # "<link><inertial/></link>"\n\n# Simple elements (basic types) are added on first write (__set__):\nelement.inertial.mass\nelement.to_xml()  # "<link><inertial/></link>"\nelement.inertial.mass = 5.0\nelement.to_xml() \n# "<link><inertial><mass>5.0</mass></inertial></link>"\n\n# default values are populated where applicable\nassert element.inertial.inertia.ixx == 1.0\n\n# Where possible types are converted automatically\nelement = State.Model()\nelement.scale  # (1.0, 1.0, 1.0), tuple\nelement.scale = "1 2 3"\nassert element.scale == (1.0, 2.0, 3.0)\nelement.scale = [5, 5, 5]\nassert element.scale == (5.0, 5.0, 5.0)\n\n# Inserting children works from sequences of kwargs\nelement = Model()\nelement.add(Link(name="test"))\nelement.add(Link(name="test2"), Link(name="test3"))\nelement.to_xml() \n# \'<model><link name="test"/><link name="test2"/><link name="test3"/><pose/></model>\'\n```\n\n**Full Modification Example**\n\n```python\nfrom pysdf import SDF, Link\n\nsample_sdf = """<?xml version="1.0" ?>\n<sdf version="1.6">\n    <model name="empty_axis">\n        <link name="link1" />\n        <link name="link2" />\n        <joint name="joint" type="fixed">\n            <parent>link1</parent>\n            <child>link2</child>\n        </joint>\n    </model>\n</sdf>\n"""\n\nparsed = SDF.from_xml(sample_sdf, remove_blank_text=True)\nmodel = parsed.model\n\nmodel.name = "modified_model"\nmodel.links[1].add(Link.ParticleEmitter(\n    Link.ParticleEmitter.Emitting(text="true"),\n    name="my_emitter",\n    type="box"\n))\n\nparsed.to_file("sample.sdf", pretty_print=True)\n```\n\n**Iterating and Filtering**\n\nYou can call `element.iter()` to recursively iterate over all child elements of\na subtree (breadth-first). `iter()` also accepts a `filter` kwarg which allows\nyou to only return children that have a desired path from the caller to the\nchild. The filter matches the tail of the path, path elements are separated by\nthe `/` character, and any SDF tag is a valid path element. This allows for easy\nselecting and bulk editing of specific children, e.g., use `filter="pose"` to\nselect all pose elements in a SDF or `filter="model/pose"` to select all pose\nelements that are direct children of a model (the model\'s pose).\n\n\nAppologies for the long example SDF, but I thought it would be nice to\ndemonstrate something more real-world.\n\n```python\nfrom pysdf import SDF\nimport numpy as np\n\n# taken from: \n# https://github.com/ignitionrobotics/sdformat/blob/sdf12/test/sdf/joint_nested_parent_child.sdf\nlarge_example = """\n<sdf version="1.8">\n  <model name="joint_nested_parent_child">\n    <model name="M1">\n      <link name="L1">\n        <pose>0 0 1 0 0 0</pose>\n      </link>\n      <link name="L2">\n        <pose>1 1 0 0 0 0</pose>\n      </link>\n      <frame name="F1">\n        <pose>1 0 0 0 0 0</pose>\n      </frame>\n      <model name="M2">\n        <pose>0 0 1 1.570796326790 0 0</pose>\n        <link name="L1"/>\n      </model>\n    </model>\n\n    <link name="L1">\n      <pose>0 0 10 0 1.57079632679 0</pose>\n    </link>\n\n    <frame name="F1" attached_to="M1::L1">\n      <pose>1 0 0 0 0 0</pose>\n    </frame>\n\n    <!-- Joint with a parent link in a nested model -->\n    <joint name="J1" type="fixed">\n      <pose>1 0 0 0 0 0</pose>\n      <parent>M1::L1</parent>\n      <child>L1</child>\n    </joint>\n    <!-- Joint with a sibling parent frame which is attached to a link in a nested model -->\n    <joint name="J2" type="fixed">\n      <pose>0 1 0 0 0 0</pose>\n      <parent>F1</parent>\n      <child>L1</child>\n    </joint>\n    <!-- Joint with a child link in a nested model -->\n    <joint name="J3" type="fixed">\n      <pose>0 0 1 0 0 0</pose>\n      <parent>L1</parent>\n      <child>M1::L2</child>\n    </joint>\n\n    <!-- Joint with a child frame in a nested model -->\n    <joint name="J4" type="fixed">\n      <pose>0 0 1 0 0 0</pose>\n      <parent>L1</parent>\n      <child>M1::F1</child>\n    </joint>\n\n    <!-- Joint with a child model in a nested model -->\n    <joint name="J5" type="fixed">\n      <pose>0 0 1 0 0 0</pose>\n      <parent>L1</parent>\n      <child>M1::M2</child>\n    </joint>\n\n    <!-- Joint with a nested model frame as a parent  -->\n    <joint name="J6" type="fixed">\n      <pose>0 0 1 0 0 0</pose>\n      <parent>M1::__model__</parent>\n      <child>L1</child>\n    </joint>\n\n    <!-- Joint with a nested model frame as a child  -->\n    <joint name="J7" type="fixed">\n      <pose>0 0 1 0 0 0</pose>\n      <parent>L1</parent>\n      <child>M1::__model__</child>\n    </joint>\n  </model>\n</sdf>\n"""\n\n# remove_blank_text strips whitespace to allow neat formatting\n# later on\nelement = SDF.from_xml(large_example, remove_blank_text=True)\nelement.version = "1.9"  # v1.9 supports pose/@degrees\n\n# convert all poses to degrees\nfor pose in element.iter("pose"):\n    pose.degrees = True\n    pose_ndarray = np.fromstring(pose.text, count=6, sep=" ")\n    rotation_rad = pose_ndarray[3:]\n    rotation_deg = rotation_rad / (2*np.pi) * 360\n    pose_ndarray[3:] = rotation_deg\n    pose.text = " ".join(map(str, pose_ndarray))\n\n# turn on self-collision for all links in the nested model\nfor link in element.iter("model/model/link"):\n    link.self_collide = True\n\n# turn self-collision off (using a different syntax)\nfor link in element.models[0].iter("link"):\n    link.self_collide = False\n\n# offset all links by some vector\nfor pose in element.iter("link/pose"):\n    pose_ndarray = np.fromstring(pose.text, count=6, sep=" ")\n    pose_ndarray[:3] += (0, 0, 1)\n    pose.text = " ".join(map(str, pose_ndarray))\n\nelement.to_file("sample.sdf", pretty_print=True)\n```\n',
    'author': 'FirefoxMetzger',
    'author_email': 'sebastian@wallkoetter.net',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/FirefoxMetzger/python-sdformat',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
