Skip to content

Commit 269bc95

Browse files
author
Tom Reitz
committed
updates to finish out functionality
1 parent 02cee3c commit 269bc95

2 files changed

Lines changed: 61 additions & 47 deletions

File tree

lightbeam/api.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ def get_params_for_endpoint(self, endpoint, type='required'):
337337
definition = util.get_swagger_ref_for_endpoint(self.lightbeam.config["namespace"], swagger, endpoint)
338338
if type=='required':
339339
return self.get_required_params_from_swagger(swagger, definition)
340+
elif type=='all':
341+
return self.get_all_params_from_swagger(swagger, definition)
340342
else:
341343
# descriptor endpoints all have the same structure and identity fields:
342344
if "Descriptor" in endpoint:
@@ -360,6 +362,28 @@ def get_required_params_from_swagger(self, swagger, definition, prefix=""):
360362
params[prop] = prefix + prop
361363
return params
362364

365+
def get_all_params_from_swagger(self, swagger, definition, prefix=""):
366+
params = {}
367+
schema = util.resolve_swagger_ref(swagger, definition)
368+
if not schema:
369+
self.logger.critical(f"Swagger contains neither `definitions` nor `components.schemas` - check that the Swagger is valid.")
370+
371+
for prop in schema["properties"].keys():
372+
if prop in ["_etag", "id", "link"]: continue
373+
if "required" in schema.keys() and prop in schema["required"]: prop_name = "[required]"+prop
374+
else: prop_name = "[optional]"+prop
375+
if "$ref" in schema["properties"][prop].keys():
376+
params[prop_name] = {}
377+
sub_definition = schema["properties"][prop]["$ref"]
378+
sub_params = self.get_all_params_from_swagger(swagger, sub_definition, prefix=prop+"_")
379+
for k,v in sub_params.items():
380+
params[prop_name][k] = v
381+
elif schema["properties"][prop]["type"]!="array":
382+
params[prop_name] = f"[{schema['properties'][prop]['type']}]" + prefix + prop
383+
else:
384+
params[prop_name] = [self.get_all_params_from_swagger(swagger, schema["properties"][prop]["items"]["$ref"], prefix=prop+"_")]
385+
return params
386+
363387
def get_identity_params_from_swagger(self, swagger, definition, prefix=""):
364388
params = {}
365389
schema = util.resolve_swagger_ref(swagger, definition)

lightbeam/create.py

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import re
23
import json
34
import yaml
45
from lightbeam import util
@@ -12,6 +13,7 @@ def __init__(self, lightbeam=None):
1213
self.earthmover_file = "earthmover.yml"
1314

1415
def create(self):
16+
self.lightbeam.api.load_swagger_docs()
1517
os.makedirs(self.template_folder, exist_ok=True)
1618
earthmover_yaml = {}
1719
# check if file exists!
@@ -31,6 +33,12 @@ def create(self):
3133
# This is an earthmover.yml file, generated with `lightbeam create`, for creating Ed-Fi JSON payloads
3234
# using earthmover. See https://github.com/edanalytics/earthmover for documentation.
3335
36+
config:
37+
macros: >
38+
{% macro descriptor_namespace() -%}
39+
uri://ed-fi.org
40+
{%- endmacro %}
41+
3442
# Define your source data here:
3543
sources:
3644
# Example:
@@ -57,59 +65,41 @@ def create_em_destination_node(self, endpoint):
5765
template: {self.template_folder}{endpoint}.jsont
5866
extension: jsonl
5967
linearize: True"""
68+
69+
def upper_repl(self, match):
70+
value = match.group(1)
71+
return "/" + value[0].upper() + value[1:] + "Descriptor#"
72+
6073

6174
def create_jsont(self, endpoint):
6275
template_file = f"{self.template_folder}{endpoint}.jsont"
6376
# check if file exists!
6477
if os.path.isfile(template_file):
6578
self.logger.critical(f"The file `{template_file}` already exists in the current directory; to re-create it, please first manually delete it.")
79+
# generate base JSON structure:
80+
content = self.lightbeam.api.get_params_for_endpoint(endpoint, type='all')
81+
# pretty-print it:
82+
content = json.dumps(content, indent=2)
83+
# annotate required/optional properties:
84+
content = content.replace('"[required]', '{# (required) #} "')
85+
content = content.replace('"[optional]', '{# (optional) #} "')
86+
# appropriate quoting based on property data type:
87+
content = re.sub('"\[string\](.*)Descriptor"', r'"{{descriptor_namespace()}}/\1Descriptor#{{\1Descriptor}}"', content)
88+
content = re.sub('/(.*)_(.*)Descriptor#', r'/\2Descriptor#', content)
89+
content = re.sub(r'/(.*)Descriptor#', self.upper_repl, content)
90+
content = re.sub('"\[string\](.*)"', r'"{{\1}}"', content)
91+
content = re.sub('"\[(integer|boolean)\](.*)"', r'{{\2}}', content)
92+
# for loops over arrays:
93+
content = re.sub('"(.*)": \[', r'"\1": [ {% for item in \1 %}', content)
94+
content = re.sub('\]', r'{% endfor %} ]', content)
95+
content = re.sub('{{(.*)_(.*)}}', r'{{item.\2}}', content)
96+
# add info header message:
97+
content = """{#
98+
This is an earthmover JSON template file, generated with `lightbeam create`, for creating Ed-Fi JSON `"""+endpoint+"""`
99+
payloads using earthmover. See https://github.com/edanalytics/earthmover for documentation.
100+
#}
101+
""" + content
66102
# write out json template
67103
self.logger.info(f"creating file `{template_file}`...")
68104
with open(template_file, 'w+') as file:
69-
# TODO: implement a function in `lightbeam/api.py` that constructs a "sample" payload for the endpoint
70-
# Example:
71-
# {
72-
# "property_bool": true,
73-
# "property_int": 1,
74-
# "property_float": 1.0,
75-
# "property_string": "string",
76-
# "property_date": "date",
77-
# "property_string_optional": "string",
78-
# "property_descriptor": "uri://ed-fi.org/SomeDescriptor#SomeValue",
79-
# "property_object": {
80-
# "property_object_1": "string",
81-
# "property_object_2": "string"
82-
# },
83-
# "property_array": [
84-
# {
85-
# "property_array_1": "string",
86-
# "property_array_2": "string"
87-
# }
88-
# ]
89-
# }
90-
# TODO: turn the "sample" payload into a Jinja template
91-
# Example:
92-
# {
93-
# "property_bool": {{property_bool}},
94-
# "property_int": {{property_int}},
95-
# "property_float": {{property_float}},
96-
# "property_string": "{{property_string}}",
97-
# "property_date": "{{property_date}}",
98-
# {% if property_string_optional %}
99-
# "property_string_optional": "{{property_string_optional}}",
100-
# {% endif %}
101-
# "property_descriptor": "uri://ed-fi.org/SomeDescriptor#{{property_descriptor}}",
102-
# "property_object": {
103-
# "property_object_1": "{{property_object_1}}",
104-
# "property_object_2": "{{property_object_2}}"
105-
# },
106-
# "property_array": [
107-
# {% for item in property_array %}
108-
# {
109-
# "property_array_1": "{{item.property_array_1}}",
110-
# "property_array_2": "{{item.property_array_2}}"
111-
# } {% if not loop.last %},{% endif %}
112-
# {% endfor %}
113-
# ]
114-
# }
115-
file.write("coming soon...") # (for now)
105+
file.write(content)

0 commit comments

Comments
 (0)