Skip to content

Commit

Permalink
docs: about writing custom objects
Browse files Browse the repository at this point in the history
  • Loading branch information
lonvia committed Sep 29, 2024
1 parent a9157c4 commit de71e7e
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 20 deletions.
7 changes: 7 additions & 0 deletions docs/reference/Dataclasses.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ valid.

::: osmium.osm.Box
::: osmium.osm.Location

## Mutable OSM objects

::: osmium.osm.mutable.OSMObject
::: osmium.osm.mutable.Node
::: osmium.osm.mutable.Way
::: osmium.osm.mutable.Relation
53 changes: 53 additions & 0 deletions docs/user_manual/06-Writing-Data.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,59 @@ You can also write data that is not based on OSM input data at all. The write
functions will accept any Python object that mimics the attributes of a
node, way or relation.

Here is a simple example that writes out four random points:

!!! example
``` python
from random import uniform

class RandomNode:
def __init__(self, name, id):
self.id = id
self.location = (uniform(-180, 180), uniform(-90, 90))
self.tags = {'name': name}

with osmium.SimpleWriter('points.opl') as writer:
for i in range(4):
writer.add_node(RandomNode(f"Random {i}", i))
```

The following table gives an overview over the recognised attributes and
acceptable types. If an attribute is missing, then pyosmium will choose a
suitable default or leave the attribute out completely from the output if
that is possible.

| attribute | types |
|-----------|----------------------------|
| id | `int` |
| version | `int` (positive non-zero value) |
| visible | `bool` |
| changeset | `int` (positive non-zero value) |
| timestamp | `str` or `datetime` (will be translated to UTC first) |
| uid | `int` |
| tags | [osmium.osm.TagList][], a dict-like object or a list of tuples, where each tuple contains a (key, value) string pair |
| user | `str` |
| location | _(node only)_ [osmium.osm.Location][] or a tuple of lon/lat coordinates |
| nodes | _(way only)_ [osmium.osm.NodeRefList][] or a list consisting of either [osmium.osm.NodeRef][]s or simple node ids |
| members | _(relation only)_ [osmium.osm.RelationMemberList][] or a list consisting of either [osmium.osm.RelationMember][]s or tuples of `(type, id, role)`. The member type must be a single character 'n', 'w' or 'r'. |

The `osmium.osm.mutable` module offers pure Python-object versions of `Node`,
`Way` and `Relation` to make the creation of custom objects easier. Any of
the allowable attributes may be set in the constructor. This makes the
example for writing random points a bit shorter:

!!! example
``` python
from random import uniform

with osmium.SimpleWriter('points.opl') as writer:
for i in range(4):
writer.add_node(osmium.osm.mutable.Node(
id=i, location = (uniform(-180, 180), uniform(-90, 90)),
tags={'name': f"Random {i}"}))
```


## Writer types

pyosmium implements three different writer classes: the basic
Expand Down
51 changes: 31 additions & 20 deletions src/osmium/osm/mutable.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,23 @@
Sequence[Union[osmium.osm.RelationMember, Tuple[str, int, str]]]]

class OSMObject:
"""Mutable version of ``osmium.osm.OSMObject``. It exposes the following
attributes ``id``, ``version``, ``visible``, ``changeset``, ``timestamp``,
``uid`` and ``tags``. Timestamps may be strings or datetime objects.
Tags can be an osmium.osm.TagList, a dict-like object
or a list of tuples, where each tuple contains a (key value) string pair.
If the ``base`` parameter is given in the constructor, then the object
will be initialised first from the attributes of this base object.
""" Mutable version of [osmium.osm.OSMObject][].
"""

def __init__(self, base: Optional['OSMObjectLike'] = None,
id: Optional[int] = None, version: Optional[int] = None,
visible: Optional[bool] = None, changeset: Optional[int] = None,
timestamp: Optional[datetime] = None, uid: Optional[int] = None,
tags: Optional['TagSequence'] = None, user: Optional[str] = None) -> None:
""" Initialise an object with the following optional
attributes: `id`, `version`, `visible`, `changeset`, `timestamp`,
`uid` and `tags`. Timestamps may be strings or datetime objects.
Tags can be an osmium.osm.TagList, a dict-like object
or a list of tuples, where each tuple contains a (key value) string pair.
If the `base` parameter is given in the constructor, then the object
will be initialised first from the attributes of this base object.
"""
if base is None:
self.id = id
self.version = version
Expand All @@ -55,14 +57,18 @@ def __init__(self, base: Optional['OSMObjectLike'] = None,


class Node(OSMObject):
"""The mutable version of ``osmium.osm.Node``. It inherits all attributes
from osmium.osm.mutable.OSMObject and adds a `location` attribute. This
may either be an `osmium.osm.Location` or a tuple of lon/lat coordinates.
""" The mutable version of [osmium.osm.Node][].
"""

def __init__(self, base: Optional[Union['Node', 'osmium.osm.Node']] = None,
location: Optional['LocationLike'] = None,
**attrs: Any) -> None:
""" Initialise a node with all optional attributes
from osmium.osm.mutable.OSMObject as well as a `location` attribute.
This may either be an [osmium.osm.Location][] or a tuple of
lon/lat coordinates.
"""
OSMObject.__init__(self, base=base, **attrs)
if base is None:
self.location = location
Expand All @@ -71,30 +77,35 @@ def __init__(self, base: Optional[Union['Node', 'osmium.osm.Node']] = None,


class Way(OSMObject):
"""The mutable version of ``osmium.osm.Way``. It inherits all attributes
from osmium.osm.mutable.OSMObject and adds a `nodes` attribute. This may
either be and ``osmium.osm.NodeList`` or a list consisting of
``osmium.osm.NodeRef`` or simple node ids.
""" The mutable version of [osmium.osm.Way][].
"""

def __init__(self, base: Optional[Union['Way', 'osmium.osm.Way']] = None,
nodes: Optional['NodeSequence'] = None, **attrs: Any) -> None:
""" Initialise a way with all optional attributes
from osmium.osm.mutable.OSMObject as well as a `nodes` attribute.
This may either be an [osmium.osm.NodeRefList][] or a list
consisting of [osmium.osm.NodeRef][] or simple node ids.
"""
OSMObject.__init__(self, base=base, **attrs)
if base is None:
self.nodes = nodes
else:
self.nodes = nodes if nodes is not None else base.nodes

class Relation(OSMObject):
"""The mutable version of ``osmium.osm.Relation``. It inherits all attributes
from osmium.osm.mutable.OSMObject and adds a `members` attribute. This
may either be an ``osmium.osm.RelationMemberList`` or a list consisting
of ``osmium.osm.RelationMember`` or tuples of (type, id, role). The
member type should be a single character 'n', 'w' or 'r'.
""" The mutable version of [osmium.osm.Relation][].
"""

def __init__(self, base: Optional[Union['Relation', 'osmium.osm.Relation']] = None,
members: Optional['MemberSequence'] = None, **attrs: Any) -> None:
""" Initialise a relation with all optional attributes
from osmium.osm.mutable.OSMObject as well as a `members` attribute.
This may either be an [osmium.osm.RelationMemberList][] or
a list consisting of [osmium.osm.RelationMember][] or
tuples of (type, id, role). The
member type must be a single character 'n', 'w' or 'r'.
"""
OSMObject.__init__(self, base=base, **attrs)
if base is None:
self.members = members
Expand Down
2 changes: 2 additions & 0 deletions test/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Copyright (C) 2022 Sarah Hoffmann.
from contextlib import contextmanager
from collections import OrderedDict
from datetime import datetime, timezone, timedelta
import uuid

import pytest
Expand Down Expand Up @@ -54,6 +55,7 @@ def __init__(self, **params):
(O(uid=987), '0 v0 dV c0 t i987 u T'),
(O(timestamp='2012-04-14T20:58:35Z'), '0 v0 dV c0 t2012-04-14T20:58:35Z i0 u T'),
(O(timestamp=mkdate(2009, 4, 14, 20, 58, 35)), '0 v0 dV c0 t2009-04-14T20:58:35Z i0 u T'),
(O(timestamp=datetime(2009, 4, 14, 20, 58, 35, tzinfo=timezone(timedelta(hours=1)))), '0 v0 dV c0 t2009-04-14T19:58:35Z i0 u T'),
(O(timestamp='1970-01-01T00:00:01Z'), '0 v0 dV c0 t1970-01-01T00:00:01Z i0 u T')
])
class TestWriteAttributes:
Expand Down

0 comments on commit de71e7e

Please sign in to comment.