Skip to content

Commit 505b9db

Browse files
committed
updating state machine in schemas
* use new field names and plurality * common state and event defintions merged by schema generator * valid state/event combinations merged by schema generator
1 parent 4dae43a commit 505b9db

8 files changed

Lines changed: 360 additions & 208 deletions

File tree

agency/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ A vehicle record is as follows:
7676
| `mfgr` | String | Vehicle Manufacturer |
7777
| `model` | String | Vehicle Model |
7878
| `state` | Enum | Current vehicle state. See [Vehicle State][vehicle-states] |
79-
| `prev_event` | Enum | Last [Vehicle Event][vehicle-event] |
79+
| `prev_events` | Enum[] | Last [Vehicle Event][vehicle-event] |
8080
| `updated` | [timestamp][ts] | Date of last event update |
8181

8282
404 Failure Response:

provider/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ Unless stated otherwise by the municipality, this endpoint must return only thos
266266
| `vehicle_type` | Enum | Required | see [vehicle types][vehicle-types] table |
267267
| `propulsion_types` | Enum[] | Required | Array of [propulsion types][propulsion-types]; allows multiple values |
268268
| `vehicle_state` | Enum | Required | See [vehicle state][vehicle-states] table |
269-
| `event_type` | Enum[] | Required | [Vehicle event(s)][vehicle-events] for state change, allowable values determined by `vehicle_state`. |
269+
| `event_types` | Enum[] | Required | [Vehicle event(s)][vehicle-events] for state change, allowable values determined by `vehicle_state` |
270270
| `event_time` | [timestamp][ts] | Required | Date/time that event occurred at. See [Event Times][event-times] |
271271
| `publication_time` | [timestamp][ts] | Optional | Date/time that event became available through the status changes endpoint |
272272
| `event_location` | GeoJSON [Point Feature][geo] | Required | |
@@ -398,8 +398,8 @@ In addition to the standard [Provider payload wrapper](#response-format), respon
398398
| `vehicle_type` | Enum | Required | see [vehicle types][vehicle-types] table |
399399
| `propulsion_types` | Enum[] | Required | Array of [propulsion types][propulsion-types]; allows multiple values |
400400
| `last_event_time` | [timestamp][ts] | Required | Date/time when last state change occurred. See [Event Times][event-times] |
401-
| `last_vehicle_state` | Enum | Required | Vehicle state of most recent state change. See [vehicle states][vehicle-states] table |
402-
| `last_vehicle_events` | Enum[] | Required | [Vehicle event(s)][vehicle-events] of most recent state change, allowable values determined by `last_vehicle_state`. |
401+
| `last_vehicle_state` | Enum | Required | [Vehicle state][vehicle-states] of most recent state change. |
402+
| `last_event_types` | Enum[] | Required | [Vehicle event(s)][vehicle-events] of most recent state change, allowable values determined by `last_vehicle_state`. |
403403
| `last_event_location` | GeoJSON [Point Feature][geo]| Required | Location of vehicle's last event |
404404
| `current_location` | GeoJSON [Point Feature][geo] | Required if Applicable | Current location of vehicle if different from last event, and the vehicle is not currently on a trip |
405405
| `battery_pct` | Float | Required if Applicable | Percent battery charge of device, expressed between 0 and 1 |

schema/generate_schemas.py

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
python generate_schemas.py [--agency] [--provider]
66
"""
77

8+
import copy
89
import json
910
import jsonschema
1011
import requests
@@ -20,6 +21,55 @@ def load_json(path):
2021
return data
2122

2223

24+
def vehicle_model(common_definitions, provider_name=True, provider_id=True):
25+
"""
26+
Extract a deep-copy of the common vehicle model definition to allow for customization.
27+
"""
28+
vehicle = copy.deepcopy(common_definitions["vehicle"])
29+
30+
if not provider_name:
31+
vehicle["required"].remove("provider_name")
32+
del vehicle["properties"]["provider_name"]
33+
34+
if not provider_id:
35+
vehicle["required"].remove("provider_id")
36+
del vehicle["properties"]["provider_id"]
37+
38+
return vehicle
39+
40+
41+
def vehicle_state_machine(common_definitions, vehicle_state=None, vehicle_events=None):
42+
"""
43+
Return a tuple (definitions, transitions) with the common vehicle state schema.
44+
* defitions is the common definitions for vehicle state fields
45+
* transitions is the rule for valid state/event combinations
46+
47+
Optionally pass field names for the vehicle_state and vehicle_events schemas
48+
to override those in transitions.
49+
"""
50+
state_machine_defs = {
51+
"vehicle_state": common_definitions["vehicle_state"],
52+
"vehicle_event": common_definitions["vehicle_event"],
53+
"vehicle_events": common_definitions["vehicle_events"],
54+
}
55+
56+
transitions = copy.deepcopy(common_definitions["vehicle_state_transitions"])
57+
58+
if vehicle_state:
59+
for option in transitions["oneOf"]:
60+
state = option["properties"]["vehicle_state"]
61+
del option["properties"]["vehicle_state"]
62+
option["properties"][vehicle_state] = state
63+
64+
if vehicle_events:
65+
for option in transitions["oneOf"]:
66+
events = option["properties"]["vehicle_events"]
67+
del option["properties"]["vehicle_events"]
68+
option["properties"][vehicle_events] = events
69+
70+
return (state_machine_defs, transitions)
71+
72+
2373
def agency_get_vehicle_schema(common_definitions):
2474
"""
2575
Create the schema for the Agency GET /vehicles endpoint.
@@ -29,18 +79,18 @@ def agency_get_vehicle_schema(common_definitions):
2979
schema["definitions"] = {
3080
"propulsion_types": common_definitions["propulsion_types"],
3181
"string": common_definitions["string"],
32-
"vehicle_state": common_definitions["vehicle_state"],
33-
"vehicle_events": common_definitions["vehicle_events"],
3482
"vehicle_type": common_definitions["vehicle_type"],
3583
"timestamp": common_definitions["timestamp"],
3684
"uuid": common_definitions["uuid"]
3785
}
3886

39-
# merge common vehicle information, with Agency tweaks
40-
vehicle = dict(common_definitions["vehicle"])
41-
vehicle["required"].remove("provider_name")
42-
del vehicle["properties"]["provider_name"]
87+
# merge the state machine definitions and transition combinations rule
88+
state_machine_defs, transitions = vehicle_state_machine(common_definitions, "state", "prev_events")
89+
schema["definitions"].update(state_machine_defs)
90+
schema["allOf"].append(transitions)
4391

92+
# merge common vehicle information, with Agency tweaks
93+
vehicle = vehicle_model(common_definitions, provider_name=False)
4494
schema["required"] = vehicle["required"] + schema["required"]
4595
schema["properties"] = { **vehicle["properties"], **schema["properties"] }
4696

@@ -64,10 +114,8 @@ def agency_post_vehicle_schema(common_definitions):
64114
}
65115

66116
# merge common vehicle information, with Agency tweaks
67-
vehicle = dict(common_definitions["vehicle"])
68-
vehicle["required"].remove("provider_name")
117+
vehicle = vehicle_model(common_definitions, provider_name=False)
69118
vehicle["required"].remove("provider_id")
70-
del vehicle["properties"]["provider_name"]
71119

72120
schema["required"] = vehicle["required"] + schema["required"]
73121
schema["properties"] = { **vehicle["properties"], **schema["properties"] }
@@ -85,12 +133,15 @@ def agency_post_vehicle_event_schema(common_definitions):
85133
# load schema template and insert definitions
86134
schema = load_json("./templates/agency/post_vehicle_event.json")
87135
schema["definitions"] = {
88-
"vehicle_state": common_definitions["vehicle_state"],
89-
"vehicle_events": common_definitions["vehicle_events"],
90136
"telemetry": common_definitions["telemetry"],
91137
"timestamp": common_definitions["timestamp"],
92138
}
93139

140+
# merge the state machine definitions and transition combinations rule
141+
state_machine_defs, transitions = vehicle_state_machine(common_definitions, "vehicle_state", "event_types")
142+
schema["definitions"].update(state_machine_defs)
143+
schema["allOf"].append(transitions)
144+
94145
# add the conditionally-required trip_id rule
95146
trip_id_ref = common_definitions["trip_id_reference"]
96147
schema["allOf"].append(trip_id_ref)
@@ -298,9 +349,10 @@ def provider_schema(endpoint, common_definitions, extra_definitions={}):
298349
# merge endpoint-specific schema with standard vehicle info
299350
endpoint_schema = load_json(f"./templates/provider/{endpoint}.json")
300351
items = endpoint_schema[endpoint]["items"]
301-
vehicle_schema = dict(common_definitions["vehicle"])
302-
items["required"] = vehicle_schema["required"] + items["required"]
303-
items["properties"] = { **vehicle_schema["properties"], **items["properties"] }
352+
353+
vehicle = vehicle_model(common_definitions)
354+
items["required"] = vehicle["required"] + items["required"]
355+
items["properties"] = { **vehicle["properties"], **items["properties"] }
304356

305357
# merge this endpoint-specific schema into the endpoint template
306358
data_schema = schema["properties"]["data"]
@@ -340,6 +392,11 @@ def provider_status_changes_schema(common_definitions):
340392
schema = provider_schema("status_changes", common_definitions)
341393
items = schema["properties"]["data"]["properties"]["status_changes"]["items"]
342394

395+
# merge the state machine definitions and transition combinations rule
396+
state_machine_defs, transitions = vehicle_state_machine(common_definitions, "vehicle_state", "event_types")
397+
schema["definitions"].update(state_machine_defs)
398+
items["allOf"].append(transitions)
399+
343400
trip_id_ref = common_definitions["trip_id_reference"]
344401
items["allOf"].append(trip_id_ref)
345402

@@ -356,9 +413,10 @@ def provider_events_schema(common_definitions):
356413
links_prop, links_def = property_definition("links", common_definitions)
357414

358415
# events is the same as status_changes, but allows paging
359-
schema = provider_schema("status_changes", common_definitions, links_def)
416+
schema = provider_status_changes_schema(common_definitions)
360417
schema["$id"] = schema["$id"].replace("status_changes", "events")
361418
schema["title"] = schema["title"].replace("status_changes", "events")
419+
schema["definitions"].update(links_def)
362420
schema["properties"].update(links_prop)
363421

364422
# verify schema validity
@@ -384,12 +442,18 @@ def provider_vehicles_schema(common_definitions):
384442
definitions.update(defn)
385443
properties.update(prop)
386444

445+
state_machine_defs, transitions = vehicle_state_machine(common_definitions, "last_vehicle_state", "last_event_types")
446+
definitions.update(state_machine_defs)
447+
387448
schema = provider_schema("vehicles", common_definitions, definitions)
388449

389450
# update list of required and properties object
390451
schema["required"].extend(["last_updated", "ttl"])
391452
schema["properties"].update(properties)
392453

454+
# add state machine transition rules
455+
schema["properties"]["data"]["properties"]["vehicles"]["items"]["allOf"].append(transitions)
456+
393457
# verify schema validity
394458
jsonschema.Draft6Validator.check_schema(schema)
395459

schema/templates/agency/get_vehicle.json

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
"year",
99
"mfgr",
1010
"model",
11-
"status",
12-
"prev_event",
11+
"state",
12+
"prev_events",
1313
"updated"
1414
],
1515
"properties": {
@@ -32,20 +32,21 @@
3232
"$ref": "#/definitions/string",
3333
"description": "The vehicle model"
3434
},
35-
"status": {
36-
"$id": "#/properties/status",
37-
"$ref": "#/definitions/vehicle_status",
38-
"description": "Current vehicle status"
35+
"state": {
36+
"$id": "#/properties/state",
37+
"$ref": "#/definitions/vehicle_state",
38+
"description": "Current vehicle state"
3939
},
40-
"prev_event": {
41-
"$id": "#/properties/prev_event",
42-
"$ref": "#/definitions/vehicle_event",
40+
"prev_events": {
41+
"$id": "#/properties/prev_events",
42+
"$ref": "#/definitions/vehicle_events",
4343
"description": "Last vehicle event"
4444
},
4545
"updated": {
4646
"$id": "#/properties/updated",
4747
"$ref": "#/definitions/timestamp"
4848
}
4949
},
50-
"additionalProperties": false
50+
"additionalProperties": false,
51+
"allOf": []
5152
}

schema/templates/agency/post_vehicle_event.json

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
"type": "object",
66
"definitions": {},
77
"required": [
8-
"event_type",
8+
"vehicle_state",
9+
"event_types",
10+
"timestamp",
911
"telemetry"
1012
],
1113
"properties": {
12-
"event_type": {
13-
"$ref": "#/definitions/vehicle_event"
14+
"vehicle_state": {
15+
"$ref": "#/definitions/vehicle_state"
16+
},
17+
"event_types": {
18+
"$ref": "#/definitions/vehicle_events"
19+
},
20+
"timestamp": {
21+
"$ref": "#/definitions/timestamp"
1422
},
1523
"telemetry": {
1624
"$ref": "#/definitions/telemetry"
@@ -19,5 +27,6 @@
1927
"$ref": "#/definitions/uuid"
2028
}
2129
},
22-
"additionalProperties": false
30+
"additionalProperties": false,
31+
"allOf": []
2332
}

0 commit comments

Comments
 (0)