Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e0fdb91
Add schema management wrapper functions using OOP models
aditigopalan Feb 9, 2026
c8fb80f
Update CLI commands to use OOP model wrapper functions
aditigopalan Feb 9, 2026
0c5bbd2
Add register-json-schema command to CLI documentation
aditigopalan Feb 9, 2026
e20b7f9
Add register and bind examples to Python tutorial
aditigopalan Feb 9, 2026
42d5b8f
[test] Add unit tests for bind-json-schema CLI command
aditigopalan Feb 9, 2026
ae634da
[test] Fix bind-json-schema test to match new wrapper implementation
aditigopalan Feb 9, 2026
a8245ef
Use JSONSchema.uri instead of manually building URI
aditigopalan Feb 10, 2026
208eaa6
Log success message in register_jsonschema instead of returning it
aditigopalan Feb 10, 2026
6cefe2e
Return JSONSchema object instead of just URI string
aditigopalan Feb 10, 2026
51814d6
Remove unnecessary fallback logic in bind_jsonschema
aditigopalan Feb 10, 2026
dc60b13
Add integration tests for schema management functions
aditigopalan Feb 10, 2026
23c8362
Use new operations API instead of deprecated syn.get()
aditigopalan Feb 10, 2026
9c4eac8
Simplify return statement in bind_jsonschema
aditigopalan Feb 10, 2026
5f1f4ae
[test]
aditigopalan Feb 10, 2026
6abca43
Fix return type annotation for bind_jsonschema
aditigopalan Feb 12, 2026
dab5d9c
Remove comments from schema_manahement.py
aditigopalan Feb 12, 2026
47ef105
Remove verbose binding details from CLI output
aditigopalan Feb 12, 2026
babfe4c
Simplify initial setup section in schema operations tutorial
aditigopalan Feb 12, 2026
64759e1
Update main.py
aditigopalan Feb 12, 2026
8a5b5de
[test] fixing import
aditigopalan Feb 12, 2026
7152d77
[test] removing assert fix
aditigopalan Feb 12, 2026
9ec6e39
Merge upstream/develop into develop
aditigopalan Feb 17, 2026
12542c5
[test] changing clean up to finalizer
aditigopalan Feb 17, 2026
49bd3d2
[test] removing try/ except blocks
aditigopalan Feb 17, 2026
12a920e
[test] add schema unbinding before folder deletion
aditigopalan Feb 17, 2026
9c814b5
[test] refactor to reuse existing test_state fixture
aditigopalan Feb 17, 2026
9bf8e8b
[test] refactor
aditigopalan Feb 17, 2026
94efc1d
[docs] moving hardcoded file paths to the top
aditigopalan Feb 17, 2026
101e60d
[test] syn.delete > project.delete
aditigopalan Feb 17, 2026
a5bb249
Add Python 3.14 compatible async versions for schema management funct…
aditigopalan Feb 17, 2026
c90a7cb
Apply suggestion from @thomasyu888
thomasyu888 Feb 18, 2026
aa1ada4
Apply suggestions from code review
thomasyu888 Feb 18, 2026
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
31 changes: 31 additions & 0 deletions docs/tutorials/command_line_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ synapse [-h] [--version] [-u SYNAPSEUSER] [-p SYNAPSE_AUTH_TOKEN] [-c CONFIGPATH
- [get-sts-token](#get-sts-token): Get an STS token for access to AWS S3 storage underlying Synapse
- [migrate](#migrate): Migrate Synapse entities to a different storage location
- [generate-json-schema](#generate-json-schema): Generate JSON Schema(s) from a data model
- [register-json-schema](#register-json-schema): Register a JSON Schema to a Synapse organization
- [bind-json-schema](#bind-json-schema): Bind a JSON Schema to a Synapse entity

### `get`

Expand Down Expand Up @@ -558,3 +560,32 @@ synapse generate-json-schema [-h] [--data-types data_type1, data_type2] [--outpu
| `--data-types` | Named | Optional list of data types to create JSON Schema for |
| `--output` | Named | Optional. Either a file path ending in '.json', or a directory path |
| `--data-model-labels` | Named | Either 'class_label', or 'display_label' |
### `register-json-schema`
Register a JSON Schema to a Synapse organization for later binding to entities.
```bash
synapse register-json-schema [-h] [--schema-version VERSION] schema_path organization_name schema_name
```
| Name | Type | Description | Default |
|-----------------------|------------|-------------------------------------------------------------------------------------|---------|
| `schema_path` | Positional | Path to the JSON schema file to register | |
| `organization_name` | Positional | Name of the organization to register the schema under | |
| `schema_name` | Positional | The name of the JSON schema | |
| `--schema-version` | Named | Version of the schema to register (e.g., '0.0.1'). If not specified, auto-generated | None |
### `bind-json-schema`
Bind a registered JSON Schema to a Synapse entity for metadata validation.
```bash
synapse bind-json-schema [-h] [--enable-derived-annotations] id json_schema_uri
```
| Name | Type | Description | Default |
|-------------------------------|------------|------------------------------------------------------------------------------------|---------|
| `id` | Positional | The Synapse ID of the entity to bind the schema to (e.g., syn12345678) | |
| `json_schema_uri` | Positional | The URI of the JSON Schema to bind (e.g., 'my.org-schema.name-1.0.0') | |
| `--enable-derived-annotations`| Named | Enable derived annotations to auto-populate annotations from schema | False |
77 changes: 49 additions & 28 deletions docs/tutorials/python/schema_operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,26 @@ JSON Schema is a tool used to validate data. In Synapse, JSON Schemas can be use

Synapse supports a subset of features from [json-schema-draft-07](https://json-schema.org/draft-07). To see the list of features currently supported, see the [JSON Schema object definition](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/schema/JsonSchema.html) from Synapse's REST API Documentation.

In this tutorial, you will learn how to create these JSON Schema using an existing data model.
In this tutorial, you will learn how to create, register, and bind JSON Schemas using an existing data model.

## Tutorial Purpose

You will create a JSON schema from your data model using the Python client as a library. To use the CLI tool, see the [documentation](../command_line_client.md).
You will learn the complete JSON Schema workflow:
1. **Generate** JSON schemas from your data model
2. **Register** schemas to a Synapse organization
3. **Bind** schemas to Synapse entities for metadata validation

This tutorial uses the Python client as a library. To use the CLI tool, see the [command line documentation](../command_line_client.md).

## Prerequisites

* You have a working [installation](../installation.md) of the Synapse Python Client.
* You have a data model, see this [data model_documentation](../../explanations/curator_data_model.md).

## 1. Imports

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=1-2}
```

## 2. Set up your variables
## 1. Initial set up

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=4-11}
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=1-18}
```

To create a JSON Schema you need a data model, and the data types you want to create.
Expand All @@ -31,74 +30,96 @@ The data model must be in either CSV or JSON-LD form. The data model may be a lo

The data types must exist in your data model. This can be a list of data types, or `None` to create all data types in the data model.

## 3. Log into Synapse

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=13-14}
```

## 4. Create a JSON Schema
## 2. Create a JSON Schema

Create a JSON Schema

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=16-23}
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=20-27}
```

You should see the first JSON Schema for the datatype you selected printed.
It will look like [this schema](https://repo-prod.prod.sagebase.org/repo/v1/schema/type/registered/dpetest-test.schematic.Patient).
By setting the `output` parameter as path to a "temp" directory, the file will be created as "temp/Patient.json".

## 5. Create multiple JSON Schema
## 3. Create multiple JSON Schema

Create multiple JSON Schema

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=26-32}
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=30-36}
```

The `data_types` parameter is a list and can have multiple data types.

## 6. Create every JSON Schema
## 4. Create every JSON Schema

Create every JSON Schema

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=34-39}
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=38-43}
```

If you don't set a `data_types` parameter a JSON Schema will be created for every data type in the data model.

## 7. Create a JSON Schema with a certain path
## 5. Create a JSON Schema with a certain path

Create a JSON Schema

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=41-47}
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=45-51}
```

If you have only one data type and set the `output` parameter to a file path(ending in.json), the JSON Schema file will have that path.

## 8. Create a JSON Schema in the current working directory
## 6. Create a JSON Schema in the current working directory

Create a JSON Schema

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=49-54}
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=53-58}
```

If you don't set `output` parameter the JSON Schema file will be created in the current working directory.

## 9. Create a JSON Schema using display names
## 7. Create a JSON Schema using display names

Create a JSON Schema

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=56-62}
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=60-66}
```

You can have Curator format the property names and valid values in the JSON Schema. This will remove whitespace and special characters.

## 8. Register a JSON Schema to Synapse

Once you've created a JSON Schema file, you can register it to a Synapse organization.

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=68-76}
```

The `register_jsonschema` function:
- Takes a path to your generated JSON Schema file
- Registers it with the specified organization in Synapse
- Returns the schema URI and a success message
- You can optionally specify a version (e.g., "0.0.1") or let it auto-generate

## 9. Bind a JSON Schema to a Synapse Entity

After registering a schema, you can bind it to Synapse entities (files, folders, etc.) for metadata validation.

```python
{!docs/tutorials/python/tutorial_scripts/schema_operations.py!lines=78-85}
```

The `bind_jsonschema` function:
- Takes a Synapse entity ID (e.g., "syn12345678")
- Binds the registered schema URI to that entity
- Optionally enables derived annotations to auto-populate metadata
- Returns binding details

## Source Code for this Tutorial

<details class="quote">
Expand Down
37 changes: 35 additions & 2 deletions docs/tutorials/python/tutorial_scripts/schema_operations.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from synapseclient import Synapse
from synapseclient.extensions.curator import generate_jsonschema
from synapseclient.extensions.curator import (
bind_jsonschema,
generate_jsonschema,
register_jsonschema,
)

# Path or URL to your data model (CSV or JSONLD format)
# Example: "path/to/my_data_model.csv" or "https://raw.githubusercontent.com/example.csv"
Expand All @@ -9,6 +13,16 @@
DATA_TYPE = ["Patient"]
# Directory where JSON Schema files will be saved
OUTPUT_DIRECTORY = "temp"
# Path to a generated JSON Schema file for registration
SCHEMA_PATH = "temp/Patient.json"
# Your Synapse organization name for schema registration
ORGANIZATION_NAME = "my.organization"
# Name for the schema
SCHEMA_NAME = "patient.schema"
# Version number for the schema
SCHEMA_VERSION = "0.0.1"
# Synapse entity ID to bind the schema to (file, folder, etc.)
ENTITY_ID = "syn12345678"

syn = Synapse()
syn.login()
Expand Down Expand Up @@ -53,10 +67,29 @@
synapse_client=syn,
)

# Create JSON Schema in using display names for both properties names and valid values
# Create JSON Schema using display names for both properties names and valid values
schemas, file_paths = generate_jsonschema(
data_model_source=DATA_MODEL_SOURCE,
data_types=DATA_TYPE,
data_model_labels="display_label",
synapse_client=syn,
)

# Register a JSON Schema to Synapse
json_schema = register_jsonschema(
schema_path=SCHEMA_PATH,
organization_name=ORGANIZATION_NAME,
schema_name=SCHEMA_NAME,
schema_version=SCHEMA_VERSION,
synapse_client=syn,
)
print(f"Registered schema URI: {json_schema.uri}")

# Bind a JSON Schema to a Synapse entity
result = bind_jsonschema(
entity_id=ENTITY_ID,
json_schema_uri=json_schema.uri,
enable_derived_annotations=True,
synapse_client=syn,
)
print(f"Successfully bound schema to entity: {result}")
77 changes: 77 additions & 0 deletions synapseclient/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
SynapseNoCredentialsError,
)
from synapseclient.extensions.curator.schema_generation import generate_jsonschema
from synapseclient.extensions.curator.schema_management import (
bind_jsonschema,
register_jsonschema,
)
from synapseclient.wiki import Wiki

tracer = trace.get_tracer("synapseclient")
Expand Down Expand Up @@ -814,6 +818,31 @@ def generate_json_schema(args, syn):
logging.info(f"Created JSON Schema files: [{paths}]")


def register_json_schema(args, syn):
"""Register a JSON schema to a Synapse organization."""
register_jsonschema(
schema_path=args.schema_path,
organization_name=args.organization_name,
schema_name=args.schema_name,
schema_version=args.schema_version,
synapse_client=syn,
)


def bind_json_schema(args, syn):
"""Bind a JSON schema to a Synapse entity."""
result = bind_jsonschema(
entity_id=args.id,
json_schema_uri=args.json_schema_uri,
enable_derived_annotations=args.enable_derived_annotations,
synapse_client=syn,
)
syn.logger.info(
f"Successfully bound schema '{args.json_schema_uri}' to entity '{args.id}'"
)
return result


def build_parser():
"""Builds the argument parser and returns the result."""

Expand Down Expand Up @@ -1845,6 +1874,54 @@ def build_parser():
)
parser_generate_json_schema.set_defaults(func=generate_json_schema)

parser_register_json_schema = subparsers.add_parser(
"register-json-schema", help="Register a JSON Schema to a Synapse organization."
)
parser_register_json_schema.add_argument(
"schema_path",
type=str,
help="Path to the JSON schema file to register",
)
parser_register_json_schema.add_argument(
"organization_name",
type=str,
help="Name of the organization to register the schema under",
)
parser_register_json_schema.add_argument(
"schema_name",
type=str,
help="The name of the JSON schema",
)
parser_register_json_schema.add_argument(
"--schema-version",
dest="schema_version",
type=str,
default=None,
help="Version of the schema to register (e.g., '0.0.1'). If not specified, a version will be auto-generated.",
)
parser_register_json_schema.set_defaults(func=register_json_schema)

parser_bind_json_schema = subparsers.add_parser(
"bind-json-schema", help="Bind a JSON Schema to a Synapse entity."
)
parser_bind_json_schema.add_argument(
"id",
type=str,
help="The Synapse ID of the entity to bind the schema to (e.g., syn12345678).",
)
parser_bind_json_schema.add_argument(
"json_schema_uri",
type=str,
help="The URI of the JSON Schema to bind (e.g., 'my.org-schema.name-1.0.0').",
)
parser_bind_json_schema.add_argument(
"--enable-derived-annotations",
action="store_true",
default=False,
help="Enable derived annotations to auto-populate annotations from schema. Defaults to False.",
)
parser_bind_json_schema.set_defaults(func=bind_json_schema)

parser_migrate.set_defaults(func=migrate)

return parser
Expand Down
10 changes: 10 additions & 0 deletions synapseclient/extensions/curator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
from .file_based_metadata_task import create_file_based_metadata_task
from .record_based_metadata_task import create_record_based_metadata_task
from .schema_generation import generate_jsonld, generate_jsonschema
from .schema_management import (
bind_jsonschema,
bind_jsonschema_async,
register_jsonschema,
register_jsonschema_async,
)
from .schema_registry import query_schema_registry

__all__ = [
Expand All @@ -15,4 +21,8 @@
"query_schema_registry",
"generate_jsonld",
"generate_jsonschema",
"register_jsonschema",
"register_jsonschema_async",
"bind_jsonschema",
"bind_jsonschema_async",
]
Loading
Loading