Skip to content

Commit

Permalink
Merge pull request ReproNim#10 from satra/enh-schema-support
Browse files Browse the repository at this point in the history
Enh schema support
  • Loading branch information
satra authored Nov 17, 2020
2 parents 15b5dc4 + d078154 commit 3b8e47d
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,4 @@ dmypy.json
.pyre/

# Pycharm
.idea
.idea/
3 changes: 3 additions & 0 deletions reproschema/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .protocol import Protocol
from .activity import Activity
from .item import Item
67 changes: 67 additions & 0 deletions reproschema/models/activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from .base import SchemaBase


class Activity(SchemaBase):
"""
class to deal with reproschema activities
"""

schema_type = "reproschema:Activity"

def __init__(self, version=None):
super().__init__(version)
self.schema["ui"] = {"shuffle": [], "order": [], "addProperties": []}

def set_ui_shuffle(self, shuffle=False):
self.schema["ui"]["shuffle"] = shuffle

def set_URI(self, URI):
self.URI = URI

def get_URI(self):
return self.URI

# TODO
# preamble
# compute
# citation
# image

def set_defaults(self, name):
self._ReproschemaSchema__set_defaults(name) # this looks wrong
self.set_ui_shuffle(False)

def update_activity(self, item_info):

# TODO
# - remove the hard coding on visibility and valueRequired

# update the content of the activity schema with new item

item_info["URI"] = "items/" + item_info["name"]

append_to_activity = {
"variableName": item_info["name"],
"isAbout": item_info["URI"],
"isVis": item_info["visibility"],
"valueRequired": False,
}

self.schema["ui"]["order"].append(item_info["URI"])
self.schema["ui"]["addProperties"].append(append_to_activity)

def sort(self):
schema_order = [
"@context",
"@type",
"@id",
"prefLabel",
"description",
"schemaVersion",
"version",
"ui",
]
self.sort_schema(schema_order)

ui_order = ["shuffle", "order", "addProperties"]
self.sort_ui(ui_order)
79 changes: 79 additions & 0 deletions reproschema/models/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import json
import os


class SchemaBase:
"""
class to deal with reproschema schemas
"""

schema_type = None

def __init__(self, version):

URL = "https://raw.githubusercontent.com/ReproNim/reproschema/"
VERSION = version or "1.0.0-rc2"

self.schema = {
"@context": URL + VERSION + "/contexts/generic",
"@type": self.schema_type,
"schemaVersion": VERSION,
"version": "0.0.1",
}

def set_filename(self, name):
self.schema_file = name + "_schema"
self.schema["@id"] = name + "_schema"

def get_name(self):
return self.schema_file.replace("_schema", "")

def get_filename(self):
return self.schema_file

def set_pref_label(self, pref_label):
self.schema["prefLabel"] = pref_label

def set_description(self, description):
self.schema["description"] = description

def set_directory(self, output_directory):
self.dir = output_directory

def __set_defaults(self, name):
self.set_filename(name)
self.set_directory(name)
self.set_pref_label(name.replace("_", " "))
self.set_description(name.replace("_", " "))

def sort_schema(self, schema_order):

reordered_dict = {k: self.schema[k] for k in schema_order}
self.schema = reordered_dict

def sort_ui(self, ui_order):

reordered_dict = {k: self.schema["ui"][k] for k in ui_order}
self.schema["ui"] = reordered_dict

def write(self, output_dir):
with open(os.path.join(output_dir, self.schema_file), "w") as ff:
json.dump(self.schema, ff, sort_keys=False, indent=4)

@classmethod
def from_data(cls, data):
if cls.schema_type is None:
raise ValueError("SchemaBase cannot be used to instantiate class")
if cls.schema_type != data["@type"]:
raise ValueError(f"Mismatch in type {data['@type']} != {cls.schema_type}")
klass = cls()
klass.schema = data
return klass

@classmethod
def from_file(cls, filepath):
with open(filepath) as fp:
data = json.load(fp)
if "@type" not in data:
raise ValueError("Missing @type key")
return cls.from_data(data)
158 changes: 158 additions & 0 deletions reproschema/models/item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
from .base import SchemaBase


class Item(SchemaBase):
"""
class to deal with reproschema activities
"""

schema_type = "reproschema:Field"

def __init__(self, version=None):
super().__init__(version)
self.schema["ui"] = {"inputType": []}
self.schema["question"] = {}
self.schema["responseOptions"] = {}
# default input type is "char"
self.set_input_type_as_char()

def set_URI(self, URI):
self.URI = URI

# TODO
# image
# readonlyValue

def set_defaults(self, name):
self._ReproschemaSchema__set_defaults(name) # this looks wrong
self.schema_file = name
self.schema["@id"] = name
self.set_input_type_as_char()

def set_question(self, question, lang="en"):
self.schema["question"][lang] = question

def set_input_type(self, input_type):
self.schema["ui"]["inputType"] = input_type

def set_response_options(self, response_options):
self.schema["responseOptions"] = response_options

"""
input types with different response choices
"""

def set_input_type_as_radio(self, response_options):
self.set_input_type("radio")
self.set_response_options(response_options)

def set_input_type_as_select(self, response_options):
self.set_input_type("select")
self.set_response_options(response_options)

def set_input_type_as_slider(self):
self.set_input_type_as_char() # until the slide item of the ui is fixed
# self.set_input_type("slider")
# self.set_response_options({"valueType": "xsd:string"})

def set_input_type_as_language(self):

URL = "https://raw.githubusercontent.com/ReproNim/reproschema/"

self.set_input_type("selectLanguage")

response_options = {
"valueType": "xsd:string",
"multipleChoice": True,
"choices": URL + "master/resources/languages.json",
}
self.set_response_options(response_options)

"""
input types with no response choice
"""

def set_input_type_as_char(self):
self.set_input_type("text")
self.set_response_options({"valueType": "xsd:string"})

def set_input_type_as_int(self):
self.set_input_type("number")
self.set_response_options({"valueType": "xsd:integer"})

def set_input_type_as_float(self):
self.set_input_type("float")
self.set_response_options({"valueType": "xsd:float"})

def set_input_type_as_time_range(self):
self.set_input_type("timeRange")
self.set_response_options({"valueType": "datetime"})

def set_input_type_as_date(self):
self.set_input_type("date")
self.set_response_options({"valueType": "xsd:date"})

"""
input types with no response choice but with some parameters
"""

def set_input_type_as_multitext(self, max_length=300):
self.set_input_type("text")
self.set_response_options({"valueType": "xsd:string", "maxLength": max_length})

# TODO
# email: EmailInput/EmailInput.vue
# audioCheck: AudioCheck/AudioCheck.vue
# audioRecord: WebAudioRecord/Audio.vue
# audioPassageRecord: WebAudioRecord/Audio.vue
# audioImageRecord: WebAudioRecord/Audio.vue
# audioRecordNumberTask: WebAudioRecord/Audio.vue
# audioAutoRecord: AudioCheckRecord/AudioCheckRecord.vue
# year: YearInput/YearInput.vue
# selectCountry: SelectInput/SelectInput.vue
# selectState: SelectInput/SelectInput.vue
# documentUpload: DocumentUpload/DocumentUpload.vue
# save: SaveData/SaveData.vue
# static: Static/Static.vue
# StaticReadOnly: Static/Static.vue

def set_basic_response_type(self, response_type):

# default (also valid for "char" input type)
self.set_input_type_as_char()

if response_type == "int":
self.set_input_type_as_int()

elif response_type == "float":
self.set_input_type_as_float()

elif response_type == "date":
self.set_input_type_as_date()

elif response_type == "time range":
self.set_input_type_as_time_range()

elif response_type == "language":
self.set_input_type_as_language()

def sort(self):
schema_order = [
"@context",
"@type",
"@id",
"prefLabel",
"description",
"schemaVersion",
"version",
"ui",
"question",
"responseOptions",
]
self.sort_schema(schema_order)
78 changes: 78 additions & 0 deletions reproschema/models/protocol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from .base import SchemaBase


class Protocol(SchemaBase):
"""
class to deal with reproschema protocols
"""

schema_type = "reproschema:Protocol"

def __init__(self, version=None):
super().__init__(version)
self.schema["ui"] = {
"allow": [],
"shuffle": [],
"order": [],
"addProperties": [],
}

def set_landing_page(self, landing_page_url, lang="en"):
self.schema["landingPage"] = {"@id": landing_page_url, "@language": lang}

# TODO
# def add_landing_page(self, landing_page_url, lang="en"):
# preamble
# compute

def set_image(self, image_url):
self.schema["image"] = image_url

def set_ui_allow(self):
self.schema["ui"]["allow"] = [
"reproschema:AutoAdvance",
"reproschema:AllowExport",
]

def set_ui_shuffle(self, shuffle=False):
self.schema["ui"]["shuffle"] = shuffle

def set_defaults(self, name):
self._ReproschemaSchema__set_defaults(name) # this looks wrong
self.set_landing_page("../../README-en.md")
self.set_ui_allow()
self.set_ui_shuffle(False)

def append_activity(self, activity):

# TODO
# - remove the hard coding on visibility and valueRequired

# update the content of the protocol with this new activity
append_to_protocol = {
"variableName": activity.get_name(),
"isAbout": activity.get_URI(),
"prefLabel": {"en": activity.schema["prefLabel"]},
"isVis": True,
"valueRequired": False,
}

self.schema["ui"]["order"].append(activity.URI)
self.schema["ui"]["addProperties"].append(append_to_protocol)

def sort(self):
schema_order = [
"@context",
"@type",
"@id",
"prefLabel",
"description",
"schemaVersion",
"version",
"landingPage",
"ui",
]
self.sort_schema(schema_order)

ui_order = ["allow", "shuffle", "order", "addProperties"]
self.sort_ui(ui_order)
Empty file.
Loading

0 comments on commit 3b8e47d

Please sign in to comment.