oapi-profile-builder 2.1.9__tar.gz → 2.3.0__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 (22) hide show
  1. oapi_profile_builder-2.3.0/PKG-INFO +565 -0
  2. oapi_profile_builder-2.3.0/README.md +520 -0
  3. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/pyproject.toml +1 -1
  4. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/generate.py +196 -14
  5. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/models.py +69 -8
  6. oapi_profile_builder-2.3.0/src/oapi_profile_builder.egg-info/PKG-INFO +565 -0
  7. oapi_profile_builder-2.1.9/PKG-INFO +0 -787
  8. oapi_profile_builder-2.1.9/README.md +0 -742
  9. oapi_profile_builder-2.1.9/src/oapi_profile_builder.egg-info/PKG-INFO +0 -787
  10. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/LICENSE +0 -0
  11. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/setup.cfg +0 -0
  12. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/__init__.py +0 -0
  13. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/cite.py +0 -0
  14. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/cite_features.py +0 -0
  15. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/cli.py +0 -0
  16. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/compile.py +0 -0
  17. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder/server_validation.py +0 -0
  18. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder.egg-info/SOURCES.txt +0 -0
  19. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder.egg-info/dependency_links.txt +0 -0
  20. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder.egg-info/entry_points.txt +0 -0
  21. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder.egg-info/requires.txt +0 -0
  22. {oapi_profile_builder-2.1.9 → oapi_profile_builder-2.3.0}/src/oapi_profile_builder.egg-info/top_level.txt +0 -0
@@ -0,0 +1,565 @@
1
+ Metadata-Version: 2.4
2
+ Name: oapi-profile-builder
3
+ Version: 2.3.0
4
+ Summary: Authoritative tooling for creating OGC API Service Profiles (EDR, Features)
5
+ Author-email: Shane Mill <shane.mill@noaa.gov>
6
+ License: Apache License
7
+ Version 2.0, January 2004
8
+ http://www.apache.org/licenses/
9
+
10
+ Copyright 2025 NOAA/NWS/Meteorological Development Laboratory
11
+
12
+ Licensed under the Apache License, Version 2.0 (the "License");
13
+ you may not use this file except in compliance with the License.
14
+ You may obtain a copy of the License at
15
+
16
+ http://www.apache.org/licenses/LICENSE-2.0
17
+
18
+ Unless required by applicable law or agreed to in writing, software
19
+ distributed under the License is distributed on an "AS IS" BASIS,
20
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ See the License for the specific language governing permissions and
22
+ limitations under the License.
23
+
24
+ Project-URL: Homepage, https://github.com/ShaneMill1/OGC-API-Service-Profile-Builder
25
+ Project-URL: Issues, https://github.com/ShaneMill1/OGC-API-Service-Profile-Builder/issues
26
+ Keywords: ogc,edr,features,environmental-data-retrieval,profile,openapi,asyncapi
27
+ Classifier: Development Status :: 4 - Beta
28
+ Classifier: Intended Audience :: Science/Research
29
+ Classifier: License :: OSI Approved :: Apache Software License
30
+ Classifier: Programming Language :: Python :: 3
31
+ Classifier: Programming Language :: Python :: 3.10
32
+ Classifier: Programming Language :: Python :: 3.11
33
+ Classifier: Programming Language :: Python :: 3.12
34
+ Classifier: Topic :: Scientific/Engineering :: GIS
35
+ Requires-Python: >=3.10
36
+ Description-Content-Type: text/markdown
37
+ License-File: LICENSE
38
+ Requires-Dist: edr-pydantic>=0.3
39
+ Requires-Dist: pydantic>=2.0
40
+ Requires-Dist: pyyaml>=6.0
41
+ Requires-Dist: requests>=2.31
42
+ Provides-Extra: validate
43
+ Requires-Dist: schemathesis>=3.0; extra == "validate"
44
+ Dynamic: license-file
45
+
46
+ # OGC API Service Profile Builder
47
+
48
+ Generate OGC API - EDR Part 3 Service Profile artifacts from a YAML config — OpenAPI 3.1.0, AsyncAPI, AsciiDoc requirements, and conformance tests.
49
+
50
+ [![PyPI](https://img.shields.io/pypi/v/oapi-profile-builder)](https://pypi.org/project/oapi-profile-builder/)
51
+ [![License](https://img.shields.io/badge/license-Apache-blue)](LICENSE)
52
+
53
+ ---
54
+
55
+ ## Quick Start
56
+
57
+ ```bash
58
+ pip install oapi-profile-builder
59
+
60
+ # Copy an example config and edit it
61
+ cp examples/minimal_profile.yaml my_profile.yaml
62
+
63
+ # Validate and generate artifacts
64
+ oapi-profile-builder generate --config my_profile.yaml --output ./output
65
+ ```
66
+
67
+ That's it. The `output/` directory will contain:
68
+
69
+ ```
70
+ output/
71
+ ├── openapi.yaml # OpenAPI 3.1.0 — ready for Swagger UI, Redoc, schemathesis
72
+ ├── profile_config.json # Round-trip serialized profile
73
+ ├── document.adoc # Metanorma root document
74
+ ├── sections/ # Abstract, Preface, Scope, Conformance, References, Terms
75
+ ├── requirements/ # Individual REQ_*.adoc files
76
+ └── abstract_tests/ # Individual ATS_*.adoc files
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Example Profiles
82
+
83
+ Three working examples are included:
84
+
85
+ | File | What it shows |
86
+ |---|---|
87
+ | [`examples/minimal_profile.yaml`](examples/minimal_profile.yaml) | Smallest valid profile — one collection, one requirement |
88
+ | [`examples/insitu_observations_profile.yaml`](examples/insitu_observations_profile.yaml) | Full meteorological profile — 8 parameters with QUDT units, CF standard names, metocean extensions, CRS listing, temporal extent, custom dimensions, `parameter_schema` |
89
+ | [`examples/nwsviz_profile.yaml`](examples/nwsviz_profile.yaml) | Production profile — 13 collections, 3 OGC API Processes, PDF metadata |
90
+
91
+ ---
92
+
93
+ ## CLI Reference
94
+
95
+ ```
96
+ oapi-profile-builder generate --config <file> --output <dir> [--pdf]
97
+ oapi-profile-builder validate --config <file>
98
+ oapi-profile-builder validate-server --config <file> --url <url> [--max-examples N] [--stateful]
99
+ oapi-profile-builder cite-test --url <url> [--report <dir>]
100
+ oapi-profile-builder cite-test-features --url <url> [--report <dir>]
101
+ oapi-profile-builder schema [--output <file>]
102
+ ```
103
+
104
+ ### `generate`
105
+
106
+ Validates the profile config and writes all artifacts to the output directory.
107
+
108
+ ```bash
109
+ oapi-profile-builder generate --config my_profile.yaml --output ./output
110
+ ```
111
+
112
+ Add `--pdf` to also compile an OGC-compliant PDF via the `metanorma/metanorma` Docker image (Docker required):
113
+
114
+ ```bash
115
+ oapi-profile-builder generate --config my_profile.yaml --output ./output --pdf
116
+ ```
117
+
118
+ ### `validate`
119
+
120
+ Validates the config without writing any files. Useful in CI before generating.
121
+
122
+ ```bash
123
+ oapi-profile-builder validate --config my_profile.yaml
124
+ # Profile 'my_profile' is valid.
125
+ ```
126
+
127
+ ### `validate-server`
128
+
129
+ Runs [schemathesis](https://schemathesis.io/) against a live server using the profile's generated OpenAPI. Requires `pip install oapi-profile-builder[validate]`.
130
+
131
+ ```bash
132
+ oapi-profile-builder validate-server \
133
+ --config my_profile.yaml \
134
+ --url https://my-server.example.com \
135
+ --max-examples 5
136
+ ```
137
+
138
+ Supply real `instanceId` values in your config so schemathesis can exercise instance-level paths:
139
+
140
+ ```yaml
141
+ collection_examples:
142
+ my_collection:
143
+ instanceId: "2025-04-02T00:00:00Z"
144
+ ```
145
+
146
+ ### `cite-test` / `cite-test-features`
147
+
148
+ Runs the official OGC CITE conformance test suites against a live server. Docker and Maven are required for `cite-test` (EDR); Docker only for `cite-test-features`.
149
+
150
+ ```bash
151
+ # OGC API - EDR Part 1 (builds ets-ogcapi-edr10 on first run, ~2 min)
152
+ oapi-profile-builder cite-test \
153
+ --url https://my-server.example.com \
154
+ --report ./cite_results
155
+
156
+ # OGC API - Features Part 1 (pulls pre-built image from Docker Hub)
157
+ oapi-profile-builder cite-test-features \
158
+ --url https://my-server.example.com \
159
+ --report ./cite_features_results
160
+ ```
161
+
162
+ Results:
163
+
164
+ ```
165
+ OGC API - EDR CITE Results
166
+ Passed: 76/84
167
+ Failed: 0
168
+ Skipped: 8
169
+
170
+ ✓ All CITE tests passed.
171
+ ```
172
+
173
+ ---
174
+
175
+ ## GitHub Actions
176
+
177
+ No local install needed. Add this to any workflow to generate profile artifacts from a config file:
178
+
179
+ ```yaml
180
+ name: Generate Profile
181
+
182
+ on:
183
+ push:
184
+ paths: ['my_profile.yaml']
185
+
186
+ jobs:
187
+ generate:
188
+ runs-on: ubuntu-latest
189
+ steps:
190
+ - uses: actions/checkout@v4
191
+
192
+ - name: Generate profile artifacts
193
+ uses: ShaneMill1/OGC-API-Service-Profile-Builder@main
194
+ with:
195
+ config: my_profile.yaml
196
+ output: ./profile_output
197
+
198
+ - name: Upload artifacts
199
+ uses: actions/upload-artifact@v4
200
+ with:
201
+ name: profile-artifacts
202
+ path: ./profile_output/
203
+ ```
204
+
205
+ **To download the artifacts:** Actions tab → click the run → scroll to **Artifacts** at the bottom → download the zip.
206
+
207
+ ### Action inputs
208
+
209
+ | Input | Default | Description |
210
+ |---|---|---|
211
+ | `config` | — | Path to the profile config YAML (required) |
212
+ | `output` | `./profile_output` | Output directory |
213
+ | `version` | `latest` | Package version to install |
214
+ | `pdf` | `false` | Compile PDF via Metanorma (Docker required on runner) |
215
+ | `cite-url` | — | Run OGC CITE tests against this server URL |
216
+ | `cite-type` | `edr` | `edr`, `features`, or `both` |
217
+
218
+ > **CITE + VPN:** The CITE test runner needs to reach the server from GitHub's runners. Servers behind a VPN require a [self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners).
219
+
220
+ ---
221
+
222
+ ## Profile Config Reference
223
+
224
+ A profile config is a YAML file. The full JSON Schema is at [`profile.schema.json`](profile.schema.json).
225
+
226
+ ### Minimal valid config
227
+
228
+ ```yaml
229
+ name: my_profile # lowercase, a-z 0-9 _ only
230
+ title: My EDR Profile
231
+ version: "1.0"
232
+
233
+ required_conformance_classes:
234
+ - "http://www.opengis.net/spec/ogcapi-edr-1/1.0/conf/core"
235
+
236
+ extent_requirements:
237
+ minimum_bbox: [-180, -90, 180, 90]
238
+ allowed_crs:
239
+ - "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
240
+
241
+ output_formats:
242
+ - name: GeoJSON
243
+ media_type: application/geo+json
244
+
245
+ collections:
246
+ - id: my_collection
247
+ links:
248
+ - href: https://example.com/collections/my_collection
249
+ rel: self
250
+ type: application/json
251
+ extent:
252
+ spatial:
253
+ bbox: [[-180, -90, 180, 90]]
254
+ crs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
255
+ parameter_names:
256
+ temperature:
257
+ type: Parameter
258
+ observedProperty:
259
+ label: Air Temperature
260
+ unit:
261
+ label: Celsius
262
+ symbol: "°C"
263
+ ```
264
+
265
+ ### Top-level fields
266
+
267
+ | Field | Type | Required | Description |
268
+ |---|---|---|---|
269
+ | `name` | string | yes | Lowercase `a-z 0-9 _`. Drives OGC URIs and OpenAPI `operationId`s |
270
+ | `title` | string | yes | Human-readable profile title |
271
+ | `version` | string | no | Defaults to `"1.0"` |
272
+ | `server_url` | string | no | Documentation only — not written to the profile OpenAPI |
273
+ | `collections` | list | yes | One or more EDR collections (see below) |
274
+ | `required_conformance_classes` | list | no | Conformance classes implementations must declare. Defaults to EDR Core |
275
+ | `extent_requirements` | object | no | Profile-level CRS/TRS/VRS constraints (see below) |
276
+ | `output_formats` | list | no | Format name → media type + schema ref mappings |
277
+ | `collection_id_pattern` | string | no | Regex all collection IDs must match |
278
+ | `parameter_name_pattern` | string | no | Regex all `parameter_names` keys must match |
279
+ | `parameter_schema` | object | no | JSON Schema for parameter objects — replaces the default schema in the generated OpenAPI (see below) |
280
+ | `processes` | list | no | OGC API Processes to expose in the OpenAPI |
281
+ | `requirements` | list | no | Normative requirements for the AsciiDoc/PDF |
282
+ | `abstract_tests` | list | no | Conformance tests — each must reference a valid requirement `id` |
283
+ | `pubsub` | object | no | OGC API - EDR Part 2 PubSub config — generates `asyncapi.yaml` |
284
+ | `collection_examples` | object | no | `{collectionId: {instanceId: "..."}}` — used by `validate-server` |
285
+ | `document_metadata` | object | no | Metanorma PDF header (doc number, editors, orgs, keywords) |
286
+
287
+ ---
288
+
289
+ ### `collections[]`
290
+
291
+ Uses the [edr-pydantic](https://github.com/KNMI/edr-pydantic) `Collection` model — the same schema an EDR server returns at `/collections/{id}`.
292
+
293
+ | Field | Required | Description |
294
+ |---|---|---|
295
+ | `id` | yes | Collection identifier |
296
+ | `title` | no | Human-readable name |
297
+ | `description` | no | Longer description |
298
+ | `links` | yes | At minimum a `self` link |
299
+ | `extent.spatial.bbox` | yes | `[[minLon, minLat, maxLon, maxLat]]` |
300
+ | `extent.spatial.crs` | yes | CRS URI — validated against `extent_requirements` |
301
+ | `extent.temporal` | no | `interval`, `values`, `trs` |
302
+ | `extent.vertical` | no | `interval`, `values`, `vrs` |
303
+ | `extent.custom` | no | Custom dimensions (e.g. `standard_name`, `level`) |
304
+ | `crs` | no | Full list of CRS values this collection supports |
305
+ | `output_formats` | no | Format names this collection supports (e.g. `[CoverageJSON, GeoJSON]`) |
306
+ | `data_queries` | no | EDR query types: `position`, `area`, `radius`, `cube`, `trajectory`, `corridor`, `locations`, `items`, `instances` |
307
+ | `parameter_names` | no | Map of parameter id → Parameter object. All parameters must have `unit` and `observedProperty` |
308
+
309
+ #### `data_queries` example
310
+
311
+ ```yaml
312
+ data_queries:
313
+ position:
314
+ link:
315
+ href: https://example.com/collections/obs/position
316
+ rel: data
317
+ variables:
318
+ query_type: position
319
+ output_formats: [CoverageJSON]
320
+ radius:
321
+ link:
322
+ href: https://example.com/collections/obs/radius
323
+ rel: data
324
+ variables:
325
+ query_type: radius
326
+ output_formats: [CoverageJSON]
327
+ within_units: [m, km]
328
+ # crs_details: per-query CRS support, validated against extent_requirements
329
+ crs_details:
330
+ - crs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
331
+ - crs: "http://www.opengis.net/def/crs/EPSG/0/4326"
332
+ ```
333
+
334
+ #### `parameter_names` example
335
+
336
+ ```yaml
337
+ parameter_names:
338
+ air-temperature-2m:
339
+ type: Parameter
340
+ label: Air Temperature at 2m
341
+ description: Instantaneous air temperature at 2 metres above ground
342
+ observedProperty:
343
+ id: "https://vocab.nerc.ac.uk/standard_name/air_temperature"
344
+ label: Air Temperature
345
+ unit:
346
+ label: Kelvin
347
+ symbol:
348
+ value: K
349
+ type: "https://qudt.org/vocab/unit/K"
350
+ measurementType:
351
+ method: point
352
+ duration: PT0S
353
+ ```
354
+
355
+ ---
356
+
357
+ ### `extent_requirements`
358
+
359
+ Constrains CRS, TRS, and VRS values across all collections. Validated at build time and embedded in the generated OpenAPI.
360
+
361
+ ```yaml
362
+ extent_requirements:
363
+ minimum_bbox: [-180, -90, 180, 90]
364
+
365
+ # Option A: exact list
366
+ allowed_crs:
367
+ - "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
368
+ - "http://www.opengis.net/def/crs/EPSG/0/4326"
369
+
370
+ # Option B: regex (accepts any OGC or EPSG CRS)
371
+ # crs_pattern: "^http://www\\.opengis\\.net/def/crs/(OGC|EPSG)/.*$"
372
+
373
+ allowed_trs:
374
+ - "http://www.opengis.net/def/uom/ISO-8601/0/Gregorian"
375
+ ```
376
+
377
+ Either `allowed_crs` or `crs_pattern` is required. The same enum/regex approach applies to `allowed_trs`/`trs_pattern` and `allowed_vrs`/`vrs_pattern`.
378
+
379
+ ---
380
+
381
+ ### `parameter_schema`
382
+
383
+ A JSON Schema fragment that replaces the default parameter schema in the generated OpenAPI. Use this to enforce field-level constraints — required fields, QUDT unit URIs, CF standard name URIs, ISO 8601 durations, and custom extension properties.
384
+
385
+ ```yaml
386
+ parameter_schema:
387
+ type: object
388
+ required:
389
+ - type
390
+ - observedProperty
391
+ - measurementType
392
+ - label
393
+ - description
394
+ - unit
395
+ - "metocean:standard_name"
396
+ - "metocean:level"
397
+ properties:
398
+ unit:
399
+ type: object
400
+ properties:
401
+ symbol:
402
+ type: object
403
+ properties:
404
+ type:
405
+ type: string
406
+ pattern: "^https://qudt\\.org/vocab/unit/.*$"
407
+ observedProperty:
408
+ type: object
409
+ properties:
410
+ id:
411
+ type: string
412
+ pattern: "^https://vocab\\.nerc\\.ac\\.uk/standard_name/.*$"
413
+ measurementType:
414
+ type: object
415
+ properties:
416
+ duration:
417
+ type: string
418
+ pattern: "^P(\\d+Y)?(\\d+M)?(\\d+D)?(T(\\d+H)?(\\d+M)?(\\d+S)?)?$"
419
+ "metocean:standard_name":
420
+ type: string
421
+ "metocean:level":
422
+ type: number
423
+ additionalProperties: true
424
+ ```
425
+
426
+ See [`examples/insitu_observations_profile.yaml`](examples/insitu_observations_profile.yaml) for a complete working example.
427
+
428
+ ---
429
+
430
+ ### `requirements[]` and `abstract_tests[]`
431
+
432
+ Requirements drive the AsciiDoc/PDF output. Abstract tests must reference a valid requirement `id`.
433
+
434
+ ```yaml
435
+ requirements:
436
+ - id: position-coveragejson # lowercase, hyphens only
437
+ statement: The position query SHALL return CoverageJSON.
438
+ parts:
439
+ - The service SHALL provide a /collections/{id}/position endpoint.
440
+ - The response Content-Type SHALL be application/prs.coverage+json.
441
+
442
+ abstract_tests:
443
+ - id: position-coveragejson # must equal requirement_id
444
+ requirement_id: position-coveragejson
445
+ steps:
446
+ - Send GET /collections/{id}/position?coords=POINT(lon lat).
447
+ - Verify Content-Type is application/prs.coverage+json.
448
+ ```
449
+
450
+ ---
451
+
452
+ ### `processes[]`
453
+
454
+ Adds OGC API Processes paths to the generated OpenAPI.
455
+
456
+ ```yaml
457
+ processes:
458
+ - id: compute-difference
459
+ title: Compute Dataset Difference
460
+ description: Calculates the difference between two datasets.
461
+ output_content:
462
+ application/zip:
463
+ schema:
464
+ type: object
465
+ ```
466
+
467
+ Generates: `/processes/compute-difference`, `/processes/compute-difference/execution`, `/jobs`, `/jobs/{jobId}`, `/jobs/{jobId}/results`.
468
+
469
+ ---
470
+
471
+ ### `pubsub`
472
+
473
+ When present, generates `asyncapi.yaml` alongside `openapi.yaml`.
474
+
475
+ ```yaml
476
+ pubsub:
477
+ broker_host: my-broker.example.com
478
+ broker_port: 5672
479
+ protocol: amqp # amqp | mqtt | kafka
480
+ collections:
481
+ - my_collection
482
+ filters:
483
+ - name: station
484
+ description: Filter by station ID
485
+ type: string
486
+ ```
487
+
488
+ ---
489
+
490
+ ### `document_metadata`
491
+
492
+ Required only when compiling a PDF with `--pdf`.
493
+
494
+ ```yaml
495
+ document_metadata:
496
+ doc_number: "25-myprofile"
497
+ doc_subtype: implementation # implementation | best-practice | engineering-report
498
+ editors:
499
+ - Jane Smith
500
+ submitting_orgs:
501
+ - My Organization
502
+ keywords:
503
+ - ogcdoc
504
+ - OGC API
505
+ - EDR
506
+ copyright_year: 2026
507
+ external_id: http://www.opengis.net/doc/dp/my-profile/1.0
508
+ ```
509
+
510
+ ---
511
+
512
+ ## Validation Rules
513
+
514
+ The tool enforces these rules at build time. Violations produce clear error messages.
515
+
516
+ | Rule | Detail |
517
+ |---|---|
518
+ | `name` format | Must match `^[a-z0-9_]+$` |
519
+ | No duplicate collection IDs | Across the whole profile |
520
+ | `extent_requirements` requires CRS spec | Either `allowed_crs` or `crs_pattern` must be set |
521
+ | Collection CRS validated | Each `extent.spatial.crs` checked against `allowed_crs`/`crs_pattern` |
522
+ | Collection TRS validated | Each `extent.temporal.trs` checked against `allowed_trs`/`trs_pattern` |
523
+ | `crs_details` validated | Each `data_queries.*.variables.crs_details[].crs` checked against CRS constraints |
524
+ | Parameters need `unit` + `observedProperty` | Required by OGC API - EDR Part 3 |
525
+ | `parameter_name_pattern` enforced | All `parameter_names` keys must match if set |
526
+ | `collection_id_pattern` enforced | All collection IDs must match if set |
527
+ | Abstract test IDs match requirements | `requirement_id` must reference an existing requirement |
528
+ | Requirement IDs | Must match `^[a-z0-9][a-z0-9\-]*$`, no trailing hyphen |
529
+
530
+ ---
531
+
532
+ ## Programmatic Use
533
+
534
+ ```python
535
+ from oapi_profile_builder.models import ServiceProfile
536
+ from oapi_profile_builder.generate import generate
537
+ from pathlib import Path
538
+ import yaml
539
+
540
+ with open("my_profile.yaml") as f:
541
+ config = yaml.safe_load(f)
542
+
543
+ profile = ServiceProfile.model_validate(config) # validates everything
544
+ generate(profile, Path("./output"))
545
+ ```
546
+
547
+ ---
548
+
549
+ ## Standards
550
+
551
+ - [OGC API - EDR Part 1: Core](https://docs.ogc.org/is/19-086r6/19-086r6.html)
552
+ - [OGC API - EDR Part 2: PubSub](https://docs.ogc.org/DRAFTS/21-009.html)
553
+ - [OGC API - EDR Part 3: Service Profiles (draft)](https://github.com/opengeospatial/ogcapi-environmental-data-retrieval)
554
+ - [OGC API - Processes Part 1](https://docs.ogc.org/is/18-062r2/18-062r2.html)
555
+ - OpenAPI 3.1.0 / AsyncAPI 3.0
556
+ - Metanorma/AsciiDoc
557
+
558
+ ## License
559
+
560
+ Apache 2.0 — see [LICENSE](LICENSE).
561
+
562
+ ## Contact
563
+
564
+ Shane Mill · NOAA/NWS/MDL · shane.mill@noaa.gov
565
+ Issues: https://github.com/ShaneMill1/OGC-API-Service-Profile-Builder/issues