new version of credtools

This commit is contained in:
Cayo Puigdefabregas 2024-02-12 12:16:18 +01:00
parent ca03f806ce
commit b05c05773e
1 changed files with 232 additions and 119 deletions

View File

@ -1,13 +1,15 @@
import pandas as pd
import json import json
# import jsonld # import jsonld
import csv import csv
import sys import sys
import jsonschema import jsonschema
from pyld import jsonld
# from jsonschema import validate, ValidationError # from jsonschema import validate, ValidationError
import requests import requests
from pyld import jsonld from pyld import jsonld
import jsonref import jsonref
from jsonpath_ng import jsonpath, parse
# def remove_null_values(dictionary): # def remove_null_values(dictionary):
# return {k: v for k, v in dictionary.items() if v is not None} # return {k: v for k, v in dictionary.items() if v is not None}
@ -17,6 +19,7 @@ def _remove_null_values(dictionary):
dictionary.clear() dictionary.clear()
dictionary.update(filtered) dictionary.update(filtered)
def validate_context(jsld): def validate_context(jsld):
"""Validate a @context string through expanding""" """Validate a @context string through expanding"""
context = jsld["@context"] context = jsld["@context"]
@ -30,6 +33,7 @@ def validate_context(jsld):
return False return False
return True return True
def compact_js(doc, context): def compact_js(doc, context):
"""Validate a @context string through compacting, returns compacted context""" """Validate a @context string through compacting, returns compacted context"""
try: try:
@ -40,6 +44,7 @@ def compact_js(doc, context):
return None return None
return compacted return compacted
def dereference_context_file(json_file): def dereference_context_file(json_file):
"""Dereference and return json-ld context from file""" """Dereference and return json-ld context from file"""
json_text = open(json_file).read() json_text = open(json_file).read()
@ -76,22 +81,36 @@ def dereference_context(jsonld_dict):
def validate_schema_file(json_schema_file): def validate_schema_file(json_schema_file):
"""Validate standalone schema from file""" """Validate standalone schema from file"""
try: try:
json_schema = open(json_schema_file).read() json_schema = json.loads(open(json_schema_file).read())
validate_schema(json_schema) validate_schema(json_schema)
except Exception as e: except Exception as e:
print(f"Error loading file {json_schema_file} or validating schema {json_schema}: {e}") print(f"Error loading file {json_schema_file} or validating schema {json_schema}: {e}")
return False return False
return True return True
def validate_schema(json_schema): def validate_schema(json_schema):
"""Validate standalone schema, returns bool (uses Draft202012Validator, alt: Draft7Validator, alt: Draft4Validator, Draft6Validator )""" """Validate standalone schema, returns bool (uses Draft202012Validator, alt: Draft7Validator, alt: Draft4Validator, Draft6Validator )"""
try: try:
jsonschema.validators.Draft202012Validator.check_schema(json_schema) jsonschema.validators.Draft202012Validator.check_schema(json_schema)
# jsonschema.validators.Draft7Validator.check_schema(json_schema) # jsonschema.validators.Draft7Validator.check_schema(json_schema)
return True
except jsonschema.exceptions.SchemaError as e: except jsonschema.exceptions.SchemaError as e:
print(e) print(e)
return False return False
return True
def validate_json_file(json_data_file, json_schema_file):
"""Validate standalone schema from file"""
try:
json_data = json.loads(open(json_data_file).read())
json_schema = json.loads(open(json_schema_file).read())
validate_json(json_data, json_schema)
except Exception as e:
print(f"Error loading file {json_schema_file} or {json_data_file}: {e}")
return False
return True
def validate_json(json_data, json_schema): def validate_json(json_data, json_schema):
"""Validate json string basic (no format) with schema, returns bool""" """Validate json string basic (no format) with schema, returns bool"""
@ -100,8 +119,10 @@ def validate_json(json_data, json_schema):
except jsonschema.exceptions.ValidationError as err: except jsonschema.exceptions.ValidationError as err:
print('Validation error: ', json_data, '\n') print('Validation error: ', json_data, '\n')
return False return False
print("Successful validation")
return True return True
def validate_json_format(json_data, json_schema): def validate_json_format(json_data, json_schema):
"""Validate a json string basic (including format) with schema, returns bool""" """Validate a json string basic (including format) with schema, returns bool"""
try: try:
@ -111,9 +132,29 @@ def validate_json_format(json_data, json_schema):
return False return False
return True return True
def schema_to_csv_file(sch_f, csv_f):
try:
json_schema = json.loads(open(sch_f).read())
except Exception as e:
print(f"Error loading file {sch_f}: {e}\nSchema:\n{json_schema}.")
return False
schema_to_csv(json_schema, csv_f)
return True
def schema_to_csv(schema, csv_file_path): def schema_to_csv(schema, csv_file_path):
"""Extract headers from an schema and write to file, returns bool""" """Extract headers from an schema and write to file, returns bool"""
headers = list(schema['properties'].keys()) jsonpath_expr = parse('$..credentialSubject.properties')
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
matches = [match.value for match in jsonpath_expr.find(schema)]
# Get the keys of the matched objects
# headers = [match.keys() for match in matches]
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
# Get the keys of the matched objects
headers = [key for match in matches for key in match.keys()]
# print('\nHeaders: ', headers)
# Create a CSV file with the headers # Create a CSV file with the headers
with open(csv_file_path, 'w', newline='') as csv_file: with open(csv_file_path, 'w', newline='') as csv_file:
@ -121,6 +162,70 @@ def schema_to_csv(schema, csv_file_path):
writer.writerow(headers) writer.writerow(headers)
return True return True
def schema_to_xls_basic(schema, xls_file_path):
"""Extract headers from an schema and write to file, returns bool"""
jsonpath_expr = parse('$..credentialSubject.properties')
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
matches = [match.value for match in jsonpath_expr.find(schema)]
# Get the keys of the matched objects
# headers = [match.keys() for match in matches]
# Get the keys of the matched objects
headers = [key for match in matches for key in match.keys() if key != 'id']
# Create a DataFrame with the fields as columns
df = pd.DataFrame(columns=headers)
# Save the DataFrame as an Excel file
# df.to_excel(xls_file_path, index=False)
df.to_excel(xls_file_path, index=False, engine='openpyxl') # For .xlsx files, and pip install openpyxl
return True
def schema_to_xls_comment(schema, xls_file_path):
"""Extract headers from an schema and write to file, returns bool"""
jsonpath_expr = parse('$..credentialSubject.properties')
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
matches = [match.value for match in jsonpath_expr.find(schema)]
# Get the keys of the matched objects
# headers = [match.keys() for match in matches]
# Get the keys of the matched objects
headers = [key for match in matches for key in match.keys() if key != 'id']
jsonpath_expr_req = parse('$..credentialSubject.required')
req = [match.value for match in jsonpath_expr_req.find(schema)][0]
# Create a DataFrame with the fields as columns
df = pd.DataFrame(columns=headers)
writer = pd.ExcelWriter(xls_file_path, engine='xlsxwriter')
# Convert the dataframe to an xlsxwriter Excel object
df.to_excel(writer, sheet_name='Full1', index=False)
# Get the xlsxwriter workbook and worksheet objects
workbook = writer.book
worksheet = writer.sheets['Full1']
# Define a format for the required header cells
req_format = workbook.add_format({'border': 1})
# cell_format = workbook.add_format({'bold': True, 'font_color': 'red'})
# Write comments to the cells
for i, header in enumerate(headers):
if header in req:
worksheet.set_column(i,i, None, req_format)
# Get the description for the current field
if 'description' in matches[0][header]:
description = matches[0][header]['description']
if description is not None:
# Write the description as a comment to the corresponding cell
worksheet.write_comment(0, i, description)
# Close the Pandas Excel writer and output the Excel file
worksheet.autofit()
writer.close()
return True
def csv_to_json(csvFilePath, schema, jsonFilePath): def csv_to_json(csvFilePath, schema, jsonFilePath):
"""Read from a csv file, check schema, write to json file, returns bool""" """Read from a csv file, check schema, write to json file, returns bool"""
@ -144,6 +249,7 @@ def csv_to_json(csvFilePath, schema, jsonFilePath):
jsonf.write(jsonString) jsonf.write(jsonString)
return True return True
def csv_to_json2(csv_file_path, json_file_path): def csv_to_json2(csv_file_path, json_file_path):
"""Read from a csv file, write to json file (assumes a row 'No' is primary key), returns bool EXPERIMENT""" """Read from a csv file, write to json file (assumes a row 'No' is primary key), returns bool EXPERIMENT"""
# Create a dictionary # Create a dictionary
@ -164,11 +270,18 @@ def csv_to_json2(csv_file_path, json_file_path):
jsonf.write(json.dumps(data, indent=4)) jsonf.write(json.dumps(data, indent=4))
return True return True
if __name__ == "__main__": if __name__ == "__main__":
sch_name = sys.argv[1] # sch_name = sys.argv[1]
sch_file = sch_name + '-schema.json' schemas = sys.argv[1:]
sch = json.loads(open(sch_file).read())
if validate_json(d, sch): # credtools.py course-credential device-purchase e-operator-claim federation-membership financial-vulnerability membership-card
generate_csv_from_schema(sch, sch_name + '-template.csv') #sch_name = 'e-operator-claim'
for i, schema in enumerate(schemas):
print(schema)
sch = json.loads(open('vc_schemas/' + schema + '.json').read())
if schema_to_xls_comment(sch,'vc_excel/' + schema + '.xlsx'):
print('Success')
else: else:
print("Validation error: ", sch_name) print("Validation error: ", schema)