oapi-profile-builder 3.7.1__tar.gz → 3.7.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {oapi_profile_builder-3.7.1/src/oapi_profile_builder.egg-info → oapi_profile_builder-3.7.4}/PKG-INFO +1 -1
  2. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/pyproject.toml +1 -1
  3. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/generate.py +87 -23
  4. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/models.py +2 -0
  5. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4/src/oapi_profile_builder.egg-info}/PKG-INFO +1 -1
  6. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/LICENSE +0 -0
  7. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/README.md +0 -0
  8. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/setup.cfg +0 -0
  9. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/__init__.py +0 -0
  10. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/cite.py +0 -0
  11. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/cite_features.py +0 -0
  12. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/cli.py +0 -0
  13. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/compile.py +0 -0
  14. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/cover.py +0 -0
  15. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder/server_validation.py +0 -0
  16. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder.egg-info/SOURCES.txt +0 -0
  17. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder.egg-info/dependency_links.txt +0 -0
  18. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder.egg-info/entry_points.txt +0 -0
  19. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder.egg-info/requires.txt +0 -0
  20. {oapi_profile_builder-3.7.1 → oapi_profile_builder-3.7.4}/src/oapi_profile_builder.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oapi-profile-builder
3
- Version: 3.7.1
3
+ Version: 3.7.4
4
4
  Summary: Authoritative tooling for creating OGC API Service Profiles (EDR, Features)
5
5
  Author-email: Shane Mill <shane.mill@noaa.gov>
6
6
  License: Apache License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "oapi-profile-builder"
7
- version = "3.7.1"
7
+ version = "3.7.4"
8
8
  description = "Authoritative tooling for creating OGC API Service Profiles (EDR, Features)"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -150,12 +150,34 @@ def _landing_page_schema(profile: "ServiceProfile") -> dict:
150
150
  "href": {"type": "string"},
151
151
  "rel": {"type": "string", "enum": link_rels},
152
152
  "type": {"type": "string"},
153
- "title": {"type": "string"}
153
+ "title": {"type": "string"},
154
+ "hreflang": {"type": "string"}
154
155
  }
155
156
  }
156
157
 
158
+ links_to_show = []
159
+ if profile.links:
160
+ for l in profile.links:
161
+ link_obj = {"href": l.href, "rel": l.rel}
162
+ if l.type: link_obj["type"] = l.type
163
+ if l.title: link_obj["title"] = l.title
164
+ if getattr(l, "hreflang", None): link_obj["hreflang"] = l.hreflang
165
+ links_to_show.append(link_obj)
166
+ else:
167
+ links_to_show = [
168
+ {"href": "/", "rel": "self", "type": "application/json", "title": "this document"},
169
+ {"href": "/api", "rel": "service-desc", "type": "application/vnd.oai.openapi+json;version=3.0.0", "title": "the API definition"},
170
+ {"href": "/conformance", "rel": "conformance", "type": "application/json", "title": "OGC API conformance classes implemented by this server"},
171
+ {"href": "/collections", "rel": "data", "type": "application/json", "title": "Information about the collections"},
172
+ {"href": profile_uri, "rel": "profile", "type": "text/html", "title": "The Service Profile for this API"}
173
+ ]
174
+
157
175
  schema_props: dict = {
158
- "links": {"type": "array", "items": link_items},
176
+ "links": {
177
+ "type": "array",
178
+ "items": link_items,
179
+ "enum": [links_to_show]
180
+ },
159
181
  "title": {"type": "string", **_const(profile.title, version)},
160
182
  "version": {"type": "string", **_const(profile.version, version)},
161
183
  "x-ogc-profile": {"type": "string", **_const(profile_uri, version)}
@@ -164,7 +186,11 @@ def _landing_page_schema(profile: "ServiceProfile") -> dict:
164
186
  if profile.description:
165
187
  schema_props["description"] = {"type": "string", **_const(profile.description, version)}
166
188
  if profile.keywords:
167
- schema_props["keywords"] = {"type": "array", "items": {"type": "string", "enum": profile.keywords}}
189
+ schema_props["keywords"] = {
190
+ "type": "array",
191
+ "items": {"type": "string"},
192
+ "enum": [profile.keywords]
193
+ }
168
194
 
169
195
  if profile.provider:
170
196
  p = profile.provider
@@ -567,7 +593,7 @@ def _parameter_schema(version: str) -> dict:
567
593
  },
568
594
  "extent": {"type": "object"},
569
595
  },
570
- "additionalProperties": True,
596
+ "additionalProperties": False,
571
597
  }
572
598
 
573
599
 
@@ -576,6 +602,7 @@ def _parameter_instance_schema(param: object, version: str) -> dict:
576
602
  schema = {
577
603
  "type": "object",
578
604
  "required": ["type", "observedProperty"],
605
+ "additionalProperties": False,
579
606
  "properties": {
580
607
  "type": {"type": "string", **_const("Parameter", version)},
581
608
  }
@@ -647,7 +674,7 @@ def _collection_response_schema(coll: Collection,
647
674
  else:
648
675
  param_item_schema = _parameter_schema(profile.openapi_version)
649
676
 
650
- param_names_schema: dict = {"type": "object", "additionalProperties": param_item_schema}
677
+ param_names_schema: dict = {"type": "object", "additionalProperties": False}
651
678
  if coll.parameter_names:
652
679
  param_names_schema["properties"] = {
653
680
  name: _parameter_instance_schema(param, version)
@@ -676,21 +703,48 @@ def _collection_response_schema(coll: Collection,
676
703
  if coll.extent and coll.extent.temporal:
677
704
  t = coll.extent.temporal
678
705
  temporal_props = {"trs": {"type": "string", **_const(t.trs, version)}}
679
- if t.interval: temporal_props["interval"] = {"type": "array", **_const(t.interval, version)}
680
- if t.values: temporal_props["values"] = {"type": "array", **_const(t.values, version)}
706
+ if t.interval:
707
+ temporal_props["interval"] = {
708
+ "type": "array",
709
+ "items": {"type": "array", "items": {"type": "string", "nullable": True}},
710
+ **_const(t.interval, version)
711
+ }
712
+ if t.values:
713
+ temporal_props["values"] = {
714
+ "type": "array",
715
+ "items": {"type": "string"},
716
+ **_const(t.values, version)
717
+ }
681
718
  extent_props["temporal"] = {"type": "object", "required": ["trs"], "properties": temporal_props}
682
719
  if coll.extent and coll.extent.vertical:
683
720
  v = coll.extent.vertical
684
721
  vertical_props = {"vrs": {"type": "string", **_const(v.vrs, version)}}
685
- if v.interval: vertical_props["interval"] = {"type": "array", **_const(v.interval, version)}
686
- if v.values: vertical_props["values"] = {"type": "array", **_const(v.values, version)}
722
+ if v.interval:
723
+ vertical_props["interval"] = {
724
+ "type": "array",
725
+ "items": {"type": "array", "items": {"type": "number"}},
726
+ **_const(v.interval, version)
727
+ }
728
+ if v.values:
729
+ vertical_props["values"] = {
730
+ "type": "array",
731
+ "items": {"type": "string"},
732
+ **_const(v.values, version)
733
+ }
687
734
  if getattr(v, "positive", None): vertical_props["positive"] = {"type": "string", **_const(v.positive, version)}
688
735
  extent_props["vertical"] = {"type": "object", "required": ["vrs"], "properties": vertical_props}
689
736
  if coll.extent and coll.extent.custom:
690
- custom_items = [{"type": "object", "required": ["id", "interval", "reference"],
691
- "properties": {"id": {"type": "string", **_const(c.id, version)},
692
- "interval": {"type": "array", **_const(c.interval, version)},
693
- "reference": {"type": "string", **_const(c.reference, version)}}} for c in coll.extent.custom]
737
+ custom_items = []
738
+ for c in coll.extent.custom:
739
+ custom_items.append({
740
+ "type": "object",
741
+ "required": ["id", "interval", "reference"],
742
+ "properties": {
743
+ "id": {"type": "string", **_const(c.id, version)},
744
+ "interval": {"type": "array", "items": {"type": "string"}, **_const(c.interval, version)},
745
+ "reference": {"type": "string", **_const(c.reference, version)},
746
+ }
747
+ })
694
748
  extent_props["custom"] = {"type": "array", "items": {"oneOf": custom_items}}
695
749
 
696
750
  dq_props = {}
@@ -714,17 +768,26 @@ def _collection_response_schema(coll: Collection,
714
768
  "variables": {"type": "object", "properties": vars_props}
715
769
  }}}}
716
770
 
771
+ links_to_show = []
772
+ if coll.links:
773
+ for l in coll.links:
774
+ link_obj = {"href": l.href, "rel": l.rel}
775
+ if l.type: link_obj["type"] = l.type
776
+ if l.title: link_obj["title"] = l.title
777
+ if getattr(l, "hreflang", None): link_obj["hreflang"] = l.hreflang
778
+ links_to_show.append(link_obj)
779
+
717
780
  schema: dict = {
718
781
  "type": "object", "required": ["id", "links", "extent"],
719
782
  "properties": {
720
783
  "id": {"type": "string", **_const(coll.id, version)},
721
784
  "title": {"type": "string", **_const(coll.title, version)} if coll.title else {"type": "string"},
722
785
  "description": {"type": "string", **_const(coll.description, version)} if coll.description else {"type": "string"},
723
- "keywords": {"type": "array", "items": {"type": "string", "enum": coll.keywords}} if coll.keywords else {"type": "array"},
724
- "links": _LINKS_ARRAY, "crs": crs_array_schema, "output_formats": output_formats_schema,
725
- "parameter_names": param_names_schema,
786
+ "keywords": {"type": "array", "items": {"type": "string"}, "enum": [coll.keywords] if coll.keywords else [[]]},
787
+ "links": {"type": "array", "items": _LINK_SCHEMA, "enum": [links_to_show]}, "crs": crs_array_schema, "output_formats": output_formats_schema,
788
+ "parameter_names": {**param_names_schema, "additionalProperties": False},
726
789
  "extent": {"type": "object", "required": ["spatial"], "properties": extent_props},
727
- "data_queries": {"type": "object", "properties": dq_props}
790
+ "data_queries": {"type": "object", "properties": dq_props, "additionalProperties": False}
728
791
  }
729
792
  }
730
793
  return {"description": "Collection metadata", "content": {"application/json": {"schema": schema}}}
@@ -1056,14 +1119,15 @@ def _core_paths(profile: ServiceProfile) -> dict:
1056
1119
  # Conformance response with required conformance classes
1057
1120
  conformance_response = copy.deepcopy(_R200_CONFORMANCE)
1058
1121
  if profile.required_conformance_classes:
1122
+ schema = conformance_response["content"]["application/json"]["schema"]
1059
1123
  if version == "3.1.0":
1060
- conformance_response["content"]["application/json"]["schema"]["properties"]["conformsTo"]["contains"] = {
1061
- "enum": profile.required_conformance_classes
1062
- }
1124
+ schema["properties"]["conformsTo"]["contains"] = {"enum": profile.required_conformance_classes}
1063
1125
  else:
1064
- conformance_response["content"]["application/json"]["schema"]["properties"]["conformsTo"]["items"] = {
1065
- "type": "string",
1066
- "enum": profile.required_conformance_classes
1126
+ # Force listing all expected classes in Swagger UI by using enum at the array level
1127
+ schema["properties"]["conformsTo"] = {
1128
+ "type": "array",
1129
+ "items": {"type": "string"},
1130
+ "enum": [profile.required_conformance_classes]
1067
1131
  }
1068
1132
 
1069
1133
  return {
@@ -44,6 +44,7 @@ from enum import Enum
44
44
  from typing import Annotated, List, Literal, Optional
45
45
 
46
46
  from annotated_types import Len
47
+ from edr_pydantic.link import Link
47
48
  from edr_pydantic.collections import Collection as EDRCollection
48
49
  from edr_pydantic.extent import Custom, Extent as EDRExtent, Spatial, Vertical
49
50
  from pydantic import AwareDatetime, BaseModel, Field, field_validator, model_validator
@@ -894,6 +895,7 @@ class ServiceProfile(BaseModel):
894
895
  default=None,
895
896
  description="Date the resource/service was published (ISO 8601 string). Surfaces as info.x-resource-publish-date.",
896
897
  )
898
+ links: list[Link] = Field(default_factory=list, description="Landing page links")
897
899
  resource_default_locale: str | None = Field(
898
900
  default=None,
899
901
  description="Default locale of the resource (e.g. 'eng'). Surfaces as info.x-default-locale.",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oapi-profile-builder
3
- Version: 3.7.1
3
+ Version: 3.7.4
4
4
  Summary: Authoritative tooling for creating OGC API Service Profiles (EDR, Features)
5
5
  Author-email: Shane Mill <shane.mill@noaa.gov>
6
6
  License: Apache License