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.
@@ -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(f"# Generated: {datetime.utcnow().isoformat(timespec='seconds')}Z")
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(f"# Generated: {datetime.utcnow().isoformat(timespec='seconds')}Z")
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-01-13T11:23:16Z
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
- :google_ListItemShape
19
- a sh:NodeShape ;
20
- sh:targetClass schema:ListItem ;
21
- sh:property [
22
- sh:path schema:item ;
23
- sh:minCount 1 ;
24
- ] ;
25
- sh:property [
26
- sh:path schema:name ;
27
- sh:minCount 1 ;
28
- ] ;
29
- sh:property [
30
- sh:path schema:position ;
31
- sh:minCount 1 ;
32
- ] ;
33
- sh:property [
34
- sh:path schema:url ;
35
- sh:minCount 1 ;
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.10.3
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=vdL1tT-TMK0Rdx88DuLVALrz1TU9wLnYXNxx4tdS518,14659
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=5_8yUGidwsGqg7gjbLRCArfmZf6f78RRiGRJhuDEeN0,858
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.10.3.dist-info/METADATA,sha256=_MeJKaaZKTzlseM2TswdotwXq1VIMr0ZXypAYIGRHzI,5184
166
- wordlift_sdk-2.10.3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
167
- wordlift_sdk-2.10.3.dist-info/RECORD,,
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,,