[pyosmium] 01/07: Imported Upstream version 2.12.1
Bas Couwenberg
sebastic at debian.org
Wed Apr 12 06:39:32 UTC 2017
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository pyosmium.
commit f3c2b7fb15abd0293a3550a658ad76ad3032e6bc
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Wed Apr 12 07:15:05 2017 +0200
Imported Upstream version 2.12.1
---
CHANGELOG.md | 28 +++++++++++
README.md | 11 ++++-
doc/conf.py | 8 ++-
doc/index.rst | 1 +
doc/ref_geom.rst | 8 +++
doc/tools.rst | 10 ++++
doc/tools_get_changes.rst | 8 +++
doc/tools_uptodate.rst | 8 +++
examples/amenity_list.py | 2 +-
examples/convert.py | 2 +-
examples/filter_coastlines.py | 4 +-
examples/normalize_boolean.py | 6 +--
examples/osm_diff_stats.py | 4 +-
examples/osm_file_stats.py | 3 +-
examples/osm_replication_stats.py | 2 +-
examples/osm_url_stats.py | 2 +-
examples/pub_names.py | 5 +-
examples/road_length.py | 2 +-
examples/use_nodecache.py | 2 +-
lib/generic_handler.hpp | 73 +++++++++++++++++++---------
lib/geom.cc | 66 +++++++++++++++++++++++++
lib/osm.cc | 29 ++++++++---
lib/osmium.cc | 24 ++-------
osmium/osm/__init__.py | 20 ++++++--
osmium/osm/mutable.py | 2 +-
osmium/version.py | 4 +-
test/helpers.py | 16 +++++-
test/test_taglist.py | 100 ++++++++++++++++++++++++++++++++++++++
tools/pyosmium-get-changes | 31 +++++++-----
tools/pyosmium-up-to-date | 35 +++++++------
30 files changed, 413 insertions(+), 103 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 79d0089..bc98618 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,34 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
+### Changed
+
+### Fixed
+
+## [2.12.1] - 2017-04-11
+
+### Added
+
+- geometry factories for WKT and GeoJSON
+- man pages for new tools
+- get() function for TagList
+- tests for TagList
+
+### Changed
+
+- example code simplified
+- use current libosmium
+
+### Fixed
+
+- area creator always called (#32)
+- various typos
+- TagList [] accessor properly throws KeyError on missing element
+
+## [2.12.0] - 2017-03-19
+
+### Added
+
- WriteHandler for writing data directly to a file
- tools for downloading changes and updating a OSM files from these changes
- get/set functions for io.Header
diff --git a/README.md b/README.md
index 3d86203..740c191 100644
--- a/README.md
+++ b/README.md
@@ -70,14 +70,21 @@ The suite can be run with:
## Documentation
-To build the documentation you need [Sphinx](http://sphinx-doc.org/).
-On Debian/Ubuntu install `python-sphinx` or `python3-sphinx`.
+To build the documentation you need [Sphinx](http://sphinx-doc.org/)
+and the [autoprogram extension](https://pythonhosted.org/sphinxcontrib-autoprogram/)
+On Debian/Ubuntu install `python-sphinx sphinxcontrib-autoprogram`
+or `python3-sphinx python3-sphinxcontrib.autoprogram`.
First compile the bindings as described above and then run:
cd doc
make html
+For building the man pages for the tools run:
+
+ cd doc
+ make man
+
## License
diff --git a/doc/conf.py b/doc/conf.py
index 850c539..67a2a7a 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -27,6 +27,7 @@ build_dir = "../build/lib.%s-%d.%d" % (
# insert after the current directory
sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath('.'), build_dir)))
+sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath('.'), '../tools')))
try:
from osmium.version import pyosmium_major, pyosmium_release
@@ -49,6 +50,7 @@ except ImportError:
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.todo',
+ 'sphinxcontrib.autoprogram',
]
# Add any paths that contain templates here, relative to this directory.
@@ -247,8 +249,10 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
- ('index', 'pyosmium', 'Pyosmium Documentation',
- ['Sarah Hoffmann'], 1)
+ ('tools_get_changes', 'pyosmium-get-changes', 'Download OSM change files',
+ ['Sarah Hoffmann'], 1),
+ ('tools_uptodate', 'pyosmium-up-to-date', 'Bring OSM files up-to-date',
+ ['Sarah Hoffmann'], 1),
]
# If true, show URL addresses after external links.
diff --git a/doc/index.rst b/doc/index.rst
index ebb7fb4..7245d0d 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -15,6 +15,7 @@ and profits from its fast implementation.
intro
reference
+ tools
* :ref:`genindex`
diff --git a/doc/ref_geom.rst b/doc/ref_geom.rst
index 0ac9ff4..1b78540 100644
--- a/doc/ref_geom.rst
+++ b/doc/ref_geom.rst
@@ -11,6 +11,14 @@ Geometry Factories
:members:
:undoc-members:
+.. autoclass:: osmium.geom.WKTFactory
+ :members:
+ :undoc-members:
+
+.. autoclass:: osmium.geom.GeoJSONFactory
+ :members:
+ :undoc-members:
+
Other Functions
^^^^^^^^^^^^^^^
diff --git a/doc/tools.rst b/doc/tools.rst
new file mode 100644
index 0000000..2c5563b
--- /dev/null
+++ b/doc/tools.rst
@@ -0,0 +1,10 @@
+Pyosmium Tools
+==============
+
+Pyosmium comes with a couple of scripts for handling change files:
+
+.. toctree::
+ :maxdepth: 1
+
+ tools_get_changes
+ tools_uptodate
diff --git a/doc/tools_get_changes.rst b/doc/tools_get_changes.rst
new file mode 100644
index 0000000..b105171
--- /dev/null
+++ b/doc/tools_get_changes.rst
@@ -0,0 +1,8 @@
+pyosmium-get-changes - Downloading OSM change files
+===================================================
+
+Usage
+-----
+
+.. autoprogram:: pyosmium-get-changes:get_arg_parser()
+ :prog:
diff --git a/doc/tools_uptodate.rst b/doc/tools_uptodate.rst
new file mode 100644
index 0000000..e84adf5
--- /dev/null
+++ b/doc/tools_uptodate.rst
@@ -0,0 +1,8 @@
+pyosmium-up-to-date - Bringing OSM files up-to-date
+===================================================
+
+Usage
+-----
+
+.. autoprogram:: pyosmium-up-to-date:get_arg_parser()
+ :prog:
diff --git a/examples/amenity_list.py b/examples/amenity_list.py
index f3be92d..6c6b7a1 100644
--- a/examples/amenity_list.py
+++ b/examples/amenity_list.py
@@ -14,7 +14,7 @@ wkbfab = o.geom.WKBFactory()
class AmenityListHandler(o.SimpleHandler):
def print_amenity(amenity, tags, lon, lat):
- name = tags['name'] if 'name' in tags else ''
+ name = tags.get('name', '')
print("%f %f %-15s %s" % (lon, lat, tags['amenity'], name))
def node(self, n):
diff --git a/examples/convert.py b/examples/convert.py
index 0c97c2d..d2563d6 100644
--- a/examples/convert.py
+++ b/examples/convert.py
@@ -11,7 +11,7 @@ import sys
class Convert(o.SimpleHandler):
def __init__(self, writer):
- o.SimpleHandler.__init__(self)
+ super(Convert, self).__init__()
self.writer = writer
def node(self, n):
diff --git a/examples/filter_coastlines.py b/examples/filter_coastlines.py
index 4fda1d7..8a0cb15 100644
--- a/examples/filter_coastlines.py
+++ b/examples/filter_coastlines.py
@@ -14,7 +14,7 @@ import sys
class WayFilter(o.SimpleHandler):
def __init__(self):
- o.SimpleHandler.__init__(self)
+ super(WayFilter, self).__init__()
self.nodes = set()
def way(self, w):
@@ -26,7 +26,7 @@ class WayFilter(o.SimpleHandler):
class CoastlineWriter(o.SimpleHandler):
def __init__(self, writer, nodes):
- o.SimpleHandler.__init__(self)
+ super(CoastlineWriter, self).__init__()
self.writer = writer
self.nodes = nodes
diff --git a/examples/normalize_boolean.py b/examples/normalize_boolean.py
index 7639985..3573e72 100644
--- a/examples/normalize_boolean.py
+++ b/examples/normalize_boolean.py
@@ -1,5 +1,5 @@
"""
-This example shows how to filter and modify tags and write the rusults back.
+This example shows how to filter and modify tags and write the results back.
It changes all tag values 'yes/no' to '1/0'.
"""
@@ -9,12 +9,12 @@ import sys
class BoolNormalizer(o.SimpleHandler):
def __init__(self, writer):
- o.SimpleHandler.__init__(self)
+ super(BoolNormalizer, self).__init__()
self.writer = writer
def normalize(self, o):
# if there are no tags we are done
- if len(o.tags) == 0:
+ if not o.tags:
return o
# new tags should be kept in a list so that the order is preserved
diff --git a/examples/osm_diff_stats.py b/examples/osm_diff_stats.py
index aeab6d8..f960d19 100644
--- a/examples/osm_diff_stats.py
+++ b/examples/osm_diff_stats.py
@@ -21,15 +21,15 @@ class Stats(object):
else:
self.modified += 1
-
def outstats(self, prefix):
print("%s added: %d" % (prefix, self.added))
print("%s modified: %d" % (prefix, self.modified))
print("%s deleted: %d" % (prefix, self.deleted))
+
class FileStatsHandler(o.SimpleHandler):
def __init__(self):
- o.SimpleHandler.__init__(self)
+ super(FileStatsHandler, self).__init__()
self.nodes = Stats()
self.ways = Stats()
self.rels = Stats()
diff --git a/examples/osm_file_stats.py b/examples/osm_file_stats.py
index 2482243..13ea102 100644
--- a/examples/osm_file_stats.py
+++ b/examples/osm_file_stats.py
@@ -7,8 +7,9 @@ import osmium as o
import sys
class FileStatsHandler(o.SimpleHandler):
+
def __init__(self):
- o.SimpleHandler.__init__(self)
+ super(FileStatsHandler, self).__init__()
self.nodes = 0
self.ways = 0
self.rels = 0
diff --git a/examples/osm_replication_stats.py b/examples/osm_replication_stats.py
index 00edc33..ab75eaf 100644
--- a/examples/osm_replication_stats.py
+++ b/examples/osm_replication_stats.py
@@ -32,7 +32,7 @@ class Stats(object):
class FileStatsHandler(o.SimpleHandler):
def __init__(self):
- o.SimpleHandler.__init__(self)
+ super(FileStatsHandler, self).__init__()
self.nodes = Stats()
self.ways = Stats()
self.rels = Stats()
diff --git a/examples/osm_url_stats.py b/examples/osm_url_stats.py
index 0f87779..5e2be08 100644
--- a/examples/osm_url_stats.py
+++ b/examples/osm_url_stats.py
@@ -10,7 +10,7 @@ import urllib.request
class FileStatsHandler(o.SimpleHandler):
def __init__(self):
- o.SimpleHandler.__init__(self)
+ super(FileStatsHandler, self).__init__()
self.nodes = 0
self.ways = 0
self.rels = 0
diff --git a/examples/pub_names.py b/examples/pub_names.py
index 4066d8f..2b7aafd 100644
--- a/examples/pub_names.py
+++ b/examples/pub_names.py
@@ -7,7 +7,7 @@ import sys
class NamesHandler(osmium.SimpleHandler):
def output_pubs(self, tags):
- if 'amenity' in tags and tags['amenity'] == 'pub':
+ if tags.get('amenity') == 'pub':
if 'name' in tags:
print(tags['name'])
@@ -22,6 +22,5 @@ if __name__ == '__main__':
print("Usage: python pub_names.py <osmfile>")
sys.exit(-1)
- h = NamesHandler()
- h.apply_file(sys.argv[1])
+ NamesHandler().apply_file(sys.argv[1])
diff --git a/examples/road_length.py b/examples/road_length.py
index 7b14d7e..89730f6 100644
--- a/examples/road_length.py
+++ b/examples/road_length.py
@@ -8,7 +8,7 @@ import sys
class RoadLengthHandler(o.SimpleHandler):
def __init__(self):
- o.SimpleHandler.__init__(self)
+ super(RoadLengthHandler, self).__init__()
self.length = 0.0
def way(self, w):
diff --git a/examples/use_nodecache.py b/examples/use_nodecache.py
index e819257..7e2fa90 100644
--- a/examples/use_nodecache.py
+++ b/examples/use_nodecache.py
@@ -4,7 +4,7 @@ import sys
class WayHandler(o.SimpleHandler):
def __init__(self, idx):
- o.SimpleHandler.__init__(self)
+ super(WayHandler).__init__()
self.idx = idx
def way(self, w):
diff --git a/lib/generic_handler.hpp b/lib/generic_handler.hpp
index 03dc489..18823ef 100644
--- a/lib/generic_handler.hpp
+++ b/lib/generic_handler.hpp
@@ -103,46 +103,47 @@ using namespace boost::python;
struct SimpleHandlerWrap: BaseHandler, wrapper<BaseHandler> {
- void node(const osmium::Node& node) {
- if (override f = this->get_override("node"))
- f(boost::ref(node));
- }
+ void node(const osmium::Node& node) override {
+ if (!(m_callbacks & osmium::osm_entity_bits::node))
+ return;
- void default_node(const osmium::Node&) {
+ if (override f = this->get_override("node")) {
+ f(boost::ref(node));
+ }
}
void way(const osmium::Way& way) {
+ if (!(m_callbacks & osmium::osm_entity_bits::way))
+ return;
+
if (override f = this->get_override("way"))
f(boost::ref(way));
}
- void default_way(const osmium::Way&) {
- }
-
void relation(const osmium::Relation& rel) {
+ if (!(m_callbacks & osmium::osm_entity_bits::relation))
+ return;
+
if (override f = this->get_override("relation"))
f(boost::ref(rel));
}
- void default_relation(const osmium::Relation&) {
- }
-
void changeset(const osmium::Changeset& cs) {
+ if (!(m_callbacks & osmium::osm_entity_bits::changeset))
+ return;
+
if (override f = this->get_override("changeset"))
f(boost::ref(cs));
}
- void default_changeset(const osmium::Changeset&) {
- }
-
void area(const osmium::Area& area) {
+ if (!(m_callbacks & osmium::osm_entity_bits::area))
+ return;
+
if (override f = this->get_override("area"))
f(boost::ref(area));
}
- void default_area(const osmium::Area&) {
- }
-
void apply_file(const std::string &filename, bool locations = false,
const std::string &idx = "sparse_mem_array")
{
@@ -155,7 +156,7 @@ struct SimpleHandlerWrap: BaseHandler, wrapper<BaseHandler> {
{
Py_buffer pybuf;
PyObject_GetBuffer(buf.ptr(), &pybuf, PyBUF_C_CONTIGUOUS);
- size_t len = pybuf.len;
+ size_t len = (size_t) pybuf.len;
const char *cbuf = reinterpret_cast<const char *>(pybuf.buf);
const char *cfmt = boost::python::extract<const char *>(format);
@@ -170,24 +171,50 @@ private:
BaseHandler::location_handler
:BaseHandler::no_handler;
- if (this->get_override("area"))
+ m_callbacks = osmium::osm_entity_bits::nothing;
+ if (hasfunc("node"))
+ m_callbacks |= osmium::osm_entity_bits::node;
+ if (hasfunc("way"))
+ m_callbacks |= osmium::osm_entity_bits::way;
+ if (hasfunc("relation"))
+ m_callbacks |= osmium::osm_entity_bits::relation;
+ if (hasfunc("area"))
+ m_callbacks |= osmium::osm_entity_bits::area;
+ if (hasfunc("changeset"))
+ m_callbacks |= osmium::osm_entity_bits::changeset;
+
+ if (m_callbacks & osmium::osm_entity_bits::area)
{
entities = osmium::osm_entity_bits::object;
handler = BaseHandler::area_handler;
} else {
- if (locations || this->get_override("node"))
+ if (locations || m_callbacks & osmium::osm_entity_bits::node)
entities |= osmium::osm_entity_bits::node;
- if (this->get_override("way"))
+ if (m_callbacks & osmium::osm_entity_bits::way)
entities |= osmium::osm_entity_bits::way;
- if (this->get_override("relation"))
+ if (m_callbacks & osmium::osm_entity_bits::relation)
entities |= osmium::osm_entity_bits::relation;
}
- if (this->get_override("changeset"))
+ if (m_callbacks & osmium::osm_entity_bits::changeset)
entities |= osmium::osm_entity_bits::changeset;
apply(file, entities, handler, idx);
}
+
+ bool hasfunc(char const *name) {
+ reference_existing_object::apply<SimpleHandlerWrap*>::type converter;
+ PyObject* obj = converter( this );
+
+ if (PyObject_HasAttrString(obj, name)) {
+ auto o = boost::python::object(handle<>(obj));
+ return o.attr(name) != boost::python::object();
+ }
+
+ return false;
+ }
+
+ osmium::osm_entity_bits::type m_callbacks;
};
#endif
diff --git a/lib/geom.cc b/lib/geom.cc
index 626c5e3..309002e 100644
--- a/lib/geom.cc
+++ b/lib/geom.cc
@@ -3,6 +3,8 @@
#include <osmium/geom/haversine.hpp>
#include <osmium/geom/factory.hpp>
#include <osmium/geom/wkb.hpp>
+#include <osmium/geom/wkt.hpp>
+#include <osmium/geom/geojson.hpp>
class WKBFactory : public osmium::geom::WKBFactory<> {
@@ -12,6 +14,9 @@ public:
{}
};
+using WKTFactory = osmium::geom::WKTFactory<>;
+using GeoJSONFactory = osmium::geom::GeoJSONFactory<>;
+
BOOST_PYTHON_MODULE(geom)
{
using namespace boost::python;
@@ -62,4 +67,65 @@ BOOST_PYTHON_MODULE(geom)
(arg("self"), arg("area")),
"Create a MultiPolygon geometry from a :py:class:`osmium.osm.Area`.")
;
+
+ class_<WKTFactory>("WKTFactory",
+ "Factory that creates WKT from osmium geometries.")
+ .add_property("epsg", &WKTFactory::epsg,
+ "(read-only) EPSG number of the output geometry.")
+ .add_property("proj_string", &WKTFactory::proj_string,
+ "(read-only) projection string of the output geometry.")
+ .def("create_point", static_cast<std::string (WKTFactory::*)(const osmium::Location&) const>(&WKTFactory::create_point),
+ (arg("self"), arg("location")),
+ "Create a point geometry from a :py:class:`osmium.osm.Location`.")
+ .def("create_point", static_cast<std::string (WKTFactory::*)(const osmium::Node&)>(&WKTFactory::create_point),
+ (arg("self"), arg("node")),
+ "Create a point geometry from a :py:class:`osmium.osm.Node`.")
+ .def("create_point", static_cast<std::string (WKTFactory::*)(const osmium::NodeRef&)>(&WKTFactory::create_point),
+ (arg("self"), arg("ref")),
+ "Create a point geometry from a :py:class:`osmium.osm.NodeRef`.")
+ .def("create_linestring", static_cast<std::string (WKTFactory::*)(const osmium::WayNodeList&, osmium::geom::use_nodes, osmium::geom::direction)>(&WKTFactory::create_linestring),
+ (arg("self"), arg("list"),
+ arg("use_nodes")=osmium::geom::use_nodes::unique,
+ arg("direction")=osmium::geom::direction::forward),
+ "Create a LineString geometry from a :py:class:`osmium.osm.WayNodeList`.")
+ .def("create_linestring", static_cast<std::string (WKTFactory::*)(const osmium::Way&, osmium::geom::use_nodes, osmium::geom::direction)>(&WKTFactory::create_linestring),
+ (arg("self"), arg("way"),
+ arg("use_nodes")=osmium::geom::use_nodes::unique,
+ arg("direction")=osmium::geom::direction::forward),
+ "Create a LineString geometry from a :py:class:`osmium.osm.Way`.")
+ .def("create_multipolygon", &WKTFactory::create_multipolygon,
+ (arg("self"), arg("area")),
+ "Create a MultiPolygon geometry from a :py:class:`osmium.osm.Area`.")
+ ;
+
+ class_<GeoJSONFactory>("GeoJSONFactory",
+ "Factory that creates GeoJSON geometries from osmium geometries.")
+ .add_property("epsg", &GeoJSONFactory::epsg,
+ "(read-only) EPSG number of the output geometry.")
+ .add_property("proj_string", &GeoJSONFactory::proj_string,
+ "(read-only) projection string of the output geometry.")
+ .def("create_point", static_cast<std::string (GeoJSONFactory::*)(const osmium::Location&) const>(&GeoJSONFactory::create_point),
+ (arg("self"), arg("location")),
+ "Create a point geometry from a :py:class:`osmium.osm.Location`.")
+ .def("create_point", static_cast<std::string (GeoJSONFactory::*)(const osmium::Node&)>(&GeoJSONFactory::create_point),
+ (arg("self"), arg("node")),
+ "Create a point geometry from a :py:class:`osmium.osm.Node`.")
+ .def("create_point", static_cast<std::string (GeoJSONFactory::*)(const osmium::NodeRef&)>(&GeoJSONFactory::create_point),
+ (arg("self"), arg("ref")),
+ "Create a point geometry from a :py:class:`osmium.osm.NodeRef`.")
+ .def("create_linestring", static_cast<std::string (GeoJSONFactory::*)(const osmium::WayNodeList&, osmium::geom::use_nodes, osmium::geom::direction)>(&GeoJSONFactory::create_linestring),
+ (arg("self"), arg("list"),
+ arg("use_nodes")=osmium::geom::use_nodes::unique,
+ arg("direction")=osmium::geom::direction::forward),
+ "Create a LineString geometry from a :py:class:`osmium.osm.WayNodeList`.")
+ .def("create_linestring", static_cast<std::string (GeoJSONFactory::*)(const osmium::Way&, osmium::geom::use_nodes, osmium::geom::direction)>(&GeoJSONFactory::create_linestring),
+ (arg("self"), arg("way"),
+ arg("use_nodes")=osmium::geom::use_nodes::unique,
+ arg("direction")=osmium::geom::direction::forward),
+ "Create a LineString geometry from a :py:class:`osmium.osm.Way`.")
+ .def("create_multipolygon", &GeoJSONFactory::create_multipolygon,
+ (arg("self"), arg("area")),
+ "Create a MultiPolygon geometry from a :py:class:`osmium.osm.Area`.")
+ ;
+
}
diff --git a/lib/osm.cc b/lib/osm.cc
index 9dbb52c..74bd212 100644
--- a/lib/osm.cc
+++ b/lib/osm.cc
@@ -8,19 +8,31 @@
#include "std_pair.hpp"
-
-inline const char *get_tag_by_key(osmium::TagList const& obj, const char *value)
+inline const char *get_tag_by_key(osmium::TagList const& obj, const char *key)
{
- const char* v = obj.get_value_by_key(value);
- if (!v)
+ if (!key) {
+ PyErr_SetString(PyExc_KeyError, "Key 'None' not allowed.");
+ boost::python::throw_error_already_set();
+ }
+
+ const char* v = obj.get_value_by_key(key);
+ if (!v) {
PyErr_SetString(PyExc_KeyError, "No tag with that key.");
+ boost::python::throw_error_already_set();
+ }
return v;
}
-inline bool taglist_contains_tag(osmium::TagList const& obj, const char *value)
+inline const char *get_tag_by_key_with_none(osmium::TagList const& obj,
+ const char *key)
{
- const char* v = obj.get_value_by_key(value);
- return v;
+ return key ? obj.get_value_by_key(key) : nullptr;
+}
+
+
+inline bool taglist_contains_tag(osmium::TagList const& obj, const char *key)
+{
+ return key && obj.has_key(key);
}
inline const char member_item_type(osmium::RelationMember& obj)
@@ -132,6 +144,9 @@ BOOST_PYTHON_MODULE(_osm)
.def("__getitem__", &get_tag_by_key)
.def("__contains__", &taglist_contains_tag)
.def("__iter__", iterator<osmium::TagList,return_internal_reference<>>())
+ .def("get", &osmium::TagList::get_value_by_key,
+ (arg("self"), arg("key"), arg("default")))
+ .def("get", &get_tag_by_key_with_none)
;
class_<osmium::NodeRef>("NodeRef",
"A reference to a OSM node that also caches the nodes location.")
diff --git a/lib/osmium.cc b/lib/osmium.cc
index 31b4997..f4a2b94 100644
--- a/lib/osmium.cc
+++ b/lib/osmium.cc
@@ -67,28 +67,14 @@ BOOST_PYTHON_MODULE(_osmium)
;
class_<SimpleHandlerWrap, boost::noncopyable>("SimpleHandler",
- "The most generic of OSM data handlers. For each data type "
- "a callback can be implemented where the object is processed. Note that "
+ "The most generic of OSM data handlers. Derive your data processor "
+ "from this class and implement callbacks for each object type you are "
+ "interested in. The following data types are recognised: \n"
+ " `node`, `way`, `relation`, `area` and `changeset`.\n "
+ "A callback takes exactly one parameter which is the object. Note that "
"all objects that are handed into the handler are only readable and are "
"only valid until the end of the callback is reached. Any data that "
"should be retained must be copied into other data structures.")
- .def("node", &BaseHandler::node, &SimpleHandlerWrap::default_node,
- (arg("self"), arg("node")),
- "Handler called for node objects.")
- .def("way", &BaseHandler::way, &SimpleHandlerWrap::default_way,
- (arg("self"), arg("way")),
- "Handler called for way objects. If the geometry of the way is "
- "needed then ``locations`` must be set to true when calling "
- "apply_file.")
- .def("relation", &BaseHandler::relation, &SimpleHandlerWrap::default_relation,
- (arg("self"), arg("relation")),
- "Handler called for relation objects.")
- .def("changeset", &BaseHandler::changeset, &SimpleHandlerWrap::default_changeset,
- (arg("self"), arg("changeset")),
- "Handler called for changeset objects.")
- .def("area", &BaseHandler::area, &SimpleHandlerWrap::default_area,
- (arg("self"), arg("area")),
- "Handler called for area objects.")
.def("apply_file", &SimpleHandlerWrap::apply_file,
(arg("self"), arg("filename"),
arg("locations")=false, arg("idx")="sparse_mem_array"),
diff --git a/osmium/osm/__init__.py b/osmium/osm/__init__.py
index 8a4908b..22712b4 100644
--- a/osmium/osm/__init__.py
+++ b/osmium/osm/__init__.py
@@ -2,13 +2,25 @@ from ._osm import *
import osmium.osm.mutable
def create_mutable_node(node, **args):
+ """ Create a mutable node replacing the properties given in the
+ named parameters. Note that this function only creates a shallow
+ copy which is still bound to the scope of the original object.
+ """
return osmium.osm.mutable.Node(base=node, **args)
-def create_mutable_way(node, **args):
- return osmium.osm.mutable.Way(base=node, **args)
+def create_mutable_way(way, **args):
+ """ Create a mutable way replacing the properties given in the
+ named parameters. Note that this function only creates a shallow
+ copy which is still bound to the scope of the original object.
+ """
+ return osmium.osm.mutable.Way(base=way, **args)
-def create_mutable_relation(node, **args):
- return osmium.osm.mutable.Relation(base=node, **args)
+def create_mutable_relation(rel, **args):
+ """ Create a mutable relation replacing the properties given in the
+ named parameters. Note that this function only creates a shallow
+ copy which is still bound to the scope of the original object.
+ """
+ return osmium.osm.mutable.Relation(base=rel, **args)
Node.replace = create_mutable_node
Way.replace = create_mutable_way
diff --git a/osmium/osm/mutable.py b/osmium/osm/mutable.py
index edf0421..b700087 100644
--- a/osmium/osm/mutable.py
+++ b/osmium/osm/mutable.py
@@ -40,7 +40,7 @@ class Node(OSMObject):
if base is None:
self.location = location
else:
- self.location = loctation if location is not None else base.location
+ self.location = location if location is not None else base.location
class Way(OSMObject):
diff --git a/osmium/version.py b/osmium/version.py
index 804c532..c3ee027 100644
--- a/osmium/version.py
+++ b/osmium/version.py
@@ -5,7 +5,7 @@ Version information.
# the major version
pyosmium_major = '2.12'
# current release (Pip version)
-pyosmium_release = '2.12.0'
+pyosmium_release = '2.12.1'
# libosmium version shipped with the Pip release
-libosmium_version = '2.12.0'
+libosmium_version = '2.12.1'
diff --git a/test/helpers.py b/test/helpers.py
index fb00777..03084bb 100644
--- a/test/helpers.py
+++ b/test/helpers.py
@@ -3,6 +3,7 @@
import random
import tempfile
import os
+from textwrap import dedent
import osmium
def _complete_object(o):
@@ -87,6 +88,15 @@ def create_osm_file(data):
return fname
+def create_opl_file(data):
+ with tempfile.NamedTemporaryFile(dir='/tmp', suffix='.opl', delete=False) as fd:
+ fname = fd.name
+ fd.write(dedent(data).encode('utf-8'))
+ fd.write(b'\n')
+
+ return fname
+
+
def osmobj(kind, **args):
ret = dict(args)
ret['type'] = kind
@@ -99,7 +109,11 @@ class HandlerTestBase:
apply_idx = 'sparse_mem_array'
def test_func(self):
- fn = create_osm_file(self.data)
+ if isinstance(self.data, (list, tuple)):
+ fn = create_osm_file(self.data)
+ else:
+ fn = create_opl_file(self.data)
+
try:
self.Handler().apply_file(fn, self.apply_locations, self.apply_idx)
finally:
diff --git a/test/test_taglist.py b/test/test_taglist.py
new file mode 100644
index 0000000..0437644
--- /dev/null
+++ b/test/test_taglist.py
@@ -0,0 +1,100 @@
+from nose.tools import *
+import unittest
+import os
+import sys
+from datetime import datetime
+
+from helpers import create_osm_file, osmobj, HandlerTestBase
+
+import osmium as o
+
+class TestTagEmptyTagListLength(HandlerTestBase, unittest.TestCase):
+ data = "n234 x1 y2"
+
+ class Handler(o.SimpleHandler):
+
+ def node(self, n):
+ assert_equals(0, len(n.tags))
+ assert_false(n.tags)
+
+class TestTagEmptyTagListContains(HandlerTestBase, unittest.TestCase):
+ data = "n234 x1 y2"
+
+ class Handler(o.SimpleHandler):
+
+ def node(self, n):
+ assert_not_in("a", n.tags)
+
+class TestTagEmptyTagListGet(HandlerTestBase, unittest.TestCase):
+ data = "n234 x1 y2"
+
+ class Handler(o.SimpleHandler):
+
+ def node(self, n):
+ assert_equals(None, n.tags.get("foo"))
+ assert_equals(None, n.tags.get("foo", None))
+ assert_equals("fs", n.tags.get("foo", "fs"))
+
+class TestTagEmptyTagListIndexOp(HandlerTestBase, unittest.TestCase):
+ data = "n234 x1 y2"
+
+ class Handler(o.SimpleHandler):
+
+ def node(self, n):
+ with assert_raises(KeyError):
+ n.tags["foo"]
+ with assert_raises(KeyError):
+ n.tags[None]
+
+class TestTagListLen(HandlerTestBase, unittest.TestCase):
+ data = """\
+ n1 x0 y0 Ta=a
+ n2 Tkey=value
+ n3 Tfoo=1,bar=2,foobar=33
+ """
+ class Handler(o.SimpleHandler):
+
+ expected_len = { 1 : 1, 2 : 1, 3 : 3}
+
+ def node(self, n):
+ assert_true(n.tags)
+ assert_equals(self.expected_len[n.id], len(n.tags))
+
+class TestTagContains(HandlerTestBase, unittest.TestCase):
+ data = "n234 Tabba=x,2=vvv,xx=abba"
+
+ class Handler(o.SimpleHandler):
+
+ def node(self, n):
+ assert_in("abba", n.tags)
+ assert_in("2", n.tags)
+ assert_in("xx", n.tags)
+ assert_not_in("x", n.tags)
+ assert_not_in(None, n.tags)
+ assert_not_in("", n.tags)
+
+class TestTagIndexOp(HandlerTestBase, unittest.TestCase):
+ data = "n234 Tabba=x,2=vvv,xx=abba"
+
+ class Handler(o.SimpleHandler):
+
+ def node(self, n):
+ eq_("x", n.tags["abba"])
+ eq_("vvv", n.tags["2"])
+ eq_("abba", n.tags["xx"])
+ for k in ("x", "addad", "..", None):
+ with assert_raises(KeyError):
+ n.tags[k]
+
+class TestTagGet(HandlerTestBase, unittest.TestCase):
+ data = "n234 Tabba=x,2=vvv,xx=abba"
+
+ class Handler(o.SimpleHandler):
+
+ def node(self, n):
+ eq_("x", n.tags.get("abba"))
+ eq_("vvv", n.tags.get("2", None))
+ eq_("abba", n.tags.get("xx", "ff"))
+ eq_("43 fg", n.tags.get("_", "43 fg"))
+ assert_is_none(n.tags.get("gerger4"))
+ assert_is_none(n.tags.get("ffleo", None))
diff --git a/tools/pyosmium-get-changes b/tools/pyosmium-get-changes
index 5be7c49..f10b305 100755
--- a/tools/pyosmium-get-changes
+++ b/tools/pyosmium-get-changes
@@ -4,7 +4,7 @@ Fetch diffs from an OSM planet server.
The starting point of the diff must be given either as a sequence ID or a date
or can be computed from an OSM file. If no output file is given, the program
-will just print the intial sequence ID it would use (or save it in a file, if
+will just print the initial sequence ID it would use (or save it in a file, if
requested) and exit. This can be used to bootstrap the update process.
The program tries to download until the latest change on the server is found
@@ -24,6 +24,7 @@ from osmium.replication import newest_change_from_file
from osmium.replication.utils import get_replication_header
from osmium import SimpleHandler, WriteHandler
+import re
import sys
import logging
from textwrap import dedent as msgfmt
@@ -105,17 +106,18 @@ def write_end_sequence(fname, seqid):
with open(fname, 'w') as fd:
fd.write(str(startseq))
-if __name__ == '__main__':
- logging.basicConfig(stream=sys.stderr,
- format='%(levelname)s: %(message)s')
+def get_arg_parser(from_main=False):
+ def h(s):
+ return re.sub("\s\s+" , " ", s)
parser = ArgumentParser(description=__doc__,
+ usage=None if from_main else 'pyosmium-get-changes [options]',
formatter_class=RawDescriptionHelpFormatter)
parser.add_argument('-v', dest='loglevel', action='count', default=0,
help='Increase verbosity')
parser.add_argument('-o', '--outfile', dest='outfile',
- help="""Name of diff output file. If omitted, only the
- sequence ID will be printed where updates would start.""")
+ help=h("""Name of diff output file. If omitted, only the
+ sequence ID will be printed where updates would start."""))
parser.add_argument('--server', action='store', dest='server_url',
help='Base URL of the replication server')
parser.add_argument('-s', '--size', dest='outsize', type=int, default=100,
@@ -130,19 +132,26 @@ if __name__ == '__main__':
group.add_argument('-O', '--start-osm-data', dest='start_file', metavar='OSMFILE',
help='start at the date of the newest OSM object in the file')
parser.add_argument('-f', '--sequence-file', dest='seq_file',
- help="""Sequence file. If the file exists, then updates
+ help=h("""Sequence file. If the file exists, then updates
will start after the id given in the file. At the
end of the process, the last sequence ID contained
- in the diff is written.""")
+ in the diff is written."""))
parser.add_argument('--ignore-osmosis-headers', dest='ignore_headers',
action='store_true',
- help="""When determining the start from an OSM file,
+ help=h("""When determining the start from an OSM file,
ignore potential replication information in the
- header and search for the newest OSM object.""")
+ header and search for the newest OSM object."""))
parser.add_argument('-d', '--no-deduplicate', action='store_false', dest='simplify',
help='Do not deduplicate and sort diffs.')
- options = parser.parse_args()
+ return parser
+
+
+if __name__ == '__main__':
+ logging.basicConfig(stream=sys.stderr,
+ format='%(levelname)s: %(message)s')
+
+ options = get_arg_parser(from_main=True).parse_args()
log.setLevel(max(3 - options.loglevel, 0) * 10)
diff --git a/tools/pyosmium-up-to-date b/tools/pyosmium-up-to-date
index cc54ad1..34fddcd 100755
--- a/tools/pyosmium-up-to-date
+++ b/tools/pyosmium-up-to-date
@@ -23,6 +23,7 @@ resolved). Any other error results in a return code larger than 1. The
output file is guaranteed to be unmodified in that case.
"""
+import re
import sys
import logging
@@ -140,41 +141,47 @@ def compute_start_point(options):
return url, seq, ts
-
-if __name__ == '__main__':
- logging.basicConfig(stream=sys.stderr,
- format='%(asctime)s %(levelname)s: %(message)s')
+def get_arg_parser(from_main=False):
+ def h(s):
+ return re.sub("\s\s+" , " ", s)
parser = ArgumentParser(description=__doc__,
+ usage=None if from_main else 'pyosmium-up-to-date [options] <osm file>',
formatter_class=RawDescriptionHelpFormatter)
parser.add_argument('-v', dest='loglevel', action='count', default=0,
help='Increase verbosity')
parser.add_argument('infile', metavar='<OSM file>', help="OSM file to update")
parser.add_argument('-o', '--outfile', dest='outfile',
- help="""Name output of file. If missing, the input file
- will be overwritten.""")
+ help=h("""Name output of file. If missing, the input file
+ will be overwritten."""))
parser.add_argument('--server', action='store', dest='server_url',
- help="""Base URL of the replication server. Default:
- 'https://planet.osm.org/replication/hour/' (
- hourly diffs from osm.org).""")
+ help=h("""Base URL of the replication server. Default:
+ 'https://planet.osm.org/replication/hour/'
+ (hourly diffs from osm.org)."""))
parser.add_argument('-s', '--size', dest='outsize', metavar='SIZE', type=int, default=1024,
help='Maximum size of change to apply at once in MB. Default: 1GB.')
parser.add_argument('--tmpdir', dest='tmpdir',
help='Directory to use for temporary files. Default: directory of input file')
parser.add_argument('--ignore-osmosis-headers', dest='ignore_headers',
action='store_true',
- help="""Ignore potential replication information in the
+ help=h("""Ignore potential replication information in the
header of the input file and search for the
- newest OSM object in the file instead.""")
+ newest OSM object in the file instead."""))
parser.add_argument('-b', '--wind-back', dest='wind_back', type=int, default=60,
- help="""Number of minutes to start downloading before
+ help=h("""Number of minutes to start downloading before
the newest addition to input data. (Ignored when
- the file contains a sequence ID.) Default: 60.""")
+ the file contains a sequence ID.) Default: 60."""))
parser.add_argument('--force-update-of-old-planet', action='store_true',
dest='force_update',
help="Apply update even if the input data is really old.")
- options = parser.parse_args()
+ return parser
+
+if __name__ == '__main__':
+ logging.basicConfig(stream=sys.stderr,
+ format='%(asctime)s %(levelname)s: %(message)s')
+
+ options = get_arg_parser(from_main=True).parse_args()
log.setLevel(max(3 - options.loglevel, 0) * 10)
try:
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/pyosmium.git
More information about the Pkg-grass-devel
mailing list