wordlift-sdk 2.11.0__py3-none-any.whl → 2.13.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.
@@ -169,13 +169,135 @@ def _prop_path(prop: str) -> str:
169
169
  return f"( {seq} )"
170
170
 
171
171
 
172
+ _SCOPED_CHILD_RULES: dict[str, dict[str, list[str]]] = {
173
+ "ItemList": {"itemListElement": ["ListItem"]},
174
+ "BreadcrumbList": {"itemListElement": ["ListItem"]},
175
+ "QAPage": {"mainEntity": ["Question"]},
176
+ "FAQPage": {"mainEntity": ["Question"]},
177
+ "Quiz": {"hasPart": ["Question"]},
178
+ "ProfilePage": {"mainEntity": ["Person", "Organization"]},
179
+ "Question": {
180
+ "acceptedAnswer": ["Answer"],
181
+ "suggestedAnswer": ["Answer"],
182
+ "comment": ["Comment"],
183
+ },
184
+ "Answer": {"comment": ["Comment"]},
185
+ "Product": {"offers": ["Offer"]},
186
+ "Recipe": {"recipeInstructions": ["HowToStep"], "step": ["HowToStep"]},
187
+ "Course": {"provider": ["Organization"], "hasPart": ["Course", "CreativeWork"]},
188
+ }
189
+
190
+
191
+ def _emit_property(
192
+ lines: list[str],
193
+ prop: str,
194
+ required: bool,
195
+ child_types: list[str] | None,
196
+ indent: int,
197
+ buckets: dict[str, dict[str, set[str]]],
198
+ visited: set[str],
199
+ ) -> None:
200
+ sp = " " * indent
201
+ path = _prop_path(prop)
202
+ lines.append(f"{sp}sh:property [")
203
+ lines.append(f"{sp} sh:path {path} ;")
204
+ lines.append(f"{sp} sh:minCount 1 ;")
205
+ if not required:
206
+ lines.append(f"{sp} sh:severity sh:Warning ;")
207
+ lines.append(f'{sp} sh:message "Recommended by Google: {prop}." ;')
208
+ if child_types:
209
+ valid_children = [
210
+ child_type
211
+ for child_type in child_types
212
+ if child_type not in visited and child_type in buckets
213
+ ]
214
+ if len(valid_children) == 1:
215
+ child_type = valid_children[0]
216
+ child_bucket = buckets.get(child_type)
217
+ node_indent = indent + 2
218
+ node_sp = " " * node_indent
219
+ lines.append(f"{node_sp}sh:node [")
220
+ _emit_node(
221
+ lines,
222
+ child_type,
223
+ child_bucket,
224
+ node_indent + 2,
225
+ buckets,
226
+ visited | {child_type},
227
+ )
228
+ lines.append(f"{node_sp}] ;")
229
+ elif len(valid_children) > 1:
230
+ or_indent = indent + 2
231
+ or_sp = " " * or_indent
232
+ lines.append(f"{or_sp}sh:or (")
233
+ for child_type in valid_children:
234
+ child_bucket = buckets.get(child_type)
235
+ lines.append(f"{or_sp} [")
236
+ _emit_node(
237
+ lines,
238
+ child_type,
239
+ child_bucket,
240
+ or_indent + 4,
241
+ buckets,
242
+ visited | {child_type},
243
+ )
244
+ lines.append(f"{or_sp} ]")
245
+ lines.append(f"{or_sp}) ;")
246
+ lines.append(f"{sp}] ;")
247
+
248
+
249
+ def _emit_node(
250
+ lines: list[str],
251
+ type_name: str,
252
+ bucket: dict[str, set[str]],
253
+ indent: int,
254
+ buckets: dict[str, dict[str, set[str]]],
255
+ visited: set[str],
256
+ ) -> None:
257
+ sp = " " * indent
258
+ lines.append(f"{sp}a sh:NodeShape ;")
259
+ lines.append(f"{sp}sh:class schema:{type_name} ;")
260
+
261
+ child_rules = _SCOPED_CHILD_RULES.get(type_name, {})
262
+ for prop in sorted(bucket["required"]):
263
+ child_types = child_rules.get(prop)
264
+ _emit_property(
265
+ lines,
266
+ prop,
267
+ required=True,
268
+ child_types=child_types,
269
+ indent=indent,
270
+ buckets=buckets,
271
+ visited=visited,
272
+ )
273
+
274
+ for prop in sorted(bucket["recommended"]):
275
+ child_types = child_rules.get(prop)
276
+ _emit_property(
277
+ lines,
278
+ prop,
279
+ required=False,
280
+ child_types=child_types,
281
+ indent=indent,
282
+ buckets=buckets,
283
+ visited=visited,
284
+ )
285
+
286
+
172
287
  def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) -> bool:
173
288
  if output_path.exists() and not overwrite:
174
289
  return False
175
290
 
176
- scoped_list_item = None
177
- if "ItemList" in feature.types and "ListItem" in feature.types:
178
- scoped_list_item = feature.types["ListItem"]
291
+ scoped_types: set[str] = set()
292
+ for parent_type, rules in _SCOPED_CHILD_RULES.items():
293
+ if parent_type not in feature.types:
294
+ continue
295
+ for child_types in rules.values():
296
+ for child_type in child_types:
297
+ if child_type == parent_type:
298
+ continue
299
+ if child_type in feature.types:
300
+ scoped_types.add(child_type)
179
301
 
180
302
  lines: list[str] = []
181
303
  slug = output_path.stem
@@ -186,7 +308,8 @@ def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) ->
186
308
  lines.append("")
187
309
  lines.append(f"# Source: {feature.url}")
188
310
  lines.append(
189
- f"# Generated: {datetime.now(timezone.utc).isoformat(timespec='seconds')}Z"
311
+ "# Generated: "
312
+ f"{datetime.now(timezone.utc).isoformat(timespec='seconds').replace('+00:00', 'Z')}"
190
313
  )
191
314
  lines.append(
192
315
  "# Notes: required properties => errors; recommended properties => warnings."
@@ -194,7 +317,7 @@ def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) ->
194
317
  lines.append("")
195
318
 
196
319
  for type_name in sorted(feature.types.keys()):
197
- if scoped_list_item and type_name == "ListItem":
320
+ if type_name in scoped_types:
198
321
  continue
199
322
  bucket = feature.types[type_name]
200
323
  shape_name = f":google_{type_name}Shape"
@@ -203,56 +326,28 @@ def _write_feature(feature: FeatureData, output_path: Path, overwrite: bool) ->
203
326
  lines.append(f" sh:targetClass schema:{type_name} ;")
204
327
 
205
328
  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
236
- path = _prop_path(prop)
237
- lines.append(" sh:property [")
238
- lines.append(f" sh:path {path} ;")
239
- lines.append(" sh:minCount 1 ;")
240
- lines.append(" ] ;")
329
+ child_types = _SCOPED_CHILD_RULES.get(type_name, {}).get(prop)
330
+ _emit_property(
331
+ lines,
332
+ prop,
333
+ required=True,
334
+ child_types=child_types,
335
+ indent=2,
336
+ buckets=feature.types,
337
+ visited={type_name},
338
+ )
241
339
 
242
340
  for prop in sorted(bucket["recommended"]):
243
- if (
244
- scoped_list_item
245
- and type_name == "ItemList"
246
- and prop == "itemListElement"
247
- ):
248
- continue
249
- path = _prop_path(prop)
250
- lines.append(" sh:property [")
251
- lines.append(f" sh:path {path} ;")
252
- lines.append(" sh:minCount 1 ;")
253
- lines.append(" sh:severity sh:Warning ;")
254
- lines.append(f' sh:message "Recommended by Google: {prop}." ;')
255
- lines.append(" ] ;")
341
+ child_types = _SCOPED_CHILD_RULES.get(type_name, {}).get(prop)
342
+ _emit_property(
343
+ lines,
344
+ prop,
345
+ required=False,
346
+ child_types=child_types,
347
+ indent=2,
348
+ buckets=feature.types,
349
+ visited={type_name},
350
+ )
256
351
 
257
352
  lines.append(".")
258
353
  lines.append("")
@@ -426,7 +521,8 @@ def generate_schema_shacls(output_file: Path, overwrite: bool) -> int:
426
521
  lines.append("")
427
522
  lines.append(f"# Source: {SCHEMA_JSONLD_URL}")
428
523
  lines.append(
429
- f"# Generated: {datetime.now(timezone.utc).isoformat(timespec='seconds')}Z"
524
+ "# Generated: "
525
+ f"{datetime.now(timezone.utc).isoformat(timespec='seconds').replace('+00:00', 'Z')}"
430
526
  )
431
527
  lines.append(
432
528
  "# Notes: schema.org grammar checks only; all constraints are warnings."
@@ -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/breadcrumb
6
- # Generated: 2026-01-13T11:23:15Z
6
+ # Generated: 2026-02-04T20:00:50Z
7
7
  # Notes: required properties => errors; recommended properties => warnings.
8
8
 
9
9
  :google_BreadcrumbListShape
@@ -12,22 +12,21 @@
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 ;
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:name ;
24
+ sh:minCount 1 ;
25
+ ] ;
26
+ sh:property [
27
+ sh:path schema:position ;
28
+ sh:minCount 1 ;
29
+ ] ;
30
+ ] ;
32
31
  ] ;
33
32
  .
@@ -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-02-04T18:12:24+00:00Z
6
+ # Generated: 2026-02-04T20:00:51Z
7
7
  # Notes: required properties => errors; recommended properties => warnings.
8
8
 
9
9
  :google_ItemListShape
@@ -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/course
6
- # Generated: 2026-01-13T11:23:18Z
6
+ # Generated: 2026-02-04T20:09:17Z
7
7
  # Notes: required properties => errors; recommended properties => warnings.
8
8
 
9
9
  :google_CourseShape
@@ -29,15 +29,15 @@
29
29
  a sh:NodeShape ;
30
30
  sh:targetClass schema:ItemList ;
31
31
  sh:property [
32
- sh:path schema:itemListElement ;
32
+ sh:path ( schema:ListItem schema:position ) ;
33
33
  sh:minCount 1 ;
34
34
  ] ;
35
35
  sh:property [
36
- sh:path schema:position ;
36
+ sh:path ( schema:ListItem schema:url ) ;
37
37
  sh:minCount 1 ;
38
38
  ] ;
39
39
  sh:property [
40
- sh:path schema:url ;
40
+ sh:path schema:itemListElement ;
41
41
  sh:minCount 1 ;
42
42
  ] ;
43
43
  .
@@ -3,26 +3,9 @@
3
3
  @prefix schema: <http://schema.org/> .
4
4
 
5
5
  # Source: https://developers.google.com/search/docs/appearance/structured-data/education-qa
6
- # Generated: 2026-01-13T11:23:22Z
6
+ # Generated: 2026-02-04T20:00:52Z
7
7
  # Notes: required properties => errors; recommended properties => warnings.
8
8
 
9
- :google_QuestionShape
10
- a sh:NodeShape ;
11
- sh:targetClass schema:Question ;
12
- sh:property [
13
- sh:path schema:acceptedAnswer ;
14
- sh:minCount 1 ;
15
- ] ;
16
- sh:property [
17
- sh:path schema:eduQuestionType ;
18
- sh:minCount 1 ;
19
- ] ;
20
- sh:property [
21
- sh:path schema:text ;
22
- sh:minCount 1 ;
23
- ] ;
24
- .
25
-
26
9
  :google_QuizShape
27
10
  a sh:NodeShape ;
28
11
  sh:targetClass schema:Quiz ;
@@ -37,6 +20,22 @@
37
20
  sh:property [
38
21
  sh:path schema:hasPart ;
39
22
  sh:minCount 1 ;
23
+ sh:node [
24
+ a sh:NodeShape ;
25
+ sh:class schema:Question ;
26
+ sh:property [
27
+ sh:path schema:acceptedAnswer ;
28
+ sh:minCount 1 ;
29
+ ] ;
30
+ sh:property [
31
+ sh:path schema:eduQuestionType ;
32
+ sh:minCount 1 ;
33
+ ] ;
34
+ sh:property [
35
+ sh:path schema:text ;
36
+ sh:minCount 1 ;
37
+ ] ;
38
+ ] ;
40
39
  ] ;
41
40
  sh:property [
42
41
  sh:path schema:text ;
@@ -49,10 +48,10 @@
49
48
  sh:message "Recommended by Google: about." ;
50
49
  ] ;
51
50
  sh:property [
52
- sh:path schema:alignmentType ;
51
+ sh:path ( schema:about schema:name ) ;
53
52
  sh:minCount 1 ;
54
53
  sh:severity sh:Warning ;
55
- sh:message "Recommended by Google: alignmentType." ;
54
+ sh:message "Recommended by Google: about.name." ;
56
55
  ] ;
57
56
  sh:property [
58
57
  sh:path schema:educationalAlignment ;
@@ -61,15 +60,15 @@
61
60
  sh:message "Recommended by Google: educationalAlignment." ;
62
61
  ] ;
63
62
  sh:property [
64
- sh:path schema:name ;
63
+ sh:path ( schema:educationalAlignment schema:alignmentType ) ;
65
64
  sh:minCount 1 ;
66
65
  sh:severity sh:Warning ;
67
- sh:message "Recommended by Google: name." ;
66
+ sh:message "Recommended by Google: educationalAlignment.alignmentType." ;
68
67
  ] ;
69
68
  sh:property [
70
- sh:path schema:targetName ;
69
+ sh:path ( schema:educationalAlignment schema:targetName ) ;
71
70
  sh:minCount 1 ;
72
71
  sh:severity sh:Warning ;
73
- sh:message "Recommended by Google: targetName." ;
72
+ sh:message "Recommended by Google: educationalAlignment.targetName." ;
74
73
  ] ;
75
74
  .
@@ -3,36 +3,34 @@
3
3
  @prefix schema: <http://schema.org/> .
4
4
 
5
5
  # Source: https://developers.google.com/search/docs/appearance/structured-data/faqpage
6
- # Generated: 2026-01-13T11:23:28Z
6
+ # Generated: 2026-02-04T20:00:53Z
7
7
  # Notes: required properties => errors; recommended properties => warnings.
8
8
 
9
- :google_AnswerShape
10
- a sh:NodeShape ;
11
- sh:targetClass schema:Answer ;
12
- sh:property [
13
- sh:path schema:text ;
14
- sh:minCount 1 ;
15
- ] ;
16
- .
17
-
18
9
  :google_FAQPageShape
19
10
  a sh:NodeShape ;
20
11
  sh:targetClass schema:FAQPage ;
21
12
  sh:property [
22
13
  sh:path schema:mainEntity ;
23
14
  sh:minCount 1 ;
24
- ] ;
25
- .
26
-
27
- :google_QuestionShape
28
- a sh:NodeShape ;
29
- sh:targetClass schema:Question ;
30
- sh:property [
31
- sh:path schema:acceptedAnswer ;
32
- sh:minCount 1 ;
33
- ] ;
34
- sh:property [
35
- sh:path schema:name ;
36
- sh:minCount 1 ;
15
+ sh:node [
16
+ a sh:NodeShape ;
17
+ sh:class schema:Question ;
18
+ sh:property [
19
+ sh:path schema:acceptedAnswer ;
20
+ sh:minCount 1 ;
21
+ sh:node [
22
+ a sh:NodeShape ;
23
+ sh:class schema:Answer ;
24
+ sh:property [
25
+ sh:path schema:text ;
26
+ sh:minCount 1 ;
27
+ ] ;
28
+ ] ;
29
+ ] ;
30
+ sh:property [
31
+ sh:path schema:name ;
32
+ sh:minCount 1 ;
33
+ ] ;
34
+ ] ;
37
35
  ] ;
38
36
  .
@@ -3,18 +3,18 @@
3
3
  @prefix schema: <http://schema.org/> .
4
4
 
5
5
  # Source: https://developers.google.com/search/docs/appearance/structured-data/merchant-listing
6
- # Generated: 2026-01-13T11:23:41Z
6
+ # Generated: 2026-02-04T20:09:18Z
7
7
  # Notes: required properties => errors; recommended properties => warnings.
8
8
 
9
9
  :google_3DModelShape
10
10
  a sh:NodeShape ;
11
11
  sh:targetClass schema:3DModel ;
12
12
  sh:property [
13
- sh:path schema:contentUrl ;
13
+ sh:path schema:encoding ;
14
14
  sh:minCount 1 ;
15
15
  ] ;
16
16
  sh:property [
17
- sh:path schema:encoding ;
17
+ sh:path ( schema:encoding schema:contentUrl ) ;
18
18
  sh:minCount 1 ;
19
19
  ] ;
20
20
  .
@@ -40,53 +40,6 @@
40
40
  ] ;
41
41
  .
42
42
 
43
- :google_OfferShape
44
- a sh:NodeShape ;
45
- sh:targetClass schema:Offer ;
46
- sh:property [
47
- sh:path schema:price ;
48
- sh:minCount 1 ;
49
- ] ;
50
- sh:property [
51
- sh:path schema:priceCurrency ;
52
- sh:minCount 1 ;
53
- ] ;
54
- sh:property [
55
- sh:path schema:priceSpecification ;
56
- sh:minCount 1 ;
57
- ] ;
58
- sh:property [
59
- sh:path schema:availability ;
60
- sh:minCount 1 ;
61
- sh:severity sh:Warning ;
62
- sh:message "Recommended by Google: availability." ;
63
- ] ;
64
- sh:property [
65
- sh:path schema:hasMerchantReturnPolicy ;
66
- sh:minCount 1 ;
67
- sh:severity sh:Warning ;
68
- sh:message "Recommended by Google: hasMerchantReturnPolicy." ;
69
- ] ;
70
- sh:property [
71
- sh:path schema:itemCondition ;
72
- sh:minCount 1 ;
73
- sh:severity sh:Warning ;
74
- sh:message "Recommended by Google: itemCondition." ;
75
- ] ;
76
- sh:property [
77
- sh:path schema:shippingDetails ;
78
- sh:minCount 1 ;
79
- sh:severity sh:Warning ;
80
- sh:message "Recommended by Google: shippingDetails." ;
81
- ] ;
82
- sh:property [
83
- sh:path schema:url ;
84
- sh:minCount 1 ;
85
- sh:severity sh:Warning ;
86
- sh:message "Recommended by Google: url." ;
87
- ] ;
88
- .
89
-
90
43
  :google_OfferShippingDetailsShape
91
44
  a sh:NodeShape ;
92
45
  sh:targetClass schema:OfferShippingDetails ;
@@ -94,10 +47,6 @@
94
47
  sh:path schema:addressCountry ;
95
48
  sh:minCount 1 ;
96
49
  ] ;
97
- sh:property [
98
- sh:path schema:currency ;
99
- sh:minCount 1 ;
100
- ] ;
101
50
  sh:property [
102
51
  sh:path schema:deliveryTime ;
103
52
  sh:minCount 1 ;
@@ -111,7 +60,11 @@
111
60
  sh:minCount 1 ;
112
61
  ] ;
113
62
  sh:property [
114
- sh:path schema:value ;
63
+ sh:path ( schema:shippingRate schema:currency ) ;
64
+ sh:minCount 1 ;
65
+ ] ;
66
+ sh:property [
67
+ sh:path ( schema:shippingRate schema:value ) ;
115
68
  sh:minCount 1 ;
116
69
  ] ;
117
70
  sh:property [
@@ -165,6 +118,52 @@
165
118
  sh:property [
166
119
  sh:path schema:offers ;
167
120
  sh:minCount 1 ;
121
+ sh:node [
122
+ a sh:NodeShape ;
123
+ sh:class schema:Offer ;
124
+ sh:property [
125
+ sh:path schema:price ;
126
+ sh:minCount 1 ;
127
+ ] ;
128
+ sh:property [
129
+ sh:path schema:priceCurrency ;
130
+ sh:minCount 1 ;
131
+ ] ;
132
+ sh:property [
133
+ sh:path schema:priceSpecification ;
134
+ sh:minCount 1 ;
135
+ ] ;
136
+ sh:property [
137
+ sh:path schema:availability ;
138
+ sh:minCount 1 ;
139
+ sh:severity sh:Warning ;
140
+ sh:message "Recommended by Google: availability." ;
141
+ ] ;
142
+ sh:property [
143
+ sh:path schema:hasMerchantReturnPolicy ;
144
+ sh:minCount 1 ;
145
+ sh:severity sh:Warning ;
146
+ sh:message "Recommended by Google: hasMerchantReturnPolicy." ;
147
+ ] ;
148
+ sh:property [
149
+ sh:path schema:itemCondition ;
150
+ sh:minCount 1 ;
151
+ sh:severity sh:Warning ;
152
+ sh:message "Recommended by Google: itemCondition." ;
153
+ ] ;
154
+ sh:property [
155
+ sh:path schema:shippingDetails ;
156
+ sh:minCount 1 ;
157
+ sh:severity sh:Warning ;
158
+ sh:message "Recommended by Google: shippingDetails." ;
159
+ ] ;
160
+ sh:property [
161
+ sh:path schema:url ;
162
+ sh:minCount 1 ;
163
+ sh:severity sh:Warning ;
164
+ sh:message "Recommended by Google: url." ;
165
+ ] ;
166
+ ] ;
168
167
  ] ;
169
168
  sh:property [
170
169
  sh:path schema:aggregateRating ;
@@ -179,10 +178,10 @@
179
178
  sh:message "Recommended by Google: audience." ;
180
179
  ] ;
181
180
  sh:property [
182
- sh:path schema:brand ;
181
+ sh:path ( schema:brand schema:name ) ;
183
182
  sh:minCount 1 ;
184
183
  sh:severity sh:Warning ;
185
- sh:message "Recommended by Google: brand." ;
184
+ sh:message "Recommended by Google: brand.name." ;
186
185
  ] ;
187
186
  sh:property [
188
187
  sh:path schema:color ;