• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenDataServices / flatten-tool / 6507626273

13 Oct 2023 11:25AM UTC coverage: 42.006% (-53.7%) from 95.72%
6507626273

Pull #433

github

odscjames
New "Geo" optional dependencies

https://github.com/OpenDataServices/flatten-tool/issues/424
Pull Request #433: New "Geo" optional dependencies

38 of 38 new or added lines in 6 files covered. (100.0%)

1466 of 3490 relevant lines covered (42.01%)

4.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

30.6
/flattentool/tests/test_json_input.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
10✔
3

4
import os
10✔
5
import sys
10✔
6
from collections import OrderedDict
10✔
7
from decimal import Decimal
10✔
8

9
import pytest
10✔
10

11
from flattentool.json_input import (
10✔
12
    BadlyFormedJSONError,
13
    BadlyFormedJSONErrorUTF8,
14
    JSONParser,
15
)
16
from flattentool.schema import SchemaParser
10✔
17
from flattentool.tests.test_schema_parser import object_in_array_example_properties
10✔
18

19

20
def listify(d):
10✔
21
    return {k: list(v) for k, v in d.items()}
10✔
22

23

24
def test_jsonparser_bad_json(tmpdir):
10✔
25
    test_json = tmpdir.join("test.json")
×
26
    test_json.write('{"a":"b",}')
×
27
    with pytest.raises(BadlyFormedJSONError):
×
28
        JSONParser(json_filename=test_json.strpath)
×
29
    # matches against Python base error type
30
    with pytest.raises(ValueError):
×
31
        JSONParser(json_filename=test_json.strpath)
×
32

33

34
def test_jsonparser_bad_json_utf8():
10✔
35
    name = os.path.join(
×
36
        os.path.dirname(os.path.realpath(__file__)), "fixtures", "bad-utf8.json"
37
    )
38
    # matches against the special error type
39
    with pytest.raises(BadlyFormedJSONErrorUTF8):
×
40
        JSONParser(json_filename=name)
×
41
    # matches against our base error type
42
    with pytest.raises(BadlyFormedJSONError):
×
43
        JSONParser(json_filename=name)
×
44
    # matches against Python base error type
45
    with pytest.raises(ValueError):
×
46
        JSONParser(json_filename=name)
×
47

48

49
def test_jsonparser_arguments_exceptions(tmpdir):
10✔
50
    """
51
    Test that JSONParser throws a ValueError if it receives too many or too few arguments.
52

53
    """
54
    test_json = tmpdir.join("test.json")
×
55
    test_json.write("{}")
×
56
    with pytest.raises(ValueError):
×
57
        JSONParser()
×
58
    with pytest.raises(ValueError):
×
59
        JSONParser(json_filename=test_json.strpath, root_json_dict={})
×
60

61

62
def test_json_filename(tmpdir):
10✔
63
    test_json = tmpdir.join("test.json")
×
64
    test_json.write('[{"a":"b"}]')
×
65
    parser = JSONParser(json_filename=test_json.strpath)
×
66
    assert list(parser.main_sheet.lines) == [{"a": "b"}]
×
67

68

69
def test_json_filename_utf8(tmpdir):
10✔
70
    test_json = tmpdir.join("test.json")
×
71
    test_json.write_text('[{"a":"éαГ😼𝒞人"}]', encoding="utf-8")
×
72
    parser = JSONParser(json_filename=test_json.strpath)
×
73
    assert list(parser.main_sheet.lines) == [{"a": "éαГ😼𝒞人"}]
×
74

75

76
def test_json_filename_ordered(tmpdir):
10✔
77
    test_json = tmpdir.join("test.json")
×
78
    test_json.write('[{"a":"b", "c": "d"}]')
×
79
    parser = JSONParser(json_filename=test_json.strpath)
×
80
    assert list(parser.main_sheet.lines) == [{"a": "b", "c": "d"}]
×
81

82

83
def test_parse_empty_json_dict():
10✔
84
    parser = JSONParser(root_json_dict={})
×
85
    assert list(parser.main_sheet) == []
×
86
    assert list(parser.main_sheet.lines) == []
×
87
    assert parser.sub_sheets == {}
×
88

89

90
def test_parse_basic_json_dict():
10✔
91
    parser = JSONParser(
×
92
        root_json_dict=[
93
            OrderedDict(
94
                [
95
                    ("a", "b"),
96
                    ("c", "d"),
97
                ]
98
            ),
99
            OrderedDict(
100
                [
101
                    ("a", "e"),
102
                    ("c", "f"),
103
                ]
104
            ),
105
        ]
106
    )
107
    assert list(parser.main_sheet) == ["a", "c"]
×
108
    assert list(parser.main_sheet.lines) == [
×
109
        {"a": "b", "c": "d"},
110
        {"a": "e", "c": "f"},
111
    ]
112
    assert parser.sub_sheets == {}
×
113

114

115
def test_parse_nested_dict_json_dict():
10✔
116
    parser = JSONParser(
×
117
        root_json_dict=[
118
            OrderedDict(
119
                [
120
                    ("a", "b"),
121
                    ("c", OrderedDict([("d", "e")])),
122
                ]
123
            )
124
        ]
125
    )
126
    assert list(parser.main_sheet) == ["a", "c/d"]
×
127
    assert list(parser.main_sheet.lines) == [{"a": "b", "c/d": "e"}]
×
128
    assert parser.sub_sheets == {}
×
129

130

131
def test_parse_nested_list_json_dict():
10✔
132
    parser = JSONParser(
×
133
        root_json_dict=[
134
            OrderedDict(
135
                [
136
                    ("a", "b"),
137
                    ("c", [OrderedDict([("d", "e")])]),
138
                ]
139
            )
140
        ]
141
    )
142
    assert list(parser.main_sheet) == ["a"]
×
143
    assert list(parser.main_sheet.lines) == [{"a": "b"}]
×
144
    assert listify(parser.sub_sheets) == {"c": ["c/0/d"]}
×
145
    assert list(parser.sub_sheets["c"].lines) == [{"c/0/d": "e"}]
×
146

147

148
def test_parse_array():
10✔
149
    parser = JSONParser(
×
150
        root_json_dict=[OrderedDict([("testarray", ["item", "anotheritem", 42])])]
151
    )
152
    assert list(parser.main_sheet) == ["testarray"]
×
153
    assert list(parser.main_sheet.lines) == [{"testarray": "item;anotheritem;42"}]
×
154
    assert parser.sub_sheets == {}
×
155

156

157
def test_parse_array_of_arrays():
10✔
158
    parser = JSONParser(
×
159
        root_json_dict=[
160
            OrderedDict([("testarray", [["item", "anotheritem", 42], ["a", "b", 1]])])
161
        ]
162
    )
163
    assert list(parser.main_sheet) == ["testarray"]
×
164
    assert list(parser.main_sheet.lines) == [{"testarray": "item,anotheritem,42;a,b,1"}]
×
165
    assert parser.sub_sheets == {}
×
166

167

168
def test_root_list_path():
10✔
169
    parser = JSONParser(
×
170
        root_json_dict={
171
            "custom_key": [
172
                OrderedDict(
173
                    [
174
                        ("a", "b"),
175
                        ("c", "d"),
176
                    ]
177
                )
178
            ]
179
        },
180
        root_list_path="custom_key",
181
    )
182
    assert list(parser.main_sheet) == ["a", "c"]
×
183
    assert list(parser.main_sheet.lines) == [{"a": "b", "c": "d"}]
×
184
    assert parser.sub_sheets == {}
×
185

186

187
class TestParseIDs(object):
10✔
188
    def test_parse_ids(self):
10✔
189
        parser = JSONParser(
×
190
            root_json_dict=[
191
                OrderedDict(
192
                    [
193
                        ("ocid", 1),
194
                        ("id", 2),
195
                        ("a", "b"),
196
                        (
197
                            "c",
198
                            [
199
                                OrderedDict([("id", 3), ("d", "e")]),
200
                                OrderedDict([("id", 3), ("d", "e2")]),
201
                            ],
202
                        ),
203
                        (
204
                            "f",
205
                            {"g": "h"},
206
                        ),  # Check that having nested objects doesn't break ID output
207
                    ]
208
                )
209
            ],
210
            root_id="ocid",
211
        )
212
        assert list(parser.main_sheet) == ["ocid", "id", "a", "f/g"]
×
213
        assert list(parser.main_sheet.lines) == [
×
214
            {"ocid": 1, "id": 2, "a": "b", "f/g": "h"}
215
        ]
216
        assert listify(parser.sub_sheets) == {"c": ["ocid", "id", "c/0/id", "c/0/d"]}
×
217
        assert list(parser.sub_sheets["c"].lines) == [
×
218
            {"ocid": 1, "id": 2, "c/0/id": 3, "c/0/d": "e"},
219
            {"ocid": 1, "id": 2, "c/0/id": 3, "c/0/d": "e2"},
220
        ]
221

222
    def test_parse_ids_subsheet(self):
10✔
223
        parser = JSONParser(
×
224
            root_json_dict=[
225
                OrderedDict(
226
                    [
227
                        ("ocid", 1),
228
                        ("id", 2),
229
                        (
230
                            "testnest",
231
                            [
232
                                OrderedDict(
233
                                    [
234
                                        ("id", 3),
235
                                        ("a", "b"),
236
                                        (
237
                                            "c",
238
                                            [
239
                                                OrderedDict([("d", "e")]),
240
                                                OrderedDict([("d", "e2")]),
241
                                            ],
242
                                        ),
243
                                        (
244
                                            "f",
245
                                            {"g": "h"},
246
                                        ),  # Check that having nested objects doesn't break ID output
247
                                    ]
248
                                )
249
                            ],
250
                        ),
251
                    ]
252
                )
253
            ],
254
            root_id="ocid",
255
        )
256
        assert list(parser.main_sheet) == ["ocid", "id"]
×
257
        assert list(parser.main_sheet.lines) == [
×
258
            {
259
                "ocid": 1,
260
                "id": 2,
261
            }
262
        ]
263
        assert listify(parser.sub_sheets) == {
×
264
            "testnest": [
265
                "ocid",
266
                "id",
267
                "testnest/0/id",
268
                "testnest/0/a",
269
                "testnest/0/f/g",
270
            ],
271
            "tes_c": ["ocid", "id", "testnest/0/id", "testnest/0/c/0/d"],
272
        }
273
        assert list(parser.sub_sheets["testnest"].lines) == [
×
274
            {
275
                "ocid": 1,
276
                "id": 2,
277
                "testnest/0/id": 3,
278
                "testnest/0/a": "b",
279
                "testnest/0/f/g": "h",
280
            },
281
        ]
282
        assert list(parser.sub_sheets["tes_c"].lines) == [
×
283
            {"ocid": 1, "id": 2, "testnest/0/id": 3, "testnest/0/c/0/d": "e"},
284
            {"ocid": 1, "id": 2, "testnest/0/id": 3, "testnest/0/c/0/d": "e2"},
285
        ]
286

287
    def test_parse_ids_nested(self):
10✔
288
        parser = JSONParser(
×
289
            root_json_dict=[
290
                OrderedDict(
291
                    [
292
                        ("ocid", 1),
293
                        ("id", 2),
294
                        ("a", "b"),
295
                        (
296
                            "testnest",
297
                            OrderedDict(
298
                                [
299
                                    ("id", 3),
300
                                    (
301
                                        "c",
302
                                        [
303
                                            OrderedDict([("d", "e")]),
304
                                            OrderedDict([("d", "e2")]),
305
                                        ],
306
                                    ),
307
                                ]
308
                            ),
309
                        ),
310
                        (
311
                            "f",
312
                            {"g": "h"},
313
                        ),  # Check that having nested objects doesn't break ID output
314
                    ]
315
                )
316
            ],
317
            root_id="ocid",
318
        )
319
        assert list(parser.main_sheet) == ["ocid", "id", "a", "testnest/id", "f/g"]
×
320
        assert list(parser.main_sheet.lines) == [
×
321
            {"ocid": 1, "id": 2, "a": "b", "testnest/id": 3, "f/g": "h"}
322
        ]
323
        assert listify(parser.sub_sheets) == {
×
324
            "tes_c": ["ocid", "id", "testnest/id", "testnest/c/0/d"]
325
        }
326
        assert list(parser.sub_sheets["tes_c"].lines) == [
×
327
            {"ocid": 1, "id": 2, "testnest/id": 3, "testnest/c/0/d": "e"},
328
            {"ocid": 1, "id": 2, "testnest/id": 3, "testnest/c/0/d": "e2"},
329
        ]
330

331

332
class TestParseUsingSchema(object):
10✔
333
    @pytest.mark.parametrize("remove_empty_schema_columns", [False, True])
10✔
334
    def test_sub_sheets(self, tmpdir, remove_empty_schema_columns):
8✔
335
        test_schema = tmpdir.join("test.json")
×
336
        test_schema.write(
×
337
            """{
338
            "properties": {
339
                "c": {
340
                    "type": "array",
341
                    "items": {"$ref": "#/testB"}
342
                },
343
                "g": {
344
                    "type": "array",
345
                    "items": {
346
                        "type": "object",
347
                        "properties": {
348
                            "h": { "type": "string"}
349
                        }
350
                    }
351
                }
352
            },
353
            "testB": {
354
                "type": "object",
355
                "properties": {
356
                    "d": { "type": "string" },
357
                    "f": { "type": "string" }
358
                }
359
            }
360
        }"""
361
        )
362
        schema_parser = SchemaParser(
×
363
            schema_filename=test_schema.strpath, root_id="ocid"
364
        )
365
        schema_parser.parse()
×
366
        parser = JSONParser(
×
367
            root_json_dict=[
368
                OrderedDict(
369
                    [
370
                        ("a", "b"),
371
                        ("c", [OrderedDict([("d", "e")])]),
372
                    ]
373
                )
374
            ],
375
            schema_parser=schema_parser,
376
            remove_empty_schema_columns=remove_empty_schema_columns,
377
        )
378
        assert list(parser.main_sheet) == ["a"]
×
379
        assert list(parser.main_sheet.lines) == [{"a": "b"}]
×
380
        assert len(parser.sub_sheets) == 2 if not remove_empty_schema_columns else 1
×
381
        if not remove_empty_schema_columns:
×
382
            assert list(parser.sub_sheets["c"]) == list(["ocid", "c/0/d", "c/0/f"])
×
383
            assert list(parser.sub_sheets["g"]) == list(["ocid", "g/0/h"])
×
384
        else:
385
            assert list(parser.sub_sheets["c"]) == list(["ocid", "c/0/d"])
×
386
        assert parser.sub_sheets["c"].lines == [{"c/0/d": "e"}]
×
387

388
    def test_column_matching(self, tmpdir):
10✔
389
        test_schema = tmpdir.join("test.json")
×
390
        test_schema.write(
×
391
            """{
392
            "properties": {
393
                "c": {
394
                    "type": "array",
395
                    "items": {"type": "string"}
396
                }
397
            }
398
        }"""
399
        )
400
        schema_parser = SchemaParser(schema_filename=test_schema.strpath)
×
401
        schema_parser.parse()
×
402
        parser = JSONParser(
×
403
            root_json_dict=[
404
                OrderedDict(
405
                    [
406
                        ("c", ["d"]),
407
                    ]
408
                )
409
            ],
410
            schema_parser=schema_parser,
411
        )
412
        assert list(parser.main_sheet) == ["c"]
×
413
        assert list(parser.main_sheet.lines) == [{"c": "d"}]
×
414
        assert len(parser.sub_sheets) == 0
×
415

416
    def test_rollup(self):
10✔
417
        schema_parser = SchemaParser(
×
418
            root_schema_dict={
419
                "properties": {
420
                    "testA": {
421
                        "type": "array",
422
                        "rollUp": ["testB"],
423
                        "items": {
424
                            "type": "object",
425
                            "properties": {
426
                                "testB": {"type": "string"},
427
                                "testC": {"type": "string"},
428
                            },
429
                        },
430
                    },
431
                }
432
            },
433
            rollup=True,
434
            root_id="ocid",
435
        )
436
        schema_parser.parse()
×
437
        parser = JSONParser(
×
438
            root_json_dict=[
439
                OrderedDict(
440
                    [
441
                        ("testA", [OrderedDict([("testB", "1"), ("testC", "2")])]),
442
                    ]
443
                )
444
            ],
445
            schema_parser=schema_parser,
446
            root_id="ocid",
447
            rollup=True,
448
        )
449
        assert list(parser.main_sheet) == ["testA/0/testB"]
×
450
        assert list(parser.main_sheet.lines) == [{"testA/0/testB": "1"}]
×
451
        assert len(parser.sub_sheets) == 1
×
452
        assert set(parser.sub_sheets["testA"]) == set(
×
453
            ["ocid", "testA/0/testB", "testA/0/testC"]
454
        )
455
        assert parser.sub_sheets["testA"].lines == [
×
456
            {"testA/0/testB": "1", "testA/0/testC": "2"}
457
        ]
458

459
    def test_rollup_multiple_values(self, recwarn):
10✔
460
        schema_parser = SchemaParser(
×
461
            root_schema_dict={
462
                "properties": {
463
                    "testA": {
464
                        "type": "array",
465
                        "rollUp": ["testB"],
466
                        "items": {
467
                            "type": "object",
468
                            "properties": {
469
                                "testB": {"type": "string"},
470
                                "testC": {"type": "string"},
471
                            },
472
                        },
473
                    },
474
                }
475
            },
476
            rollup=True,
477
        )
478
        schema_parser.parse()
×
479
        parser = JSONParser(
×
480
            root_json_dict=[
481
                OrderedDict(
482
                    [
483
                        (
484
                            "testA",
485
                            [
486
                                OrderedDict([("testB", "1"), ("testC", "2")]),
487
                                OrderedDict([("testB", "3"), ("testC", "4")]),
488
                            ],
489
                        ),
490
                    ]
491
                )
492
            ],
493
            schema_parser=schema_parser,
494
            rollup=True,
495
        )
496
        assert list(parser.main_sheet) == ["testA/0/testB"]
×
497
        assert list(parser.main_sheet.lines) == [
×
498
            {
499
                "testA/0/testB": "WARNING: More than one value supplied, consult the relevant sub-sheet for the data."
500
            }
501
        ]
502
        assert len(parser.sub_sheets) == 1
×
503
        assert set(parser.sub_sheets["testA"]) == set(
×
504
            ["testA/0/testB", "testA/0/testC"]
505
        )
506
        assert parser.sub_sheets["testA"].lines == [
×
507
            {"testA/0/testB": "1", "testA/0/testC": "2"},
508
            {"testA/0/testB": "3", "testA/0/testC": "4"},
509
        ]
510
        w = recwarn.pop(UserWarning)
×
511
        assert "Could not provide rollup" in str(w.message)
×
512

513
    def test_two_parents(self):
10✔
514
        # This is a copy of test_two_parents from test_schema_parser.py, in
515
        # order to check that flattening and template generation use the same
516
        # sheet names
517
        schema_parser = SchemaParser(
×
518
            root_schema_dict={
519
                "properties": OrderedDict(
520
                    [
521
                        (
522
                            "Atest",
523
                            {
524
                                "type": "array",
525
                                "items": {
526
                                    "type": "object",
527
                                    "properties": object_in_array_example_properties(
528
                                        "Btest", "Ctest"
529
                                    ),
530
                                },
531
                            },
532
                        ),
533
                        (
534
                            "Dtest",
535
                            {
536
                                "type": "array",
537
                                "items": {
538
                                    "type": "object",
539
                                    "properties": object_in_array_example_properties(
540
                                        "Btest", "Etest"
541
                                    ),
542
                                },
543
                            },
544
                        ),
545
                    ]
546
                )
547
            }
548
        )
549
        schema_parser.parse()
×
550
        parser = JSONParser(
×
551
            root_json_dict=[
552
                {
553
                    "Atest": [{"id": 1, "Btest": [{"Ctest": 2}]}],
554
                    "Dtest": [{"id": 3, "Btest": [{"Etest": 4}]}],
555
                }
556
            ],
557
            schema_parser=schema_parser,
558
        )
559
        assert set(parser.main_sheet) == set()
×
560
        assert set(parser.sub_sheets) == set(
×
561
            ["Atest", "Dtest", "Ate_Btest", "Dte_Btest"]
562
        )
563
        assert list(parser.sub_sheets["Atest"]) == ["Atest/0/id"]
×
564
        assert list(parser.sub_sheets["Dtest"]) == ["Dtest/0/id"]
×
565
        assert list(parser.sub_sheets["Ate_Btest"]) == [
×
566
            "Atest/0/id",
567
            "Atest/0/Btest/0/Ctest",
568
        ]
569
        assert list(parser.sub_sheets["Dte_Btest"]) == [
×
570
            "Dtest/0/id",
571
            "Dtest/0/Btest/0/Etest",
572
        ]
573

574

575
# TODO Check support for decimals, integers, booleans and Nones
576

577

578
class TestParseIDsCustomRootID(object):
10✔
579
    def test_parse_ids(self):
10✔
580
        parser = JSONParser(
×
581
            root_json_dict=[
582
                OrderedDict(
583
                    [
584
                        ("custom", 1),
585
                        ("id", 2),
586
                        ("a", "b"),
587
                        (
588
                            "c",
589
                            [
590
                                OrderedDict([("id", 3), ("d", "e")]),
591
                                OrderedDict([("id", 3), ("d", "e2")]),
592
                            ],
593
                        ),
594
                        (
595
                            "f",
596
                            {"g": "h"},
597
                        ),  # Check that having nested objects doesn't break ID output
598
                    ]
599
                )
600
            ],
601
            root_id="custom",
602
        )
603
        assert list(parser.main_sheet) == ["custom", "id", "a", "f/g"]
×
604
        assert list(parser.main_sheet.lines) == [
×
605
            {"custom": 1, "id": 2, "a": "b", "f/g": "h"}
606
        ]
607
        assert listify(parser.sub_sheets) == {"c": ["custom", "id", "c/0/id", "c/0/d"]}
×
608
        assert list(parser.sub_sheets["c"].lines) == [
×
609
            {"custom": 1, "id": 2, "c/0/id": 3, "c/0/d": "e"},
610
            {"custom": 1, "id": 2, "c/0/id": 3, "c/0/d": "e2"},
611
        ]
612

613
    def test_parse_ids_subsheet(self):
10✔
614
        parser = JSONParser(
×
615
            root_json_dict=[
616
                OrderedDict(
617
                    [
618
                        ("custom", 1),
619
                        ("id", 2),
620
                        (
621
                            "testnest",
622
                            [
623
                                OrderedDict(
624
                                    [
625
                                        ("id", 3),
626
                                        ("a", "b"),
627
                                        (
628
                                            "c",
629
                                            [
630
                                                OrderedDict([("d", "e")]),
631
                                                OrderedDict([("d", "e2")]),
632
                                            ],
633
                                        ),
634
                                        (
635
                                            "f",
636
                                            {"g": "h"},
637
                                        ),  # Check that having nested objects doesn't break ID output
638
                                    ]
639
                                )
640
                            ],
641
                        ),
642
                    ]
643
                )
644
            ],
645
            root_id="custom",
646
        )
647
        assert list(parser.main_sheet) == ["custom", "id"]
×
648
        assert list(parser.main_sheet.lines) == [
×
649
            {
650
                "custom": 1,
651
                "id": 2,
652
            }
653
        ]
654
        assert listify(parser.sub_sheets) == {
×
655
            "testnest": [
656
                "custom",
657
                "id",
658
                "testnest/0/id",
659
                "testnest/0/a",
660
                "testnest/0/f/g",
661
            ],
662
            "tes_c": ["custom", "id", "testnest/0/id", "testnest/0/c/0/d"],
663
        }
664
        assert list(parser.sub_sheets["testnest"].lines) == [
×
665
            {
666
                "custom": 1,
667
                "id": 2,
668
                "testnest/0/id": 3,
669
                "testnest/0/a": "b",
670
                "testnest/0/f/g": "h",
671
            },
672
        ]
673
        assert list(parser.sub_sheets["tes_c"].lines) == [
×
674
            {"custom": 1, "id": 2, "testnest/0/id": 3, "testnest/0/c/0/d": "e"},
675
            {"custom": 1, "id": 2, "testnest/0/id": 3, "testnest/0/c/0/d": "e2"},
676
        ]
677

678
    def test_parse_ids_nested(self):
10✔
679
        parser = JSONParser(
×
680
            root_json_dict=[
681
                OrderedDict(
682
                    [
683
                        ("custom", 1),
684
                        ("id", 2),
685
                        ("a", "b"),
686
                        (
687
                            "testnest",
688
                            OrderedDict(
689
                                [
690
                                    ("id", 3),
691
                                    (
692
                                        "c",
693
                                        [
694
                                            OrderedDict([("d", "e")]),
695
                                            OrderedDict([("d", "e2")]),
696
                                        ],
697
                                    ),
698
                                ]
699
                            ),
700
                        ),
701
                        (
702
                            "f",
703
                            {"g": "h"},
704
                        ),  # Check that having nested objects doesn't break ID output
705
                    ]
706
                )
707
            ],
708
            root_id="custom",
709
        )
710
        assert list(parser.main_sheet) == ["custom", "id", "a", "testnest/id", "f/g"]
×
711
        assert list(parser.main_sheet.lines) == [
×
712
            {"custom": 1, "id": 2, "a": "b", "testnest/id": 3, "f/g": "h"}
713
        ]
714
        assert listify(parser.sub_sheets) == {
×
715
            "tes_c": ["custom", "id", "testnest/id", "testnest/c/0/d"]
716
        }
717
        assert list(parser.sub_sheets["tes_c"].lines) == [
×
718
            {"custom": 1, "id": 2, "testnest/id": 3, "testnest/c/0/d": "e"},
719
            {"custom": 1, "id": 2, "testnest/id": 3, "testnest/c/0/d": "e2"},
720
        ]
721

722

723
class TestParseIDsNoRootID(object):
10✔
724
    def test_parse_ids(self):
10✔
725
        parser = JSONParser(
×
726
            root_json_dict=[
727
                OrderedDict(
728
                    [
729
                        ("id", 2),
730
                        ("a", "b"),
731
                        (
732
                            "c",
733
                            [
734
                                OrderedDict([("id", 3), ("d", "e")]),
735
                                OrderedDict([("id", 3), ("d", "e2")]),
736
                            ],
737
                        ),
738
                        (
739
                            "f",
740
                            {"g": "h"},
741
                        ),  # Check that having nested objects doesn't break ID output
742
                    ]
743
                )
744
            ],
745
            root_id="",
746
        )
747
        assert list(parser.main_sheet) == ["id", "a", "f/g"]
×
748
        assert list(parser.main_sheet.lines) == [{"id": 2, "a": "b", "f/g": "h"}]
×
749
        assert listify(parser.sub_sheets) == {"c": ["id", "c/0/id", "c/0/d"]}
×
750
        assert list(parser.sub_sheets["c"].lines) == [
×
751
            {"id": 2, "c/0/id": 3, "c/0/d": "e"},
752
            {"id": 2, "c/0/id": 3, "c/0/d": "e2"},
753
        ]
754

755
    def test_parse_ids_subsheet(self):
10✔
756
        parser = JSONParser(
×
757
            root_json_dict=[
758
                OrderedDict(
759
                    [
760
                        ("id", 2),
761
                        (
762
                            "testnest",
763
                            [
764
                                OrderedDict(
765
                                    [
766
                                        ("id", 3),
767
                                        ("a", "b"),
768
                                        (
769
                                            "c",
770
                                            [
771
                                                OrderedDict([("d", "e")]),
772
                                                OrderedDict([("d", "e2")]),
773
                                            ],
774
                                        ),
775
                                        (
776
                                            "f",
777
                                            {"g": "h"},
778
                                        ),  # Check that having nested objects doesn't break ID output
779
                                    ]
780
                                )
781
                            ],
782
                        ),
783
                    ]
784
                )
785
            ],
786
            root_id="",
787
        )
788
        assert list(parser.main_sheet) == ["id"]
×
789
        assert list(parser.main_sheet.lines) == [
×
790
            {
791
                "id": 2,
792
            }
793
        ]
794
        assert listify(parser.sub_sheets) == {
×
795
            "testnest": ["id", "testnest/0/id", "testnest/0/a", "testnest/0/f/g"],
796
            "tes_c": ["id", "testnest/0/id", "testnest/0/c/0/d"],
797
        }
798
        assert list(parser.sub_sheets["testnest"].lines) == [
×
799
            {
800
                "id": 2,
801
                "testnest/0/id": 3,
802
                "testnest/0/a": "b",
803
                "testnest/0/f/g": "h",
804
            },
805
        ]
806
        assert list(parser.sub_sheets["tes_c"].lines) == [
×
807
            {"id": 2, "testnest/0/id": 3, "testnest/0/c/0/d": "e"},
808
            {"id": 2, "testnest/0/id": 3, "testnest/0/c/0/d": "e2"},
809
        ]
810

811
    def test_parse_ids_nested(self):
10✔
812
        parser = JSONParser(
×
813
            root_json_dict=[
814
                OrderedDict(
815
                    [
816
                        ("id", 2),
817
                        ("a", "b"),
818
                        (
819
                            "testnest",
820
                            OrderedDict(
821
                                [
822
                                    ("id", 3),
823
                                    (
824
                                        "c",
825
                                        [
826
                                            OrderedDict([("d", "e")]),
827
                                            OrderedDict([("d", "e2")]),
828
                                        ],
829
                                    ),
830
                                ]
831
                            ),
832
                        ),
833
                        (
834
                            "f",
835
                            {"g": "h"},
836
                        ),  # Check that having nested objects doesn't break ID output
837
                    ]
838
                )
839
            ],
840
            root_id="",
841
        )
842
        assert list(parser.main_sheet) == ["id", "a", "testnest/id", "f/g"]
×
843
        assert list(parser.main_sheet.lines) == [
×
844
            {"id": 2, "a": "b", "testnest/id": 3, "f/g": "h"}
845
        ]
846
        assert listify(parser.sub_sheets) == {
×
847
            "tes_c": ["id", "testnest/id", "testnest/c/0/d"]
848
        }
849
        assert list(parser.sub_sheets["tes_c"].lines) == [
×
850
            {"id": 2, "testnest/id": 3, "testnest/c/0/d": "e"},
851
            {"id": 2, "testnest/id": 3, "testnest/c/0/d": "e2"},
852
        ]
853

854

855
@pytest.mark.geo
10✔
856
def test_parse_geojson():
8✔
857
    parser = JSONParser(
10✔
858
        root_json_dict=[
859
            {
860
                "a": "b",
861
                "c": [
862
                    {
863
                        "d": {
864
                            "type": "Point",
865
                            "coordinates": [Decimal("53.486434"), Decimal("-2.239353")],
866
                        }
867
                    },
868
                    {
869
                        "d": {
870
                            "type": "LineString",
871
                            "coordinates": [
872
                                [Decimal("-0.173"), Decimal("5.626")],
873
                                [Decimal("-0.178"), Decimal("5.807")],
874
                                [Decimal("-0.112"), Decimal("5.971")],
875
                                [Decimal("-0.211"), Decimal("5.963")],
876
                                [Decimal("-0.321"), Decimal("6.17")],
877
                                [Decimal("-0.488"), Decimal("6.29")],
878
                                [Decimal("-0.560"), Decimal("6.421")],
879
                                [Decimal("-0.752"), Decimal("6.533")],
880
                                [Decimal("-0.867"), Decimal("6.607")],
881
                                [Decimal("-1.101"), Decimal("6.585")],
882
                                [Decimal("-1.304"), Decimal("6.623")],
883
                                [Decimal("-1.461"), Decimal("6.727")],
884
                                [Decimal("-1.628"), Decimal("6.713")],
885
                            ],
886
                        }
887
                    },
888
                ],
889
            }
890
        ],
891
        convert_flags={"wkt": True},
892
    )
893
    assert list(parser.main_sheet) == ["a"]
10✔
894
    assert list(parser.main_sheet.lines) == [{"a": "b"}]
10✔
895
    assert listify(parser.sub_sheets) == {"c": ["c/0/d"]}
10✔
896
    assert list(parser.sub_sheets["c"].lines) == [
10✔
897
        {"c/0/d": "POINT (53.486434 -2.239353)"},
898
        {
899
            "c/0/d": "LINESTRING (-0.173 5.626, -0.178 5.807, -0.112 5.971, -0.211 5.963, -0.321 6.17, -0.488 6.29, -0.56 6.421, -0.752 6.533, -0.867 6.607, -1.101 6.585, -1.304 6.623, -1.461 6.727, -1.628 6.713)"
900
        },
901
    ]
902

903

904
@pytest.mark.geo
10✔
905
def test_parse_bad_geojson(recwarn):
8✔
906
    parser = JSONParser(
10✔
907
        root_json_dict=[
908
            {
909
                "a": "b",
910
                "c": [
911
                    {
912
                        "d": {
913
                            "type": "test",
914
                            "coordinates": [],
915
                        }
916
                    },
917
                    {
918
                        "d": {
919
                            "type": "Point",
920
                            "coordinates": [],
921
                        }
922
                    },
923
                    {
924
                        "d": {
925
                            "type": "Point",
926
                            "coordinates": "test",
927
                        }
928
                    },
929
                    {
930
                        "d": {
931
                            "type": "Point",
932
                            "coordinates": 3,
933
                        }
934
                    },
935
                    {
936
                        "d": {
937
                            "type": "Point",
938
                            "coordinates": [Decimal("53.486434")],
939
                        }
940
                    },
941
                    {
942
                        "d": {
943
                            "type": "LineString",
944
                            "coordinates": [
945
                                [Decimal("-0.173"), Decimal("5.626")],
946
                                [Decimal("-0.178")],
947
                                [Decimal("-0.112"), Decimal("5.971")],
948
                            ],
949
                        }
950
                    },
951
                ],
952
            }
953
        ],
954
        convert_flags={"wkt": True},
955
    )
956
    assert list(parser.main_sheet) == ["a"]
10✔
957
    assert list(parser.main_sheet.lines) == [{"a": "b"}]
10✔
958
    assert listify(parser.sub_sheets) == {"c": ["c/0/d"]}
10✔
959
    assert list(parser.sub_sheets["c"].lines) == [
10✔
960
        {},
961
        {"c/0/d": "POINT EMPTY"},
962
        {},
963
        {},
964
        {},
965
        {},
966
    ]
967
    w = recwarn.pop(UserWarning)
10✔
968
    assert (
10✔
969
        str(w.message)
970
        == "Invalid GeoJSON: GeometryTypeError(\"Unknown geometry type: 'test'\")"
971
    )
972
    w = recwarn.pop(UserWarning)
10✔
973
    assert str(w.message) == "Invalid GeoJSON: TypeError('iteration over a 0-d array')"
10✔
974
    w = recwarn.pop(UserWarning)
10✔
975
    assert (
10✔
976
        str(w.message) == "Invalid GeoJSON: TypeError(\"'int' object is not iterable\")"
977
    )
978
    w = recwarn.pop(UserWarning)
10✔
979
    # There are different warning messages for Python versions before 3.8. This
980
    # is because an old version of numpy is installed (the last compatible with
981
    # these versions of Python), which has different messages.
982
    if sys.version_info < (3, 8):
10✔
983
        assert (
2✔
984
            str(w.message)
985
            == "Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray."
986
        )
987
        w = recwarn.pop(UserWarning)
2✔
988
        assert (
2✔
989
            str(w.message)
990
            == "Invalid GeoJSON: ValueError('linestrings: Input operand 0 does not have enough dimensions (has 1, gufunc core with signature (i, d)->() requires 2)')"
991
        )
992
    else:
993
        assert (
8✔
994
            str(w.message)
995
            == "Invalid GeoJSON: ValueError('setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (3,) + inhomogeneous part.')"
996
        )
997
    assert len(recwarn.list) == 0
10✔
998

999

1000
def test_parse_geojson_wkt_off():
10✔
1001
    parser = JSONParser(
×
1002
        root_json_dict=[
1003
            {
1004
                "a": "b",
1005
                "c": [
1006
                    {
1007
                        "d": {
1008
                            "type": "Point",
1009
                            "coordinates": [Decimal("53.486434"), Decimal("-2.239353")],
1010
                        }
1011
                    },
1012
                    {
1013
                        "d": {
1014
                            "type": "LineString",
1015
                            "coordinates": [
1016
                                [Decimal("-0.173"), Decimal("5.626")],
1017
                                [Decimal("-0.178"), Decimal("5.807")],
1018
                                [Decimal("-0.112"), Decimal("5.971")],
1019
                                [Decimal("-0.211"), Decimal("5.963")],
1020
                                [Decimal("-0.321"), Decimal("6.17")],
1021
                                [Decimal("-0.488"), Decimal("6.29")],
1022
                                [Decimal("-0.560"), Decimal("6.421")],
1023
                                [Decimal("-0.752"), Decimal("6.533")],
1024
                                [Decimal("-0.867"), Decimal("6.607")],
1025
                                [Decimal("-1.101"), Decimal("6.585")],
1026
                                [Decimal("-1.304"), Decimal("6.623")],
1027
                                [Decimal("-1.461"), Decimal("6.727")],
1028
                                [Decimal("-1.628"), Decimal("6.713")],
1029
                            ],
1030
                        }
1031
                    },
1032
                ],
1033
            }
1034
        ],
1035
        convert_flags={"wkt": False},
1036
    )
1037
    assert list(parser.main_sheet) == ["a"]
×
1038
    assert list(parser.main_sheet.lines) == [{"a": "b"}]
×
1039
    assert listify(parser.sub_sheets) == {"c": ["c/0/d/type", "c/0/d/coordinates"]}
×
1040
    assert list(parser.sub_sheets["c"].lines) == [
×
1041
        {"c/0/d/type": "Point", "c/0/d/coordinates": "53.486434;-2.239353"},
1042
        {
1043
            "c/0/d/type": "LineString",
1044
            "c/0/d/coordinates": "-0.173,5.626;-0.178,5.807;-0.112,5.971;-0.211,5.963;-0.321,6.17;-0.488,6.29;-0.560,6.421;-0.752,6.533;-0.867,6.607;-1.101,6.585;-1.304,6.623;-1.461,6.727;-1.628,6.713",
1045
        },
1046
    ]
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc