oapi-profile-builder 3.4.1__tar.gz → 3.6.1__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.
- {oapi_profile_builder-3.4.1/src/oapi_profile_builder.egg-info → oapi_profile_builder-3.6.1}/PKG-INFO +101 -5
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/README.md +100 -4
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/pyproject.toml +1 -1
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/cover.py +8 -5
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/generate.py +297 -43
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/models.py +333 -6
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1/src/oapi_profile_builder.egg-info}/PKG-INFO +101 -5
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/LICENSE +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/setup.cfg +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/__init__.py +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/cite.py +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/cite_features.py +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/cli.py +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/compile.py +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder/server_validation.py +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder.egg-info/SOURCES.txt +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder.egg-info/dependency_links.txt +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder.egg-info/entry_points.txt +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder.egg-info/requires.txt +0 -0
- {oapi_profile_builder-3.4.1 → oapi_profile_builder-3.6.1}/src/oapi_profile_builder.egg-info/top_level.txt +0 -0
{oapi_profile_builder-3.4.1/src/oapi_profile_builder.egg-info → oapi_profile_builder-3.6.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oapi-profile-builder
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.1
|
|
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
|
|
@@ -181,6 +181,20 @@ OGC API - EDR CITE Results
|
|
|
181
181
|
|
|
182
182
|
## GitHub Actions
|
|
183
183
|
|
|
184
|
+
### Self-service: generate artifacts from an issue (no fork, no install)
|
|
185
|
+
|
|
186
|
+
Anyone with a GitHub account can generate artifacts from their own config without cloning or installing anything:
|
|
187
|
+
|
|
188
|
+
1. Open a new issue using the **"Generate profile artifacts"** template ([New issue](../../issues/new/choose)).
|
|
189
|
+
2. Paste your profile YAML into the config field and submit.
|
|
190
|
+
3. A workflow validates the config, generates the artifacts, and comments on the issue with a link to download them as a zip (retained for 14 days). Optionally tick "Compile a PDF?" to also get a Metanorma PDF.
|
|
191
|
+
|
|
192
|
+
The workflow only runs the generator over your declarative config — it never executes user-supplied code — and comments back on both success and failure. Don't paste secrets: the artifacts are attached to a public workflow run.
|
|
193
|
+
|
|
194
|
+
> Maintainers: create a `profile-request` label so requests are easy to filter (the workflow gates on a marker in the issue body, so it works even before the label exists).
|
|
195
|
+
|
|
196
|
+
### Use the action in your own workflow
|
|
197
|
+
|
|
184
198
|
No local install needed. Add this to any workflow to generate profile artifacts from a config file:
|
|
185
199
|
|
|
186
200
|
```yaml
|
|
@@ -239,7 +253,7 @@ Everything about the document — cover, title-page metadata, legal page, footer
|
|
|
239
253
|
| PDF colours (titles, tables, cover, backgrounds) | `document_metadata.colors` | `:presentation-metadata-color-*:` |
|
|
240
254
|
| Page-ii legal text (copyright / license / notice) | `document_metadata.boilerplate` | `:boilerplate-authority:` |
|
|
241
255
|
| Footer organisation name | `document_metadata.copyright_holder` | `:copyright-holder:` |
|
|
242
|
-
| Cover layout (logo size/position, tagline/title size, bold edition) | `document_metadata.cover.{logo_width, logo_y, tagline_font_size, title_font_size, bold_edition}` | Generated cover image |
|
|
256
|
+
| Cover layout (logo size/position, tagline/title/edition-date size, bold edition+date) | `document_metadata.cover.{logo_width, logo_y, tagline_font_size, title_font_size, edition_date_font_size, bold_edition}` | Generated cover image |
|
|
243
257
|
| Cover date | `document_metadata.doc_pub_date` | Long-format date on the generated cover + `:published-date:` |
|
|
244
258
|
| Remove the OGC logo from the legal page | `document_metadata.suppress_flavor_logo` | targeted `:pdf-stylesheet-override:` |
|
|
245
259
|
| Remove OGC design (crossing lines, circled numbers, rules, navy divider pages) | `document_metadata.suppress_design_elements` (or the individual `suppress_crossing_lines` / `plain_section_numbers` / `suppress_title_underlines`) | `:pdf-stylesheet-override:` + colour attributes |
|
|
@@ -342,6 +356,13 @@ abstract_tests: []
|
|
|
342
356
|
| `spec_uri_base` | string | no | Base URI for the requirements/conformance class identifiers. Defaults to the OGC EDR Part 3 namespace; override to publish under another SDO namespace (e.g. DGIWG) |
|
|
343
357
|
| `parameter_name_pattern` | string | no | Regex all `parameter_names` keys must match |
|
|
344
358
|
| `parameter_schema` | object | no | JSON Schema for parameter objects — replaces the default schema in the generated OpenAPI (see below) |
|
|
359
|
+
| `collection_title_max_length` | int | no | When set, every collection title must be present and within this many characters (MetOcean `/req/core/collection_title`) |
|
|
360
|
+
| `require_license_link` | bool | no | When `true`, every collection must declare a `rel='license'` link (MetOcean `/req/core/collection_license`). Defaults to `false` |
|
|
361
|
+
| `license_link_type` | string | no | Expected media type of the `rel='license'` link when `require_license_link` is set. Defaults to `text/html`; set to null to accept any type |
|
|
362
|
+
| `required_data_queries` | list | no | Data-query types every collection must define (e.g. `[locations, area, radius]`) — enforces the mandatory data-query sets |
|
|
363
|
+
| `radius_within_units_required` | list | no | Unit tokens each radius query's `within_units` must contain (e.g. `[m]`) (MetOcean `/req/core/collection_radius_data_query`) |
|
|
364
|
+
| `locations_feature_required_properties` | list | no | Feature properties (e.g. `[name]`) marked required in the generated `/locations` GeoJSON response schema, in addition to the always-required string `id` |
|
|
365
|
+
| `conformance_class_requirements` | object | no | Map of conformance-class short name → constraints (`required_data_queries`, `radius_within_units_required`) applied only to collections that declare the class. Lets one profile document model several EDR Part 3 requirements classes (see below) |
|
|
345
366
|
| `processes` | list | no | OGC API Processes to expose in the OpenAPI |
|
|
346
367
|
| `requirements` | list | no | Normative requirements for the AsciiDoc/PDF |
|
|
347
368
|
| `abstract_tests` | list | no | Conformance tests — each must reference a valid requirement `id` |
|
|
@@ -381,6 +402,8 @@ Uses the [edr-pydantic](https://github.com/KNMI/edr-pydantic) `Collection` model
|
|
|
381
402
|
| `output_formats` | no | Format names this collection supports (e.g. `[CoverageJSON, GeoJSON]`) |
|
|
382
403
|
| `data_queries` | no | EDR query types: `position`, `area`, `radius`, `cube`, `trajectory`, `corridor`, `locations`, `items`, `instances` |
|
|
383
404
|
| `parameter_names` | no | Map of parameter id → Parameter object. All parameters must have `unit` and `observedProperty` |
|
|
405
|
+
| `conformance_classes` | no | Profile conformance-class short names this collection implements (e.g. `[core, insitu-observations]`). Selects which `conformance_class_requirements` are enforced; surfaced as `x-conformance-classes` in the OpenAPI |
|
|
406
|
+
| `parameter_schema` | no | Per-collection JSON Schema for parameter objects, overriding the profile-level `parameter_schema` for this collection only (precedence: collection → profile → default) |
|
|
384
407
|
|
|
385
408
|
#### `data_queries` example
|
|
386
409
|
|
|
@@ -513,6 +536,38 @@ extent_requirements:
|
|
|
513
536
|
|
|
514
537
|
---
|
|
515
538
|
|
|
539
|
+
### Multiple conformance classes in one profile
|
|
540
|
+
|
|
541
|
+
OGC API - EDR Part 3 profiles are modular: a single profile document can define several requirements/conformance classes, and different collections in the same service may implement different classes. The MetOcean EDR Profile is a good example — Core applies everywhere, but only in-situ collections must offer `locations`/`area`/`radius` while NWP collections must offer `position`/`cube`.
|
|
542
|
+
|
|
543
|
+
Model this with `conformance_class_requirements` (profile level) plus `conformance_classes` (per collection):
|
|
544
|
+
|
|
545
|
+
```yaml
|
|
546
|
+
# Core-level rules apply to every collection:
|
|
547
|
+
collection_title_max_length: 50
|
|
548
|
+
require_license_link: true
|
|
549
|
+
|
|
550
|
+
# Class-scoped rules apply only where a collection opts in:
|
|
551
|
+
conformance_class_requirements:
|
|
552
|
+
insitu-observations:
|
|
553
|
+
required_data_queries: [locations, area, radius]
|
|
554
|
+
radius_within_units_required: [m]
|
|
555
|
+
nwp:
|
|
556
|
+
required_data_queries: [position, cube]
|
|
557
|
+
|
|
558
|
+
collections:
|
|
559
|
+
- id: insitu-observations
|
|
560
|
+
conformance_classes: [core, insitu-observations] # must have locations/area/radius
|
|
561
|
+
# ...
|
|
562
|
+
- id: nwp-forecast
|
|
563
|
+
conformance_classes: [core, nwp] # must have position/cube
|
|
564
|
+
# ...
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
The flat `required_data_queries` / `radius_within_units_required` fields still apply to *every* collection (the Core-applies-to-all shorthand); class-scoped rules are additive. See `examples/metocean_profile.yaml` for a full worked profile spanning all four MetOcean classes.
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
516
571
|
### `output_formats`
|
|
517
572
|
|
|
518
573
|
Maps format names (referenced by `collections[].output_formats` and `data_queries.*.variables.output_formats`) to a media type and, optionally, a schema reference. The `schema_ref` flows into the generated OpenAPI response `content` for that format — use it to point a format at a specific schema (e.g. a DGIWG-published schema for GeoTIFF or CoverageJSON) instead of the tool's built-in default.
|
|
@@ -654,7 +709,7 @@ When present, generates `asyncapi.yaml` alongside `openapi.yaml`.
|
|
|
654
709
|
pubsub:
|
|
655
710
|
broker_host: my-broker.example.com
|
|
656
711
|
broker_port: 5672
|
|
657
|
-
protocol: amqp # amqp | mqtt | kafka
|
|
712
|
+
protocol: amqp # amqp | amqp1 | mqtt | kafka
|
|
658
713
|
collections:
|
|
659
714
|
- my_collection
|
|
660
715
|
filters:
|
|
@@ -663,6 +718,40 @@ pubsub:
|
|
|
663
718
|
type: string
|
|
664
719
|
```
|
|
665
720
|
|
|
721
|
+
`broker_host`/`broker_port`/`protocol` synthesise a single implicit
|
|
722
|
+
`production` AsyncAPI server. To describe an exact transport topology instead —
|
|
723
|
+
e.g. a native WebSocket `/ws` endpoint plus AMQP 1.0 and MQTT brokers, as the
|
|
724
|
+
`nws_connect_profile.yaml` example does — list them explicitly under `servers`.
|
|
725
|
+
When `servers` is set, the implicit `production` server is **not** emitted:
|
|
726
|
+
|
|
727
|
+
```yaml
|
|
728
|
+
pubsub:
|
|
729
|
+
broker_host: edr-broker
|
|
730
|
+
broker_port: 5672
|
|
731
|
+
protocol: amqp1 # AMQP 1.0 (e.g. RabbitMQ 4.x native)
|
|
732
|
+
collections: [water_gauge, wwa]
|
|
733
|
+
servers:
|
|
734
|
+
- name: websocket_secure
|
|
735
|
+
description: Native WebSocket live map (production)
|
|
736
|
+
host: ''
|
|
737
|
+
protocol: wss # amqp | amqp1 | mqtt | kafka | ws | wss
|
|
738
|
+
pathname: /ws
|
|
739
|
+
- name: amqp
|
|
740
|
+
description: AMQP 1.0 broker (RabbitMQ 4.x native AMQP 1.0)
|
|
741
|
+
host: 'edr-broker:5672'
|
|
742
|
+
protocol: amqp1
|
|
743
|
+
- name: mqtt
|
|
744
|
+
description: MQTT broker (RabbitMQ MQTT plugin)
|
|
745
|
+
host: 'edr-broker:1883'
|
|
746
|
+
protocol: mqtt
|
|
747
|
+
collection_filters: # per-collection filter overrides
|
|
748
|
+
water_gauge:
|
|
749
|
+
filters:
|
|
750
|
+
- name: flood_stages
|
|
751
|
+
description: Alert for selected flood stages
|
|
752
|
+
type: array
|
|
753
|
+
```
|
|
754
|
+
|
|
666
755
|
---
|
|
667
756
|
|
|
668
757
|
### `document_metadata`
|
|
@@ -732,11 +821,12 @@ document_metadata:
|
|
|
732
821
|
font_italic: "Source Sans Pro" # optional italic face for the tagline
|
|
733
822
|
watermark: "DRAFT" # optional diagonal watermark stamped on the cover
|
|
734
823
|
# --- cover layout (all optional) ---
|
|
735
|
-
logo_width:
|
|
824
|
+
logo_width: 300 # target logo width in px (default 420)
|
|
736
825
|
logo_y: 100 # logo vertical offset from top in px (default 180)
|
|
737
826
|
tagline_font_size: 20 # tagline point size (default 30)
|
|
738
827
|
title_font_size: 40 # title point size (default 54)
|
|
739
|
-
|
|
828
|
+
edition_date_font_size: 22 # edition/date point size (default 24)
|
|
829
|
+
bold_edition: true # render the "Edition X" and "Dated ..." lines in bold (default false)
|
|
740
830
|
colors:
|
|
741
831
|
text: "#000000" # body text
|
|
742
832
|
cover_text: "#1F3864" # cover text / section numbers / ToC
|
|
@@ -898,6 +988,12 @@ The tool enforces these rules at build time. Violations produce clear error mess
|
|
|
898
988
|
| Parameters need `unit` + `observedProperty` | Required by OGC API - EDR Part 3 |
|
|
899
989
|
| `parameter_name_pattern` enforced | All `parameter_names` keys must match if set |
|
|
900
990
|
| `collection_id_pattern` enforced | All collection IDs must match if set |
|
|
991
|
+
| `collection_title_max_length` enforced | If set, every collection title must be present and within the limit |
|
|
992
|
+
| `require_license_link` enforced | If set, every collection must have a `rel='license'` link (of `license_link_type` when specified) |
|
|
993
|
+
| `required_data_queries` enforced | If set, every collection with `data_queries` must define each listed query type |
|
|
994
|
+
| `radius_within_units_required` enforced | If set, each radius query's `within_units` must contain every listed unit token |
|
|
995
|
+
| `conformance_class_requirements` enforced | Class-scoped `required_data_queries` / `radius_within_units_required` applied to collections whose `conformance_classes` include the class key |
|
|
996
|
+
| `conformance_classes` references known class | When `conformance_class_requirements` is set, a collection's `conformance_classes` may only use `core` or a defined class key (catches typos) |
|
|
901
997
|
| Abstract test IDs match requirements | `requirement_id` must reference an existing requirement |
|
|
902
998
|
| Requirement IDs | Must match `^[a-z0-9][a-z0-9\-]*$`, no trailing hyphen |
|
|
903
999
|
|
|
@@ -134,6 +134,20 @@ OGC API - EDR CITE Results
|
|
|
134
134
|
|
|
135
135
|
## GitHub Actions
|
|
136
136
|
|
|
137
|
+
### Self-service: generate artifacts from an issue (no fork, no install)
|
|
138
|
+
|
|
139
|
+
Anyone with a GitHub account can generate artifacts from their own config without cloning or installing anything:
|
|
140
|
+
|
|
141
|
+
1. Open a new issue using the **"Generate profile artifacts"** template ([New issue](../../issues/new/choose)).
|
|
142
|
+
2. Paste your profile YAML into the config field and submit.
|
|
143
|
+
3. A workflow validates the config, generates the artifacts, and comments on the issue with a link to download them as a zip (retained for 14 days). Optionally tick "Compile a PDF?" to also get a Metanorma PDF.
|
|
144
|
+
|
|
145
|
+
The workflow only runs the generator over your declarative config — it never executes user-supplied code — and comments back on both success and failure. Don't paste secrets: the artifacts are attached to a public workflow run.
|
|
146
|
+
|
|
147
|
+
> Maintainers: create a `profile-request` label so requests are easy to filter (the workflow gates on a marker in the issue body, so it works even before the label exists).
|
|
148
|
+
|
|
149
|
+
### Use the action in your own workflow
|
|
150
|
+
|
|
137
151
|
No local install needed. Add this to any workflow to generate profile artifacts from a config file:
|
|
138
152
|
|
|
139
153
|
```yaml
|
|
@@ -192,7 +206,7 @@ Everything about the document — cover, title-page metadata, legal page, footer
|
|
|
192
206
|
| PDF colours (titles, tables, cover, backgrounds) | `document_metadata.colors` | `:presentation-metadata-color-*:` |
|
|
193
207
|
| Page-ii legal text (copyright / license / notice) | `document_metadata.boilerplate` | `:boilerplate-authority:` |
|
|
194
208
|
| Footer organisation name | `document_metadata.copyright_holder` | `:copyright-holder:` |
|
|
195
|
-
| Cover layout (logo size/position, tagline/title size, bold edition) | `document_metadata.cover.{logo_width, logo_y, tagline_font_size, title_font_size, bold_edition}` | Generated cover image |
|
|
209
|
+
| Cover layout (logo size/position, tagline/title/edition-date size, bold edition+date) | `document_metadata.cover.{logo_width, logo_y, tagline_font_size, title_font_size, edition_date_font_size, bold_edition}` | Generated cover image |
|
|
196
210
|
| Cover date | `document_metadata.doc_pub_date` | Long-format date on the generated cover + `:published-date:` |
|
|
197
211
|
| Remove the OGC logo from the legal page | `document_metadata.suppress_flavor_logo` | targeted `:pdf-stylesheet-override:` |
|
|
198
212
|
| Remove OGC design (crossing lines, circled numbers, rules, navy divider pages) | `document_metadata.suppress_design_elements` (or the individual `suppress_crossing_lines` / `plain_section_numbers` / `suppress_title_underlines`) | `:pdf-stylesheet-override:` + colour attributes |
|
|
@@ -295,6 +309,13 @@ abstract_tests: []
|
|
|
295
309
|
| `spec_uri_base` | string | no | Base URI for the requirements/conformance class identifiers. Defaults to the OGC EDR Part 3 namespace; override to publish under another SDO namespace (e.g. DGIWG) |
|
|
296
310
|
| `parameter_name_pattern` | string | no | Regex all `parameter_names` keys must match |
|
|
297
311
|
| `parameter_schema` | object | no | JSON Schema for parameter objects — replaces the default schema in the generated OpenAPI (see below) |
|
|
312
|
+
| `collection_title_max_length` | int | no | When set, every collection title must be present and within this many characters (MetOcean `/req/core/collection_title`) |
|
|
313
|
+
| `require_license_link` | bool | no | When `true`, every collection must declare a `rel='license'` link (MetOcean `/req/core/collection_license`). Defaults to `false` |
|
|
314
|
+
| `license_link_type` | string | no | Expected media type of the `rel='license'` link when `require_license_link` is set. Defaults to `text/html`; set to null to accept any type |
|
|
315
|
+
| `required_data_queries` | list | no | Data-query types every collection must define (e.g. `[locations, area, radius]`) — enforces the mandatory data-query sets |
|
|
316
|
+
| `radius_within_units_required` | list | no | Unit tokens each radius query's `within_units` must contain (e.g. `[m]`) (MetOcean `/req/core/collection_radius_data_query`) |
|
|
317
|
+
| `locations_feature_required_properties` | list | no | Feature properties (e.g. `[name]`) marked required in the generated `/locations` GeoJSON response schema, in addition to the always-required string `id` |
|
|
318
|
+
| `conformance_class_requirements` | object | no | Map of conformance-class short name → constraints (`required_data_queries`, `radius_within_units_required`) applied only to collections that declare the class. Lets one profile document model several EDR Part 3 requirements classes (see below) |
|
|
298
319
|
| `processes` | list | no | OGC API Processes to expose in the OpenAPI |
|
|
299
320
|
| `requirements` | list | no | Normative requirements for the AsciiDoc/PDF |
|
|
300
321
|
| `abstract_tests` | list | no | Conformance tests — each must reference a valid requirement `id` |
|
|
@@ -334,6 +355,8 @@ Uses the [edr-pydantic](https://github.com/KNMI/edr-pydantic) `Collection` model
|
|
|
334
355
|
| `output_formats` | no | Format names this collection supports (e.g. `[CoverageJSON, GeoJSON]`) |
|
|
335
356
|
| `data_queries` | no | EDR query types: `position`, `area`, `radius`, `cube`, `trajectory`, `corridor`, `locations`, `items`, `instances` |
|
|
336
357
|
| `parameter_names` | no | Map of parameter id → Parameter object. All parameters must have `unit` and `observedProperty` |
|
|
358
|
+
| `conformance_classes` | no | Profile conformance-class short names this collection implements (e.g. `[core, insitu-observations]`). Selects which `conformance_class_requirements` are enforced; surfaced as `x-conformance-classes` in the OpenAPI |
|
|
359
|
+
| `parameter_schema` | no | Per-collection JSON Schema for parameter objects, overriding the profile-level `parameter_schema` for this collection only (precedence: collection → profile → default) |
|
|
337
360
|
|
|
338
361
|
#### `data_queries` example
|
|
339
362
|
|
|
@@ -466,6 +489,38 @@ extent_requirements:
|
|
|
466
489
|
|
|
467
490
|
---
|
|
468
491
|
|
|
492
|
+
### Multiple conformance classes in one profile
|
|
493
|
+
|
|
494
|
+
OGC API - EDR Part 3 profiles are modular: a single profile document can define several requirements/conformance classes, and different collections in the same service may implement different classes. The MetOcean EDR Profile is a good example — Core applies everywhere, but only in-situ collections must offer `locations`/`area`/`radius` while NWP collections must offer `position`/`cube`.
|
|
495
|
+
|
|
496
|
+
Model this with `conformance_class_requirements` (profile level) plus `conformance_classes` (per collection):
|
|
497
|
+
|
|
498
|
+
```yaml
|
|
499
|
+
# Core-level rules apply to every collection:
|
|
500
|
+
collection_title_max_length: 50
|
|
501
|
+
require_license_link: true
|
|
502
|
+
|
|
503
|
+
# Class-scoped rules apply only where a collection opts in:
|
|
504
|
+
conformance_class_requirements:
|
|
505
|
+
insitu-observations:
|
|
506
|
+
required_data_queries: [locations, area, radius]
|
|
507
|
+
radius_within_units_required: [m]
|
|
508
|
+
nwp:
|
|
509
|
+
required_data_queries: [position, cube]
|
|
510
|
+
|
|
511
|
+
collections:
|
|
512
|
+
- id: insitu-observations
|
|
513
|
+
conformance_classes: [core, insitu-observations] # must have locations/area/radius
|
|
514
|
+
# ...
|
|
515
|
+
- id: nwp-forecast
|
|
516
|
+
conformance_classes: [core, nwp] # must have position/cube
|
|
517
|
+
# ...
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
The flat `required_data_queries` / `radius_within_units_required` fields still apply to *every* collection (the Core-applies-to-all shorthand); class-scoped rules are additive. See `examples/metocean_profile.yaml` for a full worked profile spanning all four MetOcean classes.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
469
524
|
### `output_formats`
|
|
470
525
|
|
|
471
526
|
Maps format names (referenced by `collections[].output_formats` and `data_queries.*.variables.output_formats`) to a media type and, optionally, a schema reference. The `schema_ref` flows into the generated OpenAPI response `content` for that format — use it to point a format at a specific schema (e.g. a DGIWG-published schema for GeoTIFF or CoverageJSON) instead of the tool's built-in default.
|
|
@@ -607,7 +662,7 @@ When present, generates `asyncapi.yaml` alongside `openapi.yaml`.
|
|
|
607
662
|
pubsub:
|
|
608
663
|
broker_host: my-broker.example.com
|
|
609
664
|
broker_port: 5672
|
|
610
|
-
protocol: amqp # amqp | mqtt | kafka
|
|
665
|
+
protocol: amqp # amqp | amqp1 | mqtt | kafka
|
|
611
666
|
collections:
|
|
612
667
|
- my_collection
|
|
613
668
|
filters:
|
|
@@ -616,6 +671,40 @@ pubsub:
|
|
|
616
671
|
type: string
|
|
617
672
|
```
|
|
618
673
|
|
|
674
|
+
`broker_host`/`broker_port`/`protocol` synthesise a single implicit
|
|
675
|
+
`production` AsyncAPI server. To describe an exact transport topology instead —
|
|
676
|
+
e.g. a native WebSocket `/ws` endpoint plus AMQP 1.0 and MQTT brokers, as the
|
|
677
|
+
`nws_connect_profile.yaml` example does — list them explicitly under `servers`.
|
|
678
|
+
When `servers` is set, the implicit `production` server is **not** emitted:
|
|
679
|
+
|
|
680
|
+
```yaml
|
|
681
|
+
pubsub:
|
|
682
|
+
broker_host: edr-broker
|
|
683
|
+
broker_port: 5672
|
|
684
|
+
protocol: amqp1 # AMQP 1.0 (e.g. RabbitMQ 4.x native)
|
|
685
|
+
collections: [water_gauge, wwa]
|
|
686
|
+
servers:
|
|
687
|
+
- name: websocket_secure
|
|
688
|
+
description: Native WebSocket live map (production)
|
|
689
|
+
host: ''
|
|
690
|
+
protocol: wss # amqp | amqp1 | mqtt | kafka | ws | wss
|
|
691
|
+
pathname: /ws
|
|
692
|
+
- name: amqp
|
|
693
|
+
description: AMQP 1.0 broker (RabbitMQ 4.x native AMQP 1.0)
|
|
694
|
+
host: 'edr-broker:5672'
|
|
695
|
+
protocol: amqp1
|
|
696
|
+
- name: mqtt
|
|
697
|
+
description: MQTT broker (RabbitMQ MQTT plugin)
|
|
698
|
+
host: 'edr-broker:1883'
|
|
699
|
+
protocol: mqtt
|
|
700
|
+
collection_filters: # per-collection filter overrides
|
|
701
|
+
water_gauge:
|
|
702
|
+
filters:
|
|
703
|
+
- name: flood_stages
|
|
704
|
+
description: Alert for selected flood stages
|
|
705
|
+
type: array
|
|
706
|
+
```
|
|
707
|
+
|
|
619
708
|
---
|
|
620
709
|
|
|
621
710
|
### `document_metadata`
|
|
@@ -685,11 +774,12 @@ document_metadata:
|
|
|
685
774
|
font_italic: "Source Sans Pro" # optional italic face for the tagline
|
|
686
775
|
watermark: "DRAFT" # optional diagonal watermark stamped on the cover
|
|
687
776
|
# --- cover layout (all optional) ---
|
|
688
|
-
logo_width:
|
|
777
|
+
logo_width: 300 # target logo width in px (default 420)
|
|
689
778
|
logo_y: 100 # logo vertical offset from top in px (default 180)
|
|
690
779
|
tagline_font_size: 20 # tagline point size (default 30)
|
|
691
780
|
title_font_size: 40 # title point size (default 54)
|
|
692
|
-
|
|
781
|
+
edition_date_font_size: 22 # edition/date point size (default 24)
|
|
782
|
+
bold_edition: true # render the "Edition X" and "Dated ..." lines in bold (default false)
|
|
693
783
|
colors:
|
|
694
784
|
text: "#000000" # body text
|
|
695
785
|
cover_text: "#1F3864" # cover text / section numbers / ToC
|
|
@@ -851,6 +941,12 @@ The tool enforces these rules at build time. Violations produce clear error mess
|
|
|
851
941
|
| Parameters need `unit` + `observedProperty` | Required by OGC API - EDR Part 3 |
|
|
852
942
|
| `parameter_name_pattern` enforced | All `parameter_names` keys must match if set |
|
|
853
943
|
| `collection_id_pattern` enforced | All collection IDs must match if set |
|
|
944
|
+
| `collection_title_max_length` enforced | If set, every collection title must be present and within the limit |
|
|
945
|
+
| `require_license_link` enforced | If set, every collection must have a `rel='license'` link (of `license_link_type` when specified) |
|
|
946
|
+
| `required_data_queries` enforced | If set, every collection with `data_queries` must define each listed query type |
|
|
947
|
+
| `radius_within_units_required` enforced | If set, each radius query's `within_units` must contain every listed unit token |
|
|
948
|
+
| `conformance_class_requirements` enforced | Class-scoped `required_data_queries` / `radius_within_units_required` applied to collections whose `conformance_classes` include the class key |
|
|
949
|
+
| `conformance_classes` references known class | When `conformance_class_requirements` is set, a collection's `conformance_classes` may only use `core` or a defined class key (catches typos) |
|
|
854
950
|
| Abstract test IDs match requirements | `requirement_id` must reference an existing requirement |
|
|
855
951
|
| Requirement IDs | Must match `^[a-z0-9][a-z0-9\-]*$`, no trailing hyphen |
|
|
856
952
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oapi-profile-builder"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.6.1"
|
|
8
8
|
description = "Authoritative tooling for creating OGC API Service Profiles (EDR, Features)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -197,17 +197,20 @@ def build_cover_image(profile, output_dir: Path) -> str | None:
|
|
|
197
197
|
if m and m.doc_number:
|
|
198
198
|
y = centered(m.doc_number, fonts.regular_font(46, bold=True), y, fg) + 40
|
|
199
199
|
|
|
200
|
-
# --- Edition ---
|
|
200
|
+
# --- Edition & date ---
|
|
201
|
+
# Per DGIWG feedback these two lines are both bold and set a little smaller
|
|
202
|
+
# than the document number so they read as a compact sub-heading.
|
|
203
|
+
ed_date_fs = getattr(cover, "edition_date_font_size", 24)
|
|
204
|
+
bold_ed = bool(getattr(cover, "bold_edition", False))
|
|
205
|
+
|
|
201
206
|
edition = getattr(profile, "version", None)
|
|
202
207
|
if edition:
|
|
203
|
-
|
|
204
|
-
y = centered(f"Edition {edition}", fonts.regular_font(28, bold=bold_ed), y, fg) + 24
|
|
208
|
+
y = centered(f"Edition {edition}", fonts.regular_font(ed_date_fs, bold=bold_ed), y, fg) + 20
|
|
205
209
|
|
|
206
|
-
# --- Date ---
|
|
207
210
|
pub_date = (m.doc_pub_date or m.publication_date) if m else None
|
|
208
211
|
date_str = _format_date(pub_date)
|
|
209
212
|
if date_str:
|
|
210
|
-
y = centered(f"Dated {date_str}", fonts.regular_font(
|
|
213
|
+
y = centered(f"Dated {date_str}", fonts.regular_font(ed_date_fs, bold=bold_ed), y, fg) + 80
|
|
211
214
|
|
|
212
215
|
# --- Title (large, bold, wrapped) ---
|
|
213
216
|
title = getattr(profile, "title", "") or ""
|