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 916fdd1..8305b9c 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): @@ -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" @@ -397,26 +400,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." - ) - temporalCoverage: Optional[TemporalCoverage] = Field( - 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[List[MediaObjectPartOf]] = Field( title="Is part of", @@ -562,6 +545,16 @@ class CoreMetadata(SchemaBaseModel): citation: Optional[List[str]] = Field(title="Citation", description="A bibliographic citation for the resource.") -class DatasetSchema(CoreMetadata): - # used only for generating the JSON-LD schema for a dataset. - pass +class DatasetMetadata(CoreMetadata): + 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[SourceOrganization] = 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 50da3ac..779792b 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": { @@ -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": [ @@ -1014,40 +1029,165 @@ "description": "The name of the media object (file).", "type": "string" }, - "additionalProperty": { - "title": "Additional properties", - "description": "Additional properties of the media object.", - "default": [], + "sha256": { + "title": "SHA-256", + "description": "The SHA-256 hash of the media object.", + "type": "string" + }, + "isPartOf": { + "title": "Is part of", + "description": "Link to or citation for a related metadata document that this media object is a part of", "type": "array", "items": { - "title": "PropertyValue", + "title": "MediaObjectPartOf", "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.", + "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": "The name of the property.", + "title": "Name or title", + "description": "Submission's name or title", "type": "string" }, - "value": { - "title": "Value", - "description": "The value of the property.", - "anyOf": [ - { - "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" + ] + } + } + }, + "required": [ + "contentUrl", + "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" + }, + { + "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" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" + } }, - { + "required": [ + "name", + "value" + ] + }, + { + "type": "array", + "items": { "title": "PropertyValue", "type": "object", "properties": { @@ -1092,344 +1232,146 @@ "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": [ "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" - ] - } + "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" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + } + ] + } + }, + "additionalProperty": { + "title": "Additional properties", + "description": "Additional properties of the dataset.", + "default": [], + "type": "array", + "items": { + "title": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" }, - "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" - } - }, - "required": [ - "name", - "value" - ] - } - ] - } + "propertyID": { + "title": "Property ID", + "description": "The ID of the property.", + "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.", + "name": { + "title": "Name", + "description": "The name of the property.", + "type": "string" + }, + "value": { + "title": "Value", + "description": "The value of the property.", + "anyOf": [ + { "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": "PropertyValue", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "description": "A property-value pair.", + "default": "PropertyValue", + "const": "PropertyValue", + "type": "string" }, - { - "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" - ] + "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" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } + }, + "required": [ + "name", + "value" ] }, - "additionalProperty": { - "title": "Additional properties", - "description": "Additional properties of the place.", - "default": [], + { "type": "array", "items": { "title": "PropertyValue", @@ -1455,118 +1397,7 @@ "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" - ] - } - } - ] + "type": "string" }, "unitCode": { "title": "Measurement unit", @@ -1587,6 +1418,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": [ @@ -1595,143 +1431,91 @@ ] } } - } - }, - "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" ] }, - "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" - ] + "unitCode": { + "title": "Measurement unit", + "description": "The unit of measurement for the value.", + "type": "string" }, - "sha256": { - "title": "SHA-256", - "description": "The SHA-256 hash of the media object.", + "description": { + "title": "Description", + "description": "A description of the property.", "type": "string" }, - "isPartOf": { - "title": "Is part of", - "description": "Link to or citation for a related metadata document that this media object is a part of", - "type": "array", - "items": { - "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" - ] - } + "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" + }, + "measurementTechnique": { + "title": "Measurement technique", + "description": "A technique or technology used in a measurement.", + "type": "string" } }, "required": [ - "contentUrl", - "contentSize", - "name" + "name", + "value" ] } }, - "citation": { - "title": "Citation", - "description": "A bibliographic citation for the resource.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "name", - "description", - "url", - "creator", - "dateCreated", - "keywords", - "license", - "provider" - ], - "definitions": { - "Affiliation": { - "title": "Affiliation", + "sourceOrganization": { + "title": "SourceOrganization", + "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 data.", + "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": { @@ -2342,6 +2126,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": [ @@ -2422,6 +2211,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 +2270,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": [ @@ -2505,6 +2304,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": [ @@ -2657,6 +2461,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": [ @@ -2711,6 +2520,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": [ @@ -2740,6 +2554,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": [ @@ -2822,42 +2641,6 @@ "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" - ] - }, "MediaObjectPartOf": { "title": "MediaObjectPartOf", "type": "object", @@ -2930,648 +2713,6 @@ "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" - } - }, - "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" - ] - } - }, - "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" - } - }, - "required": [ - "name", - "value" - ] - } - ] - } - }, - "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" - ] - }, - "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.", @@ -3624,6 +2765,42 @@ "contentSize", "name" ] + }, + "SourceOrganization": { + "title": "SourceOrganization", + "type": "object", + "properties": { + "@type": { + "title": "@Type", + "default": "Organization", + "const": "Organization", + "type": "string" + }, + "name": { + "title": "Name", + "description": "Name of the organization that created the data.", + "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 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..2e0e4cd --- /dev/null +++ b/tests/data/dataset_metadata.json @@ -0,0 +1,145 @@ +{ + "@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 + } + ], + "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", + "measurementTechnique": "Lidar" + } + ], + "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 f572980..5be8669 100644 --- a/tests/test_core_schema.py +++ b/tests/test_core_schema.py @@ -386,308 +386,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.asyncio -async def test_core_schema_associated_media_encoding_format_optional( - core_data, core_model -): - """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 - that encodingFormat attribute of the associatedMedia property is optional. - Note: This test does nat add a record to the database. - """ - - core_data = core_data - core_model = core_model - - core_data["associatedMedia"] = [ - { - "@type": "MediaObject", - "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/USGS_Harvey_gages_TxLaMsAr.csv", - "contentSize": "100.17 KB", - "sha256": "2fba6f2ebac562dac6a57acf0fdc5fdfabc9654b3c910aa6ef69cf4385997e19", - "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].encodingFormat is None - - -@pytest.mark.parametrize("set_is_part_of", [True, False]) -@pytest.mark.asyncio -async def test_core_schema_associated_media_is_part_of_optional( - core_data, core_model, set_is_part_of -): - """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 - that isPartOf attribute of the associatedMedia property is optional. - Note: This test does nat add a record to the database. - """ - - core_data = core_data - core_model = core_model - - core_data["associatedMedia"] = [ - { - "@type": "MediaObject", - "contentUrl": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/logan.nc", - "contentSize": "100.17 KB", - "encodingFormat": "application/x-netcdf", - "sha256": "2fba6f2ebac562dac6a57acf0fdc5fdfabc9654b3c910aa6ef69cf4385997e19", - "name": "logan.nc", - } - ] - - if set_is_part_of: - core_data["associatedMedia"][0]["isPartOf"] = [ - { - "@type": "CreativeWork", - "name": "logan.nc.json", - "url": "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/logan.nc.json", - } - ] - # validate the data model - core_model_instance = await utils.validate_data_model(core_data, core_model) - if set_is_part_of: - assert len(core_model_instance.associatedMedia[0].isPartOf) == 1 - assert core_model_instance.associatedMedia[0].isPartOf[0].type == "CreativeWork" - assert core_model_instance.associatedMedia[0].isPartOf[0].name == "logan.nc.json" - assert ( - core_model_instance.associatedMedia[0].isPartOf[0].url - == "https://www.hydroshare.org/resource/51d1539bf6e94b15ac33f7631228118c/data/contents/logan.nc.json" - ) - else: - assert core_model_instance.associatedMedia[0].isPartOf is None - - -@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]) -@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("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]) diff --git a/tests/test_dataset_routes.py b/tests/test_dataset_routes.py index d96b80d..426fd1c 100644 --- a/tests/test_dataset_routes.py +++ b/tests/test_dataset_routes.py @@ -28,6 +28,15 @@ 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 a_property.pop("measurementTechnique") 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 +102,14 @@ 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 a_property.pop("measurementTechnique") is None assert response_data == dataset_data @@ -153,6 +170,13 @@ 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 + assert "measurementTechnique" not in a_property @pytest.mark.parametrize("multiple", [True, False]) diff --git a/tests/test_dataset_schema.py b/tests/test_dataset_schema.py index 99baa0d..015d0b9 100644 --- a/tests/test_dataset_schema.py +++ b/tests/test_dataset_schema.py @@ -3,10 +3,208 @@ 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", + "unitCode": "count", + "description": "Number of fields in the dataset", + "minValue": "5", + "maxValue": "15", + "measurementTechnique": "Counting", + }, + ] + 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"] + 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 == [] + + +@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 +248,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 +262,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 +309,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 +330,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 +366,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 +393,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 +405,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 +436,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/" + )