Skip to content

Commit

Permalink
geojsontojson: Add meta output, with output field coverage
Browse files Browse the repository at this point in the history
Helpful for
Open-Telecoms-Data/cove-ofds#6

Also fix: bug in get_json() that meant it could not be called twice
  • Loading branch information
odscjames committed Nov 7, 2022
1 parent dc834f6 commit 8c016ef
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Improved in GeoJSON to JSON:
- Makes Phases into references & populates phases array (Nodes, Spans)
- Makes Organisations into references & populates organisations array (Nodes, Spans)
- Add meta output, with output field coverage
- Fix bug that meant get_json() could not be called twice

### Changed

Expand Down
9 changes: 9 additions & 0 deletions libcoveofds/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ def main():
geojson_to_json_parser.add_argument(
"outputfilename", help="Output filename to write JSON data to"
)
geojson_to_json_parser.add_argument(
"--outputmetafilename",
help="Output filename to write meta JSON data to",
required=False,
)

args = parser.parse_args()

Expand Down Expand Up @@ -119,6 +124,10 @@ def main():
with open(args.outputfilename, "w") as fp:
json.dump(converter.get_json(), fp, indent=4)

if args.outputmetafilename:
with open(args.outputmetafilename, "w") as fp:
json.dump(converter.get_meta_json(), fp, indent=4)


if __name__ == "__main__":
main()
15 changes: 15 additions & 0 deletions libcoveofds/geojson.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import copy

from libcove2.common import fields_present_generator


class JSONToGeoJSONConverter:
def __init__(self):
Expand Down Expand Up @@ -268,6 +270,8 @@ def _process_organisation(self, network_id: str, organisation: dict) -> str:
def get_json(self) -> dict:
out: dict = {"networks": []}
for network in self._networks.values():
# We are going to change network, so we need to take a copy
network = copy.deepcopy(network)
# Arrays have minItems: 1 set - so if no content, remove the empty array
for key in ["nodes", "spans", "phases", "organisations", "contracts"]:
if not network[key]:
Expand All @@ -278,3 +282,14 @@ def get_json(self) -> dict:
network[key] = list(network[key].values())
out["networks"].append(network)
return out

def get_meta_json(self) -> dict:
out: dict = {"output_field_coverage": {}}
# field coverage
for key, value in fields_present_generator(self.get_json()):
if key not in out["output_field_coverage"]:
out["output_field_coverage"][key] = {"count": 1}
else:
out["output_field_coverage"][key]["count"] += 1
# return
return out
58 changes: 58 additions & 0 deletions tests/fixtures/geojson_to_json/basic_1.meta.expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"output_field_coverage": {
"/networks": {
"count": 1
},
"/networks/id": {
"count": 1
},
"/networks/name": {
"count": 1
},
"/networks/nodes": {
"count": 1
},
"/networks/nodes/id": {
"count": 2
},
"/networks/nodes/name": {
"count": 2
},
"/networks/nodes/location": {
"count": 2
},
"/networks/nodes/location/type": {
"count": 2
},
"/networks/nodes/location/coordinates": {
"count": 2
},
"/networks/nodes/status": {
"count": 1
},
"/networks/spans": {
"count": 1
},
"/networks/spans/id": {
"count": 1
},
"/networks/spans/name": {
"count": 1
},
"/networks/spans/start": {
"count": 1
},
"/networks/spans/end": {
"count": 1
},
"/networks/spans/route": {
"count": 1
},
"/networks/spans/route/type": {
"count": 1
},
"/networks/spans/route/coordinates": {
"count": 1
}
}
}
40 changes: 40 additions & 0 deletions tests/fixtures/geojson_to_json/no_geometry_1.meta.expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"output_field_coverage": {
"/networks": {
"count": 1
},
"/networks/id": {
"count": 1
},
"/networks/name": {
"count": 1
},
"/networks/nodes": {
"count": 1
},
"/networks/nodes/id": {
"count": 2
},
"/networks/nodes/name": {
"count": 2
},
"/networks/nodes/status": {
"count": 1
},
"/networks/spans": {
"count": 1
},
"/networks/spans/id": {
"count": 1
},
"/networks/spans/name": {
"count": 1
},
"/networks/spans/start": {
"count": 1
},
"/networks/spans/end": {
"count": 1
}
}
}
91 changes: 91 additions & 0 deletions tests/fixtures/geojson_to_json/organisations_1.meta.expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"output_field_coverage": {
"/networks": {
"count": 1
},
"/networks/id": {
"count": 1
},
"/networks/name": {
"count": 1
},
"/networks/nodes": {
"count": 1
},
"/networks/nodes/id": {
"count": 2
},
"/networks/nodes/name": {
"count": 2
},
"/networks/nodes/physicalInfrastructureProvider": {
"count": 2
},
"/networks/nodes/physicalInfrastructureProvider/id": {
"count": 2
},
"/networks/nodes/networkProvider": {
"count": 2
},
"/networks/nodes/networkProvider/id": {
"count": 2
},
"/networks/nodes/location": {
"count": 2
},
"/networks/nodes/location/type": {
"count": 2
},
"/networks/nodes/location/coordinates": {
"count": 2
},
"/networks/nodes/status": {
"count": 1
},
"/networks/spans": {
"count": 1
},
"/networks/spans/id": {
"count": 1
},
"/networks/spans/name": {
"count": 1
},
"/networks/spans/start": {
"count": 1
},
"/networks/spans/end": {
"count": 1
},
"/networks/spans/physicalInfrastructureProvider": {
"count": 1
},
"/networks/spans/physicalInfrastructureProvider/id": {
"count": 1
},
"/networks/spans/networkProvider": {
"count": 1
},
"/networks/spans/networkProvider/id": {
"count": 1
},
"/networks/spans/route": {
"count": 1
},
"/networks/spans/route/type": {
"count": 1
},
"/networks/spans/route/coordinates": {
"count": 1
},
"/networks/organisations": {
"count": 1
},
"/networks/organisations/id": {
"count": 2
},
"/networks/organisations/name": {
"count": 2
}
}
}
82 changes: 82 additions & 0 deletions tests/fixtures/geojson_to_json/phases_1.meta.expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"output_field_coverage": {
"/networks": {
"count": 1
},
"/networks/id": {
"count": 1
},
"/networks/name": {
"count": 1
},
"/networks/nodes": {
"count": 1
},
"/networks/nodes/id": {
"count": 2
},
"/networks/nodes/name": {
"count": 2
},
"/networks/nodes/phase": {
"count": 2
},
"/networks/nodes/phase/id": {
"count": 2
},
"/networks/nodes/location": {
"count": 2
},
"/networks/nodes/location/type": {
"count": 2
},
"/networks/nodes/location/coordinates": {
"count": 2
},
"/networks/nodes/status": {
"count": 1
},
"/networks/spans": {
"count": 1
},
"/networks/spans/id": {
"count": 1
},
"/networks/spans/name": {
"count": 1
},
"/networks/spans/start": {
"count": 1
},
"/networks/spans/end": {
"count": 1
},
"/networks/spans/phase": {
"count": 1
},
"/networks/spans/phase/id": {
"count": 1
},
"/networks/spans/route": {
"count": 1
},
"/networks/spans/route/type": {
"count": 1
},
"/networks/spans/route/coordinates": {
"count": 1
},
"/networks/phases": {
"count": 1
},
"/networks/phases/id": {
"count": 1
},
"/networks/phases/name": {
"count": 1
},
"/networks/phases/description": {
"count": 1
}
}
}
10 changes: 10 additions & 0 deletions tests/test_geojson_to_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ def test_geojson_to_json(filename):
"geojson_to_json",
filename + ".expected.json",
)
meta_expected_filename = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"fixtures",
"geojson_to_json",
filename + ".meta.expected.json",
)

with open(nodes_filename) as fp:
nodes_data = json.load(fp)
Expand All @@ -51,3 +57,7 @@ def test_geojson_to_json(filename):
with open(expected_filename) as fp:
expected_data = json.load(fp)
assert expected_data == converter.get_json()

with open(meta_expected_filename) as fp:
meta_expected_data = json.load(fp)
assert meta_expected_data == converter.get_meta_json()

0 comments on commit 8c016ef

Please sign in to comment.