From a5fb830e2eafce0778b673fdbbd3f959aa396115 Mon Sep 17 00:00:00 2001 From: pkdash Date: Thu, 18 Jun 2026 15:56:55 -0400 Subject: [PATCH 1/5] fix: update pydantic requirement to allow versions >=2.8,<3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 103ecdf..926a12f 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ exclude=("tests",)), install_requires=[ 'rdflib<6.0.0', - 'pydantic==2.8.*', + 'pydantic>=2.8,<3', 'email-validator' ], url='https://github.com/hydroshare/hsmodels', From 8922c67a1b963bede008fd00538cb45bc4e47f3c Mon Sep 17 00:00:00 2001 From: pkdash Date: Thu, 18 Jun 2026 19:06:23 -0400 Subject: [PATCH 2/5] fix: enhance rdf_parse_identifier to accept AnyUrl and str types --- hsmodels/schemas/rdf/validators.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hsmodels/schemas/rdf/validators.py b/hsmodels/schemas/rdf/validators.py index db1c1bc..447b26b 100644 --- a/hsmodels/schemas/rdf/validators.py +++ b/hsmodels/schemas/rdf/validators.py @@ -1,3 +1,4 @@ +from pydantic import AnyUrl from pydantic_core import Url from hsmodels.schemas.enums import CoverageType, DateType @@ -15,7 +16,7 @@ def rdf_parse_extended_metadata(cls, value): def rdf_parse_identifier(cls, value): - if isinstance(value, Url): + if isinstance(value, (Url, AnyUrl, str)): return {"hydroshare_identifier": value} return value From 54029ed6ee39640eebbea44741bd8aeae5a9f3fa Mon Sep 17 00:00:00 2001 From: pkdash Date: Thu, 18 Jun 2026 19:07:01 -0400 Subject: [PATCH 3/5] fix: update _rdf_graph to handle AnyUrl in addition to Url --- hsmodels/schemas/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hsmodels/schemas/__init__.py b/hsmodels/schemas/__init__.py index f1e89a3..ea2a23d 100644 --- a/hsmodels/schemas/__init__.py +++ b/hsmodels/schemas/__init__.py @@ -1,7 +1,7 @@ import inspect from enum import Enum -from pydantic import BaseModel +from pydantic import AnyUrl, BaseModel from pydantic_core import Url from rdflib import Graph, Literal, URIRef @@ -127,7 +127,7 @@ def _rdf_graph(schema, graph=None): graph = _rdf_graph(value, graph) else: # primitive value - if isinstance(value, Url): + if isinstance(value, (Url, AnyUrl)): value = URIRef(str(value)) elif isinstance(value, TermEnum): value = URIRef(value.value) From 3d7b4c62e33b1dbad5b4c1bbd075b508bed5e992 Mon Sep 17 00:00:00 2001 From: pkdash Date: Thu, 18 Jun 2026 19:20:35 -0400 Subject: [PATCH 4/5] fix: forward referencing issues with newer version of pydantic --- hsmodels/schemas/rdf/aggregations.py | 30 ++++++++++------------------ hsmodels/schemas/rdf/resource.py | 9 +++------ 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/hsmodels/schemas/rdf/aggregations.py b/hsmodels/schemas/rdf/aggregations.py index 3efa671..e22d2cc 100644 --- a/hsmodels/schemas/rdf/aggregations.py +++ b/hsmodels/schemas/rdf/aggregations.py @@ -51,8 +51,7 @@ class BaseAggregationMetadataInRDF(RDFBaseModel): class GeographicRasterMetadataInRDF(BaseAggregationMetadataInRDF): rdf_type: AnyUrl = Field(json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.GeographicRasterAggregation) - _label_literal = Literal["Geographic Raster Content: A geographic grid represented by a virtual raster tile (.vrt) file and one or more geotiff (.tif) files"] - label: _label_literal = Field( + label: Literal["Geographic Raster Content: A geographic grid represented by a virtual raster tile (.vrt) file and one or more geotiff (.tif) files"] = Field( frozen=True, default="Geographic Raster Content: A geographic grid represented by a virtual " "raster tile (.vrt) file and one or more geotiff (.tif) files", @@ -79,8 +78,7 @@ class GeographicFeatureMetadataInRDF(BaseAggregationMetadataInRDF): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.GeographicFeatureAggregation ) - _label_literal = Literal["Geographic Feature Content: The multiple files that are part of a geographic shapefile"] - label: _label_literal = Field( + label: Literal["Geographic Feature Content: The multiple files that are part of a geographic shapefile"] = Field( frozen=True, default="Geographic Feature Content: The multiple files that are part of a " "geographic shapefile" ) dc_type: AnyUrl = Field( @@ -108,8 +106,7 @@ class MultidimensionalMetadataInRDF(BaseAggregationMetadataInRDF): rdf_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.MultidimensionalAggregation ) - _label_literal = Literal['Multidimensional Content: A multidimensional dataset represented by a NetCDF file (.nc) and text file giving its NetCDF header content'] - label: _label_literal = Field( + label: Literal['Multidimensional Content: A multidimensional dataset represented by a NetCDF file (.nc) and text file giving its NetCDF header content'] = Field( frozen=True, default="Multidimensional Content: A multidimensional dataset represented by a " "NetCDF file (.nc) and text file giving its NetCDF header content", @@ -135,8 +132,7 @@ class TimeSeriesMetadataInRDF(BaseAggregationMetadataInRDF): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.TimeSeriesAggregation ) - _label_literal = Literal["Time Series Content: One or more time series held in an ODM2 format SQLite file and optional source comma separated (.csv) files"] - label: _label_literal = Field( + label: Literal["Time Series Content: One or more time series held in an ODM2 format SQLite file and optional source comma separated (.csv) files"] = Field( frozen=True, default="Time Series Content: One or more time series held in an ODM2 format " "SQLite file and optional source comma separated (.csv) files", @@ -164,8 +160,7 @@ class ReferencedTimeSeriesMetadataInRDF(BaseAggregationMetadataInRDF): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.ReferencedTimeSeriesAggregation ) - _label_literal = Literal["Referenced Time Series Content: A reference to one or more time series served from HydroServers outside of HydroShare in WaterML format"] - label: _label_literal = Field( + label: Literal["Referenced Time Series Content: A reference to one or more time series served from HydroServers outside of HydroShare in WaterML format"] = Field( frozen=True, default="Referenced Time Series Content: A reference to one or more time series " "served from HydroServers outside of HydroShare in WaterML format", @@ -183,8 +178,7 @@ class FileSetMetadataInRDF(BaseAggregationMetadataInRDF): rdf_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.FileSetAggregation ) - _label_literal = Literal["File Set Content: One or more files with specific metadata"] - label: _label_literal = Field(frozen=True, default="File Set Content: One or more files with specific metadata") + label: Literal["File Set Content: One or more files with specific metadata"] = Field(frozen=True, default="File Set Content: One or more files with specific metadata") dc_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": DC.type}, default=HSTERMS.FileSetAggregation, frozen=True ) @@ -199,8 +193,7 @@ class SingleFileMetadataInRDF(BaseAggregationMetadataInRDF): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.SingleFileAggregation ) - _label_literal = Literal["Single File Content: A single file with file specific metadata"] - label: _label_literal = Field(frozen=True, default="Single File Content: A single file with file specific metadata") + label: Literal["Single File Content: A single file with file specific metadata"] = Field(frozen=True, default="Single File Content: A single file with file specific metadata") dc_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": DC.type}, default=HSTERMS.SingleFileAggregation, frozen=True ) @@ -215,8 +208,7 @@ class ModelProgramMetadataInRDF(BaseAggregationMetadataInRDF): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.ModelProgramAggregation ) - _label_literal = Literal["Model Program Content: One or more files with specific metadata"] - label: _label_literal = Field(frozen=True, default="Model Program Content: One or more files with specific metadata") + label: Literal["Model Program Content: One or more files with specific metadata"] = Field(frozen=True, default="Model Program Content: One or more files with specific metadata") dc_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": DC.type}, default=HSTERMS.ModelProgramAggregation, frozen=True ) @@ -255,8 +247,7 @@ class ModelInstanceMetadataInRDF(BaseAggregationMetadataInRDF): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.ModelInstanceAggregation ) - _label_literal = Literal["Model Instance Content: One or more files with specific metadata"] - label: _label_literal = Field(frozen=True, default="Model Instance Content: One or more files with specific metadata") + label: Literal["Model Instance Content: One or more files with specific metadata"] = Field(frozen=True, default="Model Instance Content: One or more files with specific metadata") dc_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": DC.type}, default=HSTERMS.ModelInstanceAggregation, frozen=True ) @@ -278,8 +269,7 @@ class CSVFileMetadataInRDF(BaseAggregationMetadataInRDF): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.CSVFileAggregation ) - _label_literal = Literal["CSV File Content: A CSV file with file specific metadata"] - label: _label_literal = Field( + label: Literal["CSV File Content: A CSV file with file specific metadata"] = Field( frozen=True, default="CSV File Content: A CSV file with file specific metadata" ) diff --git a/hsmodels/schemas/rdf/resource.py b/hsmodels/schemas/rdf/resource.py index b66d022..97d1df1 100644 --- a/hsmodels/schemas/rdf/resource.py +++ b/hsmodels/schemas/rdf/resource.py @@ -109,8 +109,7 @@ class ResourceMetadataInRDF(BaseResource): json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.CompositeResource ) - _label_literal = Literal["Composite Resource"] - label: _label_literal = Field(default="Composite Resource", frozen=True, alias='label') + label: Literal["Composite Resource"] = Field(default="Composite Resource", frozen=True, alias='label') @field_serializer('dc_type', 'rdf_type') def serialize_url(self, _type: URIRef, _info): @@ -124,8 +123,7 @@ class CollectionMetadataInRDF(BaseResource): rdf_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.CollectionResource ) - _label_literal = Literal["Collection Resource"] - label: _label_literal = Field(default="Collection Resource", frozen=True, alias='label') + label: Literal["Collection Resource"] = Field(default="Collection Resource", frozen=True, alias='label') @field_serializer('dc_type', 'rdf_type') def serialize_url(self, _type: URIRef, _info): @@ -139,8 +137,7 @@ class WebAppMetadataInRDF(BaseResource): rdf_type: AnyUrl = Field( json_schema_extra={"rdf_predicate": RDF.type}, frozen=True, default=HSTERMS.ToolResource ) - _label_literal = Literal["Web App Resource"] - label: _label_literal = Field(default="Web App Resource", frozen=True, alias='label') + label: Literal["Web App Resource"] = Field(default="Web App Resource", frozen=True, alias='label') @field_serializer('dc_type', 'rdf_type') def serialize_url(self, _type: URIRef, _info): From b76ab20bf6581f7f0c3e8e3cd713d5c21b4fa052 Mon Sep 17 00:00:00 2001 From: pkdash Date: Thu, 18 Jun 2026 22:01:30 -0400 Subject: [PATCH 5/5] fix: update Python version classifiers in setup.py --- setup.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 926a12f..ea95592 100644 --- a/setup.py +++ b/setup.py @@ -21,11 +21,15 @@ long_description=README, long_description_content_type="text/markdown", classifiers=[ + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ], )