wordlift-sdk 2.10.3__py3-none-any.whl → 2.11.0__py3-none-any.whl
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.
- wordlift_sdk/validation/generator.py +49 -3
- wordlift_sdk/validation/shacls/google-carousel.ttl +25 -22
- {wordlift_sdk-2.10.3.dist-info → wordlift_sdk-2.11.0.dist-info}/METADATA +5 -2
- {wordlift_sdk-2.10.3.dist-info → wordlift_sdk-2.11.0.dist-info}/RECORD +5 -5
- {wordlift_sdk-2.10.3.dist-info → wordlift_sdk-2.11.0.dist-info}/WHEEL +0 -0
|
@@ -6,7 +6,7 @@ import argparse
|
|
|
6
6
|
import html as html_lib
|
|
7
7
|
import re
|
|
8
8
|
from dataclasses import dataclass
|
|
9
|
-
from datetime import datetime
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Iterable
|
|
12
12
|
|
|
@@ -173,6 +173,10 @@ def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) ->
|
|
|
173
173
|
if output_path.exists() and not overwrite:
|
|
174
174
|
return False
|
|
175
175
|
|
|
176
|
+
scoped_list_item = None
|
|
177
|
+
if "ItemList" in feature.types and "ListItem" in feature.types:
|
|
178
|
+
scoped_list_item = feature.types["ListItem"]
|
|
179
|
+
|
|
176
180
|
lines: list[str] = []
|
|
177
181
|
slug = output_path.stem
|
|
178
182
|
prefix_base = f"https://wordlift.io/shacl/google/{slug}/"
|
|
@@ -181,13 +185,17 @@ def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) ->
|
|
|
181
185
|
lines.append("@prefix schema: <http://schema.org/> .")
|
|
182
186
|
lines.append("")
|
|
183
187
|
lines.append(f"# Source: {feature.url}")
|
|
184
|
-
lines.append(
|
|
188
|
+
lines.append(
|
|
189
|
+
f"# Generated: {datetime.now(timezone.utc).isoformat(timespec='seconds')}Z"
|
|
190
|
+
)
|
|
185
191
|
lines.append(
|
|
186
192
|
"# Notes: required properties => errors; recommended properties => warnings."
|
|
187
193
|
)
|
|
188
194
|
lines.append("")
|
|
189
195
|
|
|
190
196
|
for type_name in sorted(feature.types.keys()):
|
|
197
|
+
if scoped_list_item and type_name == "ListItem":
|
|
198
|
+
continue
|
|
191
199
|
bucket = feature.types[type_name]
|
|
192
200
|
shape_name = f":google_{type_name}Shape"
|
|
193
201
|
lines.append(shape_name)
|
|
@@ -195,6 +203,36 @@ def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) ->
|
|
|
195
203
|
lines.append(f" sh:targetClass schema:{type_name} ;")
|
|
196
204
|
|
|
197
205
|
for prop in sorted(bucket["required"]):
|
|
206
|
+
if (
|
|
207
|
+
scoped_list_item
|
|
208
|
+
and type_name == "ItemList"
|
|
209
|
+
and prop == "itemListElement"
|
|
210
|
+
):
|
|
211
|
+
lines.append(" sh:property [")
|
|
212
|
+
lines.append(" sh:path schema:itemListElement ;")
|
|
213
|
+
lines.append(" sh:minCount 1 ;")
|
|
214
|
+
lines.append(" sh:node [")
|
|
215
|
+
lines.append(" a sh:NodeShape ;")
|
|
216
|
+
lines.append(" sh:class schema:ListItem ;")
|
|
217
|
+
for item_prop in sorted(scoped_list_item["required"]):
|
|
218
|
+
item_path = _prop_path(item_prop)
|
|
219
|
+
lines.append(" sh:property [")
|
|
220
|
+
lines.append(f" sh:path {item_path} ;")
|
|
221
|
+
lines.append(" sh:minCount 1 ;")
|
|
222
|
+
lines.append(" ] ;")
|
|
223
|
+
for item_prop in sorted(scoped_list_item["recommended"]):
|
|
224
|
+
item_path = _prop_path(item_prop)
|
|
225
|
+
lines.append(" sh:property [")
|
|
226
|
+
lines.append(f" sh:path {item_path} ;")
|
|
227
|
+
lines.append(" sh:minCount 1 ;")
|
|
228
|
+
lines.append(" sh:severity sh:Warning ;")
|
|
229
|
+
lines.append(
|
|
230
|
+
f' sh:message "Recommended by Google: {item_prop}." ;'
|
|
231
|
+
)
|
|
232
|
+
lines.append(" ] ;")
|
|
233
|
+
lines.append(" ] ;")
|
|
234
|
+
lines.append(" ] ;")
|
|
235
|
+
continue
|
|
198
236
|
path = _prop_path(prop)
|
|
199
237
|
lines.append(" sh:property [")
|
|
200
238
|
lines.append(f" sh:path {path} ;")
|
|
@@ -202,6 +240,12 @@ def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) ->
|
|
|
202
240
|
lines.append(" ] ;")
|
|
203
241
|
|
|
204
242
|
for prop in sorted(bucket["recommended"]):
|
|
243
|
+
if (
|
|
244
|
+
scoped_list_item
|
|
245
|
+
and type_name == "ItemList"
|
|
246
|
+
and prop == "itemListElement"
|
|
247
|
+
):
|
|
248
|
+
continue
|
|
205
249
|
path = _prop_path(prop)
|
|
206
250
|
lines.append(" sh:property [")
|
|
207
251
|
lines.append(f" sh:path {path} ;")
|
|
@@ -381,7 +425,9 @@ def generate_schema_shacls(output_file: Path, overwrite: bool) -> int:
|
|
|
381
425
|
lines.append(f"@prefix schema: <{SCHEMA_DATA}> .")
|
|
382
426
|
lines.append("")
|
|
383
427
|
lines.append(f"# Source: {SCHEMA_JSONLD_URL}")
|
|
384
|
-
lines.append(
|
|
428
|
+
lines.append(
|
|
429
|
+
f"# Generated: {datetime.now(timezone.utc).isoformat(timespec='seconds')}Z"
|
|
430
|
+
)
|
|
385
431
|
lines.append(
|
|
386
432
|
"# Notes: schema.org grammar checks only; all constraints are warnings."
|
|
387
433
|
)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
@prefix schema: <http://schema.org/> .
|
|
4
4
|
|
|
5
5
|
# Source: https://developers.google.com/search/docs/appearance/structured-data/carousel
|
|
6
|
-
# Generated: 2026-
|
|
6
|
+
# Generated: 2026-02-04T18:12:24+00:00Z
|
|
7
7
|
# Notes: required properties => errors; recommended properties => warnings.
|
|
8
8
|
|
|
9
9
|
:google_ItemListShape
|
|
@@ -12,26 +12,29 @@
|
|
|
12
12
|
sh:property [
|
|
13
13
|
sh:path schema:itemListElement ;
|
|
14
14
|
sh:minCount 1 ;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
15
|
+
sh:node [
|
|
16
|
+
a sh:NodeShape ;
|
|
17
|
+
sh:class schema:ListItem ;
|
|
18
|
+
sh:property [
|
|
19
|
+
sh:path schema:item ;
|
|
20
|
+
sh:minCount 1 ;
|
|
21
|
+
] ;
|
|
22
|
+
sh:property [
|
|
23
|
+
sh:path ( schema:item schema:name ) ;
|
|
24
|
+
sh:minCount 1 ;
|
|
25
|
+
] ;
|
|
26
|
+
sh:property [
|
|
27
|
+
sh:path ( schema:item schema:url ) ;
|
|
28
|
+
sh:minCount 1 ;
|
|
29
|
+
] ;
|
|
30
|
+
sh:property [
|
|
31
|
+
sh:path schema:position ;
|
|
32
|
+
sh:minCount 1 ;
|
|
33
|
+
] ;
|
|
34
|
+
sh:property [
|
|
35
|
+
sh:path schema:url ;
|
|
36
|
+
sh:minCount 1 ;
|
|
37
|
+
] ;
|
|
38
|
+
] ;
|
|
36
39
|
] ;
|
|
37
40
|
.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wordlift-sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.0
|
|
4
4
|
Summary:
|
|
5
5
|
Author: David Riccitelli
|
|
6
6
|
Author-email: david@wordlift.io
|
|
@@ -118,6 +118,10 @@ Override the web page import callback by placing `web_page_import_protocol.py` w
|
|
|
118
118
|
|
|
119
119
|
Add `.ttl.liquid` files under `data/templates`. Templates render with `account` fields available (e.g., `{{ account.dataset_uri }}`) and are uploaded before URL handling begins.
|
|
120
120
|
|
|
121
|
+
## Validation
|
|
122
|
+
|
|
123
|
+
SHACL validation utilities and generated Google Search Gallery shapes are included. Carousel `ListItem` requirements are scoped under `ItemList` when both types are present to avoid enforcing carousel constraints on non-carousel lists (for example, `BreadcrumbList`).
|
|
124
|
+
|
|
121
125
|
## Testing
|
|
122
126
|
|
|
123
127
|
```bash
|
|
@@ -129,4 +133,3 @@ poetry run pytest
|
|
|
129
133
|
|
|
130
134
|
- [Google Sheets Lookup](docs/google_sheets_lookup.md): Utility for O(1) lookups from Google Sheets.
|
|
131
135
|
|
|
132
|
-
|
|
@@ -103,13 +103,13 @@ wordlift_sdk/utils/get_me.py,sha256=-mr0DscVWEDFvgBYtmgND3_gIuh2q7kfD-OiqrYwLJU,
|
|
|
103
103
|
wordlift_sdk/utils/html_converter.py,sha256=MGdXQg2EAhI2K7CWtbIzZip08clVPUgL84Xt_xxa-h4,1945
|
|
104
104
|
wordlift_sdk/utils/import_url.py,sha256=KiUFkU4mRfd7YWFlLoz5bB13AgPURV8Km8H05LxevCI,1299
|
|
105
105
|
wordlift_sdk/validation/__init__.py,sha256=cR_8BggTFb6SYCFYGMESY12gYo0i8D6E8gMZcGwaPkw,203
|
|
106
|
-
wordlift_sdk/validation/generator.py,sha256=
|
|
106
|
+
wordlift_sdk/validation/generator.py,sha256=0pylpxk8vOoN7dq2gVlGBJwz5uqYxPi78AxGVr0GJEE,16638
|
|
107
107
|
wordlift_sdk/validation/shacl.py,sha256=tWBde7KUMhW2ectmAP1cEBcsIBGQ3Z1sQrANESDU__M,6299
|
|
108
108
|
wordlift_sdk/validation/shacls/__init__.py,sha256=5YWoHfTB4SKFDKz3KXqFnDrxqDy-YACu0zIn_GkT6Mk,29
|
|
109
109
|
wordlift_sdk/validation/shacls/google-article.ttl,sha256=FpAu-0CZsmDb8hswN45YU6l0QPng6hqU-JX7VSDiUyU,3774
|
|
110
110
|
wordlift_sdk/validation/shacls/google-book.ttl,sha256=Tdfr9TNWTv_ttH2wFYHt20K4KaIaCJpcj_RXAWy2BYI,13517
|
|
111
111
|
wordlift_sdk/validation/shacls/google-breadcrumb.ttl,sha256=rCeUoTQ3OwtIMjW94oEno33xhHOsKv5tGc8Sr1zG5Og,807
|
|
112
|
-
wordlift_sdk/validation/shacls/google-carousel.ttl,sha256=
|
|
112
|
+
wordlift_sdk/validation/shacls/google-carousel.ttl,sha256=_rIgw4W0DU6O8nf_wi916APFKQrKoo_itPyHdF7XUMU,1042
|
|
113
113
|
wordlift_sdk/validation/shacls/google-carousels-beta.ttl,sha256=TKevYHEaK1s0bZ1hr03TbcDpfD1nJcQpWFOQtEa5tro,7189
|
|
114
114
|
wordlift_sdk/validation/shacls/google-course.ttl,sha256=J3SEn5nVaeNIqTf3cp8WZYRSMR5Q6Scjds4a7mZsgqw,1010
|
|
115
115
|
wordlift_sdk/validation/shacls/google-dataset.ttl,sha256=-hdkj1umQNJduaRvSKhl9LZ5A6j7i0sJqhH7ZEbUX3U,3758
|
|
@@ -162,6 +162,6 @@ wordlift_sdk/workflow/url_handler/default_url_handler.py,sha256=irMoJftx9Gyq-8HQ
|
|
|
162
162
|
wordlift_sdk/workflow/url_handler/search_console_url_handler.py,sha256=uOwD4t009-cA9JI7ZtbYhCGRwjhLzDpBNTWHERPnNqI,2698
|
|
163
163
|
wordlift_sdk/workflow/url_handler/url_handler.py,sha256=meyOpWVhLk2NcbtUOO_V0z6_T9q-D3pD7kWQCRioYh0,129
|
|
164
164
|
wordlift_sdk/workflow/url_handler/web_page_import_url_handler.py,sha256=xQiy-fgFj_dWKFFBNWeodAGhIMJQereSPdgnjK-Crmo,3529
|
|
165
|
-
wordlift_sdk-2.
|
|
166
|
-
wordlift_sdk-2.
|
|
167
|
-
wordlift_sdk-2.
|
|
165
|
+
wordlift_sdk-2.11.0.dist-info/METADATA,sha256=1wxWzz4h7tW1xyuCO720ihilDgEll-Kmv-RZN-Fdt9o,5467
|
|
166
|
+
wordlift_sdk-2.11.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
167
|
+
wordlift_sdk-2.11.0.dist-info/RECORD,,
|
|
File without changes
|