From ffe2a0a288d60ecee11143516c714d5482c30e40 Mon Sep 17 00:00:00 2001 From: pkdash Date: Tue, 12 Mar 2024 10:58:53 -0400 Subject: [PATCH 1/7] [#98] moving some attributes from MediaObject to DatasetMetadata --- api/models/catalog.py | 5 +- api/models/management/generate_schema.py | 6 +- api/models/schema.py | 19 +- api/models/schemas/schema.json | 2849 ++++++++++------------ 4 files changed, 1252 insertions(+), 1627 deletions(-) diff --git a/api/models/catalog.py b/api/models/catalog.py index 9ff18d3..3b289bc 100644 --- a/api/models/catalog.py +++ b/api/models/catalog.py @@ -3,8 +3,7 @@ from beanie import Document from api.models.user import Submission - -from .schema import CoreMetadata +from .schema import CoreMetadata, DatasetMetadata class CoreMetadataDOC(Document, CoreMetadata): @@ -32,5 +31,5 @@ def as_submission(self) -> Submission: ) -class DatasetMetadataDOC(CoreMetadataDOC): +class DatasetMetadataDOC(CoreMetadataDOC, DatasetMetadata): repository_identifier: str = None diff --git a/api/models/management/generate_schema.py b/api/models/management/generate_schema.py index f0b9b35..e6cdb91 100644 --- a/api/models/management/generate_schema.py +++ b/api/models/management/generate_schema.py @@ -3,12 +3,12 @@ import typer -from api.models.schema import DatasetSchema +from api.models.schema import DatasetMetadata def main(output_name: str = "api/models/schemas/schema.json"): - schema = DatasetSchema.schema() - json_schema = DatasetSchema.schema_json()#indent=2) + schema = DatasetMetadata.schema() + json_schema = DatasetMetadata.schema_json()#indent=2) # Have to run it a few times for the definitions to get updated before inserted into another model while "#/definitions/" in json_schema: for definition in schema["definitions"]: diff --git a/api/models/schema.py b/api/models/schema.py index aff0c99..38b785f 100644 --- a/api/models/schema.py +++ b/api/models/schema.py @@ -413,10 +413,6 @@ class MediaObject(SchemaBaseModel): title="Temporal coverage", description="The temporal coverage of the media object." ) - sourceOrganization: Optional[MediaObjectSourceOrganization] = Field( - title="Source organization", - description="The organization that provided the media object." - ) sha256: Optional[str] = Field(title="SHA-256", description="The SHA-256 hash of the media object.") isPartOf: Optional[MediaObjectPartOf] = Field( title="Is part of", @@ -561,6 +557,17 @@ class CoreMetadata(SchemaBaseModel): citation: Optional[List[str]] = Field(title="Citation", description="A bibliographic citation for the resource.") -class DatasetSchema(CoreMetadata): +class DatasetMetadata(CoreMetadata): # used only for generating the JSON-LD schema for a dataset. - pass + variableMeasured: Optional[List[Union[str, PropertyValue]]] = Field( + title="Variables measured", description="Measured variables." + ) + additionalProperty: Optional[List[PropertyValue]] = Field( + title="Additional properties", + default=[], + description="Additional properties of the Dataset." + ) + sourceOrganization: Optional[MediaObjectSourceOrganization] = Field( + title="Source organization", + description="The organization that provided the data for this dataset." + ) diff --git a/api/models/schemas/schema.json b/api/models/schemas/schema.json index eed64b1..0019d74 100644 --- a/api/models/schemas/schema.json +++ b/api/models/schemas/schema.json @@ -1,5 +1,5 @@ { - "title": "DatasetSchema", + "title": "DatasetMetadata", "type": "object", "properties": { "@context": { @@ -1014,185 +1014,80 @@ "description": "The name of the media object (file).", "type": "string" }, - "additionalProperty": { - "title": "Additional properties", - "description": "Additional properties of the media object.", - "default": [], - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } + "spatialCoverage": { + "title": "Place", + "description": "The spatial coverage of the media object.", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "Represents the focus area of the record's content.", + "default": "Place", + "type": "string" + }, + "name": { + "title": "Name", + "description": "Name of the place.", + "type": "string" + }, + "geo": { + "title": "Geo", + "description": "Specifies the geographic coordinates of the place in the form of a point location, line, or area coverage extent.", + "anyOf": [ + { + "title": "GeoCoordinates", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", + "default": "GeoCoordinates", + "type": "string" }, - "required": [ - "name", - "value" - ] + "latitude": { + "title": "Latitude", + "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", + "type": "number" + }, + "longitude": { + "title": "Longitude", + "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", + "type": "number" + } }, - { - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] + "required": [ + "latitude", + "longitude" + ] + }, + { + "title": "GeoShape", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A structured representation that describes the coordinates of a geographic feature.", + "default": "GeoShape", + "type": "string" + }, + "box": { + "title": "Box", + "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", + "type": "string" } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } + }, + "required": [ + "box" + ] + } + ] }, - "required": [ - "name", - "value" - ] - } - }, - "variableMeasured": { - "title": "Variables measured", - "description": "Measured variables.", - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { + "additionalProperty": { + "title": "Additional properties", + "description": "Additional properties of the place.", + "default": [], + "type": "array", + "items": { "title": "PropertyValue", "type": "object", "properties": { @@ -1355,258 +1250,19 @@ "value" ] } - ] + } } }, - "spatialCoverage": { - "title": "Place", - "description": "The spatial coverage of the media object.", + "temporalCoverage": { + "title": "TemporalCoverage", + "description": "The temporal coverage of the media object.", "type": "object", "properties": { - "@type": { - "title": "@Type", - "description": "Represents the focus area of the record's content.", - "default": "Place", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the place.", - "type": "string" - }, - "geo": { - "title": "Geo", - "description": "Specifies the geographic coordinates of the place in the form of a point location, line, or area coverage extent.", - "anyOf": [ - { - "title": "GeoCoordinates", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", - "default": "GeoCoordinates", - "type": "string" - }, - "latitude": { - "title": "Latitude", - "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", - "type": "number" - }, - "longitude": { - "title": "Longitude", - "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", - "type": "number" - } - }, - "required": [ - "latitude", - "longitude" - ] - }, - { - "title": "GeoShape", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A structured representation that describes the coordinates of a geographic feature.", - "default": "GeoShape", - "type": "string" - }, - "box": { - "title": "Box", - "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", - "type": "string" - } - }, - "required": [ - "box" - ] - } - ] - }, - "additionalProperty": { - "title": "Additional properties", - "description": "Additional properties of the place.", - "default": [], - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - { - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - } - }, - "temporalCoverage": { - "title": "TemporalCoverage", - "description": "The temporal coverage of the media object.", - "type": "object", - "properties": { - "startDate": { - "title": "Start date", - "description": "A date/time object containing the instant corresponding to the commencement of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM).", - "type": "string", - "format": "date-time" + "startDate": { + "title": "Start date", + "description": "A date/time object containing the instant corresponding to the commencement of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM).", + "type": "string", + "format": "date-time" }, "endDate": { "title": "End date", @@ -1619,25 +1275,30 @@ "startDate" ] }, - "sourceOrganization": { - "title": "MediaObjectSourceOrganization", - "description": "The organization that provided the media object.", + "sha256": { + "title": "SHA-256", + "description": "The SHA-256 hash of the media object.", + "type": "string" + }, + "isPartOf": { + "title": "MediaObjectPartOf", + "description": "Link to or citation for a related metadata document that this media object is a part of", "type": "object", "properties": { "@type": { "title": "@Type", - "default": "Organization", - "const": "Organization", + "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", + "default": "CreativeWork", "type": "string" }, "name": { - "title": "Name", - "description": "Name of the organization that created the media object.", + "title": "Name or title", + "description": "Submission's name or title", "type": "string" }, "url": { "title": "URL", - "description": "A URL to the homepage for the organization.", + "description": "The URL address to the related metadata document.", "minLength": 1, "maxLength": 2083, "type": "string", @@ -1646,133 +1307,472 @@ "pattern": "must match format \"url\"" } }, - "address": { - "title": "Address", - "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", + "description": { + "title": "Description", + "description": "Information about a related metadata document.", "type": "string" } }, "required": [ "name" ] - }, - "sha256": { - "title": "SHA-256", - "description": "The SHA-256 hash of the media object.", + } + }, + "required": [ + "contentUrl", + "encodingFormat", + "contentSize", + "name" + ] + } + }, + "citation": { + "title": "Citation", + "description": "A bibliographic citation for the resource.", + "type": "array", + "items": { + "type": "string" + } + }, + "variableMeasured": { + "title": "Variables measured", + "description": "Measured variables.", + "type": "array", + "items": { + "anyOf": [ + { "type": "string" }, - "isPartOf": { - "title": "MediaObjectPartOf", - "description": "Link to or citation for a related metadata document that this media object is a part of", + { + "title": "PropertyValue", "type": "object", "properties": { "@type": { "title": "@Type", - "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", - "default": "CreativeWork", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", "type": "string" }, "name": { - "title": "Name or title", - "description": "Submission's name or title", + "title": "Name", + "description": "The name of the property.", "type": "string" }, - "url": { - "title": "URL", - "description": "The URL address to the related metadata document.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } + "value": { + "title": "Value", + "description": "The value of the property.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "type": "string" + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + }, + { + "type": "array", + "items": { + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "type": "string" + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + } + } + ] + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" }, "description": { "title": "Description", - "description": "Information about a related metadata document.", + "description": "A description of the property.", "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" } }, "required": [ - "name" + "name", + "value" ] } - }, - "required": [ - "contentUrl", - "encodingFormat", - "contentSize", - "name" ] } }, - "citation": { - "title": "Citation", - "description": "A bibliographic citation for the resource.", + "additionalProperty": { + "title": "Additional properties", + "description": "Additional properties of the Dataset.", + "default": [], "type": "array", "items": { - "type": "string" - } - } - }, - "required": [ - "name", - "description", - "url", - "creator", - "dateCreated", - "keywords", - "license", - "provider" - ], - "definitions": { - "Affiliation": { - "title": "Affiliation", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "Organization", - "const": "Organization", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the organization the creator is affiliated with.", - "type": "string" - }, - "url": { - "title": "URL", - "description": "A URL to the homepage for the organization.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } - }, - "address": { - "title": "Address", - "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "Creator": { - "title": "Creator", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A person.", - "default": "Person", - "const": "Person", - "type": "string" + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "type": "string" + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + }, + { + "type": "array", + "items": { + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "type": "string" + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + } + } + ] + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + } + }, + "sourceOrganization": { + "title": "MediaObjectSourceOrganization", + "description": "The organization that provided the data for this dataset.", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "Organization", + "const": "Organization", + "type": "string" + }, + "name": { + "title": "Name", + "description": "Name of the organization that created the media object.", + "type": "string" + }, + "url": { + "title": "URL", + "description": "A URL to the homepage for the organization.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "address": { + "title": "Address", + "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", + "type": "string" + } + }, + "required": [ + "name" + ] + } + }, + "required": [ + "name", + "description", + "url", + "creator", + "dateCreated", + "keywords", + "license", + "provider" + ], + "definitions": { + "Affiliation": { + "title": "Affiliation", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "Organization", + "const": "Organization", + "type": "string" + }, + "name": { + "title": "Name", + "description": "Name of the organization the creator is affiliated with.", + "type": "string" + }, + "url": { + "title": "URL", + "description": "A URL to the homepage for the organization.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "address": { + "title": "Address", + "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "Creator": { + "title": "Creator", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A person.", + "default": "Person", + "const": "Person", + "type": "string" }, "name": { "title": "Name", @@ -1988,783 +1988,23 @@ ] }, "PublisherOrganization": { - "title": "PublisherOrganization", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "Organization", - "const": "Organization", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the publishing organization.", - "type": "string" - }, - "url": { - "title": "URL", - "description": "A URL to the homepage for the publisher organization or repository.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } - }, - "address": { - "title": "Address", - "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "SubjectOf": { - "title": "SubjectOf", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", - "default": "CreativeWork", - "type": "string" - }, - "name": { - "title": "Name or title", - "description": "Submission's name or title", - "type": "string" - }, - "url": { - "title": "URL", - "description": "The URL address that serves as a reference to access additional details related to the record. It is important to note that this type of metadata solely pertains to the record itself and may not necessarily be an integral component of the record, unlike the HasPart metadata.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } - }, - "description": { - "title": "Description", - "description": "Information about a related resource that is about or describes this resource - e.g., a related metadata document describing the resource.", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "LanguageEnum": { - "title": "Language", - "description": "", - "enum": [ - "eng", - "esp" - ], - "type": "string" - }, - "Draft": { - "title": "Draft", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "DefinedTerm", - "type": "string" - }, - "name": { - "title": "Name", - "default": "Draft", - "type": "string" - }, - "description": { - "title": "Description", - "description": "The description of the item being defined.", - "default": "The resource is in draft state and should not be considered final. Content and metadata may change", - "readOnly": true, - "type": "string" - } - } - }, - "Incomplete": { - "title": "Incomplete", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "DefinedTerm", - "type": "string" - }, - "name": { - "title": "Name", - "default": "Incomplete", - "type": "string" - }, - "description": { - "title": "Description", - "description": "The description of the item being defined.", - "default": "Data collection is ongoing or the resource is not completed", - "readOnly": true, - "type": "string" - } - } - }, - "Obsolete": { - "title": "Obsolete", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "DefinedTerm", - "type": "string" - }, - "name": { - "title": "Name", - "default": "Obsolete", - "type": "string" - }, - "description": { - "title": "Description", - "description": "The description of the item being defined.", - "default": "The resource has been replaced by a newer version, or the resource is no longer considered applicable", - "readOnly": true, - "type": "string" - } - } - }, - "Published": { - "title": "Published", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "DefinedTerm", - "type": "string" - }, - "name": { - "title": "Name", - "default": "Published", - "type": "string" - }, - "description": { - "title": "Description", - "description": "The description of the item being defined.", - "default": "The resource has been permanently published and should be considered final and complete", - "readOnly": true, - "type": "string" - } - } - }, - "Grant": { - "title": "Grant", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "This metadata represents details about a grant or financial assistance provided to an individual(s) or organization(s) for supporting the work related to the record.", - "default": "MonetaryGrant", - "type": "string" - }, - "name": { - "title": "Name or title", - "description": "A text string indicating the name or title of the grant or financial assistance.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A text string describing the grant or financial assistance.", - "type": "string" - }, - "identifier": { - "title": "Funding identifier", - "description": "Grant award number or other identifier.", - "type": "string" - }, - "funder": { - "title": "Funding Organization", - "description": "The organization that provided the funding or sponsorship.", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "Organization", - "const": "Organization", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the organization.", - "type": "string" - }, - "url": { - "title": "URL", - "description": "A URL to the homepage for the organization.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } - }, - "address": { - "title": "Address", - "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", - "type": "string" - } - }, - "required": [ - "name" - ] - } - }, - "required": [ - "name" - ] - }, - "TemporalCoverage": { - "title": "TemporalCoverage", - "type": "object", - "properties": { - "startDate": { - "title": "Start date", - "description": "A date/time object containing the instant corresponding to the commencement of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM).", - "type": "string", - "format": "date-time" - }, - "endDate": { - "title": "End date", - "description": "A date/time object containing the instant corresponding to the termination of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM). If the ending date is left off, that means the temporal coverage is ongoing.", - "type": "string", - "format": "date-time" - } - }, - "required": [ - "startDate" - ] - }, - "GeoCoordinates": { - "title": "GeoCoordinates", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", - "default": "GeoCoordinates", - "type": "string" - }, - "latitude": { - "title": "Latitude", - "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", - "type": "number" - }, - "longitude": { - "title": "Longitude", - "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", - "type": "number" - } - }, - "required": [ - "latitude", - "longitude" - ] - }, - "GeoShape": { - "title": "GeoShape", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A structured representation that describes the coordinates of a geographic feature.", - "default": "GeoShape", - "type": "string" - }, - "box": { - "title": "Box", - "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", - "type": "string" - } - }, - "required": [ - "box" - ] - }, - "PropertyValueBase": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - "PropertyValue": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - { - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - "Place": { - "title": "Place", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Represents the focus area of the record's content.", - "default": "Place", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the place.", - "type": "string" - }, - "geo": { - "title": "Geo", - "description": "Specifies the geographic coordinates of the place in the form of a point location, line, or area coverage extent.", - "anyOf": [ - { - "title": "GeoCoordinates", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", - "default": "GeoCoordinates", - "type": "string" - }, - "latitude": { - "title": "Latitude", - "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", - "type": "number" - }, - "longitude": { - "title": "Longitude", - "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", - "type": "number" - } - }, - "required": [ - "latitude", - "longitude" - ] - }, - { - "title": "GeoShape", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A structured representation that describes the coordinates of a geographic feature.", - "default": "GeoShape", - "type": "string" - }, - "box": { - "title": "Box", - "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", - "type": "string" - } - }, - "required": [ - "box" - ] - } - ] - }, - "additionalProperty": { - "title": "Additional properties", - "description": "Additional properties of the place.", - "default": [], - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - { - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - } - }, - "HasPart": { - "title": "HasPart", + "title": "PublisherOrganization", "type": "object", "properties": { "@type": { "title": "@Type", - "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", - "default": "CreativeWork", + "default": "Organization", + "const": "Organization", "type": "string" }, "name": { - "title": "Name or title", - "description": "Submission's name or title", + "title": "Name", + "description": "Name of the publishing organization.", "type": "string" }, "url": { "title": "URL", - "description": "The URL address to the data resource.", + "description": "A URL to the homepage for the publisher organization or repository.", "minLength": 1, "maxLength": 2083, "type": "string", @@ -2773,9 +2013,9 @@ "pattern": "must match format \"url\"" } }, - "description": { - "title": "Description", - "description": "Information about a related resource that is part of this resource.", + "address": { + "title": "Address", + "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", "type": "string" } }, @@ -2783,8 +2023,8 @@ "name" ] }, - "IsPartOf": { - "title": "IsPartOf", + "SubjectOf": { + "title": "SubjectOf", "type": "object", "properties": { "@type": { @@ -2800,7 +2040,7 @@ }, "url": { "title": "URL", - "description": "The URL address to the data resource.", + "description": "The URL address that serves as a reference to access additional details related to the record. It is important to note that this type of metadata solely pertains to the record itself and may not necessarily be an integral component of the record, unlike the HasPart metadata.", "minLength": 1, "maxLength": 2083, "type": "string", @@ -2811,125 +2051,534 @@ }, "description": { "title": "Description", - "description": "Information about a related resource that this resource is a part of - e.g., a related collection.", + "description": "Information about a related resource that is about or describes this resource - e.g., a related metadata document describing the resource.", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "LanguageEnum": { + "title": "Language", + "description": "", + "enum": [ + "eng", + "esp" + ], + "type": "string" + }, + "Draft": { + "title": "Draft", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "DefinedTerm", + "type": "string" + }, + "name": { + "title": "Name", + "default": "Draft", + "type": "string" + }, + "description": { + "title": "Description", + "description": "The description of the item being defined.", + "default": "The resource is in draft state and should not be considered final. Content and metadata may change", + "readOnly": true, + "type": "string" + } + } + }, + "Incomplete": { + "title": "Incomplete", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "DefinedTerm", + "type": "string" + }, + "name": { + "title": "Name", + "default": "Incomplete", + "type": "string" + }, + "description": { + "title": "Description", + "description": "The description of the item being defined.", + "default": "Data collection is ongoing or the resource is not completed", + "readOnly": true, + "type": "string" + } + } + }, + "Obsolete": { + "title": "Obsolete", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "DefinedTerm", + "type": "string" + }, + "name": { + "title": "Name", + "default": "Obsolete", + "type": "string" + }, + "description": { + "title": "Description", + "description": "The description of the item being defined.", + "default": "The resource has been replaced by a newer version, or the resource is no longer considered applicable", + "readOnly": true, + "type": "string" + } + } + }, + "Published": { + "title": "Published", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "DefinedTerm", + "type": "string" + }, + "name": { + "title": "Name", + "default": "Published", + "type": "string" + }, + "description": { + "title": "Description", + "description": "The description of the item being defined.", + "default": "The resource has been permanently published and should be considered final and complete", + "readOnly": true, + "type": "string" + } + } + }, + "Grant": { + "title": "Grant", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "This metadata represents details about a grant or financial assistance provided to an individual(s) or organization(s) for supporting the work related to the record.", + "default": "MonetaryGrant", + "type": "string" + }, + "name": { + "title": "Name or title", + "description": "A text string indicating the name or title of the grant or financial assistance.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A text string describing the grant or financial assistance.", + "type": "string" + }, + "identifier": { + "title": "Funding identifier", + "description": "Grant award number or other identifier.", + "type": "string" + }, + "funder": { + "title": "Funding Organization", + "description": "The organization that provided the funding or sponsorship.", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "Organization", + "const": "Organization", + "type": "string" + }, + "name": { + "title": "Name", + "description": "Name of the organization.", + "type": "string" + }, + "url": { + "title": "URL", + "description": "A URL to the homepage for the organization.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "address": { + "title": "Address", + "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", + "type": "string" + } + }, + "required": [ + "name" + ] + } + }, + "required": [ + "name" + ] + }, + "TemporalCoverage": { + "title": "TemporalCoverage", + "type": "object", + "properties": { + "startDate": { + "title": "Start date", + "description": "A date/time object containing the instant corresponding to the commencement of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM).", + "type": "string", + "format": "date-time" + }, + "endDate": { + "title": "End date", + "description": "A date/time object containing the instant corresponding to the termination of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM). If the ending date is left off, that means the temporal coverage is ongoing.", + "type": "string", + "format": "date-time" + } + }, + "required": [ + "startDate" + ] + }, + "GeoCoordinates": { + "title": "GeoCoordinates", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", + "default": "GeoCoordinates", + "type": "string" + }, + "latitude": { + "title": "Latitude", + "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", + "type": "number" + }, + "longitude": { + "title": "Longitude", + "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", + "type": "number" + } + }, + "required": [ + "latitude", + "longitude" + ] + }, + "GeoShape": { + "title": "GeoShape", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A structured representation that describes the coordinates of a geographic feature.", + "default": "GeoShape", + "type": "string" + }, + "box": { + "title": "Box", + "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", "type": "string" } }, "required": [ - "name" + "box" ] }, - "MediaObjectSourceOrganization": { - "title": "MediaObjectSourceOrganization", + "PropertyValueBase": { + "title": "PropertyValue", "type": "object", "properties": { "@type": { "title": "@Type", - "default": "Organization", - "const": "Organization", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", "type": "string" }, "name": { "title": "Name", - "description": "Name of the organization that created the media object.", + "description": "The name of the property.", "type": "string" }, - "url": { - "title": "URL", - "description": "A URL to the homepage for the organization.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } + "value": { + "title": "Value", + "description": "The value of the property.", + "type": "string" }, - "address": { - "title": "Address", - "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" } }, "required": [ - "name" + "name", + "value" ] }, - "MediaObjectPartOf": { - "title": "MediaObjectPartOf", + "PropertyValue": { + "title": "PropertyValue", "type": "object", "properties": { "@type": { "title": "@Type", - "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", - "default": "CreativeWork", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", "type": "string" }, "name": { - "title": "Name or title", - "description": "Submission's name or title", + "title": "Name", + "description": "The name of the property.", "type": "string" }, - "url": { - "title": "URL", - "description": "The URL address to the related metadata document.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } + "value": { + "title": "Value", + "description": "The value of the property.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "type": "string" + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + }, + { + "type": "array", + "items": { + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" + }, + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "type": "string" + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + } + } + ] + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" }, "description": { "title": "Description", - "description": "Information about a related metadata document.", + "description": "A description of the property.", "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" } }, "required": [ - "name" + "name", + "value" ] }, - "MediaObject": { - "title": "MediaObject", + "Place": { + "title": "Place", "type": "object", "properties": { "@type": { "title": "@Type", - "description": "An item that encodes the record.", - "default": "MediaObject", - "type": "string" - }, - "contentUrl": { - "title": "Content URL", - "description": "The direct URL link to access or download the actual content of the media object.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } - }, - "encodingFormat": { - "title": "Encoding format", - "description": "Represents the specific file format in which the media is encoded.", - "type": "string" - }, - "contentSize": { - "title": "Content size", - "description": "Represents the file size, expressed in bytes, kilobytes, megabytes, or another unit of measurement.", + "description": "Represents the focus area of the record's content.", + "default": "Place", "type": "string" }, "name": { "title": "Name", - "description": "The name of the media object (file).", + "description": "Name of the place.", "type": "string" }, + "geo": { + "title": "Geo", + "description": "Specifies the geographic coordinates of the place in the form of a point location, line, or area coverage extent.", + "anyOf": [ + { + "title": "GeoCoordinates", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", + "default": "GeoCoordinates", + "type": "string" + }, + "latitude": { + "title": "Latitude", + "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", + "type": "number" + }, + "longitude": { + "title": "Longitude", + "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", + "type": "number" + } + }, + "required": [ + "latitude", + "longitude" + ] + }, + { + "title": "GeoShape", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A structured representation that describes the coordinates of a geographic feature.", + "default": "GeoShape", + "type": "string" + }, + "box": { + "title": "Box", + "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", + "type": "string" + } + }, + "required": [ + "box" + ] + } + ] + }, "additionalProperty": { "title": "Additional properties", - "description": "Additional properties of the media object.", + "description": "Additional properties of the place.", "default": [], "type": "array", "items": { @@ -3053,223 +2702,194 @@ "minValue": { "title": "Minimum value", "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - }, - "variableMeasured": { - "title": "Variables measured", - "description": "Measured variables.", - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - { - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" + } + }, + "required": [ + "name", + "value" + ] + } } - }, - "required": [ - "name", - "value" ] + }, + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "A description of the property.", + "type": "string" + }, + "minValue": { + "title": "Minimum value", + "description": "The minimum allowed value for the property.", + "type": "number" + }, + "maxValue": { + "title": "Maximum value", + "description": "The maximum allowed value for the property.", + "type": "number" } + }, + "required": [ + "name", + "value" ] } + } + } + }, + "HasPart": { + "title": "HasPart", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", + "default": "CreativeWork", + "type": "string" + }, + "name": { + "title": "Name or title", + "description": "Submission's name or title", + "type": "string" + }, + "url": { + "title": "URL", + "description": "The URL address to the data resource.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "description": { + "title": "Description", + "description": "Information about a related resource that is part of this resource.", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "IsPartOf": { + "title": "IsPartOf", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", + "default": "CreativeWork", + "type": "string" + }, + "name": { + "title": "Name or title", + "description": "Submission's name or title", + "type": "string" + }, + "url": { + "title": "URL", + "description": "The URL address to the data resource.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "description": { + "title": "Description", + "description": "Information about a related resource that this resource is a part of - e.g., a related collection.", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "MediaObjectPartOf": { + "title": "MediaObjectPartOf", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "Submission type can include various forms of content, such as datasets, software source code, digital documents, etc.", + "default": "CreativeWork", + "type": "string" + }, + "name": { + "title": "Name or title", + "description": "Submission's name or title", + "type": "string" + }, + "url": { + "title": "URL", + "description": "The URL address to the related metadata document.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "description": { + "title": "Description", + "description": "Information about a related metadata document.", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "MediaObject": { + "title": "MediaObject", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "An item that encodes the record.", + "default": "MediaObject", + "type": "string" + }, + "contentUrl": { + "title": "Content URL", + "description": "The direct URL link to access or download the actual content of the media object.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "encodingFormat": { + "title": "Encoding format", + "description": "Represents the specific file format in which the media is encoded.", + "type": "string" + }, + "contentSize": { + "title": "Content size", + "description": "Represents the file size, expressed in bytes, kilobytes, megabytes, or another unit of measurement.", + "type": "string" + }, + "name": { + "title": "Name", + "description": "The name of the media object (file).", + "type": "string" }, "spatialCoverage": { "title": "Place", @@ -3532,43 +3152,6 @@ "startDate" ] }, - "sourceOrganization": { - "title": "MediaObjectSourceOrganization", - "description": "The organization that provided the media object.", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "default": "Organization", - "const": "Organization", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the organization that created the media object.", - "type": "string" - }, - "url": { - "title": "URL", - "description": "A URL to the homepage for the organization.", - "minLength": 1, - "maxLength": 2083, - "type": "string", - "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", - "errorMessage": { - "pattern": "must match format \"url\"" - } - }, - "address": { - "title": "Address", - "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", - "type": "string" - } - }, - "required": [ - "name" - ] - }, "sha256": { "title": "SHA-256", "description": "The SHA-256 hash of the media object.", @@ -3618,6 +3201,42 @@ "contentSize", "name" ] + }, + "MediaObjectSourceOrganization": { + "title": "MediaObjectSourceOrganization", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "Organization", + "const": "Organization", + "type": "string" + }, + "name": { + "title": "Name", + "description": "Name of the organization that created the media object.", + "type": "string" + }, + "url": { + "title": "URL", + "description": "A URL to the homepage for the organization.", + "minLength": 1, + "maxLength": 2083, + "type": "string", + "pattern": "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$", + "errorMessage": { + "pattern": "must match format \"url\"" + } + }, + "address": { + "title": "Address", + "description": "Full address for the organization - e.g., \u201c8200 Old Main Hill, Logan, UT 84322-8200\u201d.", + "type": "string" + } + }, + "required": [ + "name" + ] } } } \ No newline at end of file From c4bce4765cb618bab3db2ef3cbda62e1767fdb39 Mon Sep 17 00:00:00 2001 From: pkdash Date: Tue, 12 Mar 2024 11:06:41 -0400 Subject: [PATCH 2/7] [#98] updating/adding tests --- tests/conftest.py | 25 +- tests/data/dataset_metadata.json | 146 ++++++++++++ tests/test_core_schema.py | 119 ---------- tests/test_dataset_routes.py | 22 +- tests/test_dataset_schema.py | 377 +++++++++++++++++++++++-------- 5 files changed, 454 insertions(+), 235 deletions(-) create mode 100644 tests/data/dataset_metadata.json diff --git a/tests/conftest.py b/tests/conftest.py index fba78dd..ee1662c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ from api.main import app from api.authentication.user import get_current_user from api.models.catalog import CoreMetadataDOC, Submission -from api.models.schema import CoreMetadata +from api.models.schema import CoreMetadata, DatasetMetadata from api.models.user import User from api.procedures.user import create_or_update_user @@ -72,10 +72,9 @@ async def core_data(change_test_dir): @pytest_asyncio.fixture -async def dataset_data(core_data): - _dataset_data = core_data.copy() - # currently the dataset model does not have any additional fields - return _dataset_data +async def dataset_data(change_test_dir): + with open("data/dataset_metadata.json", "r") as f: + return json.loads(f.read()) @pytest_asyncio.fixture @@ -85,10 +84,7 @@ async def core_model(): @pytest_asyncio.fixture async def dataset_model(): - class _Dataset(CoreMetadata): - pass - - return _Dataset + return DatasetMetadata @pytest_asyncio.fixture @@ -105,20 +101,17 @@ async def hydroshare_collection_metadata(hydroshare_resource_metadata): relations = [ { "type": "This resource includes", - "value": "Tarboton, D. (2019). Created from iRODS by copy from create resource page, HydroShare, http://www.hydroshare.org/resource/abba182072cc48b691ca61509019e9f8" + "value": "Tarboton, D. (2019). Created from iRODS by copy from create resource page, HydroShare, http://www.hydroshare.org/resource/abba182072cc48b691ca61509019e9f8", }, { "type": "This resource includes", - "value": "Dash, P. (2017). Water quality sensor data from the Little Bear River at Mendon Road near Mendon, UT, HydroShare, http://www.hydroshare.org/resource/fd6f39c25ccf492992c79465a2bf0030" + "value": "Dash, P. (2017). Water quality sensor data from the Little Bear River at Mendon Road near Mendon, UT, HydroShare, http://www.hydroshare.org/resource/fd6f39c25ccf492992c79465a2bf0030", }, { "type": "This resource includes", - "value": "Gan, T. (2016). Composite Resource Type Design, HydroShare, http://www.hydroshare.org/resource/e8cd813e376347c5b617deb321227a36" + "value": "Gan, T. (2016). Composite Resource Type Design, HydroShare, http://www.hydroshare.org/resource/e8cd813e376347c5b617deb321227a36", }, - { - "type": "This resource is described by", - "value": "another resource" - } + {"type": "This resource is described by", "value": "another resource"}, ] collection_meta["relations"] = relations return collection_meta diff --git a/tests/data/dataset_metadata.json b/tests/data/dataset_metadata.json new file mode 100644 index 0000000..fa40278 --- /dev/null +++ b/tests/data/dataset_metadata.json @@ -0,0 +1,146 @@ +{ + "@context": "https://schema.org", + "@type": "Dataset", + "name": "Test Dataset", + "description": "This is a test dataset metadata json file to test catalog api", + "url": "https://hydroshare.org/resource/e2fdf99cbb0c4275b32afd3c16ae6863", + "identifier": ["https://www.hydroshare.org/resource/6625bdbde41c45c2b906f32be7ea70f0/"], + "creator": [ + { + "@type": "Person", + "name": "John Doe", + "email": "john.doe@gmail.com", + "identifier": "https://orcid.org/0000-0000-0000-0001", + "affiliation": { + "@type": "Organization", + "name": "Utah State University", + "url": "https://www.usu.edu/", + "address": "Logan, UT 84322" + } + } + ], + "dateCreated": "2021-01-01T00:00:00", + "keywords": ["keyword1", "keyword2"], + "license": { + "@type": "CreativeWork", + "name": "MIT License", + "url": "https://spdx.org/licenses/MIT", + "description": "A permissive license that is short and to the point. It lets people do anything with your code with proper attribution and without warranty." + }, + "provider": { + "@type": "Organization", + "name": "HydroShare", + "url": "https://hydroshare.org", + "address": "1167 Massachusetts Ave Suites 418 & 419, Arlington, MA 02476" + }, + "publisher": { + "@type": "Organization", + "name": "HydroShare", + "url": "https://hydroshare.org", + "address": "1167 Massachusetts Ave Suites 418 & 419, Arlington, MA 02476" + }, + "datePublished": "2023-05-10T00:00:00", + "subjectOf": [ + { + "@type": "CreativeWork", + "name": "Dublin Core Metadata Document Describing the Dataset", + "url": "https://www.hydroshare.org/hsapi/resource/c1be74eeea614d65a29a185a66a7552f/scimeta/", + "description": "Dublin Core Metadata Document Describing the Dataset" + } + ], + "version": "1.0", + "inLanguage": "eng", + "creativeWorkStatus": { + "@type": "DefinedTerm", + "name": "Draft", + "description": "This is a draft dataset" + }, + "dateModified": "2021-01-10T00:00:00", + "funding": [ + { + "@type": "MonetaryGrant", + "name": "HDR Institute: Geospatial Understanding through an Integrative Discovery Environment", + "description": "This project is part of the National Science Foundation's Big Idea activities in Harnessing the Data Revolution (HDR). The award by the Office of Advanced Cyberinfrastructure is jointly supported by the Division of Behavioral and Cognitive Sciences, the Division of Social and Economic Sciences, and the Office of Multidisciplinary Activities within the Directorate for Social, Behavioral and Economic Sciences; the Division of Earth Sciences within the Directorate for Geosciences; the Division of Mathematical Sciences within the Directorate for Mathematical and Physical Sciences, and by the Division of Information and Intelligent Systems within the Directorate for Computer and Information Science and Engineering.", + "identifier": "NSF AWARD 2118329", + "funder": { + "@type": "Organization", + "name": "National Science Foundation", + "url": "https://www.nsf.gov/", + "address": "2415 Eisenhower Avenue, Alexandria, VA 22314" + } + } + ], + "temporalCoverage": { + "startDate": "2007-03-01T13:00:00Z", + "endDate": "2008-05-11T15:30:00Z" + }, + "spatialCoverage": { + "@type": "Place", + "name": "Somewhere in the world", + "geo": { + "@type": "GeoShape", + "box": "40.1126 -88.2249 40.1126 -88.2249" + }, + "additionalProperty": [] + }, + "hasPart": [ + { + "@type": "CreativeWork", + "name": "Great Salt Lake Bathymetry", + "description": "Digital Elevation Model for the Great Salt Lake, lake bed bathymetry.", + "url": "https://orcid.org/0000-0000-0000-0001" + } + ], + "isPartOf": [ + { + "@type": "CreativeWork", + "name": "Collection of Great Salt Lake Data", + "description": "Data from the Great Salt Lake and its basin", + "url": "https://orcid.org/0000-0000-0000-0001" + } + ], + "associatedMedia": [ + { + "@type": "DataDownload", + "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/USGS_Harvey_gages_TxLaMsAr.csv", + "encodingFormat": "text/csv", + "contentSize": "0.17 MB", + "name": "USGS gage locations within the Harvey-affected areas in Texas", + "sha256": "830f4b50e78e8a8fb0f7eee7369171dacbcaa43cc2c4deb59cef8e4fd2f641c5", + "isPartOf": null, + "spatialCoverage": null, + "temporalCoverage": null + } + ], + "citation": ["Citation for the dataset"], + "additionalProperty": [ + { + "@type": "PropertyValue", + "name": "Rows", + "value": "4981" + }, + { + "@type": "PropertyValue", + "name": "Columns", + "value": "2956" + } + ], + "variableMeasured": [ + { + "@type": "PropertyValue", + "propertyID": "Variable Name", + "name": "Elevation", + "value": "Elevation", + "unitCode": "m", + "minValue": 1358.2, + "maxValue": 3040.8, + "description": "Digital Elevation Model" + } + ], + "sourceOrganization": { + "@type": "Organization", + "name": "The US Geological Survey (USGS)", + "url": "https://www.usgs.gov/3d-elevation-program", + "address": null + } +} \ No newline at end of file diff --git a/tests/test_core_schema.py b/tests/test_core_schema.py index 6be4bad..b5bfe84 100644 --- a/tests/test_core_schema.py +++ b/tests/test_core_schema.py @@ -376,63 +376,6 @@ async def test_core_schema_associated_media_content_size( # validate the data model core_model_instance = await utils.validate_data_model(core_data, core_model) assert core_model_instance.associatedMedia[0].contentSize == content_size_format - assert core_model_instance.associatedMedia[0].additionalProperty == [] - - -@pytest.mark.parametrize("set_additional_property", [True, False]) -@pytest.mark.asyncio -async def test_core_schema_associated_media_additional_property( - core_data, core_model, set_additional_property -): - """Test that a core metadata pydantic model can be created from core metadata json. - Purpose of the test is to validate core metadata schema as defined by the pydantic model where we are testing - valid values for the additionalProperty attribute of the associatedMedia property. - Note: This test does not add a record to the database. - """ - - core_data = core_data - core_model = core_model - content_size_format = "100.17 KB" - core_data["associatedMedia"] = [ - { - "@type": "MediaObject", - "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/USGS_Harvey_gages_TxLaMsAr.csv", - "encodingFormat": "text/csv", - "contentSize": content_size_format, - "name": "USGS gage locations within the Harvey-affected areas in Texas", - } - ] - if set_additional_property: - core_data["associatedMedia"][0]["additionalProperty"] = [ - { - "@type": "PropertyValue", - "name": "Feature Count", - "value": 7, - }, - { - "@type": "PropertyValue", - "name": "Field Count", - "value": 10, - }, - ] - - # validate the data model - core_model_instance = await utils.validate_data_model(core_data, core_model) - assert core_model_instance.associatedMedia[0].contentSize == content_size_format - if set_additional_property: - assert len(core_model_instance.associatedMedia[0].additionalProperty) == 2 - assert ( - core_model_instance.associatedMedia[0].additionalProperty[0].name - == "Feature Count" - ) - assert core_model_instance.associatedMedia[0].additionalProperty[0].value == "7" - assert ( - core_model_instance.associatedMedia[0].additionalProperty[1].name - == "Field Count" - ) - assert core_model_instance.associatedMedia[0].additionalProperty[1].value == '10' - else: - assert core_model_instance.associatedMedia[0].additionalProperty == [] @pytest.mark.parametrize("set_spatial_coverage", [True, False]) @@ -543,68 +486,6 @@ async def test_core_schema_associated_media_temporal_coverage( assert core_model_instance.associatedMedia[0].temporalCoverage is None -@pytest.mark.parametrize("set_source_organization", [True, False]) -@pytest.mark.asyncio -async def test_core_schema_associated_media_source_organization( - core_data, core_model, set_source_organization -): - """Test that a core metadata pydantic model can be created from core metadata json. - Purpose of the test is to validate core metadata schema as defined by the pydantic model where we are testing - valid values for the sourceOrganization attribute of the associatedMedia property. - Note: This test does not add a record to the database. - """ - - core_data = core_data - core_model = core_model - content_size_format = "100.17 KB" - source_organization = { - "@type": "Organization", - "name": "National Hydrography Dataset", - "url": "https://www.usgs.gov/national-hydrography/national-hydrography-dataset", - } - - if set_source_organization: - core_data["associatedMedia"] = [ - { - "@type": "MediaObject", - "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/USGS_Harvey_gages_TxLaMsAr.csv", - "encodingFormat": "text/csv", - "contentSize": content_size_format, - "name": "USGS gage locations within the Harvey-affected areas in Texas", - "sourceOrganization": source_organization, - } - ] - else: - core_data["associatedMedia"] = [ - { - "@type": "MediaObject", - "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/USGS_Harvey_gages_TxLaMsAr.csv", - "encodingFormat": "text/csv", - "contentSize": content_size_format, - "name": "USGS gage locations within the Harvey-affected areas in Texas", - } - ] - - # validate the data model - core_model_instance = await utils.validate_data_model(core_data, core_model) - assert core_model_instance.associatedMedia[0].contentSize == content_size_format - if set_source_organization: - assert ( - core_model_instance.associatedMedia[0].sourceOrganization.type - == source_organization["@type"] - ) - assert ( - core_model_instance.associatedMedia[0].sourceOrganization.name - == source_organization["name"] - ) - assert ( - core_model_instance.associatedMedia[0].sourceOrganization.url - == source_organization["url"] - ) - else: - assert core_model_instance.associatedMedia[0].sourceOrganization is None - - @pytest.mark.parametrize("include_coverage", [True, False]) @pytest.mark.asyncio async def test_core_schema_temporal_coverage_optional(core_data, core_model, include_coverage): diff --git a/tests/test_dataset_routes.py b/tests/test_dataset_routes.py index d96b80d..a459d5f 100644 --- a/tests/test_dataset_routes.py +++ b/tests/test_dataset_routes.py @@ -28,6 +28,14 @@ async def test_create_dataset(client_test, dataset_data, test_user_access_token) response_data['temporalCoverage']['endDate'] = response_data['temporalCoverage']['endDate'][:end_date_length] # assert that the response contains the expected data response_data.pop("repository_identifier") + # remove additional property fields from response_data for which the test data does not have values + for a_property in response_data["additionalProperty"]: + assert a_property.pop("description") is None + assert a_property.pop("minValue") is None + assert a_property.pop("maxValue") is None + assert a_property.pop("unitCode") is None + assert a_property.pop("propertyID") is None + assert response_data == dataset_data # there should be one related submission record in the db submissions = await Submission.find().to_list() @@ -93,6 +101,13 @@ async def test_update_dataset(client_test, dataset_data): response_data.pop('_id') # assert that the response contains the expected data response_data.pop("repository_identifier") + # remove additional property fields from response_data for which the test data does not have values + for a_property in response_data["additionalProperty"]: + assert a_property.pop("description") is None + assert a_property.pop("minValue") is None + assert a_property.pop("maxValue") is None + assert a_property.pop("unitCode") is None + assert a_property.pop("propertyID") is None assert response_data == dataset_data @@ -153,7 +168,12 @@ async def test_get_datasets_exclude_none(client_test, dataset_data): assert dataset_response.status_code == 200 dataset_response_data = dataset_response.json() assert "version" not in dataset_response_data[0] - + for a_property in dataset_response_data[0]["additionalProperty"]: + assert "description" not in a_property + assert "minValue" not in a_property + assert "maxValue" not in a_property + assert "unitCode" not in a_property + assert "propertyID" not in a_property @pytest.mark.parametrize("multiple", [True, False]) @pytest.mark.asyncio diff --git a/tests/test_dataset_schema.py b/tests/test_dataset_schema.py index 99baa0d..313fee3 100644 --- a/tests/test_dataset_schema.py +++ b/tests/test_dataset_schema.py @@ -3,10 +3,194 @@ from tests import utils -@pytest.mark.skip(reason="Dataset specific metadata is currently not implemented") -@pytest.mark.parametrize('multiple_distribution', [True, False]) +@pytest.mark.parametrize("set_additional_property", [True, False]) @pytest.mark.asyncio -async def test_dataset_schema_distribution_cardinality(dataset_data, dataset_model, multiple_distribution): +async def test_dataset_schema_additional_property( + dataset_data, dataset_model, set_additional_property +): + """Test that a dataset metadata pydantic model can be created from dataset metadata json. + Purpose of the test is to validate dataset metadata schema as defined by the pydantic model where we are testing + valid values for the additionalProperty property. + Note: This test does not add a record to the database. + """ + + dataset_data = dataset_data + dataset_model = dataset_model + additional_property = [ + { + "@type": "PropertyValue", + "name": "Feature Count", + "value": "7", + }, + { + "@type": "PropertyValue", + "name": "Field Count", + "value": "10", + }, + ] + if set_additional_property: + dataset_data["additionalProperty"] = additional_property + else: + dataset_data.pop("additionalProperty", None) + + # validate the data model + dataset_model_instance = await utils.validate_data_model(dataset_data, dataset_model) + if set_additional_property: + assert len(dataset_model_instance.additionalProperty) == 2 + assert dataset_model_instance.additionalProperty[0].name == additional_property[0]["name"] + assert dataset_model_instance.additionalProperty[0].value == additional_property[0]["value"] + assert dataset_model_instance.additionalProperty[1].name == additional_property[1]["name"] + assert dataset_model_instance.additionalProperty[1].value == additional_property[1]["value"] + else: + assert dataset_model_instance.additionalProperty == [] + + +@pytest.mark.parametrize("set_source_organization", [True, False]) +@pytest.mark.asyncio +async def test_dataset_schema_source_organization( + dataset_data, dataset_model, set_source_organization +): + """Test that a dataset metadata pydantic model can be created from dataset metadata json. + Purpose of the test is to validate dataset metadata schema as defined by the pydantic model where we are testing + valid values for the sourceOrganization property. + Note: This test does not add a record to the database. + """ + + dataset_data = dataset_data + dataset_model = dataset_model + source_organization = { + "@type": "Organization", + "name": "National Hydrography Dataset", + "url": "https://www.usgs.gov/national-hydrography/national-hydrography-dataset", + } + + if set_source_organization: + dataset_data["sourceOrganization"] = source_organization + else: + dataset_data.pop("sourceOrganization", None) + + # validate the data model + dataset_instance = await utils.validate_data_model(dataset_data, dataset_model) + if set_source_organization: + assert dataset_instance.sourceOrganization.type == source_organization["@type"] + assert dataset_instance.sourceOrganization.name == source_organization["name"] + assert dataset_instance.sourceOrganization.url == source_organization["url"] + else: + assert dataset_instance.sourceOrganization is None + + +@pytest.mark.parametrize("multiple_variable", [True, False, None]) +@pytest.mark.asyncio +async def test_dataset_schema_variable_cardinality( + dataset_data, dataset_model, multiple_variable +): + """Test that a dataset pydantic model can be created from dataset json data. + Purpose of the test is to validate dataset pydantic model where the variableMeasured property can + have 0 or more values. + Note: This test does nat add a record to the database. + """ + dataset_data = dataset_data + dataset_model = dataset_model + + if multiple_variable and multiple_variable is not None: + dataset_data["variableMeasured"] = [ + { + "@type": "PropertyValue", + "name": "Streambed interface temperature values", + "value": "10.5", + "unitCode": "degC", + }, + { + "@type": "PropertyValue", + "name": "Air flow rate", + "value": "0.5", + "unitCode": "m/sec" + }, + ] + elif multiple_variable is not None: + dataset_data["variableMeasured"] = [ + { + "@type": "PropertyValue", + "name": "Streambed interface temperature values", + "value": "10.5", + "unitCode": "degC", + } + ] + else: + dataset_data["variableMeasured"] = [] + + # validate the dataset model + dataset_instance = await utils.validate_data_model(dataset_data, dataset_model) + # checking dataset specific metadata + if multiple_variable and multiple_variable is not None: + assert len(dataset_instance.variableMeasured) == 2 + assert dataset_instance.variableMeasured[0].name == "Streambed interface temperature values" + assert dataset_instance.variableMeasured[1].name == "Air flow rate" + assert dataset_instance.variableMeasured[0].unitCode == "degC" + assert dataset_instance.variableMeasured[1].unitCode == "m/sec" + assert dataset_instance.variableMeasured[0].value == "10.5" + assert dataset_instance.variableMeasured[1].value == "0.5" + elif multiple_variable is not None: + assert dataset_instance.variableMeasured[0].name == "Streambed interface temperature values" + assert dataset_instance.variableMeasured[0].unitCode == "degC" + assert dataset_instance.variableMeasured[0].value == "10.5" + else: + assert dataset_instance.variableMeasured == [] + +@pytest.mark.parametrize( + "data_format", + [ + [ + { + "@type": "PropertyValue", + "propertyID": "Variable Name", + "name": "Elevation", + "value": "Elevation", + "unitCode": "m", + "minValue": "1358.2", + "maxValue": "3040.8", + "description": "Digital Elevation Model", + }, + ], + ["Var-1", "Var-2"], + + ], +) +@pytest.mark.asyncio +async def test_dataset_schema_variable_value_type( + dataset_data, dataset_model, data_format +): + """Test that a dataset pydantic model can be created from dataset json data. + Purpose of the test is to validate dataset pydantic model where we are testing allowed value types for + the variableMeasured property. + Note: This test does nat add a record to the database. + """ + dataset_data = dataset_data + dataset_model = dataset_model + dataset_data["variableMeasured"] = data_format + # validate the data model + dataset_instance = await utils.validate_data_model(dataset_data, dataset_model) + # checking dataset specific metadata + if isinstance(data_format[0], dict): + assert dataset_instance.variableMeasured[0].type == "PropertyValue" + assert dataset_instance.variableMeasured[0].propertyID == "Variable Name" + assert dataset_instance.variableMeasured[0].name == "Elevation" + assert dataset_instance.variableMeasured[0].value == "Elevation" + assert dataset_instance.variableMeasured[0].name == data_format[0]["name"] + assert dataset_instance.variableMeasured[0].unitCode == data_format[0]["unitCode"] + assert dataset_instance.variableMeasured[0].minValue == float(data_format[0]["minValue"]) + assert dataset_instance.variableMeasured[0].maxValue == float(data_format[0]["maxValue"]) + assert dataset_instance.variableMeasured[0].description == data_format[0]["description"] + else: + assert dataset_instance.variableMeasured == data_format + + +@pytest.mark.skip(reason="Dataset distribution metadata field is currently not implemented") +@pytest.mark.parametrize("multiple_distribution", [True, False]) +@pytest.mark.asyncio +async def test_dataset_schema_distribution_cardinality( + dataset_data, dataset_model, multiple_distribution +): """Test that a dataset pydantic model can be created from dataset json data. Purpose of the test is to validate dataset pydantic model where we are testing the distribution property can have one or more values. @@ -50,7 +234,10 @@ async def test_dataset_schema_distribution_cardinality(dataset_data, dataset_mod assert dataset_instance.distribution[1].name == "Bulk Data Download (CSV)" assert dataset_instance.distribution[0].contentSize == "100.5 MB" assert dataset_instance.distribution[1].contentSize == "102.1 MB" - assert dataset_instance.distribution[0].contentUrl == "https://www.ncdc.noaa.gov/stormevents/" + assert ( + dataset_instance.distribution[0].contentUrl + == "https://www.ncdc.noaa.gov/stormevents/" + ) assert ( dataset_instance.distribution[1].contentUrl == "https://www.ncei.noaa.gov/pub/data/swdi/stormevents/csvfiles/" @@ -61,13 +248,16 @@ async def test_dataset_schema_distribution_cardinality(dataset_data, dataset_mod assert dataset_instance.distribution.type == "DataDownload" assert dataset_instance.distribution.name == "Search" assert dataset_instance.distribution.contentSize == "100.5 MB" - assert dataset_instance.distribution.contentUrl == "https://www.ncdc.noaa.gov/stormevents/" + assert ( + dataset_instance.distribution.contentUrl + == "https://www.ncdc.noaa.gov/stormevents/" + ) assert dataset_instance.distribution.encodingFormat == "text/csv" -@pytest.mark.skip(reason="Dataset specific metadata is currently not implemented") +@pytest.mark.skip(reason="Dataset distribution metadata field is currently not implemented") @pytest.mark.parametrize( - 'data_format', + "data_format", [ {"@type": "DataDownload", "name": "Fiber_opticdist.zip"}, { @@ -105,7 +295,9 @@ async def test_dataset_schema_distribution_cardinality(dataset_data, dataset_mod ], ) @pytest.mark.asyncio -async def test_dataset_schema_distribution_value_type(dataset_data, dataset_model, data_format): +async def test_dataset_schema_distribution_value_type( + dataset_data, dataset_model, data_format +): """Test that a dataset pydantic model can be created from dataset json data. Purpose of the test is to validate dataset pydantic model where we are testing allowed value types for distribution property. @@ -124,89 +316,27 @@ async def test_dataset_schema_distribution_value_type(dataset_data, dataset_mode assert dataset_instance.distribution.contentUrl == data_format["contentUrl"] if "encodingFormat" in data_format: if isinstance(data_format["encodingFormat"], list): - assert dataset_instance.distribution.encodingFormat == data_format["encodingFormat"] + assert ( + dataset_instance.distribution.encodingFormat + == data_format["encodingFormat"] + ) else: - assert dataset_instance.distribution.encodingFormat == data_format["encodingFormat"] + assert ( + dataset_instance.distribution.encodingFormat + == data_format["encodingFormat"] + ) if "contentSize" in data_format: assert dataset_instance.distribution.contentSize == data_format["contentSize"] if "comment" in data_format: assert dataset_instance.distribution.comment == data_format["comment"] -@pytest.mark.skip(reason="Dataset specific metadata is currently not implemented") -@pytest.mark.parametrize('multiple_variable', [True, False, None]) -@pytest.mark.asyncio -async def test_dataset_schema_variable_cardinality(dataset_data, dataset_model, multiple_variable): - """Test that a dataset pydantic model can be created from dataset json data. - Purpose of the test is to validate dataset pydantic model where the variable property can have 0 or more values. - Note: This test does nat add a record to the database. - """ - dataset_data = dataset_data - dataset_model = dataset_model - - if multiple_variable and multiple_variable is not None: - dataset_data["variableMeasured"] = [ - {"@type": "PropertyValue", "name": "Streambed interface temperature values", "unitText": "degC"}, - {"@type": "PropertyValue", "name": "Air flow rate", "unitText": "m/sec"}, - ] - elif multiple_variable is not None: - dataset_data["variableMeasured"] = { - "@type": "PropertyValue", - "name": "Streambed interface temperature values", - "unitText": "degC", - } - else: - dataset_data.pop("variableMeasured", None) - - # validate the dataset model - dataset_instance = await utils.validate_data_model(dataset_data, dataset_model) - # checking dataset specific metadata - if multiple_variable and multiple_variable is not None: - assert len(dataset_instance.variableMeasured) == 2 - assert dataset_instance.variableMeasured[0].name == "Streambed interface temperature values" - assert dataset_instance.variableMeasured[1].name == "Air flow rate" - assert dataset_instance.variableMeasured[0].unitText == "degC" - assert dataset_instance.variableMeasured[1].unitText == "m/sec" - elif multiple_variable is not None: - assert dataset_instance.variableMeasured.name == "Streambed interface temperature values" - assert dataset_instance.variableMeasured.unitText == "degC" - else: - assert dataset_instance.variableMeasured is None - - -@pytest.mark.skip(reason="Dataset specific metadata is currently not implemented") -@pytest.mark.parametrize( - 'data_format', - [ - {"@type": "PropertyValue", "name": "Streambed interface temperature values", "unitText": "degC"}, - "Streambed interface temperature values", - ], -) -@pytest.mark.asyncio -async def test_dataset_schema_variable_value_type(dataset_data, dataset_model, data_format): - """Test that a dataset pydantic model can be created from dataset json data. - Purpose of the test is to validate dataset pydantic model where we are testing allowed value types for - the variable property. - Note: This test does nat add a record to the database. - """ - dataset_data = dataset_data - dataset_model = dataset_model - dataset_data["variableMeasured"] = data_format - # validate the data model - dataset_instance = await utils.validate_data_model(dataset_data, dataset_model) - # checking dataset specific metadata - if isinstance(data_format, dict): - assert dataset_instance.variableMeasured.type == "PropertyValue" - assert dataset_instance.variableMeasured.name == data_format["name"] - assert dataset_instance.variableMeasured.unitText == data_format["unitText"] - else: - assert dataset_instance.variableMeasured == data_format - - -@pytest.mark.skip(reason="Dataset specific metadata is currently not implemented") -@pytest.mark.parametrize('multiple_data_catalog', [True, False]) +@pytest.mark.skip(reason="Dataset includedInDataCatalog metadata field is currently not implemented") +@pytest.mark.parametrize("multiple_data_catalog", [True, False]) @pytest.mark.asyncio -async def test_dataset_schema_variable_cardinality(dataset_data, dataset_model, multiple_data_catalog): +async def test_dataset_schema_data_catalog_cardinality( + dataset_data, dataset_model, multiple_data_catalog +): """Test that a dataset pydantic model can be created from dataset json data. Purpose of the test is to validate dataset pydantic model where the includedInDataCatalog property can have one or more values. @@ -222,7 +352,11 @@ async def test_dataset_schema_variable_cardinality(dataset_data, dataset_model, "description": "The Science Data Catalog (SDC) is the official public and searchable index that aggregates descriptions of all public research data that have been published by the USGS.", "url": "https://data.usgs.gov/datacatalog/", "identifier": "6625bdbde41c45c2b906f32be7ea70f0", - "creator": {"@type": "Organization", "name": "U.S. Geological Survey", "url": "https://www.usgs.gov/"}, + "creator": { + "@type": "Organization", + "name": "U.S. Geological Survey", + "url": "https://www.usgs.gov/", + }, }, { "@type": "DataCatalog", @@ -245,7 +379,11 @@ async def test_dataset_schema_variable_cardinality(dataset_data, dataset_model, "description": "The Science Data Catalog (SDC) is the official public and searchable index that aggregates descriptions of all public research data that have been published by the USGS.", "url": "https://data.usgs.gov/datacatalog/", "identifier": "6625bdbde41c45c2b906f32be7ea70f0", - "creator": {"@type": "Organization", "name": "U.S. Geological Survey", "url": "https://www.usgs.gov/"}, + "creator": { + "@type": "Organization", + "name": "U.S. Geological Survey", + "url": "https://www.usgs.gov/", + }, } ] # validate the dataset model @@ -253,12 +391,29 @@ async def test_dataset_schema_variable_cardinality(dataset_data, dataset_model, # checking dataset specific metadata if multiple_data_catalog: assert len(dataset_instance.includedInDataCatalog) == 2 - assert dataset_instance.includedInDataCatalog[0].name == "The USGS Science Data Catalog (SDC)" - assert dataset_instance.includedInDataCatalog[1].name == "The I-GUIDE Data Catalog" - assert dataset_instance.includedInDataCatalog[0].identifier == "6625bdbde41c45c2b906f32be7ea70f0" - assert dataset_instance.includedInDataCatalog[1].identifier == "e2fdf99cbb0c4275b32afd3c16ae6863" - assert dataset_instance.includedInDataCatalog[0].url == "https://data.usgs.gov/datacatalog/" - assert dataset_instance.includedInDataCatalog[1].url == "https://iguide.cuahsi.io/discover" + assert ( + dataset_instance.includedInDataCatalog[0].name + == "The USGS Science Data Catalog (SDC)" + ) + assert ( + dataset_instance.includedInDataCatalog[1].name == "The I-GUIDE Data Catalog" + ) + assert ( + dataset_instance.includedInDataCatalog[0].identifier + == "6625bdbde41c45c2b906f32be7ea70f0" + ) + assert ( + dataset_instance.includedInDataCatalog[1].identifier + == "e2fdf99cbb0c4275b32afd3c16ae6863" + ) + assert ( + dataset_instance.includedInDataCatalog[0].url + == "https://data.usgs.gov/datacatalog/" + ) + assert ( + dataset_instance.includedInDataCatalog[1].url + == "https://iguide.cuahsi.io/discover" + ) assert ( dataset_instance.includedInDataCatalog[0].description == "The Science Data Catalog (SDC) is the official public and searchable index that aggregates descriptions of all public research data that have been published by the USGS." @@ -267,21 +422,45 @@ async def test_dataset_schema_variable_cardinality(dataset_data, dataset_model, dataset_instance.includedInDataCatalog[1].description == "A centralized metadata catalog capable of indexing data from the diverse, distributed data required by the I-GUIDE project focus areas." ) - assert dataset_instance.includedInDataCatalog[0].creator.name == "U.S. Geological Survey" + assert ( + dataset_instance.includedInDataCatalog[0].creator.name + == "U.S. Geological Survey" + ) assert ( dataset_instance.includedInDataCatalog[1].creator.name == "NSF Institute for Geospatial Understanding through an Integrative Discovery Environment (I-GUIDE)" ) - assert dataset_instance.includedInDataCatalog[0].creator.url == "https://www.usgs.gov/" - assert dataset_instance.includedInDataCatalog[1].creator.url == "https://iguide.illinois.edu/" + assert ( + dataset_instance.includedInDataCatalog[0].creator.url + == "https://www.usgs.gov/" + ) + assert ( + dataset_instance.includedInDataCatalog[1].creator.url + == "https://iguide.illinois.edu/" + ) else: assert len(dataset_instance.includedInDataCatalog) == 1 - assert dataset_instance.includedInDataCatalog[0].name == "The USGS Science Data Catalog (SDC)" - assert dataset_instance.includedInDataCatalog[0].identifier == "6625bdbde41c45c2b906f32be7ea70f0" - assert dataset_instance.includedInDataCatalog[0].url == "https://data.usgs.gov/datacatalog/" + assert ( + dataset_instance.includedInDataCatalog[0].name + == "The USGS Science Data Catalog (SDC)" + ) + assert ( + dataset_instance.includedInDataCatalog[0].identifier + == "6625bdbde41c45c2b906f32be7ea70f0" + ) + assert ( + dataset_instance.includedInDataCatalog[0].url + == "https://data.usgs.gov/datacatalog/" + ) assert ( dataset_instance.includedInDataCatalog[0].description == "The Science Data Catalog (SDC) is the official public and searchable index that aggregates descriptions of all public research data that have been published by the USGS." ) - assert dataset_instance.includedInDataCatalog[0].creator.name == "U.S. Geological Survey" - assert dataset_instance.includedInDataCatalog[0].creator.url == "https://www.usgs.gov/" + assert ( + dataset_instance.includedInDataCatalog[0].creator.name + == "U.S. Geological Survey" + ) + assert ( + dataset_instance.includedInDataCatalog[0].creator.url + == "https://www.usgs.gov/" + ) From 7bdcac6012af091ad8255cf0521970e752ced263 Mon Sep 17 00:00:00 2001 From: pkdash Date: Tue, 12 Mar 2024 11:29:44 -0400 Subject: [PATCH 3/7] [#98] moving some more attributes from MediaObject to DatasetMetadata --- api/models/schema.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/api/models/schema.py b/api/models/schema.py index 38b785f..f85ef9d 100644 --- a/api/models/schema.py +++ b/api/models/schema.py @@ -397,14 +397,6 @@ class MediaObject(SchemaBaseModel): "unit of measurement." ) name: str = Field(description="The name of the media object (file).") - additionalProperty: Optional[List[PropertyValue]] = Field( - title="Additional properties", - default=[], - description="Additional properties of the media object." - ) - variableMeasured: Optional[List[Union[str, PropertyValue]]] = Field( - title="Variables measured", description="Measured variables." - ) spatialCoverage: Optional[Place] = Field( title="Spatial coverage", description="The spatial coverage of the media object." From 59832465386b2041e8b57c77615000474993d9f0 Mon Sep 17 00:00:00 2001 From: pkdash Date: Tue, 12 Mar 2024 11:34:23 -0400 Subject: [PATCH 4/7] [#98] removing spatial and temporal coverage from MediaObject --- api/models/schema.py | 8 - api/models/schemas/schema.json | 522 ------------------------------- tests/data/dataset_metadata.json | 4 +- tests/test_core_schema.py | 108 ------- 4 files changed, 1 insertion(+), 641 deletions(-) diff --git a/api/models/schema.py b/api/models/schema.py index f85ef9d..19ce412 100644 --- a/api/models/schema.py +++ b/api/models/schema.py @@ -397,14 +397,6 @@ class MediaObject(SchemaBaseModel): "unit of measurement." ) name: str = Field(description="The name of the media object (file).") - spatialCoverage: Optional[Place] = Field( - title="Spatial coverage", - description="The spatial coverage of the media object." - ) - temporalCoverage: Optional[TemporalCoverage] = Field( - title="Temporal coverage", - description="The temporal coverage of the media object." - ) sha256: Optional[str] = Field(title="SHA-256", description="The SHA-256 hash of the media object.") isPartOf: Optional[MediaObjectPartOf] = Field( title="Is part of", diff --git a/api/models/schemas/schema.json b/api/models/schemas/schema.json index 0019d74..96c9d3a 100644 --- a/api/models/schemas/schema.json +++ b/api/models/schemas/schema.json @@ -1014,267 +1014,6 @@ "description": "The name of the media object (file).", "type": "string" }, - "spatialCoverage": { - "title": "Place", - "description": "The spatial coverage of the media object.", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Represents the focus area of the record's content.", - "default": "Place", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the place.", - "type": "string" - }, - "geo": { - "title": "Geo", - "description": "Specifies the geographic coordinates of the place in the form of a point location, line, or area coverage extent.", - "anyOf": [ - { - "title": "GeoCoordinates", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", - "default": "GeoCoordinates", - "type": "string" - }, - "latitude": { - "title": "Latitude", - "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", - "type": "number" - }, - "longitude": { - "title": "Longitude", - "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", - "type": "number" - } - }, - "required": [ - "latitude", - "longitude" - ] - }, - { - "title": "GeoShape", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A structured representation that describes the coordinates of a geographic feature.", - "default": "GeoShape", - "type": "string" - }, - "box": { - "title": "Box", - "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", - "type": "string" - } - }, - "required": [ - "box" - ] - } - ] - }, - "additionalProperty": { - "title": "Additional properties", - "description": "Additional properties of the place.", - "default": [], - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - { - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - } - }, - "temporalCoverage": { - "title": "TemporalCoverage", - "description": "The temporal coverage of the media object.", - "type": "object", - "properties": { - "startDate": { - "title": "Start date", - "description": "A date/time object containing the instant corresponding to the commencement of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM).", - "type": "string", - "format": "date-time" - }, - "endDate": { - "title": "End date", - "description": "A date/time object containing the instant corresponding to the termination of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM). If the ending date is left off, that means the temporal coverage is ongoing.", - "type": "string", - "format": "date-time" - } - }, - "required": [ - "startDate" - ] - }, "sha256": { "title": "SHA-256", "description": "The SHA-256 hash of the media object.", @@ -2891,267 +2630,6 @@ "description": "The name of the media object (file).", "type": "string" }, - "spatialCoverage": { - "title": "Place", - "description": "The spatial coverage of the media object.", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Represents the focus area of the record's content.", - "default": "Place", - "type": "string" - }, - "name": { - "title": "Name", - "description": "Name of the place.", - "type": "string" - }, - "geo": { - "title": "Geo", - "description": "Specifies the geographic coordinates of the place in the form of a point location, line, or area coverage extent.", - "anyOf": [ - { - "title": "GeoCoordinates", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "Geographic coordinates that represent a specific location on the Earth's surface. GeoCoordinates typically consists of two components: latitude and longitude.", - "default": "GeoCoordinates", - "type": "string" - }, - "latitude": { - "title": "Latitude", - "description": "Represents the angular distance of a location north or south of the equator, measured in degrees and ranges from -90 to +90 degrees.", - "type": "number" - }, - "longitude": { - "title": "Longitude", - "description": "Represents the angular distance of a location east or west of the Prime Meridian, measured in degrees and ranges from -180 to +180 degrees.", - "type": "number" - } - }, - "required": [ - "latitude", - "longitude" - ] - }, - { - "title": "GeoShape", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A structured representation that describes the coordinates of a geographic feature.", - "default": "GeoShape", - "type": "string" - }, - "box": { - "title": "Box", - "description": "A box is a rectangular region defined by a pair of coordinates representing the southwest and northeast corners of the box.", - "type": "string" - } - }, - "required": [ - "box" - ] - } - ] - }, - "additionalProperty": { - "title": "Additional properties", - "description": "Additional properties of the place.", - "default": [], - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "type": "string" - }, - { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - }, - { - "type": "array", - "items": { - "title": "PropertyValue", - "type": "object", - "properties": { - "@type": { - "title": "@Type", - "description": "A property-value pair.", - "default": "PropertyValue", - "const": "PropertyValue", - "type": "string" - }, - "propertyID": { - "title": "Property ID", - "description": "The ID of the property.", - "type": "string" - }, - "name": { - "title": "Name", - "description": "The name of the property.", - "type": "string" - }, - "value": { - "title": "Value", - "description": "The value of the property.", - "type": "string" - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - ] - }, - "unitCode": { - "title": "Measurement unit", - "description": "The unit of measurement for the value.", - "type": "string" - }, - "description": { - "title": "Description", - "description": "A description of the property.", - "type": "string" - }, - "minValue": { - "title": "Minimum value", - "description": "The minimum allowed value for the property.", - "type": "number" - }, - "maxValue": { - "title": "Maximum value", - "description": "The maximum allowed value for the property.", - "type": "number" - } - }, - "required": [ - "name", - "value" - ] - } - } - } - }, - "temporalCoverage": { - "title": "TemporalCoverage", - "description": "The temporal coverage of the media object.", - "type": "object", - "properties": { - "startDate": { - "title": "Start date", - "description": "A date/time object containing the instant corresponding to the commencement of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM).", - "type": "string", - "format": "date-time" - }, - "endDate": { - "title": "End date", - "description": "A date/time object containing the instant corresponding to the termination of the time interval (ISO8601 formatted date - YYYY-MM-DDTHH:MM). If the ending date is left off, that means the temporal coverage is ongoing.", - "type": "string", - "format": "date-time" - } - }, - "required": [ - "startDate" - ] - }, "sha256": { "title": "SHA-256", "description": "The SHA-256 hash of the media object.", diff --git a/tests/data/dataset_metadata.json b/tests/data/dataset_metadata.json index fa40278..bd32e8d 100644 --- a/tests/data/dataset_metadata.json +++ b/tests/data/dataset_metadata.json @@ -107,9 +107,7 @@ "contentSize": "0.17 MB", "name": "USGS gage locations within the Harvey-affected areas in Texas", "sha256": "830f4b50e78e8a8fb0f7eee7369171dacbcaa43cc2c4deb59cef8e4fd2f641c5", - "isPartOf": null, - "spatialCoverage": null, - "temporalCoverage": null + "isPartOf": null } ], "citation": ["Citation for the dataset"], diff --git a/tests/test_core_schema.py b/tests/test_core_schema.py index b5bfe84..45fbf70 100644 --- a/tests/test_core_schema.py +++ b/tests/test_core_schema.py @@ -378,114 +378,6 @@ async def test_core_schema_associated_media_content_size( assert core_model_instance.associatedMedia[0].contentSize == content_size_format -@pytest.mark.parametrize("set_spatial_coverage", [True, False]) -@pytest.mark.parametrize("spatial_coverage_with_additional_property", [True, False]) -@pytest.mark.asyncio -async def test_core_schema_associated_media_spatial_coverage( - core_data, - core_model, - set_spatial_coverage, - spatial_coverage_with_additional_property, -): - """Test that a core metadata pydantic model can be created from core metadata json. - Purpose of the test is to validate core metadata schema as defined by the pydantic model where we are testing - valid values for the spatialCoverage attribute of the associatedMedia property. - Note: This test does not add a record to the database. - """ - - core_data = core_data - core_model = core_model - content_size_format = "100.17 KB" - coverage_value = { - "@type": "Place", - "name": "CUAHSI Office", - "geo": {"@type": "GeoCoordinates", "latitude": 42.4127, "longitude": -71.1197}, - } - core_data["associatedMedia"] = [ - { - "@type": "MediaObject", - "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/USGS_Harvey_gages_TxLaMsAr.csv", - "encodingFormat": "text/csv", - "contentSize": content_size_format, - "name": "USGS gage locations within the Harvey-affected areas in Texas", - } - ] - if set_spatial_coverage: - core_data["associatedMedia"][0]["spatialCoverage"] = coverage_value - if spatial_coverage_with_additional_property: - core_data["associatedMedia"][0]["spatialCoverage"]["additionalProperty"] = [ - { - "@type": "PropertyValue", - "name": "Geographic Coordinate System", - "value": "WGS 84 EPSG:4326", - }, - ] - - # validate the data model - core_model_instance = await utils.validate_data_model(core_data, core_model) - assert core_model_instance.associatedMedia[0].contentSize == content_size_format - if set_spatial_coverage: - special_coverage = core_model_instance.associatedMedia[0].spatialCoverage - assert special_coverage.type == coverage_value["@type"] - assert special_coverage.name == coverage_value["name"] - geo = special_coverage.geo - assert geo.type == coverage_value["geo"]["@type"] - assert geo.latitude == coverage_value["geo"]["latitude"] - assert geo.longitude == coverage_value["geo"]["longitude"] - if spatial_coverage_with_additional_property: - assert len(core_model_instance.associatedMedia[0].spatialCoverage.additionalProperty) == 1 - additional_property = core_model_instance.associatedMedia[0].spatialCoverage.additionalProperty[0] - assert additional_property.type == "PropertyValue" - assert additional_property.name == "Geographic Coordinate System" - assert additional_property.value == "WGS 84 EPSG:4326" - else: - assert core_model_instance.associatedMedia[0].spatialCoverage.additionalProperty == [] - else: - assert core_model_instance.associatedMedia[0].spatialCoverage is None - - -@pytest.mark.parametrize("set_temporal_coverage", [True, False]) -@pytest.mark.asyncio -async def test_core_schema_associated_media_temporal_coverage( - core_data, core_model, set_temporal_coverage -): - """Test that a core metadata pydantic model can be created from core metadata json. - Purpose of the test is to validate core metadata schema as defined by the pydantic model where we are testing - valid values for the temporalCoverage attribute of the associatedMedia property. - Note: This test does not add a record to the database. - """ - - core_data = core_data - core_model = core_model - content_size_format = "100.17 KB" - coverage_value = { - "startDate": "2007-03-01T13:00:00", - "endDate": "2008-05-11T15:30:00", - } - - core_data["associatedMedia"] = [ - { - "@type": "MediaObject", - "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/USGS_Harvey_gages_TxLaMsAr.csv", - "encodingFormat": "text/csv", - "contentSize": content_size_format, - "name": "USGS gage locations within the Harvey-affected areas in Texas", - } - ] - if set_temporal_coverage: - core_data["associatedMedia"][0]["temporalCoverage"] = coverage_value - - # validate the data model - core_model_instance = await utils.validate_data_model(core_data, core_model) - assert core_model_instance.associatedMedia[0].contentSize == content_size_format - if set_temporal_coverage: - temporal_coverage = core_model_instance.associatedMedia[0].temporalCoverage - assert temporal_coverage.startDate == datetime.datetime(2007, 3, 1, 13, 0, 0) - assert temporal_coverage.endDate == datetime.datetime(2008, 5, 11, 15, 30, 0) - else: - assert core_model_instance.associatedMedia[0].temporalCoverage is None - - @pytest.mark.parametrize("include_coverage", [True, False]) @pytest.mark.asyncio async def test_core_schema_temporal_coverage_optional(core_data, core_model, include_coverage): From d17594e09733d80f61efcf470e91f2d1e5fc9a60 Mon Sep 17 00:00:00 2001 From: pkdash Date: Wed, 13 Mar 2024 22:35:06 -0400 Subject: [PATCH 5/7] [#98] adding measurementTechnique to PropertyValue schema model --- api/models/schema.py | 3 ++ api/models/schemas/schema.json | 92 +++++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/api/models/schema.py b/api/models/schema.py index 19ce412..4649460 100644 --- a/api/models/schema.py +++ b/api/models/schema.py @@ -337,6 +337,9 @@ class PropertyValueBase(SchemaBaseModel): maxValue: Optional[float] = Field( title="Maximum value", description="The maximum allowed value for the property." ) + measurementTechnique: Optional[str] = Field( + title="Measurement technique", description="A technique or technology used in a measurement." + ) class Config: title = "PropertyValue" diff --git a/api/models/schemas/schema.json b/api/models/schemas/schema.json index 96c9d3a..797da6b 100644 --- a/api/models/schemas/schema.json +++ b/api/models/schemas/schema.json @@ -799,6 +799,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -853,6 +858,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -882,6 +892,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -1155,6 +1170,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -1209,6 +1229,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -1238,6 +1263,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -1250,7 +1280,7 @@ }, "additionalProperty": { "title": "Additional properties", - "description": "Additional properties of the Dataset.", + "description": "Additional properties of the dataset.", "default": [], "type": "array", "items": { @@ -1326,6 +1356,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -1380,6 +1415,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -1409,6 +1449,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -1418,7 +1463,7 @@ } }, "sourceOrganization": { - "title": "MediaObjectSourceOrganization", + "title": "SourceOrganization", "description": "The organization that provided the data for this dataset.", "type": "object", "properties": { @@ -1430,7 +1475,7 @@ }, "name": { "title": "Name", - "description": "Name of the organization that created the media object.", + "description": "Name of the organization that created the data.", "type": "string" }, "url": { @@ -2078,6 +2123,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -2158,6 +2208,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -2212,6 +2267,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -2241,6 +2301,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -2393,6 +2458,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -2447,6 +2517,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -2476,6 +2551,11 @@ "title": "Maximum value", "description": "The maximum allowed value for the property.", "type": "number" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ @@ -2680,8 +2760,8 @@ "name" ] }, - "MediaObjectSourceOrganization": { - "title": "MediaObjectSourceOrganization", + "SourceOrganization": { + "title": "SourceOrganization", "type": "object", "properties": { "@type": { @@ -2692,7 +2772,7 @@ }, "name": { "title": "Name", - "description": "Name of the organization that created the media object.", + "description": "Name of the organization that created the data.", "type": "string" }, "url": { From 08fd98880f8ad07cabec027a3b9069cddaaf233e Mon Sep 17 00:00:00 2001 From: pkdash Date: Wed, 13 Mar 2024 23:21:09 -0400 Subject: [PATCH 6/7] [#98] updating tests for measurementTechnique attribute of PropertyValue model --- tests/data/dataset_metadata.json | 3 ++- tests/test_dataset_routes.py | 4 ++++ tests/test_dataset_schema.py | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/data/dataset_metadata.json b/tests/data/dataset_metadata.json index bd32e8d..2e0e4cd 100644 --- a/tests/data/dataset_metadata.json +++ b/tests/data/dataset_metadata.json @@ -132,7 +132,8 @@ "unitCode": "m", "minValue": 1358.2, "maxValue": 3040.8, - "description": "Digital Elevation Model" + "description": "Digital Elevation Model", + "measurementTechnique": "Lidar" } ], "sourceOrganization": { diff --git a/tests/test_dataset_routes.py b/tests/test_dataset_routes.py index a459d5f..426fd1c 100644 --- a/tests/test_dataset_routes.py +++ b/tests/test_dataset_routes.py @@ -35,6 +35,7 @@ async def test_create_dataset(client_test, dataset_data, test_user_access_token) assert a_property.pop("maxValue") is None assert a_property.pop("unitCode") is None assert a_property.pop("propertyID") is None + assert a_property.pop("measurementTechnique") is None assert response_data == dataset_data # there should be one related submission record in the db @@ -108,6 +109,7 @@ async def test_update_dataset(client_test, dataset_data): assert a_property.pop("maxValue") is None assert a_property.pop("unitCode") is None assert a_property.pop("propertyID") is None + assert a_property.pop("measurementTechnique") is None assert response_data == dataset_data @@ -174,6 +176,8 @@ async def test_get_datasets_exclude_none(client_test, dataset_data): assert "maxValue" not in a_property assert "unitCode" not in a_property assert "propertyID" not in a_property + assert "measurementTechnique" not in a_property + @pytest.mark.parametrize("multiple", [True, False]) @pytest.mark.asyncio diff --git a/tests/test_dataset_schema.py b/tests/test_dataset_schema.py index 313fee3..015d0b9 100644 --- a/tests/test_dataset_schema.py +++ b/tests/test_dataset_schema.py @@ -26,6 +26,11 @@ async def test_dataset_schema_additional_property( "@type": "PropertyValue", "name": "Field Count", "value": "10", + "unitCode": "count", + "description": "Number of fields in the dataset", + "minValue": "5", + "maxValue": "15", + "measurementTechnique": "Counting", }, ] if set_additional_property: @@ -41,6 +46,14 @@ async def test_dataset_schema_additional_property( assert dataset_model_instance.additionalProperty[0].value == additional_property[0]["value"] assert dataset_model_instance.additionalProperty[1].name == additional_property[1]["name"] assert dataset_model_instance.additionalProperty[1].value == additional_property[1]["value"] + assert dataset_model_instance.additionalProperty[1].unitCode == additional_property[1]["unitCode"] + assert dataset_model_instance.additionalProperty[1].description == additional_property[1]["description"] + assert dataset_model_instance.additionalProperty[1].minValue == float(additional_property[1]["minValue"]) + assert dataset_model_instance.additionalProperty[1].maxValue == float(additional_property[1]["maxValue"]) + assert ( + dataset_model_instance.additionalProperty[1].measurementTechnique + == additional_property[1]["measurementTechnique"] + ) else: assert dataset_model_instance.additionalProperty == [] @@ -137,6 +150,7 @@ async def test_dataset_schema_variable_cardinality( else: assert dataset_instance.variableMeasured == [] + @pytest.mark.parametrize( "data_format", [ From 01b92238447ee9300520827274e9c21a53deacfe Mon Sep 17 00:00:00 2001 From: pkdash Date: Wed, 13 Mar 2024 23:22:05 -0400 Subject: [PATCH 7/7] [#98] model name change for source organization --- api/models/schema.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/api/models/schema.py b/api/models/schema.py index 4649460..2ea3ec0 100644 --- a/api/models/schema.py +++ b/api/models/schema.py @@ -107,8 +107,8 @@ class PublisherOrganization(Organization): ) -class MediaObjectSourceOrganization(Organization): - name: str = Field(description="Name of the organization that created the media object.") +class SourceOrganization(Organization): + name: str = Field(description="Name of the organization that created the data.") class DefinedTerm(SchemaBaseModel): @@ -545,16 +545,15 @@ class CoreMetadata(SchemaBaseModel): class DatasetMetadata(CoreMetadata): - # used only for generating the JSON-LD schema for a dataset. variableMeasured: Optional[List[Union[str, PropertyValue]]] = Field( title="Variables measured", description="Measured variables." ) additionalProperty: Optional[List[PropertyValue]] = Field( title="Additional properties", default=[], - description="Additional properties of the Dataset." + description="Additional properties of the dataset." ) - sourceOrganization: Optional[MediaObjectSourceOrganization] = Field( + sourceOrganization: Optional[SourceOrganization] = Field( title="Source organization", description="The organization that provided the data for this dataset." )