Skip to content

Commit bcae478

Browse files
authored
Merge pull request #88 from PDAL/issue-87
Use out_metadata for output metadata
2 parents d71bb14 + ca02b03 commit bcae478

File tree

4 files changed

+62
-67
lines changed

4 files changed

+62
-67
lines changed

pdal/plang/Environment.cpp

Lines changed: 52 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,25 @@ static void loadPython()
7979
}
8080
#endif
8181

82+
namespace
83+
{
84+
85+
std::string readPythonString(PyObject* dict, const std::string& key)
86+
{
87+
std::string s;
88+
89+
PyObject* o = PyDict_GetItemString(dict, key.c_str());
90+
if (o)
91+
{
92+
PyObject* r = PyObject_Str(o);
93+
if (r)
94+
s = PyUnicode_AsUTF8AndSize(r, NULL);
95+
}
96+
return s;
97+
}
98+
99+
} // unnamed namespace
100+
82101
// http://www.linuxjournal.com/article/3641
83102
// http://www.codeproject.com/Articles/11805/Embedding-Python-in-C-C-Part-I
84103
// http://stackoverflow.com/questions/6596016/python-threads-in-c
@@ -199,9 +218,9 @@ std::string getTraceback()
199218
PyObject* r = PyObject_Repr(l);
200219
if (!r)
201220
throw pdal::pdal_error("unable to get repr in getTraceback");
202-
Py_ssize_t size;
203-
const char *d = PyUnicode_AsUTF8AndSize(r, &size);
204-
mssg << d;
221+
const char *d = PyUnicode_AsUTF8AndSize(r, NULL);
222+
if (d)
223+
mssg << d;
205224
}
206225

207226
// clean up
@@ -213,9 +232,9 @@ std::string getTraceback()
213232
PyObject* r = PyObject_Repr(value);
214233
if (!r)
215234
throw pdal::pdal_error("couldn't make string representation of traceback value");
216-
Py_ssize_t size;
217-
const char *d = PyUnicode_AsUTF8AndSize(r, &size);
218-
mssg << d;
235+
const char *d = PyUnicode_AsUTF8AndSize(r, NULL);
236+
if (d)
237+
mssg << d;
219238
}
220239
else
221240
mssg << "unknown error that we are unable to get a traceback for."
@@ -231,21 +250,6 @@ std::string getTraceback()
231250
// Returns a new reference.
232251
PyObject *fromMetadata(MetadataNode m)
233252
{
234-
std::string name = m.name();
235-
std::string value = m.value();
236-
std::string type = m.type();
237-
std::string description = m.description();
238-
239-
MetadataNodeList children = m.children();
240-
PyObject *submeta(0);
241-
if (children.size())
242-
{
243-
submeta = PyList_New(0);
244-
for (MetadataNode& child : children)
245-
PyList_Append(submeta, fromMetadata(child));
246-
}
247-
PyObject *data = PyDict_New();
248-
249253
auto getString = [](const std::string& s)
250254
{
251255
PyObject *o = PyUnicode_FromString(s.data());
@@ -254,68 +258,59 @@ PyObject *fromMetadata(MetadataNode m)
254258
return o;
255259
};
256260

257-
PyDict_SetItemString(data, "name", getString(name));
258-
PyDict_SetItemString(data, "value", getString(value));
259-
PyDict_SetItemString(data, "type", getString(value));
260-
PyDict_SetItemString(data, "description", getString(description));
261+
PyObject *data = PyDict_New();
262+
263+
PyDict_SetItemString(data, "name", getString(m.name()));
264+
PyDict_SetItemString(data, "value", getString(m.value()));
265+
PyDict_SetItemString(data, "type", getString(m.type()));
266+
PyDict_SetItemString(data, "description", getString(m.description()));
261267

268+
MetadataNodeList children = m.children();
262269
if (children.size())
270+
{
271+
PyObject *submeta = PyList_New(0);
272+
for (MetadataNode& child : children)
273+
PyList_Append(submeta, fromMetadata(child));
263274
PyDict_SetItemString(data, "children", submeta);
275+
}
276+
264277
return data;
265278
}
266279

267-
std::string readPythonString(PyObject* dict, const std::string& key)
268-
{
269-
std::stringstream ss;
270280

271-
PyObject* o = PyDict_GetItemString(dict, key.c_str());
272-
if (!o)
273-
{
274-
std::stringstream oss;
275-
oss << "Unable to get dictionary item '" << key << "'";
276-
throw pdal_error(oss.str());
277-
}
278-
279-
PyObject* r = PyObject_Str(o);
280-
if (!r)
281-
throw pdal::pdal_error("unable to get repr in readPythonString");
282-
Py_ssize_t size;
283-
const char *d = PyUnicode_AsUTF8AndSize(r, &size);
284-
ss << d;
285-
286-
return ss.str();
287-
}
288281
void addMetadata(PyObject *dict, MetadataNode m)
289282
{
290283
if (!dict)
291-
{
292284
return;
293-
}
294285

295286
if (!PyDict_Check(dict))
296-
throw pdal::pdal_error("'metadata' member must be a dictionary!");
287+
throw pdal::pdal_error("Output metadata must be in a dictionary.");
297288

298289
std::string name = readPythonString(dict, "name");
299290
std::string value = readPythonString(dict, "value");
300-
301291
std::string type = readPythonString(dict, "type");
292+
std::string description = readPythonString(dict, "description");
293+
if (name.empty())
294+
return;
302295
if (type.empty())
303296
type = Metadata::inferType(value);
304297

305-
std::string description = readPythonString(dict, "description");
306-
298+
m.addWithType(name, value, type, description);
307299
PyObject *submeta = PyDict_GetItemString(dict, "children");
308300
if (submeta)
309301
{
310302
if (!PyList_Check(submeta))
311-
throw pdal::pdal_error("'children' metadata member must be a list!");
312-
313-
for (Py_ssize_t i = 0; i < PyList_Size(submeta); ++i)
303+
throw pdal::pdal_error("Ouput metadata 'children' must be a list.");
304+
Py_ssize_t size = PyList_Size(submeta);
305+
if (size)
314306
{
315-
PyObject* p = PyList_GetItem(submeta, i);
316-
addMetadata(p, m);
307+
m = m.add("children");
308+
for (Py_ssize_t i = 0; i < PyList_Size(submeta); ++i)
309+
{
310+
PyObject* p = PyList_GetItem(submeta, i);
311+
addMetadata(p, m);
312+
}
317313
}
318-
MetadataNode child = m.addWithType(name, value, type, description);
319314
}
320315
}
321316

pdal/plang/Invocation.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,10 @@ void Invocation::extractData(PointViewPtr& view, PyObject *arrays)
473473

474474
void Invocation::extractMetadata(MetadataNode stageMetadata)
475475
{
476-
PyObject *key = PyUnicode_FromString("metadata");
476+
PyObject *key = PyUnicode_FromString("out_metadata");
477477
PyObject *dictionary = PyModule_GetDict(m_module);
478478
PyObject *pyMeta = PyDict_GetItem(dictionary, key);
479-
if (pyMeta)
480-
addMetadata(pyMeta, stageMetadata);
479+
addMetadata(pyMeta, stageMetadata);
481480
Py_DECREF(key);
482481
}
483482

pdal/test/PythonFilterTest.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,9 @@ TEST_F(PythonFilterTest, metadata)
223223
"import sys\n"
224224
"import redirector\n"
225225
"def myfunc(ins,outs):\n"
226-
" global metadata\n"
226+
" global out_metadata\n"
227227
" #print('before', globals(), file=sys.stderr,)\n"
228-
" metadata = {'name': 'root', 'value': 'a string', 'type': 'string', 'description': 'a description', 'children': [{'name': 'filters.python', 'value': 52, 'type': 'integer', 'description': 'a filter description', 'children': []}, {'name': 'readers.faux', 'value': 'another string', 'type': 'string', 'description': 'a reader description', 'children': []}]}\n"
228+
" out_metadata = {'name': 'root', 'value': 'a string', 'type': 'string', 'description': 'a description', 'children': [{'name': 'somechildren', 'value': 52, 'type': 'integer', 'description': 'a filter description', 'children': []}, {'name': 'otherchildren', 'value': 'another string', 'type': 'string', 'description': 'a reader description', 'children': []}]}\n"
229229
" # print ('schema', schema, file=sys.stderr,)\n"
230230
" return True\n"
231231
);
@@ -250,10 +250,11 @@ TEST_F(PythonFilterTest, metadata)
250250
MetadataNode m = table.metadata();
251251
m = m.findChild("filters.python");
252252
MetadataNodeList l = m.children();
253-
EXPECT_EQ(l.size(), 3u);
254-
EXPECT_EQ(l[0].name(), "filters.python");
255-
EXPECT_EQ(l[0].value(), "52");
256-
EXPECT_EQ(l[0].description(), "a filter description");
253+
EXPECT_EQ(l.size(), 2u);
254+
m = m.findChild("children");
255+
EXPECT_EQ(m.children().size(), 2u);
256+
m = m.findChild("somechildren");
257+
EXPECT_EQ(m.value(), "52");
257258
}
258259

259260
TEST_F(PythonFilterTest, pdalargs)

test/test_pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ class TestDimensions(PDALTest):
228228
def test_fetch_dimensions(self):
229229
"""Ask PDAL for its valid dimensions list"""
230230
dims = pdal.dimensions
231-
self.assertLess(len(dims), 100)
231+
self.assertLess(len(dims), 120)
232232
self.assertGreater(len(dims), 71)
233233

234234
class TestMesh(PDALTest):

0 commit comments

Comments
 (0)