oapi-profile-builder 2.0.2__tar.gz → 2.1.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.
- {oapi_profile_builder-2.0.2/src/oapi_profile_builder.egg-info → oapi_profile_builder-2.1.0}/PKG-INFO +168 -9
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/README.md +167 -8
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/pyproject.toml +1 -1
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/generate.py +292 -20
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/models.py +115 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0/src/oapi_profile_builder.egg-info}/PKG-INFO +168 -9
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/LICENSE +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/setup.cfg +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/__init__.py +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/cite.py +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/cite_features.py +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/cli.py +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/compile.py +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder/server_validation.py +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder.egg-info/SOURCES.txt +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder.egg-info/dependency_links.txt +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder.egg-info/entry_points.txt +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder.egg-info/requires.txt +0 -0
- {oapi_profile_builder-2.0.2 → oapi_profile_builder-2.1.0}/src/oapi_profile_builder.egg-info/top_level.txt +0 -0
{oapi_profile_builder-2.0.2/src/oapi_profile_builder.egg-info → oapi_profile_builder-2.1.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oapi-profile-builder
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
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
|
|
@@ -63,6 +63,9 @@ pip install oapi-profile-builder
|
|
|
63
63
|
|
|
64
64
|
## Workflow
|
|
65
65
|
|
|
66
|
+
<img width="1001" height="721" alt="OGC API Service Profile Builder - Pydantic Validation Architecture drawio" src="https://github.com/user-attachments/assets/092c3dfc-549e-41b0-8a92-af0b89689950" />
|
|
67
|
+
|
|
68
|
+
|
|
66
69
|
### 1. Author a Profile Config
|
|
67
70
|
|
|
68
71
|
A profile config is a YAML or JSON file. Start with the minimal example:
|
|
@@ -128,7 +131,7 @@ abstract_tests:
|
|
|
128
131
|
- Verify each feature contains gauge_height property.
|
|
129
132
|
```
|
|
130
133
|
|
|
131
|
-
See [`examples/minimal_profile.yaml`](examples/minimal_profile.yaml) for a complete working example and [`examples/nwsviz_profile.yaml`](examples/nwsviz_profile.yaml) for a full profile with 13 collections, 3 processes, requirements, abstract tests, and document metadata.
|
|
134
|
+
See [`examples/minimal_profile.yaml`](examples/minimal_profile.yaml) for a complete working example, [`examples/insitu_observations_profile.yaml`](examples/insitu_observations_profile.yaml) for a full in-situ observations profile with rich parameter constraints, CRS listing, temporal extent, and custom dimensions, and [`examples/nwsviz_profile.yaml`](examples/nwsviz_profile.yaml) for a full profile with 13 collections, 3 processes, requirements, abstract tests, and document metadata.
|
|
132
135
|
|
|
133
136
|
### 2. Generate Profile Artifacts
|
|
134
137
|
|
|
@@ -293,6 +296,133 @@ The skipped tests are optional features not implemented by the server.
|
|
|
293
296
|
|
|
294
297
|
---
|
|
295
298
|
|
|
299
|
+
## Profile Configuration Guide
|
|
300
|
+
|
|
301
|
+
This section explains what is and isn't allowed when creating a profile, and how the tool validates your configuration.
|
|
302
|
+
|
|
303
|
+
### What Gets Validated
|
|
304
|
+
|
|
305
|
+
When you run `generate` or `validate`, the tool instantiates a `ServiceProfile` Pydantic model that enforces all of the following rules before any files are written. If any rule is violated, you get a clear error message pointing to the offending field.
|
|
306
|
+
|
|
307
|
+
#### Profile-Level Fields
|
|
308
|
+
|
|
309
|
+
| Field | Rules |
|
|
310
|
+
|---|---|
|
|
311
|
+
| `name` | Must match `^[a-z0-9_]+$` — lowercase letters, digits, and underscores only. Used in OGC URIs. |
|
|
312
|
+
| `title` | Any non-empty string. |
|
|
313
|
+
| `version` | Any string. Defaults to `"1.0"`. |
|
|
314
|
+
| `collections` | At least one collection is required. No duplicate `id` values. |
|
|
315
|
+
|
|
316
|
+
#### Collection IDs
|
|
317
|
+
|
|
318
|
+
By default, collection IDs can be any string accepted by edr-pydantic. To enforce a naming convention across all collections, use `collection_id_pattern`:
|
|
319
|
+
|
|
320
|
+
```yaml
|
|
321
|
+
# Only allow lowercase snake_case collection IDs
|
|
322
|
+
collection_id_pattern: "^[a-z][a-z0-9_]*$"
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The pattern is matched using Python's `re.fullmatch()`, so it must match the **entire** ID string.
|
|
326
|
+
|
|
327
|
+
#### CRS, TRS, and VRS Constraints
|
|
328
|
+
|
|
329
|
+
Each collection declares a CRS in `extent.spatial.crs`, and optionally a TRS in `extent.temporal.trs` and VRS in `extent.vertical.vrs`. The profile can constrain these values in two ways:
|
|
330
|
+
|
|
331
|
+
**Enumerated list** — only the exact values listed are accepted:
|
|
332
|
+
|
|
333
|
+
```yaml
|
|
334
|
+
extent_requirements:
|
|
335
|
+
minimum_bbox: [-180, -90, 180, 90]
|
|
336
|
+
allowed_crs:
|
|
337
|
+
- "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
|
|
338
|
+
- "http://www.opengis.net/def/crs/EPSG/0/4326"
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Regex pattern** — any value matching the pattern is accepted:
|
|
342
|
+
|
|
343
|
+
```yaml
|
|
344
|
+
extent_requirements:
|
|
345
|
+
minimum_bbox: [-180, -90, 180, 90]
|
|
346
|
+
# Accept any OGC or EPSG CRS
|
|
347
|
+
crs_pattern: "^http://www\\.opengis\\.net/def/crs/(OGC|EPSG)/.*$"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
If both `allowed_crs` and `crs_pattern` are specified, a collection's CRS must satisfy **both**. At least one of `allowed_crs` or `crs_pattern` is required when `extent_requirements` is present.
|
|
351
|
+
|
|
352
|
+
The same enum/regex approach works for TRS (`allowed_trs` / `trs_pattern`) and VRS (`allowed_vrs` / `vrs_pattern`).
|
|
353
|
+
|
|
354
|
+
#### Parameter Name Constraints
|
|
355
|
+
|
|
356
|
+
By default, parameter names (the keys in `parameter_names`) can be any string. To enforce a naming convention, use `parameter_name_pattern`:
|
|
357
|
+
|
|
358
|
+
```yaml
|
|
359
|
+
# CF-style lowercase parameter names
|
|
360
|
+
parameter_name_pattern: "^[a-z][a-z0-9_]*$"
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
```yaml
|
|
364
|
+
# Allow uppercase abbreviations like WMO codes
|
|
365
|
+
parameter_name_pattern: "^[A-Za-z][A-Za-z0-9_]*$"
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Every key in every collection's `parameter_names` must match this pattern. The pattern uses `re.fullmatch()`.
|
|
369
|
+
|
|
370
|
+
Additionally, per OGC API - EDR Part 3, every parameter must specify both `unit` and `observedProperty`. The tool enforces this automatically.
|
|
371
|
+
|
|
372
|
+
#### Requirement and Test IDs
|
|
373
|
+
|
|
374
|
+
| Field | Rules |
|
|
375
|
+
|---|---|
|
|
376
|
+
| Requirement `id` | Must match `^[a-z0-9][a-z0-9\-]*$` — lowercase, digits, hyphens. Cannot end with a hyphen. |
|
|
377
|
+
| AbstractTest `id` | Must exactly equal its `requirement_id`. |
|
|
378
|
+
| AbstractTest `requirement_id` | Must reference an existing requirement `id`. |
|
|
379
|
+
|
|
380
|
+
#### What Happens When Validation Fails
|
|
381
|
+
|
|
382
|
+
The tool prints a Pydantic validation error with the field path and a human-readable message. For example:
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
Value error, Collection 'my_data' CRS 'urn:ogc:def:crs:EPSG::4326'
|
|
386
|
+
does not match crs_pattern '^http://www\.opengis\.net/def/crs/(OGC|EPSG)/.*$'
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
Value error, Parameter name 'WIND_SPEED' in collection 'weather'
|
|
391
|
+
does not match parameter_name_pattern '^[a-z][a-z0-9_]*$'
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
```
|
|
395
|
+
Value error, Collection id 'My-Collection' does not match
|
|
396
|
+
collection_id_pattern '^[a-z][a-z0-9_]*$'
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### How Patterns Flow Into the Generated OpenAPI
|
|
400
|
+
|
|
401
|
+
When you specify `crs_pattern`, `allowed_crs`, or `parameter_name_pattern`, those constraints are embedded in the generated `openapi.yaml` so that runtime validation tools can enforce them:
|
|
402
|
+
|
|
403
|
+
- `crs_pattern` → `pattern` on the CRS string schema in collection responses
|
|
404
|
+
- `allowed_crs` → `enum` on the CRS string schema
|
|
405
|
+
- `trs_pattern` / `allowed_trs` → `pattern` / `enum` on the TRS field in extent.temporal
|
|
406
|
+
- `vrs_pattern` / `allowed_vrs` → `pattern` / `enum` on the VRS field in extent.vertical
|
|
407
|
+
- `parameter_name_pattern` → `propertyNames.pattern` on the `parameter_names` object schema
|
|
408
|
+
|
|
409
|
+
This means schemathesis, CITE tests, and client SDKs can validate server responses against these constraints without needing access to the original profile YAML.
|
|
410
|
+
|
|
411
|
+
### Quick Reference: Regex Examples
|
|
412
|
+
|
|
413
|
+
| Use Case | Pattern |
|
|
414
|
+
|---|---|
|
|
415
|
+
| Only OGC CRS84 | `^http://www\\.opengis\\.net/def/crs/OGC/1\\.3/CRS84$` |
|
|
416
|
+
| Any OGC or EPSG CRS | `^http://www\\.opengis\\.net/def/crs/(OGC\|EPSG)/.*$` |
|
|
417
|
+
| Any valid CRS URI | `^http://www\\.opengis\\.net/def/crs/.*$` |
|
|
418
|
+
| ISO-8601 TRS family | `^http://www\\.opengis\\.net/def/uom/ISO-8601/.*$` |
|
|
419
|
+
| Lowercase snake_case names | `^[a-z][a-z0-9_]*$` |
|
|
420
|
+
| CF standard name style | `^[a-z][a-z0-9_]*(_[a-z0-9]+)*$` |
|
|
421
|
+
| WMO-style alphanumeric | `^[A-Za-z][A-Za-z0-9_]*$` |
|
|
422
|
+
| Lowercase with hyphens | `^[a-z][a-z0-9\\-]*$` |
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
296
426
|
## Config Reference
|
|
297
427
|
|
|
298
428
|
### Top-level fields
|
|
@@ -313,7 +443,8 @@ The skipped tests are optional features not implemented by the server.
|
|
|
313
443
|
| `required_conformance_classes` | `list[string]` | no | Conformance classes that implementations must declare. Defaults to EDR Core |
|
|
314
444
|
| `extent_requirements` | `object` | no | Profile-level extent restrictions (see below) |
|
|
315
445
|
| `output_formats` | `list` | no | Profile-level output format definitions with schema references (see below) |
|
|
316
|
-
| `collection_id_pattern` | `string` | no | Regex pattern
|
|
446
|
+
| `collection_id_pattern` | `string` | no | Regex pattern that all collection IDs must match (validated at build time) |
|
|
447
|
+
| `parameter_name_pattern` | `string` | no | Regex pattern that all `parameter_names` keys must match (validated at build time) |
|
|
317
448
|
|
|
318
449
|
---
|
|
319
450
|
|
|
@@ -376,7 +507,7 @@ parameter_names:
|
|
|
376
507
|
|
|
377
508
|
### `extent_requirements`
|
|
378
509
|
|
|
379
|
-
Profile-level extent restrictions per OGC API - EDR Part 3 REQ_extent.
|
|
510
|
+
Profile-level extent restrictions per OGC API - EDR Part 3 REQ_extent. These constraints are **enforced at profile build time** — if any collection's CRS, TRS, or VRS value violates the rules here, the profile will be rejected with a clear error message. The constraints are also **embedded in the generated OpenAPI** so that downstream tools (schemathesis, CITE tests, client SDKs) can enforce them at runtime.
|
|
380
511
|
|
|
381
512
|
| Field | Type | Required | Description |
|
|
382
513
|
|---|---|---|---|
|
|
@@ -390,6 +521,8 @@ Profile-level extent restrictions per OGC API - EDR Part 3 REQ_extent.
|
|
|
390
521
|
|
|
391
522
|
**Note:** Either `allowed_crs` or `crs_pattern` must be specified.
|
|
392
523
|
|
|
524
|
+
**Enum approach** — lock down to specific values:
|
|
525
|
+
|
|
393
526
|
```yaml
|
|
394
527
|
extent_requirements:
|
|
395
528
|
minimum_bbox: [-180, -90, 180, 90]
|
|
@@ -400,6 +533,19 @@ extent_requirements:
|
|
|
400
533
|
- "http://www.opengis.net/def/uom/ISO-8601/0/Gregorian"
|
|
401
534
|
```
|
|
402
535
|
|
|
536
|
+
**Regex approach** — allow any CRS from a family:
|
|
537
|
+
|
|
538
|
+
```yaml
|
|
539
|
+
extent_requirements:
|
|
540
|
+
minimum_bbox: [-180, -90, 180, 90]
|
|
541
|
+
# Accept any OGC or EPSG CRS
|
|
542
|
+
crs_pattern: "^http://www\\.opengis\\.net/def/crs/(OGC|EPSG)/.*$"
|
|
543
|
+
# Accept any ISO-8601 TRS
|
|
544
|
+
trs_pattern: "^http://www\\.opengis\\.net/def/uom/ISO-8601/.*$"
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
Both approaches can coexist — if both `allowed_crs` and `crs_pattern` are specified, a collection's CRS must satisfy **both** constraints.
|
|
548
|
+
|
|
403
549
|
---
|
|
404
550
|
|
|
405
551
|
### `output_formats[]`
|
|
@@ -546,6 +692,7 @@ This tool implements the requirements of OGC API - EDR Part 3: Service Profiles
|
|
|
546
692
|
### Key Compliance Features
|
|
547
693
|
|
|
548
694
|
1. **Profile OpenAPI Document** (REQ_publishing)
|
|
695
|
+
- Generated OpenAPI version is **3.1.0** (required by OGC API - EDR Part 3)
|
|
549
696
|
- Generated OpenAPI has empty `servers` array (profile is implementation-independent)
|
|
550
697
|
- Landing page schema requires `profile` link relation
|
|
551
698
|
- Profile URI advertised in `x-ogc-profile` info field
|
|
@@ -561,12 +708,23 @@ This tool implements the requirements of OGC API - EDR Part 3: Service Profiles
|
|
|
561
708
|
4. **Extent Requirements** (REQ_extent)
|
|
562
709
|
- Profile-level `extent_requirements` specify minimum bounds
|
|
563
710
|
- CRS/TRS/VRS restrictions via enumerated lists or regex patterns
|
|
711
|
+
- **Enforced at build time**: collection CRS/TRS/VRS values are validated against `allowed_*` lists and `*_pattern` regexes
|
|
712
|
+
- **Propagated to OpenAPI**: constraints appear as `enum` or `pattern` in the generated collection response schemas
|
|
713
|
+
|
|
714
|
+
5. **Parameter Names** (REQ_parameter-names)
|
|
715
|
+
- Validates that all parameters specify `unit` and `observedProperty`
|
|
716
|
+
- Optional `parameter_name_pattern` enforces naming conventions across all collections
|
|
717
|
+
- Pattern constraints are embedded in the generated OpenAPI as `propertyNames.pattern`
|
|
718
|
+
|
|
719
|
+
6. **Collection ID Pattern**
|
|
720
|
+
- Optional `collection_id_pattern` enforces naming conventions for collection IDs
|
|
721
|
+
- Validated at build time via `re.fullmatch()`
|
|
564
722
|
|
|
565
|
-
|
|
723
|
+
7. **Output Formats** (REQ_output-format)
|
|
566
724
|
- Profile-level `output_formats` with schema references
|
|
567
725
|
- Links to JSON Schema, XML Schema, or format specifications
|
|
568
726
|
|
|
569
|
-
|
|
727
|
+
8. **Pub/Sub** (REQ_pubsub)
|
|
570
728
|
- Automatically adds Part 2 conformance requirement when `pubsub` is present
|
|
571
729
|
- AsyncAPI document specifies channels and payloads
|
|
572
730
|
|
|
@@ -602,8 +760,9 @@ generate(profile, Path("./output"))
|
|
|
602
760
|
│ ├── cite.py # OGC CITE test suite orchestration
|
|
603
761
|
│ └── cli.py # CLI entry point
|
|
604
762
|
├── examples/
|
|
605
|
-
│ ├──
|
|
606
|
-
│
|
|
763
|
+
│ ├── minimal_profile.yaml # Minimal working profile
|
|
764
|
+
│ ├── insitu_observations_profile.yaml # Full in-situ profile: parameters, CRS, temporal, custom dims
|
|
765
|
+
│ └── nwsviz_profile.yaml # Full NWSViz profile: 13 collections, 3 processes, PDF metadata
|
|
607
766
|
├── profile.schema.json # Machine-readable JSON Schema for profile configs
|
|
608
767
|
└── pyproject.toml
|
|
609
768
|
```
|
|
@@ -619,7 +778,7 @@ generate(profile, Path("./output"))
|
|
|
619
778
|
|
|
620
779
|
## License
|
|
621
780
|
|
|
622
|
-
|
|
781
|
+
Apache — See [LICENSE](LICENSE) for details.
|
|
623
782
|
|
|
624
783
|
## Contact
|
|
625
784
|
|
|
@@ -18,6 +18,9 @@ pip install oapi-profile-builder
|
|
|
18
18
|
|
|
19
19
|
## Workflow
|
|
20
20
|
|
|
21
|
+
<img width="1001" height="721" alt="OGC API Service Profile Builder - Pydantic Validation Architecture drawio" src="https://github.com/user-attachments/assets/092c3dfc-549e-41b0-8a92-af0b89689950" />
|
|
22
|
+
|
|
23
|
+
|
|
21
24
|
### 1. Author a Profile Config
|
|
22
25
|
|
|
23
26
|
A profile config is a YAML or JSON file. Start with the minimal example:
|
|
@@ -83,7 +86,7 @@ abstract_tests:
|
|
|
83
86
|
- Verify each feature contains gauge_height property.
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
See [`examples/minimal_profile.yaml`](examples/minimal_profile.yaml) for a complete working example and [`examples/nwsviz_profile.yaml`](examples/nwsviz_profile.yaml) for a full profile with 13 collections, 3 processes, requirements, abstract tests, and document metadata.
|
|
89
|
+
See [`examples/minimal_profile.yaml`](examples/minimal_profile.yaml) for a complete working example, [`examples/insitu_observations_profile.yaml`](examples/insitu_observations_profile.yaml) for a full in-situ observations profile with rich parameter constraints, CRS listing, temporal extent, and custom dimensions, and [`examples/nwsviz_profile.yaml`](examples/nwsviz_profile.yaml) for a full profile with 13 collections, 3 processes, requirements, abstract tests, and document metadata.
|
|
87
90
|
|
|
88
91
|
### 2. Generate Profile Artifacts
|
|
89
92
|
|
|
@@ -248,6 +251,133 @@ The skipped tests are optional features not implemented by the server.
|
|
|
248
251
|
|
|
249
252
|
---
|
|
250
253
|
|
|
254
|
+
## Profile Configuration Guide
|
|
255
|
+
|
|
256
|
+
This section explains what is and isn't allowed when creating a profile, and how the tool validates your configuration.
|
|
257
|
+
|
|
258
|
+
### What Gets Validated
|
|
259
|
+
|
|
260
|
+
When you run `generate` or `validate`, the tool instantiates a `ServiceProfile` Pydantic model that enforces all of the following rules before any files are written. If any rule is violated, you get a clear error message pointing to the offending field.
|
|
261
|
+
|
|
262
|
+
#### Profile-Level Fields
|
|
263
|
+
|
|
264
|
+
| Field | Rules |
|
|
265
|
+
|---|---|
|
|
266
|
+
| `name` | Must match `^[a-z0-9_]+$` — lowercase letters, digits, and underscores only. Used in OGC URIs. |
|
|
267
|
+
| `title` | Any non-empty string. |
|
|
268
|
+
| `version` | Any string. Defaults to `"1.0"`. |
|
|
269
|
+
| `collections` | At least one collection is required. No duplicate `id` values. |
|
|
270
|
+
|
|
271
|
+
#### Collection IDs
|
|
272
|
+
|
|
273
|
+
By default, collection IDs can be any string accepted by edr-pydantic. To enforce a naming convention across all collections, use `collection_id_pattern`:
|
|
274
|
+
|
|
275
|
+
```yaml
|
|
276
|
+
# Only allow lowercase snake_case collection IDs
|
|
277
|
+
collection_id_pattern: "^[a-z][a-z0-9_]*$"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The pattern is matched using Python's `re.fullmatch()`, so it must match the **entire** ID string.
|
|
281
|
+
|
|
282
|
+
#### CRS, TRS, and VRS Constraints
|
|
283
|
+
|
|
284
|
+
Each collection declares a CRS in `extent.spatial.crs`, and optionally a TRS in `extent.temporal.trs` and VRS in `extent.vertical.vrs`. The profile can constrain these values in two ways:
|
|
285
|
+
|
|
286
|
+
**Enumerated list** — only the exact values listed are accepted:
|
|
287
|
+
|
|
288
|
+
```yaml
|
|
289
|
+
extent_requirements:
|
|
290
|
+
minimum_bbox: [-180, -90, 180, 90]
|
|
291
|
+
allowed_crs:
|
|
292
|
+
- "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
|
|
293
|
+
- "http://www.opengis.net/def/crs/EPSG/0/4326"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Regex pattern** — any value matching the pattern is accepted:
|
|
297
|
+
|
|
298
|
+
```yaml
|
|
299
|
+
extent_requirements:
|
|
300
|
+
minimum_bbox: [-180, -90, 180, 90]
|
|
301
|
+
# Accept any OGC or EPSG CRS
|
|
302
|
+
crs_pattern: "^http://www\\.opengis\\.net/def/crs/(OGC|EPSG)/.*$"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
If both `allowed_crs` and `crs_pattern` are specified, a collection's CRS must satisfy **both**. At least one of `allowed_crs` or `crs_pattern` is required when `extent_requirements` is present.
|
|
306
|
+
|
|
307
|
+
The same enum/regex approach works for TRS (`allowed_trs` / `trs_pattern`) and VRS (`allowed_vrs` / `vrs_pattern`).
|
|
308
|
+
|
|
309
|
+
#### Parameter Name Constraints
|
|
310
|
+
|
|
311
|
+
By default, parameter names (the keys in `parameter_names`) can be any string. To enforce a naming convention, use `parameter_name_pattern`:
|
|
312
|
+
|
|
313
|
+
```yaml
|
|
314
|
+
# CF-style lowercase parameter names
|
|
315
|
+
parameter_name_pattern: "^[a-z][a-z0-9_]*$"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
```yaml
|
|
319
|
+
# Allow uppercase abbreviations like WMO codes
|
|
320
|
+
parameter_name_pattern: "^[A-Za-z][A-Za-z0-9_]*$"
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Every key in every collection's `parameter_names` must match this pattern. The pattern uses `re.fullmatch()`.
|
|
324
|
+
|
|
325
|
+
Additionally, per OGC API - EDR Part 3, every parameter must specify both `unit` and `observedProperty`. The tool enforces this automatically.
|
|
326
|
+
|
|
327
|
+
#### Requirement and Test IDs
|
|
328
|
+
|
|
329
|
+
| Field | Rules |
|
|
330
|
+
|---|---|
|
|
331
|
+
| Requirement `id` | Must match `^[a-z0-9][a-z0-9\-]*$` — lowercase, digits, hyphens. Cannot end with a hyphen. |
|
|
332
|
+
| AbstractTest `id` | Must exactly equal its `requirement_id`. |
|
|
333
|
+
| AbstractTest `requirement_id` | Must reference an existing requirement `id`. |
|
|
334
|
+
|
|
335
|
+
#### What Happens When Validation Fails
|
|
336
|
+
|
|
337
|
+
The tool prints a Pydantic validation error with the field path and a human-readable message. For example:
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
Value error, Collection 'my_data' CRS 'urn:ogc:def:crs:EPSG::4326'
|
|
341
|
+
does not match crs_pattern '^http://www\.opengis\.net/def/crs/(OGC|EPSG)/.*$'
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
Value error, Parameter name 'WIND_SPEED' in collection 'weather'
|
|
346
|
+
does not match parameter_name_pattern '^[a-z][a-z0-9_]*$'
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
Value error, Collection id 'My-Collection' does not match
|
|
351
|
+
collection_id_pattern '^[a-z][a-z0-9_]*$'
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### How Patterns Flow Into the Generated OpenAPI
|
|
355
|
+
|
|
356
|
+
When you specify `crs_pattern`, `allowed_crs`, or `parameter_name_pattern`, those constraints are embedded in the generated `openapi.yaml` so that runtime validation tools can enforce them:
|
|
357
|
+
|
|
358
|
+
- `crs_pattern` → `pattern` on the CRS string schema in collection responses
|
|
359
|
+
- `allowed_crs` → `enum` on the CRS string schema
|
|
360
|
+
- `trs_pattern` / `allowed_trs` → `pattern` / `enum` on the TRS field in extent.temporal
|
|
361
|
+
- `vrs_pattern` / `allowed_vrs` → `pattern` / `enum` on the VRS field in extent.vertical
|
|
362
|
+
- `parameter_name_pattern` → `propertyNames.pattern` on the `parameter_names` object schema
|
|
363
|
+
|
|
364
|
+
This means schemathesis, CITE tests, and client SDKs can validate server responses against these constraints without needing access to the original profile YAML.
|
|
365
|
+
|
|
366
|
+
### Quick Reference: Regex Examples
|
|
367
|
+
|
|
368
|
+
| Use Case | Pattern |
|
|
369
|
+
|---|---|
|
|
370
|
+
| Only OGC CRS84 | `^http://www\\.opengis\\.net/def/crs/OGC/1\\.3/CRS84$` |
|
|
371
|
+
| Any OGC or EPSG CRS | `^http://www\\.opengis\\.net/def/crs/(OGC\|EPSG)/.*$` |
|
|
372
|
+
| Any valid CRS URI | `^http://www\\.opengis\\.net/def/crs/.*$` |
|
|
373
|
+
| ISO-8601 TRS family | `^http://www\\.opengis\\.net/def/uom/ISO-8601/.*$` |
|
|
374
|
+
| Lowercase snake_case names | `^[a-z][a-z0-9_]*$` |
|
|
375
|
+
| CF standard name style | `^[a-z][a-z0-9_]*(_[a-z0-9]+)*$` |
|
|
376
|
+
| WMO-style alphanumeric | `^[A-Za-z][A-Za-z0-9_]*$` |
|
|
377
|
+
| Lowercase with hyphens | `^[a-z][a-z0-9\\-]*$` |
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
251
381
|
## Config Reference
|
|
252
382
|
|
|
253
383
|
### Top-level fields
|
|
@@ -268,7 +398,8 @@ The skipped tests are optional features not implemented by the server.
|
|
|
268
398
|
| `required_conformance_classes` | `list[string]` | no | Conformance classes that implementations must declare. Defaults to EDR Core |
|
|
269
399
|
| `extent_requirements` | `object` | no | Profile-level extent restrictions (see below) |
|
|
270
400
|
| `output_formats` | `list` | no | Profile-level output format definitions with schema references (see below) |
|
|
271
|
-
| `collection_id_pattern` | `string` | no | Regex pattern
|
|
401
|
+
| `collection_id_pattern` | `string` | no | Regex pattern that all collection IDs must match (validated at build time) |
|
|
402
|
+
| `parameter_name_pattern` | `string` | no | Regex pattern that all `parameter_names` keys must match (validated at build time) |
|
|
272
403
|
|
|
273
404
|
---
|
|
274
405
|
|
|
@@ -331,7 +462,7 @@ parameter_names:
|
|
|
331
462
|
|
|
332
463
|
### `extent_requirements`
|
|
333
464
|
|
|
334
|
-
Profile-level extent restrictions per OGC API - EDR Part 3 REQ_extent.
|
|
465
|
+
Profile-level extent restrictions per OGC API - EDR Part 3 REQ_extent. These constraints are **enforced at profile build time** — if any collection's CRS, TRS, or VRS value violates the rules here, the profile will be rejected with a clear error message. The constraints are also **embedded in the generated OpenAPI** so that downstream tools (schemathesis, CITE tests, client SDKs) can enforce them at runtime.
|
|
335
466
|
|
|
336
467
|
| Field | Type | Required | Description |
|
|
337
468
|
|---|---|---|---|
|
|
@@ -345,6 +476,8 @@ Profile-level extent restrictions per OGC API - EDR Part 3 REQ_extent.
|
|
|
345
476
|
|
|
346
477
|
**Note:** Either `allowed_crs` or `crs_pattern` must be specified.
|
|
347
478
|
|
|
479
|
+
**Enum approach** — lock down to specific values:
|
|
480
|
+
|
|
348
481
|
```yaml
|
|
349
482
|
extent_requirements:
|
|
350
483
|
minimum_bbox: [-180, -90, 180, 90]
|
|
@@ -355,6 +488,19 @@ extent_requirements:
|
|
|
355
488
|
- "http://www.opengis.net/def/uom/ISO-8601/0/Gregorian"
|
|
356
489
|
```
|
|
357
490
|
|
|
491
|
+
**Regex approach** — allow any CRS from a family:
|
|
492
|
+
|
|
493
|
+
```yaml
|
|
494
|
+
extent_requirements:
|
|
495
|
+
minimum_bbox: [-180, -90, 180, 90]
|
|
496
|
+
# Accept any OGC or EPSG CRS
|
|
497
|
+
crs_pattern: "^http://www\\.opengis\\.net/def/crs/(OGC|EPSG)/.*$"
|
|
498
|
+
# Accept any ISO-8601 TRS
|
|
499
|
+
trs_pattern: "^http://www\\.opengis\\.net/def/uom/ISO-8601/.*$"
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
Both approaches can coexist — if both `allowed_crs` and `crs_pattern` are specified, a collection's CRS must satisfy **both** constraints.
|
|
503
|
+
|
|
358
504
|
---
|
|
359
505
|
|
|
360
506
|
### `output_formats[]`
|
|
@@ -501,6 +647,7 @@ This tool implements the requirements of OGC API - EDR Part 3: Service Profiles
|
|
|
501
647
|
### Key Compliance Features
|
|
502
648
|
|
|
503
649
|
1. **Profile OpenAPI Document** (REQ_publishing)
|
|
650
|
+
- Generated OpenAPI version is **3.1.0** (required by OGC API - EDR Part 3)
|
|
504
651
|
- Generated OpenAPI has empty `servers` array (profile is implementation-independent)
|
|
505
652
|
- Landing page schema requires `profile` link relation
|
|
506
653
|
- Profile URI advertised in `x-ogc-profile` info field
|
|
@@ -516,12 +663,23 @@ This tool implements the requirements of OGC API - EDR Part 3: Service Profiles
|
|
|
516
663
|
4. **Extent Requirements** (REQ_extent)
|
|
517
664
|
- Profile-level `extent_requirements` specify minimum bounds
|
|
518
665
|
- CRS/TRS/VRS restrictions via enumerated lists or regex patterns
|
|
666
|
+
- **Enforced at build time**: collection CRS/TRS/VRS values are validated against `allowed_*` lists and `*_pattern` regexes
|
|
667
|
+
- **Propagated to OpenAPI**: constraints appear as `enum` or `pattern` in the generated collection response schemas
|
|
668
|
+
|
|
669
|
+
5. **Parameter Names** (REQ_parameter-names)
|
|
670
|
+
- Validates that all parameters specify `unit` and `observedProperty`
|
|
671
|
+
- Optional `parameter_name_pattern` enforces naming conventions across all collections
|
|
672
|
+
- Pattern constraints are embedded in the generated OpenAPI as `propertyNames.pattern`
|
|
673
|
+
|
|
674
|
+
6. **Collection ID Pattern**
|
|
675
|
+
- Optional `collection_id_pattern` enforces naming conventions for collection IDs
|
|
676
|
+
- Validated at build time via `re.fullmatch()`
|
|
519
677
|
|
|
520
|
-
|
|
678
|
+
7. **Output Formats** (REQ_output-format)
|
|
521
679
|
- Profile-level `output_formats` with schema references
|
|
522
680
|
- Links to JSON Schema, XML Schema, or format specifications
|
|
523
681
|
|
|
524
|
-
|
|
682
|
+
8. **Pub/Sub** (REQ_pubsub)
|
|
525
683
|
- Automatically adds Part 2 conformance requirement when `pubsub` is present
|
|
526
684
|
- AsyncAPI document specifies channels and payloads
|
|
527
685
|
|
|
@@ -557,8 +715,9 @@ generate(profile, Path("./output"))
|
|
|
557
715
|
│ ├── cite.py # OGC CITE test suite orchestration
|
|
558
716
|
│ └── cli.py # CLI entry point
|
|
559
717
|
├── examples/
|
|
560
|
-
│ ├──
|
|
561
|
-
│
|
|
718
|
+
│ ├── minimal_profile.yaml # Minimal working profile
|
|
719
|
+
│ ├── insitu_observations_profile.yaml # Full in-situ profile: parameters, CRS, temporal, custom dims
|
|
720
|
+
│ └── nwsviz_profile.yaml # Full NWSViz profile: 13 collections, 3 processes, PDF metadata
|
|
562
721
|
├── profile.schema.json # Machine-readable JSON Schema for profile configs
|
|
563
722
|
└── pyproject.toml
|
|
564
723
|
```
|
|
@@ -574,7 +733,7 @@ generate(profile, Path("./output"))
|
|
|
574
733
|
|
|
575
734
|
## License
|
|
576
735
|
|
|
577
|
-
|
|
736
|
+
Apache — See [LICENSE](LICENSE) for details.
|
|
578
737
|
|
|
579
738
|
## Contact
|
|
580
739
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oapi-profile-builder"
|
|
7
|
-
version = "2.0
|
|
7
|
+
version = "2.1.0"
|
|
8
8
|
description = "Authoritative tooling for creating OGC API Service Profiles (EDR, Features)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|