Skip to content

Commit 91a878c

Browse files
committed
Reflect mapnik::parameters + save_map_to_string() [WIP] [skip ci]
1 parent 4277e59 commit 91a878c

6 files changed

Lines changed: 47 additions & 237 deletions

File tree

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def check_output(args):
8686
"src/mapnik_logger.cpp",
8787
"src/mapnik_placement_finder.cpp",
8888
"src/mapnik_text_symbolizer.cpp",
89+
"src/mapnik_parameters.cpp",
8990
],
9091
extra_compile_args=extra_comp_args,
9192
extra_link_args=linkflags,

src/mapnik_map.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <mapnik/projection.hpp>
3030
#include <mapnik/view_transform.hpp>
3131
#include <mapnik/feature_type_style.hpp>
32+
#include "mapnik_value_converter.hpp"
3233
#include "python_optional.hpp"
3334
//pybind11
3435
#include <pybind11/pybind11.h>
@@ -46,11 +47,12 @@ using mapnik::Map;
4647

4748
PYBIND11_MAKE_OPAQUE(std::vector<mapnik::layer>);
4849
PYBIND11_MAKE_OPAQUE(std::map<std::string, mapnik::feature_type_style>);
49-
50+
PYBIND11_MAKE_OPAQUE(mapnik::parameters);
5051

5152
namespace {
5253
std::vector<layer>& (Map::*set_layers)() = &Map::layers;
5354
std::vector<layer> const& (Map::*get_layers)() const = &Map::layers;
55+
mapnik::parameters const& (Map::*params_const)() const = &Map::get_extra_parameters;
5456
mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters;
5557

5658
void insert_style(mapnik::Map & m, std::string const& name, mapnik::feature_type_style const& style)
@@ -368,8 +370,10 @@ void export_map(py::module const& m)
368370
">>> m.zoom_to_box(extent)\n",
369371
py::arg("bounding_box")
370372
)
371-
372-
//.add_property("parameters",make_function(params_nonconst,return_value_policy<reference_existing_object>()),"TODO")
373+
.def_property("parameters",
374+
params_const,
375+
params_nonconst,
376+
"extra parameters")
373377

374378
.def_property("aspect_fix_mode",
375379
&Map::get_aspect_fix_mode,

src/mapnik_parameters.cpp

Lines changed: 5 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -27,213 +27,18 @@
2727
#include <mapnik/unicode.hpp>
2828
#include <mapnik/value.hpp>
2929
#include <mapnik/value/types.hpp>
30-
// stl
31-
#include <iterator>
30+
#include "mapnik_value_converter.hpp"
3231
//pybind11
3332
#include <pybind11/pybind11.h>
34-
33+
#include <pybind11/stl.h>
34+
#include <pybind11/stl_bind.h>
3535
namespace py = pybind11;
3636

3737
using mapnik::parameter;
3838
using mapnik::parameters;
3939

40-
struct parameter_pickle_suite : boost::python::pickle_suite
41-
{
42-
static boost::python::tuple
43-
getinitargs(const parameter& p)
44-
{
45-
using namespace boost::python;
46-
return boost::python::make_tuple(p.first,p.second);
47-
}
48-
};
49-
50-
struct parameters_pickle_suite : boost::python::pickle_suite
51-
{
52-
static boost::python::tuple
53-
getstate(const parameters& p)
54-
{
55-
using namespace boost::python;
56-
dict d;
57-
parameters::const_iterator pos=p.begin();
58-
while(pos!=p.end())
59-
{
60-
d[pos->first] = pos->second;
61-
++pos;
62-
}
63-
return boost::python::make_tuple(d);
64-
}
65-
66-
static void setstate(parameters& p, boost::python::tuple state)
67-
{
68-
using namespace boost::python;
69-
if (len(state) != 1)
70-
{
71-
PyErr_SetObject(PyExc_ValueError,
72-
("expected 1-item tuple in call to __setstate__; got %s"
73-
% state).ptr()
74-
);
75-
throw_error_already_set();
76-
}
77-
78-
dict d = extract<dict>(state[0]);
79-
boost::python::list keys = d.keys();
80-
for (int i=0; i<len(keys); ++i)
81-
{
82-
std::string key = extract<std::string>(keys[i]);
83-
object obj = d[key];
84-
extract<std::string> ex0(obj);
85-
extract<mapnik::value_integer> ex1(obj);
86-
extract<double> ex2(obj);
87-
extract<mapnik::value_unicode_string> ex3(obj);
88-
89-
// TODO - this is never hit - we need proper python string -> std::string to get invoked here
90-
if (ex0.check())
91-
{
92-
p[key] = ex0();
93-
}
94-
else if (ex1.check())
95-
{
96-
p[key] = ex1();
97-
}
98-
else if (ex2.check())
99-
{
100-
p[key] = ex2();
101-
}
102-
else if (ex3.check())
103-
{
104-
std::string buffer;
105-
mapnik::to_utf8(ex3(),buffer);
106-
p[key] = buffer;
107-
}
108-
else
109-
{
110-
MAPNIK_LOG_DEBUG(bindings) << "parameters_pickle_suite: Could not unpickle key=" << key;
111-
}
112-
}
113-
}
114-
};
115-
116-
117-
mapnik::value_holder get_params_by_key1(mapnik::parameters const& p, std::string const& key)
118-
{
119-
parameters::const_iterator pos = p.find(key);
120-
if (pos != p.end())
121-
{
122-
// will be auto-converted to proper python type by `mapnik_params_to_python`
123-
return pos->second;
124-
}
125-
return mapnik::value_null();
126-
}
127-
128-
mapnik::value_holder get_params_by_key2(mapnik::parameters const& p, std::string const& key)
129-
{
130-
parameters::const_iterator pos = p.find(key);
131-
if (pos == p.end())
132-
{
133-
PyErr_SetString(PyExc_KeyError, key.c_str());
134-
boost::python::throw_error_already_set();
135-
}
136-
// will be auto-converted to proper python type by `mapnik_params_to_python`
137-
return pos->second;
138-
}
139-
140-
mapnik::parameter get_params_by_index(mapnik::parameters const& p, int index)
141-
{
142-
if (index < 0 || static_cast<unsigned>(index) > p.size())
143-
{
144-
PyErr_SetString(PyExc_IndexError, "Index is out of range");
145-
throw boost::python::error_already_set();
146-
}
147-
148-
parameters::const_iterator itr = p.begin();
149-
std::advance(itr, index);
150-
if (itr != p.end())
151-
{
152-
return *itr;
153-
}
154-
PyErr_SetString(PyExc_IndexError, "Index is out of range");
155-
throw boost::python::error_already_set();
156-
}
157-
158-
std::size_t get_params_size(mapnik::parameters const& p)
159-
{
160-
return p.size();
161-
}
162-
163-
void add_parameter(mapnik::parameters & p, mapnik::parameter const& param)
164-
{
165-
p[param.first] = param.second;
166-
}
167-
168-
mapnik::value_holder get_param(mapnik::parameter const& p, int index)
169-
{
170-
if (index == 0)
171-
{
172-
return p.first;
173-
}
174-
else if (index == 1)
175-
{
176-
return p.second;
177-
}
178-
else
179-
{
180-
PyErr_SetString(PyExc_IndexError, "Index is out of range");
181-
throw boost::python::error_already_set();
182-
}
183-
}
184-
185-
std::shared_ptr<mapnik::parameter> create_parameter(mapnik::value_unicode_string const& key, mapnik::value_holder const& value)
186-
{
187-
std::string key_utf8;
188-
mapnik::to_utf8(key, key_utf8);
189-
return std::make_shared<mapnik::parameter>(key_utf8,value);
190-
}
191-
192-
bool contains(mapnik::parameters const& p, std::string const& key)
193-
{
194-
parameters::const_iterator pos = p.find(key);
195-
return pos != p.end();
196-
}
197-
198-
// needed for Python_Unicode to std::string (utf8) conversion
199-
200-
std::shared_ptr<mapnik::parameter> create_parameter_from_string(mapnik::value_unicode_string const& key, mapnik::value_unicode_string const& ustr)
201-
{
202-
std::string key_utf8;
203-
std::string ustr_utf8;
204-
mapnik::to_utf8(key, key_utf8);
205-
mapnik::to_utf8(ustr,ustr_utf8);
206-
return std::make_shared<mapnik::parameter>(key_utf8, ustr_utf8);
207-
}
20840

209-
void export_parameters()
41+
void export_parameters(py::module const& m)
21042
{
211-
using namespace boost::python;
212-
implicitly_convertible<std::string,mapnik::value_holder>();
213-
implicitly_convertible<mapnik::value_null,mapnik::value_holder>();
214-
implicitly_convertible<mapnik::value_integer,mapnik::value_holder>();
215-
implicitly_convertible<mapnik::value_double,mapnik::value_holder>();
216-
217-
class_<parameter,std::shared_ptr<parameter> >("Parameter",no_init)
218-
.def("__init__", make_constructor(create_parameter),
219-
"Create a mapnik.Parameter from a pair of values, the first being a string\n"
220-
"and the second being either a string, and integer, or a float")
221-
.def("__init__", make_constructor(create_parameter_from_string),
222-
"Create a mapnik.Parameter from a pair of values, the first being a string\n"
223-
"and the second being either a string, and integer, or a float")
224-
225-
.def_pickle(parameter_pickle_suite())
226-
.def("__getitem__",get_param)
227-
;
228-
229-
class_<parameters>("Parameters",init<>())
230-
.def_pickle(parameters_pickle_suite())
231-
.def("get",get_params_by_key1)
232-
.def("__getitem__",get_params_by_key2)
233-
.def("__getitem__",get_params_by_index)
234-
.def("__len__",get_params_size)
235-
.def("__contains__",contains)
236-
.def("append",add_parameter)
237-
.def("iteritems",iterator<parameters>())
238-
;
43+
py::bind_map<mapnik::parameters>(m, "Parameters", py::module_local());
23944
}

src/mapnik_python.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ void export_style(py::module const&);
612612
void export_logger(py::module const&);
613613
void export_placement_finder(py::module const&);
614614
void export_text_symbolizer(py::module const&);
615+
void export_parameters(py::module const&);
615616

616617
using mapnik::load_map;
617618
using mapnik::load_map_string;
@@ -647,6 +648,7 @@ PYBIND11_MODULE(_mapnik, m) {
647648
export_logger(m);
648649
export_placement_finder(m);
649650
export_text_symbolizer(m);
651+
export_parameters(m);
650652

651653
m.def("mapnik_version", &mapnik_version,"Get the Mapnik version number");
652654
m.def("mapnik_version_string", &mapnik_version_string,"Get the Mapnik version string");
@@ -801,6 +803,10 @@ PYBIND11_MODULE(_mapnik, m) {
801803
py::arg("filename"),
802804
py::arg("explicit_defaults") = false);
803805

806+
m.def("save_map_to_string", &save_map_to_string,
807+
py::arg("Map"),
808+
py::arg("explicit_defaults") = false);
809+
804810
m.def("clear_cache", &clear_cache,
805811
"\n"
806812
"Clear all global caches of markers and mapped memory regions.\n"

test/python_tests/extra_map_props_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ def test_arbitrary_parameters_attached_to_map(setup):
2121
assert m.parameters['integer'] == 10
2222
assert m.parameters['decimal'] == .999
2323
m2 = mapnik.Map(256, 256)
24-
for k, v in m.parameters:
25-
m2.parameters.append(mapnik.Parameter(k, v))
24+
for k, v in m.parameters.items():
25+
m2.parameters[k] = v
2626
assert len(m2.parameters) == 5
2727
assert m2.parameters['key'] == 'value2'
2828
assert m2.parameters['key3'] == 'value3'
@@ -42,8 +42,8 @@ def test_arbitrary_parameters_attached_to_map(setup):
4242

4343
def test_serializing_arbitrary_parameters():
4444
m = mapnik.Map(256, 256)
45-
m.parameters.append(mapnik.Parameter('width', m.width))
46-
m.parameters.append(mapnik.Parameter('height', m.height))
45+
m.parameters['width'] = m.width
46+
m.parameters['height'] = m.height
4747

4848
m2 = mapnik.Map(1, 1)
4949
mapnik.load_map_from_string(m2, mapnik.save_map_to_string(m))

test/python_tests/parameters_test.py

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,45 @@
22
import mapnik
33

44
def test_parameter_null():
5-
p = mapnik.Parameter('key', None)
6-
assert p[0] == 'key'
7-
assert p[1] == None
5+
p = mapnik.Parameters()
6+
p['key'] = None
7+
assert p['key'] is None
88

99

1010
def test_parameter_string():
11-
p = mapnik.Parameter('key', 'value')
12-
assert p[0] == 'key'
13-
assert p[1] == 'value'
11+
p = mapnik.Parameters()
12+
p['key'] = 'value'
13+
assert p['key'] == 'value'
1414

1515

1616
def test_parameter_unicode():
17-
p = mapnik.Parameter('key', u'value')
18-
assert p[0] == 'key'
19-
assert p[1] == u'value'
17+
p = mapnik.Parameters()
18+
p['key'] = u'value'
19+
assert p['key'] == u'value'
2020

2121

2222
def test_parameter_integer():
23-
p = mapnik.Parameter('int', sys.maxsize)
24-
assert p[0] == 'int'
25-
assert p[1] == sys.maxsize
23+
p = mapnik.Parameters()
24+
p['int'] = sys.maxsize
25+
assert p['int'] == sys.maxsize
2626

2727

2828
def test_parameter_double():
29-
p = mapnik.Parameter('double', float(sys.maxsize))
30-
assert p[0] == 'double'
31-
assert p[1] == float(sys.maxsize)
29+
p = mapnik.Parameters()
30+
p['double'] = float(sys.maxsize)
31+
assert p['double'] == float(sys.maxsize)
3232

3333

3434
def test_parameter_boolean():
35-
p = mapnik.Parameter('boolean', True)
36-
assert p[0] == 'boolean'
37-
assert p[1] == True
38-
assert bool(p[1]) == True
35+
p = mapnik.Parameters()
36+
p['boolean'] = True
37+
assert p['boolean'] == True
38+
assert bool(p['boolean']) == True
3939

4040

4141
def test_parameters():
42-
params = mapnik.Parameters()
43-
p = mapnik.Parameter('float', 1.0777)
44-
assert p[0] == 'float'
45-
assert p[1] == 1.0777
46-
47-
params.append(p)
48-
49-
assert params[0][0] == 'float'
50-
assert params[0][1] == 1.0777
51-
52-
assert params.get('float') == 1.0777
42+
p = mapnik.Parameters()
43+
p['float'] = 1.0777
44+
p['int'] = 123456789
45+
assert p['float'] == 1.0777
46+
assert p['int'] == 123456789

0 commit comments

Comments
 (0)