Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def create_json_schema_entity_view(
synapse_client=syn,
)
assert isinstance(entity, (Folder, Project))
jsb = entity.get_schema()
jsb = entity.get_schema(synapse_client=syn)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we don't have to do synapse_client=syn here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version_info = jsb.json_schema_version_info
schema = JSONSchema(version_info.schema_name, version_info.organization_name)
body = schema.get_body(version=version_info.semantic_version, synapse_client=syn)
Expand All @@ -77,10 +77,10 @@ def create_json_schema_entity_view(
view_type_mask=view_type_mask,
columns=columns,
).store(synapse_client=syn)
# This reorder is so that these show up in the front of the EntityView in Synapse
view.reorder_column(name="createdBy", index=0)
# This reorder is so that these show up in the front of the EntityView in Synapse.
view.reorder_column(name="name", index=0)
view.reorder_column(name="id", index=0)
view.reorder_column(name="id", index=1)
view.reorder_column(name="createdBy", index=2)
view.store(synapse_client=syn)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to set the first three columns all at once? As the code, it seems the name,id and createdBy are the first three columns.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we try what Dan suggested? Also, if this pattern comes up more often, I would recommend adding a function so that we could change the column order in bulk rather than calling reorder_column and changing the order one at a time

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, as far as I can tell, currently there is no function that does this in one line for OrderedDicts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rewrote it to be more readable.

return view.id

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
"""Integration tests for create_file_based_metadata_task."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been fixed in the other PR.


import uuid
from typing import Any, Callable, Generator

import pytest

from synapseclient import Synapse
from synapseclient.core.exceptions import SynapseHTTPError
from synapseclient.extensions.curator.file_based_metadata_task import (
create_file_based_metadata_task,
)
from synapseclient.models import (
CurationTask,
EntityView,
Folder,
JSONSchema,
Project,
SchemaOrganization,
)


def _test_name() -> str:
random_string = "".join(c for c in str(uuid.uuid4()) if c.isalpha())
return f"SYNPY.TEST.{random_string}"


@pytest.fixture(scope="module")
def patient_schema_uri(syn: Synapse, request: pytest.FixtureRequest) -> str:
"""
Create a SchemaOrganization and a Patient JSON schema for the module.
Returns the schema URI.
"""
org_name = _test_name()
schema_name = "test.schematic.Patient"

org = SchemaOrganization(name=org_name)
org.store(synapse_client=syn)

schema = JSONSchema(name=schema_name, organization_name=org_name)
schema_body = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": f"https://example.com/schema/{org_name}-{schema_name}.json",
"title": "Patient",
"type": "object",
"properties": {
"PatientID": {"type": "string"},
"Sex": {"type": "string", "enum": ["Male", "Female", "Other"]},
"Age": {"type": "integer", "minimum": 0},
},
"required": ["PatientID"],
}
schema.store(schema_body=schema_body, synapse_client=syn)

def cleanup():
for js in org.get_json_schemas(synapse_client=syn):
js.delete(synapse_client=syn)
org.delete(synapse_client=syn)

request.addfinalizer(cleanup)

return schema.uri


@pytest.fixture(scope="function")
def folder(
syn: Synapse,
project: Project,
schedule_for_cleanup: Callable[[Any], None],
) -> Generator[Folder, None, None]:
"""Returns a Synapse Folder"""
folder = Folder(name=_test_name(), parent_id=project.id).store(synapse_client=syn)
schedule_for_cleanup(folder.id)
yield folder
Comment thread
andrewelamb marked this conversation as resolved.
# Unbind any JSON schema from the folder before teardown so the module-scoped
# schema cleanup (which runs before the session-scoped folder deletion) is not
# blocked by "Cannot delete a schema that is bound to an object".
try:
folder.unbind_schema(synapse_client=syn)
except SynapseHTTPError:
# No schema bound to this folder; nothing to unbind.
pass


class TestCreateFileBasedMetadataTask:
"""Integration tests for create_file_based_metadata_task."""

def test_create_file_based_metadata_task(
self,
syn: Synapse,
schedule_for_cleanup: Callable[[Any], None],
request: pytest.FixtureRequest,
patient_schema_uri: str,
folder: Folder,
) -> None:
"""Test successful creation of CurationTask and EntityView"""
# GIVEN a folder, a Patient JSON schema, and a unique task name
test_name = _test_name()

# WHEN a file-based metadata task is created for the folder
entity_view_id, task_id = create_file_based_metadata_task(
folder_id=folder.id,
curation_task_name=test_name,
instructions="Contribute Patient data.",
entity_view_name=test_name,
schema_uri=patient_schema_uri,
synapse_client=syn,
)
schedule_for_cleanup(entity_view_id)

# The CurationTask is not a deletable entity via syn.delete, so it keeps a
# dedicated finalizer. The EntityView it points at is cleaned up via
# schedule_for_cleanup above, so delete_source is not needed here.
request.addfinalizer(
lambda: CurationTask(task_id=task_id).delete(synapse_client=syn)
)

# THEN both the entity view and the curation task were created
assert entity_view_id is not None
assert task_id is not None

# AND the entity view exists in Synapse with the expected name
view = EntityView(id=entity_view_id).get(
include_columns=True, synapse_client=syn
)
assert view.id == entity_view_id
assert view.name == test_name

# AND the curation task exists in Synapse pointing at that view
task = CurationTask(task_id=task_id).get(synapse_client=syn)
assert task.task_id == task_id
assert task.data_type == test_name
assert task.task_properties.file_view_id == entity_view_id

# AND the leading columns are ordered with "name" first
column_names = list(view.columns.keys())
assert column_names[:3] == ["name", "id", "createdBy"]
12 changes: 8 additions & 4 deletions tests/unit/synapseclient/extensions/unit_test_curator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import tempfile
import unittest
from typing import Any
from unittest.mock import Mock, mock_open, patch
from unittest.mock import Mock, call, mock_open, patch

import pandas as pd
import pytest
Expand Down Expand Up @@ -1553,9 +1553,13 @@ def test_create_json_schema_entity_view_success(

# THEN the entity view should be created successfully
assert result == "syn87654321"
mock_view.reorder_column.assert_any_call(name="createdBy", index=0)
mock_view.reorder_column.assert_any_call(name="name", index=0)
mock_view.reorder_column.assert_any_call(name="id", index=0)
# AND the columns are reordered so that "name", "id", and "createdBy"
# appear first, in that order.
assert mock_view.reorder_column.call_args_list == [
call(name="name", index=0),
call(name="id", index=1),
call(name="createdBy", index=2),
]

@patch("synapseclient.extensions.curator.file_based_metadata_task.isinstance")
@patch("synapseclient.extensions.curator.file_based_metadata_task.EntityView")
Expand Down
Loading