Skip to content

Commit

Permalink
Merge pull request #513 from djarecka/ga_rel_generate
Browse files Browse the repository at this point in the history
updates to the release GA
  • Loading branch information
djarecka authored Jun 18, 2024
2 parents 01f10db + ccba7f9 commit 693dec1
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 15 deletions.
24 changes: 22 additions & 2 deletions .github/workflows/validate_and_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,32 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: 3.12

- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools
pip install linkml astor pre-commit
pip install git+https://github.com/ReproNim/reproschema-py.git
- name: Generate pydantic using linml and fixing it with reproschema specific script
run: |
gen-pydantic --pydantic-version 2 linkml-schema/reproschema.yaml > reproschema_model_autogen.py
python scripts/fix_pydantic.py reproschema_model_autogen.py reproschema_model.py
pre-commit run --files reproschema_model.py || true
- name: Generate jsonld format using linkml
run: |
gen-jsonld --context contexts/reproschema linkml-schema/reproschema.yaml > reproschema.jsonld
- name: Generate n-triples and turtle formats using reproschema
run: |
reproschema convert --format n-triples reproschema.jsonld > reproschema.nt
reproschema convert --format turtle reproschema.jsonld > reproschema.ttl
- name: Make a release
run: |
echo "Making a release ${{ inputs.version }}"
mkdir releases/${{ inputs.version }}
cp contexts/reproschema releases/${{ inputs.version }}/base
cp contexts/reproschema releases/${{ inputs.version }}/reproschema
cp reproschema_model.py releases/${{ inputs.version }}/reproschema_model.py
cp reproschema.jsonld releases/${{ inputs.version }}/reproschema.jsonld
cp reproschema.nt releases/${{ inputs.version }}/reproschema.nt
cp reproschema.ttl releases/${{ inputs.version }}/reproschema.ttl
# python scripts/makeRelease.py ${{ inputs.version }}

- name: Open pull requests to add files
Expand Down
22 changes: 9 additions & 13 deletions linkml-schema/reproschema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ slots:
slot_uri: schema:associatedMedia
audio:
title: audio
description: TODO
description: An audio object.
slot_uri: schema:audio
any_of:
- range: uri
Expand Down Expand Up @@ -101,12 +101,8 @@ slots:
contentUrl:
slot_uri: schema:contentUrl
range: uriorcurie
creator:
slot_uri: schema:creator
range: Person
cronTable:
title: cronTable
description: TODO not described in reproschema
slot_uri: reproschema:cronTable
datumType:
title: datumType
Expand Down Expand Up @@ -264,7 +260,7 @@ slots:
range: OverrideProperty
preamble:
title: Preamble
description: The preamble for an assessment
description: The preamble for an assessment.
slot_uri: reproschema:preamble
multivalued: true
range: langString
Expand Down Expand Up @@ -326,7 +322,7 @@ slots:
range: datetime
slot_uri: prov:startedAtTime
subject_id:
slot_uri: nidm:subject_id #TODO check this @type:rdf:Property
slot_uri: nidm:subject_id
range: string
ui:
title: UI
Expand Down Expand Up @@ -502,7 +498,7 @@ classes:
class_uri: rdf:langString
MediaObject:
title: Media Object
description: Add description #TODO
description: A media object, such as an image, video, audio, or text object embedded in a web page or a downloadable dataset.
is_a: Thing
class_uri: schema:MediaObject
slots:
Expand Down Expand Up @@ -542,7 +538,7 @@ classes:
- id
- subject_id
class_uri: reproschema:Participant
Protocol: # TODO multiple types
Protocol:
title: Protocol
description: A representation of a study which comprises one or more assessments.
is_a: Thing
Expand All @@ -555,6 +551,7 @@ classes:
- description
- landingPage
- messages
- preamble
- prefLabel
- schemaVersion
- ui
Expand Down Expand Up @@ -596,7 +593,7 @@ classes:
- unitOptions
- valueType
class_uri: reproschema:ResponseOption
SoftwareAgent: # TODO multiple types
SoftwareAgent:
title: Software Agent
description:
Captures information about some action that took place. It also links to information
Expand All @@ -616,9 +613,8 @@ classes:
- category
class_uri: schema:Thing
UI:
title: todo
description:
- todo
title: UI properties
description: A group of properties related to UI.
slots:
- order
- addProperties
Expand Down
102 changes: 102 additions & 0 deletions scripts/fix_pydantic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
""" Using ast transformer to fix issues with automatic pydantic generation"""

import ast
import sys

import astor


class ClassRemover(ast.NodeTransformer):
def __init__(self, class_name):
self.class_name = class_name

def visit_ClassDef(self, node):
# Remove the class if its name matches the class_to_remove
if node.name == self.class_name:
return None
return node

def visit_Expr(self, node):
# Check if the node is a call expression
if isinstance(node.value, ast.Call):
# Check if the call expression is an attribute (method call)
if isinstance(node.value.func, ast.Attribute):
# Check if the method call matches the specified class
if (
isinstance(node.value.func.value, ast.Name)
and node.value.func.value.id == self.class_name
):
return None # Remove this node
return self.generic_visit(node)


class TypeReplacer(ast.NodeTransformer):
def __init__(self, old_type, new_type):
self.old_type = old_type
self.new_type = new_type

def visit_FunctionDef(self, node):
# Check all arguments in the function definition
for arg in node.args.args:
if arg.annotation:
arg.annotation = self.visit(arg.annotation)
return self.generic_visit(node)

def visit_AsyncFunctionDef(self, node):
# Handle async function definitions similarly
for arg in node.args.args:
if arg.annotation:
arg.annotation = self.visit(arg.annotation)
return self.generic_visit(node)

def visit_Name(self, node):
# Replace the old type with the new type
if node.id == self.old_type:
node.id = self.new_type
return node

def visit_Subscript(self, node):
# Handle Union, Optional, and other subscripted types
node.value = self.visit(node.value)
node.slice = self.visit(node.slice)
return node

def visit_Index(self, node):
# Handle the index part of subscripted types
node.value = self.visit(node.value)
return node

def visit_Tuple(self, node):
# Handle tuples in type annotations
node.elts = [self.visit(elt) for elt in node.elts]
return node


def edit_pydantic(input_file, output_file):

with open(input_file, "r") as file:
tree = ast.parse(file.read())

transformer_class = ClassRemover(class_name="LangString")
tree_modclass = transformer_class.visit(tree)

transformer_tp = TypeReplacer(
old_type="LangString", new_type="Dict[str, str]"
)
tree_modclass_modtype = transformer_tp.visit(tree_modclass)

with open(output_file, "w") as file:
file.write(astor.to_source(tree_modclass_modtype))


if __name__ == "__main__":
input_file = sys.argv[1]
if len(sys.argv) < 3:
output_file = input_file
else:
output_file = sys.argv[2]
print(
f"Fixing automatically generated pydantic file {input_file} "
f"and saving to {output_file}"
)
edit_pydantic(input_file, output_file)

0 comments on commit 693dec1

Please sign in to comment.