Skip to content

Commit

Permalink
Merge pull request #16 from hydroshare/metadata-in
Browse files Browse the repository at this point in the history
Metadata in
  • Loading branch information
sblack-usu authored Nov 3, 2021
2 parents a8e4b55 + aae54f8 commit 2af3296
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 79 deletions.
5 changes: 2 additions & 3 deletions hsmodels/schemas/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import inspect
from datetime import datetime
from enum import Enum

from pydantic import AnyUrl, BaseModel
from rdflib import Graph, Literal, URIRef

from hsmodels.namespaces import DC, HSTERMS, ORE, RDF, RDFS1, XSD
from hsmodels.namespaces import DC, HSTERMS, ORE, RDF, RDFS1
from hsmodels.schemas.aggregations import (
FileSetMetadata,
GeographicFeatureMetadata,
Expand Down Expand Up @@ -84,7 +83,7 @@ def parse_file(schema, file, file_format='xml', subject=None):
def rdf_graph(schema):
for rdf_schema, user_schema in user_schemas.items():
if isinstance(schema, user_schema):
return _rdf_graph(rdf_schema(**schema.dict()), Graph())
return _rdf_graph(rdf_schema(**schema.dict(to_rdf=True)), Graph())
return _rdf_graph(schema, Graph())


Expand Down
6 changes: 2 additions & 4 deletions hsmodels/schemas/aggregations.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
)
from hsmodels.schemas.rdf.validators import language_constraint, subjects_constraint
from hsmodels.schemas.root_validators import (
normalize_additional_metadata,
parse_abstract,
parse_additional_metadata,
parse_file_types,
parse_url,
split_coverages,
)
from hsmodels.schemas.validators import (
normalize_additional_metadata,
parse_multidimensional_spatial_reference,
parse_spatial_coverage,
parse_spatial_reference,
Expand Down Expand Up @@ -84,9 +84,7 @@ class BaseAggregationMetadata(BaseMetadata):
_subjects_constraint = validator('subjects', allow_reuse=True)(subjects_constraint)
_language_constraint = validator('language', allow_reuse=True)(language_constraint)
_parse_spatial_coverage = validator("spatial_coverage", allow_reuse=True, pre=True)(parse_spatial_coverage)
_normalize_additional_metadata = validator("additional_metadata", allow_reuse=True, pre=True)(
normalize_additional_metadata
)
_normalize_additional_metadata = root_validator(allow_reuse=True, pre=True)(normalize_additional_metadata)


class GeographicRasterMetadata(BaseAggregationMetadata):
Expand Down
3 changes: 2 additions & 1 deletion hsmodels/schemas/base_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def dict(
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = True,
to_rdf: bool = False
) -> 'DictStrAny':
"""
Generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
Expand All @@ -35,7 +36,7 @@ def dict(
exclude_none=exclude_none,
)

if hasattr(self.Config, "schema_config"):
if to_rdf and hasattr(self.Config, "schema_config"):
schema_config = self.Config.schema_config
if "dictionary_field" in schema_config:
for field in schema_config["dictionary_field"]:
Expand Down
10 changes: 9 additions & 1 deletion hsmodels/schemas/rdf/root_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,16 @@ def rdf_parse_file_types(cls, values):

def parse_rdf_extended_metadata(cls, values):
if "additional_metadata" in values:
values["extended_metadata"] = values["additional_metadata"]
if type(values["additional_metadata"] is list):
values["extended_metadata"] = values["additional_metadata"]
else:
assert type(values["additional_metadata"]) is dict
em = []
for key, value in values["additional_metadata"].items():
em.append({"key": key, "value": value})
values["extended_metadata"] = em
del values["additional_metadata"]

return values


Expand Down
109 changes: 59 additions & 50 deletions hsmodels/schemas/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,28 @@
)
from hsmodels.schemas.rdf.validators import language_constraint, subjects_constraint
from hsmodels.schemas.root_validators import (
normalize_additional_metadata,
parse_abstract,
parse_additional_metadata,
parse_url,
split_coverages,
split_dates,
)
from hsmodels.schemas.validators import (
list_not_empty,
normalize_additional_metadata,
parse_identifier,
parse_sources,
parse_spatial_coverage,
)
from hsmodels.schemas.validators import list_not_empty, parse_identifier, parse_sources, parse_spatial_coverage


class ResourceMetadata(BaseMetadata):
class ResourceMetadataIn(BaseMetadata):
"""
A class used to represent the metadata for a resource
A class used to represent the metadata for a resource that can be modified
"""

class Config:
title = 'Resource Metadata'

schema_config = {
'read_only': ['type', 'identifier', 'created', 'modified', 'published', 'url'],
'dictionary_field': ['additional_metadata'],
}

type: str = Field(
const=True,
default="CompositeResource",
title="Resource Type",
description="An object containing a URL that points to the HydroShare resource type selected from the hsterms namespace",
allow_mutation=False,
)

url: AnyUrl = Field(title="URL", description="An object containing the URL for a resource", allow_mutation=False)

identifier: AnyUrl = Field(
title="Identifier",
description="An object containing the URL-encoded unique identifier for a resource",
allow_mutation=False,
)
title: str = Field(
max_length=300, default=None, title="Title", description="A string containing the name given to a resource"
)
Expand Down Expand Up @@ -99,24 +78,6 @@ class Config:
rights: Rights = Field(
title="Rights", description="An object containing information about rights held in an over a resource"
)
created: datetime = Field(
default_factory=datetime.now,
title="Creation date",
description="A datetime object containing the instant associated with when a resource was created",
allow_mutation=False,
)
modified: datetime = Field(
default_factory=datetime.now,
title="Modified date",
description="A datetime object containing the instant associated with when a resource was last modified",
allow_mutation=False,
)
published: datetime = Field(
default=None,
title="Published date",
description="A datetime object containing the instant associated with when a resource was published",
allow_mutation=False,
)
awards: List[AwardInfo] = Field(
default=[],
title="Funding agency information",
Expand All @@ -142,18 +103,66 @@ class Config:
)

_parse_coverages = root_validator(pre=True, allow_reuse=True)(split_coverages)
_parse_dates = root_validator(pre=True, allow_reuse=True)(split_dates)
_parse_additional_metadata = root_validator(pre=True, allow_reuse=True)(parse_additional_metadata)
_parse_abstract = root_validator(pre=True)(parse_abstract)
_parse_url = root_validator(pre=True, allow_reuse=True)(parse_url)

_parse_identifier = validator("identifier", pre=True)(parse_identifier)
_parse_sources = validator("sources", pre=True)(parse_sources)
_parse_spatial_coverage = validator("spatial_coverage", allow_reuse=True, pre=True)(parse_spatial_coverage)
_normalize_additional_metadata = validator("additional_metadata", allow_reuse=True, pre=True)(
normalize_additional_metadata
)

_normalize_additional_metadata = root_validator(allow_reuse=True, pre=True)(normalize_additional_metadata)

_subjects_constraint = validator('subjects', allow_reuse=True)(subjects_constraint)
_language_constraint = validator('language', allow_reuse=True)(language_constraint)
_creators_constraint = validator('creators')(list_not_empty)


class ResourceMetadata(ResourceMetadataIn):
"""
A class used to represent the metadata for a resource
"""

class Config:
title = 'Resource Metadata'

schema_config = {
'read_only': ['type', 'identifier', 'created', 'modified', 'published', 'url'],
'dictionary_field': ['additional_metadata'],
}

type: str = Field(
const=True,
default="CompositeResource",
title="Resource Type",
description="An object containing a URL that points to the HydroShare resource type selected from the hsterms namespace",
allow_mutation=False,
)

url: AnyUrl = Field(title="URL", description="An object containing the URL for a resource", allow_mutation=False)

identifier: AnyUrl = Field(
title="Identifier",
description="An object containing the URL-encoded unique identifier for a resource",
allow_mutation=False,
)
created: datetime = Field(
default_factory=datetime.now,
title="Creation date",
description="A datetime object containing the instant associated with when a resource was created",
allow_mutation=False,
)
modified: datetime = Field(
default_factory=datetime.now,
title="Modified date",
description="A datetime object containing the instant associated with when a resource was last modified",
allow_mutation=False,
)
published: datetime = Field(
default=None,
title="Published date",
description="A datetime object containing the instant associated with when a resource was published",
allow_mutation=False,
)

_parse_dates = root_validator(pre=True, allow_reuse=True)(split_dates)
_parse_url = root_validator(pre=True, allow_reuse=True)(parse_url)

_parse_identifier = validator("identifier", pre=True)(parse_identifier)
19 changes: 19 additions & 0 deletions hsmodels/schemas/root_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,22 @@ def parse_file_types(cls, values):
del values[file_type.name]
values['file_types'] = file_types_list
return values


def normalize_additional_metadata(cls, values):
if "additional_metadata" in values:
value = values["additional_metadata"]
if isinstance(value, list):
as_dict = {}
for val in value:
if not isinstance(val, dict):
raise ValueError(f"List entry {val} must be a dict")
if "key" not in val:
raise ValueError(f"Missing the 'key' key in {val}")
if "value" not in val:
raise ValueError(f"Missing the 'value' key in {val}")
if val["key"] in as_dict:
raise ValueError(f"Found a duplicate key {val['key']}")
as_dict[val["key"]] = val["value"]
values["additional_metadata"] = as_dict
return values
17 changes: 0 additions & 17 deletions hsmodels/schemas/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,6 @@ def parse_spatial_coverage(cls, value):
return value


def normalize_additional_metadata(cls, value):
if isinstance(value, list):
as_dict = {}
for val in value:
if not isinstance(val, dict):
raise ValueError(f"List entry {val} must be a dict")
if "key" not in val:
raise ValueError(f"Missing the 'key' key in {val}")
if "value" not in val:
raise ValueError(f"Missing the 'value' key in {val}")
if val["key"] in as_dict:
raise ValueError(f"Found a duplicate key {val['key']}")
as_dict[val["key"]] = val["value"]
return as_dict
return value


def list_not_empty(cls, l):
if len(l) == 0:
raise ValueError("list must contain at least one entry")
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

setup(
name='hsmodels',
version='0.3.0',
version='0.3.1',
packages=find_packages(include=['hsmodels', 'hsmodels.*', 'hsmodels.schemas.*', 'hsmodels.schemas.rdf.*'],
exclude=("tests",)),
install_requires=[
Expand Down
3 changes: 2 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import os

import pytest


@pytest.fixture
def change_test_dir(request):
os.chdir(request.fspath.dirname)
yield
os.chdir(request.config.invocation_dir)
os.chdir(request.config.invocation_dir)
Loading

0 comments on commit 2af3296

Please sign in to comment.