-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from osm-without-borders/test_with_pandas
check number of zones by country - POC
- Loading branch information
Showing
9 changed files
with
678 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
__pycache__ | ||
.pytest_cache | ||
data_volumetric.csv | ||
data_volumetric.json | ||
cosmogony.geojson |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[[source]] | ||
|
||
name = "pypi" | ||
url = "https://pypi.python.org/simple" | ||
verify_ssl = true | ||
|
||
|
||
[packages] | ||
|
||
matplotlib = "*" | ||
pandas = "*" | ||
geopandas = "*" | ||
pytest = "*" | ||
ijson = "*" | ||
ipython = "*" | ||
cffi = "*" | ||
|
||
[dev-packages] |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# coding: utf-8 | ||
import pandas as pd | ||
|
||
from utils import ZonesIndex | ||
|
||
|
||
def pytest_addoption(parser): | ||
parser.addoption("--cosmogony", action="store", required=True, | ||
help="a cosmogony json file") | ||
|
||
def pytest_generate_tests(metafunc): | ||
cosmogony_path = metafunc.config.getoption('cosmogony') | ||
zones_index = ZonesIndex.init_from_cosmogony(cosmogony_path) | ||
|
||
expected_values = pd.read_csv('reference_stats_values.csv') | ||
rows = (row for idx,row in expected_values.iterrows()) | ||
|
||
if 'line' in metafunc.fixturenames: | ||
metafunc.parametrize('line', rows) | ||
if 'zones_index' in metafunc.fixturenames: | ||
metafunc.parametrize('zones_index', [zones_index]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Volumetric Data Dashboard</title> | ||
<meta charset='utf-8'/> | ||
<meta name='viewport' content='initial-scale=1,user-scalable=yes'/> | ||
<style> | ||
table, | ||
td, | ||
th { | ||
margin: 10px 0; | ||
padding: 2px 4px; | ||
text-align: center; | ||
border-collapse: collapse; | ||
} | ||
td, | ||
th { | ||
border: 1px solid black; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<table id="volumetric-dashboard" class="sort"></table> | ||
<script> | ||
fetch(`data_volumetric.json`).then((r) => r.json()).then((data) => { | ||
var table = document.getElementById('volumetric-dashboard'); | ||
|
||
var col = ['name', 'zone_type', 'result', 'status'] | ||
|
||
for (var i = 0; i < data.length; i++) { | ||
var result_text = `${ (data[i]['total'] != -1) | ||
? data[i]['total'] | ||
: "??"} ` | ||
result_text += `<br>(expected : ${data[i]['expected_min']} ~ ${data[i]['expected_max']})` | ||
|
||
var status = '' | ||
if (data[i]['test_status'] == 'ok') { | ||
status = '✅' | ||
status += (data[i]['is_known_failure'] == "yes") | ||
? " 😍 " | ||
: "✅"; | ||
} | ||
if (data[i]['test_status'] == 'ko') { | ||
status += (data[i]['is_known_failure'] == "yes") | ||
? "📉" | ||
: "❎❎"; | ||
} | ||
if (data[i]['test_status'] == 'skip') { | ||
status = '🤔' | ||
} | ||
|
||
var tr = table.insertRow(-1); | ||
tr.insertCell(-1).innerHTML = data[i]['name'] | ||
tr.insertCell(-1).innerHTML = data[i]['zone_type'] | ||
var tabCell = tr.insertCell(-1); | ||
tabCell.innerHTML = result_text; | ||
tr.insertCell(-1).innerHTML = status | ||
|
||
} | ||
var header = table.createTHead(); | ||
var trh = header.insertRow(0); | ||
for (var i = 0; i < col.length; i++) { | ||
var th = document.createElement("th"); | ||
th.innerHTML = col[i]; | ||
trh.appendChild(th); | ||
} | ||
|
||
}) | ||
</script> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# coding: utf-8 | ||
import pandas as pd | ||
import json | ||
import csv | ||
import pytest | ||
|
||
from utils import UnknownWikidataId | ||
|
||
def check_if_test_passes(expected_min, expected_max, total): | ||
if expected_min <= total <= expected_max: | ||
return "ok" | ||
else: | ||
return "ko" | ||
|
||
class TestCosmogony: | ||
@classmethod | ||
def setup_class(cls): | ||
cls.results = pd.DataFrame() | ||
|
||
@classmethod | ||
def teardown_class(cls): | ||
cls.results.to_json('data_volumetric.json', orient='records') | ||
|
||
def test_row(self, line, zones_index): | ||
try: | ||
matched_zones = list(zones_index.iter_children( | ||
line['wikidata_id'], | ||
lambda z:z['zone_type']==line['zone_type'] | ||
)) | ||
except UnknownWikidataId: | ||
total = -1 | ||
test_status = 'skip' | ||
else: | ||
total = len(matched_zones) | ||
test_status = check_if_test_passes(line.expected_min, line.expected_max, total) | ||
|
||
line['total'] = total | ||
line['test_status'] = test_status | ||
TestCosmogony.results = TestCosmogony.results.append(line) | ||
|
||
if test_status == 'skip': | ||
pytest.skip("no data for this test") | ||
|
||
assert(test_status == "ok"), "Country {} - expected between {} and {} for {}, found {}".format( | ||
line['name'], line['expected_min'], line['expected_max'], line['zone_type'], total) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .index import ZonesIndex, UnknownWikidataId |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from collections import defaultdict | ||
|
||
import ijson.backends.yajl2_cffi as ijson | ||
|
||
|
||
class UnknownWikidataId(Exception): | ||
pass | ||
|
||
class ZonesIndex: | ||
""" | ||
Index cosmogony zones both by internal `id` and wikidata id | ||
""" | ||
@classmethod | ||
def init_from_cosmogony(cls, cosmogony_path): | ||
zones_index = cls() | ||
|
||
print('Reading zones...') | ||
with open(cosmogony_path, 'rb') as f: | ||
zones = ijson.items(f, 'zones.item') | ||
for z in zones: | ||
z.pop('geometry', None) | ||
zones_index.insert(z) | ||
print('{} zones have been read'.format(len(zones_index))) | ||
|
||
zones_index.build_children() | ||
return zones_index | ||
|
||
def __init__(self): | ||
self.id_to_zone = dict() | ||
self.wd_to_zone = dict() | ||
self.id_to_children = defaultdict(list) | ||
|
||
def insert(self, zone): | ||
self.id_to_zone[zone['id']] = zone | ||
wikidata_id = zone.get('wikidata') | ||
if wikidata_id: | ||
self.wd_to_zone[wikidata_id] = zone | ||
|
||
def build_children(self): | ||
for z in self.id_to_zone.values(): | ||
parent_id = z.get('parent') | ||
if parent_id: | ||
self.id_to_children[parent_id].append(z) | ||
|
||
def _iter_all_children(self, zone): | ||
children = self.id_to_children[zone['id']] | ||
for c in children: | ||
yield c | ||
yield from self._iter_all_children(c) | ||
|
||
def iter_children(self, wikidata_id, filter_fun=lambda x: True): | ||
try: | ||
zone = self.wd_to_zone[wikidata_id] | ||
except KeyError as e: | ||
raise UnknownWikidataId from e | ||
|
||
return filter(filter_fun, self._iter_all_children(zone)) | ||
|
||
def __len__(self): | ||
return len(self.id_to_zone) |